From 7d12e780e003f93433d49ce78cfedf4b4c52adc5 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 5 Oct 2006 14:55:46 +0100 Subject: IRQ: Maintain regs pointer globally rather than passing to IRQ handlers Maintain a per-CPU global "struct pt_regs *" variable which can be used instead of passing regs around manually through all ~1800 interrupt handlers in the Linux kernel. The regs pointer is used in few places, but it potentially costs both stack space and code to pass it around. On the FRV arch, removing the regs parameter from all the genirq function results in a 20% speed up of the IRQ exit path (ie: from leaving timer_interrupt() to leaving do_IRQ()). Where appropriate, an arch may override the generic storage facility and do something different with the variable. On FRV, for instance, the address is maintained in GR28 at all times inside the kernel as part of general exception handling. Having looked over the code, it appears that the parameter may be handed down through up to twenty or so layers of functions. Consider a USB character device attached to a USB hub, attached to a USB controller that posts its interrupts through a cascaded auxiliary interrupt controller. A character device driver may want to pass regs to the sysrq handler through the input layer which adds another few layers of parameter passing. I've build this code with allyesconfig for x86_64 and i386. I've runtested the main part of the code on FRV and i386, though I can't test most of the drivers. I've also done partial conversion for powerpc and MIPS - these at least compile with minimal configurations. This will affect all archs. Mostly the changes should be relatively easy. Take do_IRQ(), store the regs pointer at the beginning, saving the old one: struct pt_regs *old_regs = set_irq_regs(regs); And put the old one back at the end: set_irq_regs(old_regs); Don't pass regs through to generic_handle_irq() or __do_IRQ(). In timer_interrupt(), this sort of change will be necessary: - update_process_times(user_mode(regs)); - profile_tick(CPU_PROFILING, regs); + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); I'd like to move update_process_times()'s use of get_irq_regs() into itself, except that i386, alone of the archs, uses something other than user_mode(). Some notes on the interrupt handling in the drivers: (*) input_dev() is now gone entirely. The regs pointer is no longer stored in the input_dev struct. (*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does something different depending on whether it's been supplied with a regs pointer or not. (*) Various IRQ handler function pointers have been moved to type irq_handler_t. Signed-Off-By: David Howells (cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit) --- drivers/block/DAC960.c | 24 ++++++++---------------- drivers/block/DAC960.h | 14 +++++++------- drivers/block/acsi.c | 4 ++-- drivers/block/acsi_slm.c | 4 ++-- drivers/block/amiflop.c | 4 ++-- drivers/block/ataflop.c | 4 ++-- drivers/block/cciss.c | 6 +++--- drivers/block/cpqarray.c | 4 ++-- drivers/block/floppy.c | 4 ++-- drivers/block/ps2esdi.c | 6 ++---- drivers/block/swim3.c | 8 ++++---- drivers/block/swim_iop.c | 4 ++-- drivers/block/sx8.c | 2 +- drivers/block/ub.c | 6 +++--- drivers/block/umem.c | 2 +- drivers/block/xd.c | 3 +-- drivers/block/xd.h | 3 +-- 17 files changed, 45 insertions(+), 57 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index b3f639fbf22..3e8ab84b944 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -2698,8 +2698,7 @@ DAC960_DetectController(struct pci_dev *PCI_Device, { struct DAC960_privdata *privdata = (struct DAC960_privdata *)entry->driver_data; - irqreturn_t (*InterruptHandler)(int, void *, struct pt_regs *) = - privdata->InterruptHandler; + irq_handler_t InterruptHandler = privdata->InterruptHandler; unsigned int MemoryWindowSize = privdata->MemoryWindowSize; DAC960_Controller_T *Controller = NULL; unsigned char DeviceFunction = PCI_Device->devfn; @@ -5253,8 +5252,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command) */ static irqreturn_t DAC960_GEM_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier, - struct pt_regs *InterruptRegisters) + void *DeviceIdentifier) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; @@ -5295,8 +5293,7 @@ static irqreturn_t DAC960_GEM_InterruptHandler(int IRQ_Channel, */ static irqreturn_t DAC960_BA_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier, - struct pt_regs *InterruptRegisters) + void *DeviceIdentifier) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; @@ -5338,8 +5335,7 @@ static irqreturn_t DAC960_BA_InterruptHandler(int IRQ_Channel, */ static irqreturn_t DAC960_LP_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier, - struct pt_regs *InterruptRegisters) + void *DeviceIdentifier) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; @@ -5381,8 +5377,7 @@ static irqreturn_t DAC960_LP_InterruptHandler(int IRQ_Channel, */ static irqreturn_t DAC960_LA_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier, - struct pt_regs *InterruptRegisters) + void *DeviceIdentifier) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; @@ -5420,8 +5415,7 @@ static irqreturn_t DAC960_LA_InterruptHandler(int IRQ_Channel, */ static irqreturn_t DAC960_PG_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier, - struct pt_regs *InterruptRegisters) + void *DeviceIdentifier) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; @@ -5459,8 +5453,7 @@ static irqreturn_t DAC960_PG_InterruptHandler(int IRQ_Channel, */ static irqreturn_t DAC960_PD_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier, - struct pt_regs *InterruptRegisters) + void *DeviceIdentifier) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; @@ -5498,8 +5491,7 @@ static irqreturn_t DAC960_PD_InterruptHandler(int IRQ_Channel, */ static irqreturn_t DAC960_P_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier, - struct pt_regs *InterruptRegisters) + void *DeviceIdentifier) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; void __iomem *ControllerBaseAddress = Controller->BaseAddress; diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h index f9217c34bc2..cec539e601f 100644 --- a/drivers/block/DAC960.h +++ b/drivers/block/DAC960.h @@ -2175,7 +2175,7 @@ static char struct DAC960_privdata { DAC960_HardwareType_T HardwareType; DAC960_FirmwareType_T FirmwareType; - irqreturn_t (*InterruptHandler)(int, void *, struct pt_regs *); + irq_handler_t InterruptHandler; unsigned int MemoryWindowSize; }; @@ -4412,12 +4412,12 @@ static void DAC960_FinalizeController(DAC960_Controller_T *); static void DAC960_V1_QueueReadWriteCommand(DAC960_Command_T *); static void DAC960_V2_QueueReadWriteCommand(DAC960_Command_T *); static void DAC960_RequestFunction(struct request_queue *); -static irqreturn_t DAC960_BA_InterruptHandler(int, void *, struct pt_regs *); -static irqreturn_t DAC960_LP_InterruptHandler(int, void *, struct pt_regs *); -static irqreturn_t DAC960_LA_InterruptHandler(int, void *, struct pt_regs *); -static irqreturn_t DAC960_PG_InterruptHandler(int, void *, struct pt_regs *); -static irqreturn_t DAC960_PD_InterruptHandler(int, void *, struct pt_regs *); -static irqreturn_t DAC960_P_InterruptHandler(int, void *, struct pt_regs *); +static irqreturn_t DAC960_BA_InterruptHandler(int, void *); +static irqreturn_t DAC960_LP_InterruptHandler(int, void *); +static irqreturn_t DAC960_LA_InterruptHandler(int, void *); +static irqreturn_t DAC960_PG_InterruptHandler(int, void *); +static irqreturn_t DAC960_PD_InterruptHandler(int, void *); +static irqreturn_t DAC960_P_InterruptHandler(int, void *); static void DAC960_V1_QueueMonitoringCommand(DAC960_Command_T *); static void DAC960_V2_QueueMonitoringCommand(DAC960_Command_T *); static void DAC960_MonitoringTimerFunction(unsigned long); diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c index 0b80fbb8dbf..706cdc6a69e 100644 --- a/drivers/block/acsi.c +++ b/drivers/block/acsi.c @@ -346,7 +346,7 @@ static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int rwflag, int enable); static int acsi_reqsense( char *buffer, int targ, int lun); static void acsi_print_error(const unsigned char *errblk, struct acsi_info_struct *aip); -static irqreturn_t acsi_interrupt (int irq, void *data, struct pt_regs *fp); +static irqreturn_t acsi_interrupt (int irq, void *data); static void unexpected_acsi_interrupt( void ); static void bad_rw_intr( void ); static void read_intr( void ); @@ -726,7 +726,7 @@ static void acsi_print_error(const unsigned char *errblk, struct acsi_info_struc * *******************************************************************/ -static irqreturn_t acsi_interrupt(int irq, void *data, struct pt_regs *fp ) +static irqreturn_t acsi_interrupt(int irq, void *data ) { void (*acsi_irq_handler)(void) = do_acsi; diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c index 4030a8fd118..8e41c87b026 100644 --- a/drivers/block/acsi_slm.c +++ b/drivers/block/acsi_slm.c @@ -246,7 +246,7 @@ static int slm_getstats( char *buffer, int device ); static ssize_t slm_read( struct file* file, char *buf, size_t count, loff_t *ppos ); static void start_print( int device ); -static irqreturn_t slm_interrupt(int irc, void *data, struct pt_regs *fp); +static irqreturn_t slm_interrupt(int irc, void *data); static void slm_test_ready( unsigned long dummy ); static void set_dma_addr( unsigned long paddr ); static unsigned long get_dma_addr( void ); @@ -452,7 +452,7 @@ static void start_print( int device ) /* Only called when an error happened or at the end of a page */ -static irqreturn_t slm_interrupt(int irc, void *data, struct pt_regs *fp) +static irqreturn_t slm_interrupt(int irc, void *data) { unsigned long addr; int stat; diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 2641597c654..5d254b71450 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -209,7 +209,7 @@ static int fd_device[4] = { 0, 0, 0, 0 }; /* Milliseconds timer */ -static irqreturn_t ms_isr(int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t ms_isr(int irq, void *dummy) { ms_busy = -1; wake_up(&ms_wait); @@ -560,7 +560,7 @@ static unsigned long fd_get_drive_id(int drive) return (id); } -static irqreturn_t fd_block_done(int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t fd_block_done(int irq, void *dummy) { if (block_flag) custom.dsklen = 0x4000; diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index c39650920bd..14d6b949275 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -342,7 +342,7 @@ static void fd_select_drive( int drive ); static void fd_deselect( void ); static void fd_motor_off_timer( unsigned long dummy ); static void check_change( unsigned long dummy ); -static irqreturn_t floppy_irq (int irq, void *dummy, struct pt_regs *fp); +static irqreturn_t floppy_irq (int irq, void *dummy); static void fd_error( void ); static int do_format(int drive, int type, struct atari_format_descr *desc); static void do_fd_action( int drive ); @@ -573,7 +573,7 @@ static inline void copy_buffer(void *from, void *to) static void (*FloppyIRQHandler)( int status ) = NULL; -static irqreturn_t floppy_irq (int irq, void *dummy, struct pt_regs *fp) +static irqreturn_t floppy_irq (int irq, void *dummy) { unsigned char status; void (*handler)( int ); diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 36b88f6c5f8..dcccaf2782f 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -130,7 +130,7 @@ static struct board_type products[] = { static ctlr_info_t *hba[MAX_CTLR]; static void do_cciss_request(request_queue_t *q); -static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t do_cciss_intr(int irq, void *dev_id); static int cciss_open(struct inode *inode, struct file *filep); static int cciss_release(struct inode *inode, struct file *filep); static int cciss_ioctl(struct inode *inode, struct file *filep, @@ -2300,7 +2300,7 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use #ifdef CONFIG_CISS_SCSI_TAPE /* if we saved some commands for later, process them now. */ if (info_p->scsi_rejects.ncompletions > 0) - do_cciss_intr(0, info_p, NULL); + do_cciss_intr(0, info_p); #endif cmd_free(info_p, c, 1); return status; @@ -2652,7 +2652,7 @@ static inline long interrupt_not_for_us(ctlr_info_t *h) #endif } -static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t do_cciss_intr(int irq, void *dev_id) { ctlr_info_t *h = dev_id; CommandList_struct *c; diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index ada68e65b5f..570d2f04932 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -169,7 +169,7 @@ static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c); static inline void complete_buffers(struct bio *bio, int ok); static inline void complete_command(cmdlist_t *cmd, int timeout); -static irqreturn_t do_ida_intr(int irq, void *dev_id, struct pt_regs * regs); +static irqreturn_t do_ida_intr(int irq, void *dev_id); static void ida_timer(unsigned long tdata); static int ida_revalidate(struct gendisk *disk); static int revalidate_allvol(ctlr_info_t *host); @@ -1042,7 +1042,7 @@ static inline void complete_command(cmdlist_t *cmd, int timeout) * Find the command on the completion queue, remove it, tell the OS and * try to queue up more IO */ -static irqreturn_t do_ida_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t do_ida_intr(int irq, void *dev_id) { ctlr_info_t *h = dev_id; cmdlist_t *c; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 629c5769d99..9e6d3a87cbe 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -221,7 +221,7 @@ static DEFINE_SPINLOCK(floppy_lock); static struct completion device_release; static unsigned short virtual_dma_port = 0x3f0; -irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t floppy_interrupt(int irq, void *dev_id); static int set_dor(int fdc, char mask, char data); #define K_64 0x10000 /* 64KB */ @@ -1726,7 +1726,7 @@ static void print_result(char *message, int inr) } /* interrupt handler. Note that this can be called externally on the Sparc */ -irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t floppy_interrupt(int irq, void *dev_id) { void (*handler) (void) = do_floppy; int do_print; diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index 5537974fb24..688a4fb0dc9 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -75,8 +75,7 @@ static int ps2esdi_out_cmd_blk(u_short * cmd_blk); static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode); -static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id, - struct pt_regs *regs); +static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id); static void (*current_int_handler) (u_int) = NULL; static void ps2esdi_normal_interrupt_handler(u_int); static void ps2esdi_initial_reset_int_handler(u_int); @@ -687,8 +686,7 @@ static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode) -static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id) { u_int int_ret_code; diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index fdc8f892eb8..1a65979f1f0 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -238,8 +238,8 @@ static void scan_timeout(unsigned long data); static void seek_timeout(unsigned long data); static void settle_timeout(unsigned long data); static void xfer_timeout(unsigned long data); -static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs); -/*static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs);*/ +static irqreturn_t swim3_interrupt(int irq, void *dev_id); +/*static void fd_dma_interrupt(int irq, void *dev_id);*/ static int grab_drive(struct floppy_state *fs, enum swim_state state, int interruptible); static void release_drive(struct floppy_state *fs); @@ -624,7 +624,7 @@ static void xfer_timeout(unsigned long data) start_request(fs); } -static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t swim3_interrupt(int irq, void *dev_id) { struct floppy_state *fs = (struct floppy_state *) dev_id; struct swim3 __iomem *sw = fs->swim3; @@ -777,7 +777,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs) } /* -static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void fd_dma_interrupt(int irq, void *dev_id) { } */ diff --git a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c index dfda796eba5..ed7b06cf3e6 100644 --- a/drivers/block/swim_iop.c +++ b/drivers/block/swim_iop.c @@ -94,7 +94,7 @@ static char *drive_names[7] = { int swimiop_init(void); static void swimiop_init_request(struct swim_iop_req *); static int swimiop_send_request(struct swim_iop_req *); -static void swimiop_receive(struct iop_msg *, struct pt_regs *); +static void swimiop_receive(struct iop_msg *); static void swimiop_status_update(int, struct swim_drvstatus *); static int swimiop_eject(struct floppy_state *fs); @@ -257,7 +257,7 @@ static int swimiop_send_request(struct swim_iop_req *req) * 2. An unsolicited message was received from the IOP. */ -void swimiop_receive(struct iop_msg *msg, struct pt_regs *regs) +void swimiop_receive(struct iop_msg *msg) { struct swim_iop_req *req; struct swimmsg_status *sm; diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index c6beee18a07..47d6975268f 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -1200,7 +1200,7 @@ static inline void carm_handle_responses(struct carm_host *host) host->resp_idx += work; } -static irqreturn_t carm_interrupt(int irq, void *__host, struct pt_regs *regs) +static irqreturn_t carm_interrupt(int irq, void *__host) { struct carm_host *host = __host; void __iomem *mmio; diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 45a8f402b07..0d5c73f0726 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -362,7 +362,7 @@ static void ub_end_rq(struct request *rq, unsigned int status); static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun, struct ub_request *urq, struct ub_scsi_cmd *cmd); static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static void ub_urb_complete(struct urb *urb, struct pt_regs *pt); +static void ub_urb_complete(struct urb *urb); static void ub_scsi_action(unsigned long _dev); static void ub_scsi_dispatch(struct ub_dev *sc); static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd); @@ -959,7 +959,7 @@ static void ub_urb_timeout(unsigned long arg) * the sc->lock taken) and from an interrupt (while we do NOT have * the sc->lock taken). Therefore, bounce this off to a tasklet. */ -static void ub_urb_complete(struct urb *urb, struct pt_regs *pt) +static void ub_urb_complete(struct urb *urb) { struct ub_dev *sc = urb->context; @@ -1923,7 +1923,7 @@ err_alloc: /* */ -static void ub_probe_urb_complete(struct urb *urb, struct pt_regs *pt) +static void ub_probe_urb_complete(struct urb *urb) { struct completion *cop = urb->context; complete(cop); diff --git a/drivers/block/umem.c b/drivers/block/umem.c index cbb9d0f21ac..30f16bd8365 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -571,7 +571,7 @@ static int mm_make_request(request_queue_t *q, struct bio *bio) -- mm_interrupt ----------------------------------------------------------------------------------- */ -static irqreturn_t mm_interrupt(int irq, void *__card, struct pt_regs *regs) +static irqreturn_t mm_interrupt(int irq, void *__card) { struct cardinfo *card = (struct cardinfo *) __card; unsigned int dma_status; diff --git a/drivers/block/xd.c b/drivers/block/xd.c index ebf3025721d..10cc38783bd 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -462,8 +462,7 @@ static void xd_recalibrate (u_char drive) } /* xd_interrupt_handler: interrupt service routine */ -static irqreturn_t xd_interrupt_handler(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t xd_interrupt_handler(int irq, void *dev_id) { if (inb(XD_STATUS) & STAT_INTERRUPT) { /* check if it was our device */ #ifdef DEBUG_OTHER diff --git a/drivers/block/xd.h b/drivers/block/xd.h index 71ac2e3dffc..82e090fea95 100644 --- a/drivers/block/xd.h +++ b/drivers/block/xd.h @@ -109,8 +109,7 @@ static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsi static int xd_readwrite (u_char operation,XD_INFO *disk,char *buffer,u_int block,u_int count); static void xd_recalibrate (u_char drive); -static irqreturn_t xd_interrupt_handler(int irq, void *dev_id, - struct pt_regs *regs); +static irqreturn_t xd_interrupt_handler(int irq, void *dev_id); static u_char xd_setup_dma (u_char opcode,u_char *buffer,u_int count); static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control); static void xd_watchdog (unsigned long unused); -- cgit v1.2.3-70-g09d2