This moves the code around so that we can avoid a dozen
forward-declarations, then move the few remaining ones above the
table that use them. No semantic changes.

Signed-off-by: Linus Walleij <[email protected]>
---
 drivers/block/xd.c | 801 +++++++++++++++++++++++++++--------------------------
 drivers/block/xd.h |  33 ---
 2 files changed, 415 insertions(+), 419 deletions(-)

diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index 9e00753..ffa6e76 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -121,6 +121,20 @@ static struct xd_info xd_info[XD_MAXDRIVES];
 #define xd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
 static char *xd_dma_buffer;
 
+/* card specific setup and geometry gathering code */
+static void xd_dtc_init_controller (unsigned int address);
+static void xd_dtc5150cx_init_drive (u_char drive);
+static void xd_dtc_init_drive (u_char drive);
+static void xd_wd_init_controller (unsigned int address);
+static void xd_wd_init_drive (u_char drive);
+static void xd_seagate_init_controller (unsigned int address);
+static void xd_seagate_init_drive (u_char drive);
+static void xd_omti_init_controller (unsigned int address);
+static void xd_omti_init_drive (u_char drive);
+static void xd_xebec_init_controller (unsigned int address);
+static void xd_xebec_init_drive (u_char drive);
+static void xd_override_init_drive (u_char drive);
+
 static struct xd_signature xd_sigs[] __initdata = {
        { 0x0000,"Override geometry handler",NULL,xd_override_init_drive,"n 
unknown" }, /* Pat Mackinlay, [email protected] */
        { 0x0008,"[BXD06 (C) DTC 
17-MAY-1985]",xd_dtc_init_controller,xd_dtc5150cx_init_drive," DTC 5150CX" }, 
/* Andrzej Krzysztofowicz, [email protected] */
@@ -150,13 +164,6 @@ static DEFINE_SPINLOCK(xd_lock);
 
 static struct gendisk *xd_gendisk[2];
 
-static int xd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
-
-static const struct block_device_operations xd_fops = {
-       .owner  = THIS_MODULE,
-       .ioctl  = xd_ioctl,
-       .getgeo = xd_getgeo,
-};
 static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int);
 static u_char xd_drives, xd_irq = 5, xd_dma = 3, xd_maxsectors;
 static u_char xd_override __initdata = 0, xd_type __initdata = 0;
@@ -171,251 +178,206 @@ static bool nodma = XD_DONT_USE_DMA;
 
 static struct request_queue *xd_queue;
 
-/* xd_init: register the block device number and set up pointer tables */
-static int __init xd_init(void)
+/**
+ * xd_setup_dma() - set up the DMA controller for a data transfer
+ */
+static u_char xd_setup_dma(u_char mode, u_char *buffer, u_int count)
 {
-       u_char i,controller;
-       unsigned int address;
-       int err;
+       unsigned long f;
 
-#ifdef MODULE
-       {
-               u_char count = 0;
-               for (i = 4; i > 0; i--)
-                       if (((xd[i] = xd[i-1]) >= 0) && !count)
-                               count = i;
-               if ((xd[0] = count))
-                       do_xd_setup(xd);
+       if (nodma)
+               return (PIO_MODE);
+       if (((unsigned long) buffer & 0xFFFF0000) != (((unsigned long) buffer + 
count) & 0xFFFF0000)) {
+#ifdef DEBUG_OTHER
+               printk("xd_setup_dma: using PIO, transfer overlaps 64k 
boundary\n");
+#endif /* DEBUG_OTHER */
+               return (PIO_MODE);
        }
-#endif
 
-       init_timer (&xd_watchdog_int); xd_watchdog_int.function = xd_watchdog;
-
-       err = -EBUSY;
-       if (register_blkdev(XT_DISK_MAJOR, "xd"))
-               goto out1;
+       f=claim_dma_lock();
+       disable_dma(xd_dma);
+       clear_dma_ff(xd_dma);
+       set_dma_mode(xd_dma,mode);
+       set_dma_addr(xd_dma, (unsigned long) buffer);
+       set_dma_count(xd_dma,count);
 
-       err = -ENOMEM;
-       xd_queue = blk_init_queue(do_xd_request, &xd_lock);
-       if (!xd_queue)
-               goto out1a;
+       release_dma_lock(f);
 
-       if (xd_detect(&controller,&address)) {
+       return (DMA_MODE); /* use DMA and INT */
+}
 
-               printk("Detected a%s controller (type %d) at address %06x\n",
-                       xd_sigs[controller].name,controller,address);
-               if (!request_region(xd_iobase,4,"xd")) {
-                       printk("xd: Ports at 0x%x are not available\n",
-                               xd_iobase);
-                       goto out2;
-               }
-               if (controller)
-                       xd_sigs[controller].init_controller(address);
-               xd_drives = xd_initdrives(xd_sigs[controller].init_drive);
+/**
+ * xd_build() - put stuff into an array in a format suitable for
+ * the controller
+ */
+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)
+{
+       cmdblk[0] = command;
+       cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F);
+       cmdblk[2] = ((cylinder & 0x300) >> 2) | (sector & 0x3F);
+       cmdblk[3] = cylinder & 0xFF;
+       cmdblk[4] = count;
+       cmdblk[5] = control;
 
-               printk("Detected %d hard drive%s (using IRQ%d & DMA%d)\n",
-                       xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma);
-       }
+       return (cmdblk);
+}
 
-       /*
-        * With the drive detected, xd_maxsectors should now be known.
-        * If xd_maxsectors is 0, nothing was detected and we fall through
-        * to return -ENODEV
-        */
-       if (!xd_dma_buffer && xd_maxsectors) {
-               xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
-               if (!xd_dma_buffer) {
-                       printk(KERN_ERR "xd: Out of memory.\n");
-                       goto out3;
-               }
-       }
+/**
+ * xd_waitport() - waits until port & mask == flags or a timeout occurs.
+ * return 1 for a timeout
+ */
+static inline u_char xd_waitport(u_short port, u_char flags,
+                                u_char mask, u_long timeout)
+{
+       u_long expiry = jiffies + timeout;
+       int success;
 
-       err = -ENODEV;
-       if (!xd_drives)
-               goto out3;
+       xdc_busy = 1;
+       while ((success = ((inb(port) & mask) != flags)) && 
time_before(jiffies, expiry))
+               schedule_timeout_uninterruptible(1);
+       xdc_busy = 0;
+       return (success);
+}
 
-       for (i = 0; i < xd_drives; i++) {
-               struct xd_info *p = &xd_info[i];
-               struct gendisk *disk = alloc_disk(64);
-               if (!disk)
-                       goto Enomem;
-               p->unit = i;
-               disk->major = XT_DISK_MAJOR;
-               disk->first_minor = i<<6;
-               sprintf(disk->disk_name, "xd%c", i+'a');
-               disk->fops = &xd_fops;
-               disk->private_data = p;
-               disk->queue = xd_queue;
-               set_capacity(disk, p->heads * p->cylinders * p->sectors);
-               printk(" %s: CHS=%d/%d/%d\n", disk->disk_name,
-                       p->cylinders, p->heads, p->sectors);
-               xd_gendisk[i] = disk;
-       }
+static inline u_int xd_wait_for_IRQ(void)
+{
+       unsigned long flags;
+       xd_watchdog_int.expires = jiffies + 30 * HZ;
+       add_timer(&xd_watchdog_int);
 
-       err = -EBUSY;
-       if (request_irq(xd_irq,xd_interrupt_handler, 0, "XT hard disk", NULL)) {
-               printk("xd: unable to get IRQ%d\n",xd_irq);
-               goto out4;
-       }
+       flags = claim_dma_lock();
+       enable_dma(xd_dma);
+       release_dma_lock(flags);
 
-       if (request_dma(xd_dma,"xd")) {
-               printk("xd: unable to get DMA%d\n",xd_dma);
-               goto out5;
-       }
+       sleep_on(&xd_wait_int);
+       del_timer(&xd_watchdog_int);
+       xdc_busy = 0;
 
-       /* xd_maxsectors depends on controller - so set after detection */
-       blk_queue_max_hw_sectors(xd_queue, xd_maxsectors);
+       flags = claim_dma_lock();
+       disable_dma(xd_dma);
+       release_dma_lock(flags);
 
-       for (i = 0; i < xd_drives; i++)
-               add_disk(xd_gendisk[i]);
+       if (xd_error) {
+               printk("xd: missed IRQ - command aborted\n");
+               xd_error = 0;
+               return (1);
+       }
+       return (0);
+}
 
-       return 0;
+/**
+ * xd_command() - handle all data transfers necessary for a single command
+ */
+static u_int xd_command(u_char *command, u_char mode, u_char *indata,
+                       u_char *outdata, u_char *sense, u_long timeout)
+{
+       u_char cmdblk[6], csb, complete = 0;
 
-out5:
-       free_irq(xd_irq, NULL);
-out4:
-       for (i = 0; i < xd_drives; i++)
-               put_disk(xd_gendisk[i]);
-out3:
-       if (xd_maxsectors)
-               release_region(xd_iobase,4);
+#ifdef DEBUG_COMMAND
+       printk("xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata 
= 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
+#endif /* DEBUG_COMMAND */
 
-       if (xd_dma_buffer)
-               xd_dma_mem_free((unsigned long)xd_dma_buffer,
-                               xd_maxsectors * 0x200);
-out2:
-       blk_cleanup_queue(xd_queue);
-out1a:
-       unregister_blkdev(XT_DISK_MAJOR, "xd");
-out1:
-       return err;
-Enomem:
-       err = -ENOMEM;
-       while (i--)
-               put_disk(xd_gendisk[i]);
-       goto out3;
-}
+       outb(0,XD_SELECT);
+       udelay(OUTB_DELAY);
+       outb(mode,XD_CONTROL);
+       udelay(OUTB_DELAY);
 
-/* xd_detect: scan the possible BIOS ROM locations for the signature strings */
-static u_char __init xd_detect(u_char *controller, unsigned int *address)
-{
-       int i, j;
+       if (xd_waitport(XD_STATUS,STAT_SELECT,STAT_SELECT,timeout))
+               return (1);
 
-       if (xd_override)
-       {
-               *controller = xd_type;
-               *address = 0;
-               return(1);
-       }
+       while (!complete) {
+               if (xd_waitport(XD_STATUS,STAT_READY,STAT_READY,timeout))
+                       return (1);
 
-       for (i = 0; i < ARRAY_SIZE(xd_bases); i++) {
-               void __iomem *p = ioremap(xd_bases[i], 0x2000);
-               if (!p)
-                       continue;
-               for (j = 1; j < ARRAY_SIZE(xd_sigs); j++) {
-                       const char *s = xd_sigs[j].string;
-                       if (check_signature(p + xd_sigs[j].offset, s, 
strlen(s))) {
-                               *controller = j;
-                               xd_type = j;
-                               *address = xd_bases[i];
-                               iounmap(p);
-                               return 1;
-                       }
+               switch (inb(XD_STATUS) & (STAT_COMMAND | STAT_INPUT)) {
+                       case 0:
+                               if (mode == DMA_MODE) {
+                                       if (xd_wait_for_IRQ())
+                                               return (1);
+                               } else {
+                                       outb(outdata ? *outdata++ : 0,XD_DATA);
+                                       udelay(OUTB_DELAY);
+                               }
+                               break;
+                       case STAT_INPUT:
+                               if (mode == DMA_MODE) {
+                                       if (xd_wait_for_IRQ())
+                                               return (1);
+                               } else
+                                       if (indata)
+                                               *indata++ = inb(XD_DATA);
+                                       else
+                                               inb(XD_DATA);
+                               break;
+                       case STAT_COMMAND:
+                               outb(command ? *command++ : 0,XD_DATA);
+                               udelay(OUTB_DELAY);
+                               break;
+                       case STAT_COMMAND | STAT_INPUT:
+                               complete = 1;
+                               break;
                }
-               iounmap(p);
        }
-       return 0;
-}
+       csb = inb(XD_DATA);
 
-/* do_xd_request: handle an incoming request */
-static void do_xd_request(struct request_queue * q)
-{
-       struct request *req;
+       if (xd_waitport(XD_STATUS,0,STAT_SELECT,timeout))                       
                /* wait until deselected */
+               return (1);
 
-       if (xdc_busy)
-               return;
+       if (csb & CSB_ERROR) {                                                  
                /* read sense data if error */
+               xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0);
+               if (xd_command(cmdblk,0,sense,NULL,NULL,XD_TIMEOUT))
+                       printk("xd: warning! sense command failed!\n");
+       }
 
-       req = blk_fetch_request(q);
-       while (req) {
-               unsigned block = blk_rq_pos(req);
-               unsigned count = blk_rq_cur_sectors(req);
-               struct xd_info *disk = req->rq_disk->private_data;
-               int res = 0;
-               int retry;
+#ifdef DEBUG_COMMAND
+       printk("xd_command: completed with csb = 0x%X\n",csb);
+#endif /* DEBUG_COMMAND */
 
-               if (req->cmd_type != REQ_TYPE_FS) {
-                       pr_err("unsupported request: %d\n", req->cmd_type);
-                       res = -EIO;
-                       goto done;
-               }
-               if (block + count > get_capacity(req->rq_disk)) {
-                       pr_err("request beyond device capacity\n");
-                       res = -EIO;
-                       goto done;
-               }
-               for (retry = 0; (retry < XD_RETRIES) && !res; retry++)
-                       res = xd_readwrite(rq_data_dir(req), disk, req->buffer,
-                                          block, count);
-       done:
-               /* wrap up, 0 = success, -errno = fail */
-               if (!__blk_end_request_cur(req, res))
-                       req = blk_fetch_request(q);
-       }
+       return (csb & CSB_ERROR);
 }
 
-static int xd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+/**
+ * xd_setparam() - set the drive characteristics
+ */
+static void __init xd_setparam (u_char command, u_char drive, u_char heads,
+                               u_short cylinders, u_short rwrite,
+                               u_short wprecomp, u_char ecc)
 {
-       struct xd_info *p = bdev->bd_disk->private_data;
+       u_char cmdblk[14];
 
-       geo->heads = p->heads;
-       geo->sectors = p->sectors;
-       geo->cylinders = p->cylinders;
-       return 0;
-}
+       xd_build(cmdblk,command,drive,0,0,0,0,0);
+       cmdblk[6] = (u_char) (cylinders >> 8) & 0x03;
+       cmdblk[7] = (u_char) (cylinders & 0xFF);
+       cmdblk[8] = heads & 0x1F;
+       cmdblk[9] = (u_char) (rwrite >> 8) & 0x03;
+       cmdblk[10] = (u_char) (rwrite & 0xFF);
+       cmdblk[11] = (u_char) (wprecomp >> 8) & 0x03;
+       cmdblk[12] = (u_char) (wprecomp & 0xFF);
+       cmdblk[13] = ecc;
 
-/* xd_ioctl: handle device ioctl's */
-static int xd_locked_ioctl(struct block_device *bdev, fmode_t mode,
-                          u_int cmd, u_long arg)
-{
-       switch (cmd) {
-               case HDIO_SET_DMA:
-                       if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-                       if (xdc_busy) return -EBUSY;
-                       nodma = !arg;
-                       if (nodma && xd_dma_buffer) {
-                               xd_dma_mem_free((unsigned long)xd_dma_buffer,
-                                               xd_maxsectors * 0x200);
-                               xd_dma_buffer = NULL;
-                       } else if (!nodma && !xd_dma_buffer) {
-                               xd_dma_buffer = (char 
*)xd_dma_mem_alloc(xd_maxsectors * 0x200);
-                               if (!xd_dma_buffer) {
-                                       nodma = XD_DONT_USE_DMA;
-                                       return -ENOMEM;
-                               }
-                       }
-                       return 0;
-               case HDIO_GET_DMA:
-                       return put_user(!nodma, (long __user *) arg);
-               case HDIO_GET_MULTCOUNT:
-                       return put_user(xd_maxsectors, (long __user *) arg);
-               default:
-                       return -EINVAL;
-       }
+       /* Some controllers require geometry info as data, not command */
+       if (xd_command(cmdblk,PIO_MODE,NULL,&cmdblk[6],NULL,XD_TIMEOUT * 2))
+               printk("xd: error setting characteristics for xd%c\n", 
'a'+drive);
 }
 
-static int xd_ioctl(struct block_device *bdev, fmode_t mode,
-                   unsigned int cmd, unsigned long param)
+/**
+ * xd_recalibrate() - recalibrate a given drive and reset controller if
+ * necessary
+ */
+static void xd_recalibrate(u_char drive)
 {
-       int ret;
-
-       mutex_lock(&xd_mutex);
-       ret = xd_locked_ioctl(bdev, mode, cmd, param);
-       mutex_unlock(&xd_mutex);
+       u_char cmdblk[6];
 
-       return ret;
+       xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0);
+       if (xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 8))
+               printk("xd%c: warning! error recalibrating, controller may be 
unstable\n", 'a'+drive);
 }
 
-/* xd_readwrite: handle a read/write request */
+/**
+ * xd_readwrite() - handle a read/write request
+ */
 static int xd_readwrite(u_char operation, struct xd_info *p, char *buffer,
                        u_int block, u_int count)
 {
@@ -496,187 +458,154 @@ static int xd_readwrite(u_char operation, struct 
xd_info *p, char *buffer,
        return 0;
 }
 
-/* xd_recalibrate: recalibrate a given drive and reset controller if necessary 
*/
-static void xd_recalibrate(u_char drive)
+/* xd_detect: scan the possible BIOS ROM locations for the signature strings */
+static u_char __init xd_detect(u_char *controller, unsigned int *address)
 {
-       u_char cmdblk[6];
+       int i, j;
 
-       xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0);
-       if (xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 8))
-               printk("xd%c: warning! error recalibrating, controller may be 
unstable\n", 'a'+drive);
-}
+       if (xd_override)
+       {
+               *controller = xd_type;
+               *address = 0;
+               return(1);
+       }
 
-/* xd_interrupt_handler: interrupt service routine */
-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
-               printk("xd_interrupt_handler: interrupt detected\n");
-#endif /* DEBUG_OTHER */
-               outb(0,XD_CONTROL); /* acknowledge interrupt */
-               udelay(OUTB_DELAY);
-               wake_up(&xd_wait_int);  /* and wake up sleeping processes */
-               return IRQ_HANDLED;
+       for (i = 0; i < ARRAY_SIZE(xd_bases); i++) {
+               void __iomem *p = ioremap(xd_bases[i], 0x2000);
+               if (!p)
+                       continue;
+               for (j = 1; j < ARRAY_SIZE(xd_sigs); j++) {
+                       const char *s = xd_sigs[j].string;
+                       if (check_signature(p + xd_sigs[j].offset, s, 
strlen(s))) {
+                               *controller = j;
+                               xd_type = j;
+                               *address = xd_bases[i];
+                               iounmap(p);
+                               return 1;
+                       }
+               }
+               iounmap(p);
        }
-       else
-               printk("xd: unexpected interrupt\n");
-       return IRQ_NONE;
+       return 0;
 }
 
-/* xd_setup_dma: set up the DMA controller for a data transfer */
-static u_char xd_setup_dma(u_char mode, u_char *buffer, u_int count)
+/* do_xd_request: handle an incoming request */
+static void do_xd_request(struct request_queue * q)
 {
-       unsigned long f;
-
-       if (nodma)
-               return (PIO_MODE);
-       if (((unsigned long) buffer & 0xFFFF0000) != (((unsigned long) buffer + 
count) & 0xFFFF0000)) {
-#ifdef DEBUG_OTHER
-               printk("xd_setup_dma: using PIO, transfer overlaps 64k 
boundary\n");
-#endif /* DEBUG_OTHER */
-               return (PIO_MODE);
-       }
+       struct request *req;
 
-       f=claim_dma_lock();
-       disable_dma(xd_dma);
-       clear_dma_ff(xd_dma);
-       set_dma_mode(xd_dma,mode);
-       set_dma_addr(xd_dma, (unsigned long) buffer);
-       set_dma_count(xd_dma,count);
+       if (xdc_busy)
+               return;
 
-       release_dma_lock(f);
+       req = blk_fetch_request(q);
+       while (req) {
+               unsigned block = blk_rq_pos(req);
+               unsigned count = blk_rq_cur_sectors(req);
+               struct xd_info *disk = req->rq_disk->private_data;
+               int res = 0;
+               int retry;
 
-       return (DMA_MODE); /* use DMA and INT */
+               if (req->cmd_type != REQ_TYPE_FS) {
+                       pr_err("unsupported request: %d\n", req->cmd_type);
+                       res = -EIO;
+                       goto done;
+               }
+               if (block + count > get_capacity(req->rq_disk)) {
+                       pr_err("request beyond device capacity\n");
+                       res = -EIO;
+                       goto done;
+               }
+               for (retry = 0; (retry < XD_RETRIES) && !res; retry++)
+                       res = xd_readwrite(rq_data_dir(req), disk, req->buffer,
+                                          block, count);
+       done:
+               /* wrap up, 0 = success, -errno = fail */
+               if (!__blk_end_request_cur(req, res))
+                       req = blk_fetch_request(q);
+       }
 }
 
-/* xd_build: put stuff into an array in a format suitable for the controller */
-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 int xd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-       cmdblk[0] = command;
-       cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F);
-       cmdblk[2] = ((cylinder & 0x300) >> 2) | (sector & 0x3F);
-       cmdblk[3] = cylinder & 0xFF;
-       cmdblk[4] = count;
-       cmdblk[5] = control;
-
-       return (cmdblk);
-}
+       struct xd_info *p = bdev->bd_disk->private_data;
 
-static void xd_watchdog(unsigned long unused)
-{
-       xd_error = 1;
-       wake_up(&xd_wait_int);
+       geo->heads = p->heads;
+       geo->sectors = p->sectors;
+       geo->cylinders = p->cylinders;
+       return 0;
 }
 
-/* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 
for a timeout */
-static inline u_char xd_waitport(u_short port, u_char flags,
-                                u_char mask, u_long timeout)
+static int xd_locked_ioctl(struct block_device *bdev, fmode_t mode,
+                          u_int cmd, u_long arg)
 {
-       u_long expiry = jiffies + timeout;
-       int success;
-
-       xdc_busy = 1;
-       while ((success = ((inb(port) & mask) != flags)) && 
time_before(jiffies, expiry))
-               schedule_timeout_uninterruptible(1);
-       xdc_busy = 0;
-       return (success);
+       switch (cmd) {
+               case HDIO_SET_DMA:
+                       if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+                       if (xdc_busy) return -EBUSY;
+                       nodma = !arg;
+                       if (nodma && xd_dma_buffer) {
+                               xd_dma_mem_free((unsigned long)xd_dma_buffer,
+                                               xd_maxsectors * 0x200);
+                               xd_dma_buffer = NULL;
+                       } else if (!nodma && !xd_dma_buffer) {
+                               xd_dma_buffer = (char 
*)xd_dma_mem_alloc(xd_maxsectors * 0x200);
+                               if (!xd_dma_buffer) {
+                                       nodma = XD_DONT_USE_DMA;
+                                       return -ENOMEM;
+                               }
+                       }
+                       return 0;
+               case HDIO_GET_DMA:
+                       return put_user(!nodma, (long __user *) arg);
+               case HDIO_GET_MULTCOUNT:
+                       return put_user(xd_maxsectors, (long __user *) arg);
+               default:
+                       return -EINVAL;
+       }
 }
 
-static inline u_int xd_wait_for_IRQ(void)
+/**
+ * xd_ioctl() - handle device ioctl's
+ */
+static int xd_ioctl(struct block_device *bdev, fmode_t mode,
+                   unsigned int cmd, unsigned long param)
 {
-       unsigned long flags;
-       xd_watchdog_int.expires = jiffies + 30 * HZ;
-       add_timer(&xd_watchdog_int);
+       int ret;
 
-       flags=claim_dma_lock();
-       enable_dma(xd_dma);
-       release_dma_lock(flags);
+       mutex_lock(&xd_mutex);
+       ret = xd_locked_ioctl(bdev, mode, cmd, param);
+       mutex_unlock(&xd_mutex);
 
-       sleep_on(&xd_wait_int);
-       del_timer(&xd_watchdog_int);
-       xdc_busy = 0;
+       return ret;
+}
 
-       flags=claim_dma_lock();
-       disable_dma(xd_dma);
-       release_dma_lock(flags);
+static const struct block_device_operations xd_fops = {
+       .owner  = THIS_MODULE,
+       .ioctl  = xd_ioctl,
+       .getgeo = xd_getgeo,
+};
 
-       if (xd_error) {
-               printk("xd: missed IRQ - command aborted\n");
-               xd_error = 0;
-               return (1);
+/* xd_interrupt_handler: interrupt service routine */
+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
+               printk("xd_interrupt_handler: interrupt detected\n");
+#endif /* DEBUG_OTHER */
+               outb(0,XD_CONTROL); /* acknowledge interrupt */
+               udelay(OUTB_DELAY);
+               wake_up(&xd_wait_int);  /* and wake up sleeping processes */
+               return IRQ_HANDLED;
        }
-       return (0);
+       else
+               printk("xd: unexpected interrupt\n");
+       return IRQ_NONE;
 }
 
-/* xd_command: handle all data transfers necessary for a single command */
-static u_int xd_command(u_char *command, u_char mode, u_char *indata,
-                       u_char *outdata, u_char *sense, u_long timeout)
+static void xd_watchdog(unsigned long unused)
 {
-       u_char cmdblk[6], csb, complete = 0;
-
-#ifdef DEBUG_COMMAND
-       printk("xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata 
= 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
-#endif /* DEBUG_COMMAND */
-
-       outb(0,XD_SELECT);
-       udelay(OUTB_DELAY);
-       outb(mode,XD_CONTROL);
-       udelay(OUTB_DELAY);
-
-       if (xd_waitport(XD_STATUS,STAT_SELECT,STAT_SELECT,timeout))
-               return (1);
-
-       while (!complete) {
-               if (xd_waitport(XD_STATUS,STAT_READY,STAT_READY,timeout))
-                       return (1);
-
-               switch (inb(XD_STATUS) & (STAT_COMMAND | STAT_INPUT)) {
-                       case 0:
-                               if (mode == DMA_MODE) {
-                                       if (xd_wait_for_IRQ())
-                                               return (1);
-                               } else {
-                                       outb(outdata ? *outdata++ : 0,XD_DATA);
-                                       udelay(OUTB_DELAY);
-                               }
-                               break;
-                       case STAT_INPUT:
-                               if (mode == DMA_MODE) {
-                                       if (xd_wait_for_IRQ())
-                                               return (1);
-                               } else
-                                       if (indata)
-                                               *indata++ = inb(XD_DATA);
-                                       else
-                                               inb(XD_DATA);
-                               break;
-                       case STAT_COMMAND:
-                               outb(command ? *command++ : 0,XD_DATA);
-                               udelay(OUTB_DELAY);
-                               break;
-                       case STAT_COMMAND | STAT_INPUT:
-                               complete = 1;
-                               break;
-               }
-       }
-       csb = inb(XD_DATA);
-
-       if (xd_waitport(XD_STATUS,0,STAT_SELECT,timeout))                       
                /* wait until deselected */
-               return (1);
-
-       if (csb & CSB_ERROR) {                                                  
                /* read sense data if error */
-               xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0);
-               if (xd_command(cmdblk,0,sense,NULL,NULL,XD_TIMEOUT))
-                       printk("xd: warning! sense command failed!\n");
-       }
-
-#ifdef DEBUG_COMMAND
-       printk("xd_command: completed with csb = 0x%X\n",csb);
-#endif /* DEBUG_COMMAND */
-
-       return (csb & CSB_ERROR);
+       xd_error = 1;
+       wake_up(&xd_wait_int);
 }
 
 static u_char __init xd_initdrives(void (*init_drive)(u_char drive))
@@ -1083,29 +1012,129 @@ static void __init do_xd_setup(int *integers)
        xd_maxsectors = 0x01;
 }
 
-/**
- * xd_setparam() - set the drive characteristics
- */
-static void __init xd_setparam (u_char command, u_char drive, u_char heads,
-                               u_short cylinders, u_short rwrite,
-                               u_short wprecomp, u_char ecc)
+/* xd_init: register the block device number and set up pointer tables */
+static int __init xd_init(void)
 {
-       u_char cmdblk[14];
+       u_char i,controller;
+       unsigned int address;
+       int err;
 
-       xd_build(cmdblk,command,drive,0,0,0,0,0);
-       cmdblk[6] = (u_char) (cylinders >> 8) & 0x03;
-       cmdblk[7] = (u_char) (cylinders & 0xFF);
-       cmdblk[8] = heads & 0x1F;
-       cmdblk[9] = (u_char) (rwrite >> 8) & 0x03;
-       cmdblk[10] = (u_char) (rwrite & 0xFF);
-       cmdblk[11] = (u_char) (wprecomp >> 8) & 0x03;
-       cmdblk[12] = (u_char) (wprecomp & 0xFF);
-       cmdblk[13] = ecc;
+#ifdef MODULE
+       {
+               u_char count = 0;
+               for (i = 4; i > 0; i--)
+                       if (((xd[i] = xd[i-1]) >= 0) && !count)
+                               count = i;
+               if ((xd[0] = count))
+                       do_xd_setup(xd);
+       }
+#endif
 
-       /* Some controllers require geometry info as data, not command */
+       init_timer (&xd_watchdog_int); xd_watchdog_int.function = xd_watchdog;
 
-       if (xd_command(cmdblk,PIO_MODE,NULL,&cmdblk[6],NULL,XD_TIMEOUT * 2))
-               printk("xd: error setting characteristics for xd%c\n", 
'a'+drive);
+       err = -EBUSY;
+       if (register_blkdev(XT_DISK_MAJOR, "xd"))
+               goto out1;
+
+       err = -ENOMEM;
+       xd_queue = blk_init_queue(do_xd_request, &xd_lock);
+       if (!xd_queue)
+               goto out1a;
+
+       if (xd_detect(&controller,&address)) {
+
+               printk("Detected a%s controller (type %d) at address %06x\n",
+                       xd_sigs[controller].name,controller,address);
+               if (!request_region(xd_iobase,4,"xd")) {
+                       printk("xd: Ports at 0x%x are not available\n",
+                               xd_iobase);
+                       goto out2;
+               }
+               if (controller)
+                       xd_sigs[controller].init_controller(address);
+               xd_drives = xd_initdrives(xd_sigs[controller].init_drive);
+
+               printk("Detected %d hard drive%s (using IRQ%d & DMA%d)\n",
+                       xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma);
+       }
+
+       /*
+        * With the drive detected, xd_maxsectors should now be known.
+        * If xd_maxsectors is 0, nothing was detected and we fall through
+        * to return -ENODEV
+        */
+       if (!xd_dma_buffer && xd_maxsectors) {
+               xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
+               if (!xd_dma_buffer) {
+                       printk(KERN_ERR "xd: Out of memory.\n");
+                       goto out3;
+               }
+       }
+
+       err = -ENODEV;
+       if (!xd_drives)
+               goto out3;
+
+       for (i = 0; i < xd_drives; i++) {
+               struct xd_info *p = &xd_info[i];
+               struct gendisk *disk = alloc_disk(64);
+               if (!disk)
+                       goto Enomem;
+               p->unit = i;
+               disk->major = XT_DISK_MAJOR;
+               disk->first_minor = i<<6;
+               sprintf(disk->disk_name, "xd%c", i+'a');
+               disk->fops = &xd_fops;
+               disk->private_data = p;
+               disk->queue = xd_queue;
+               set_capacity(disk, p->heads * p->cylinders * p->sectors);
+               printk(" %s: CHS=%d/%d/%d\n", disk->disk_name,
+                       p->cylinders, p->heads, p->sectors);
+               xd_gendisk[i] = disk;
+       }
+
+       err = -EBUSY;
+       if (request_irq(xd_irq,xd_interrupt_handler, 0, "XT hard disk", NULL)) {
+               printk("xd: unable to get IRQ%d\n",xd_irq);
+               goto out4;
+       }
+
+       if (request_dma(xd_dma,"xd")) {
+               printk("xd: unable to get DMA%d\n",xd_dma);
+               goto out5;
+       }
+
+       /* xd_maxsectors depends on controller - so set after detection */
+       blk_queue_max_hw_sectors(xd_queue, xd_maxsectors);
+
+       for (i = 0; i < xd_drives; i++)
+               add_disk(xd_gendisk[i]);
+
+       return 0;
+
+out5:
+       free_irq(xd_irq, NULL);
+out4:
+       for (i = 0; i < xd_drives; i++)
+               put_disk(xd_gendisk[i]);
+out3:
+       if (xd_maxsectors)
+               release_region(xd_iobase,4);
+
+       if (xd_dma_buffer)
+               xd_dma_mem_free((unsigned long)xd_dma_buffer,
+                               xd_maxsectors * 0x200);
+out2:
+       blk_cleanup_queue(xd_queue);
+out1a:
+       unregister_blkdev(XT_DISK_MAJOR, "xd");
+out1:
+       return err;
+Enomem:
+       err = -ENOMEM;
+       while (i--)
+               put_disk(xd_gendisk[i]);
+       goto out3;
 }
 
 #ifdef MODULE
diff --git a/drivers/block/xd.h b/drivers/block/xd.h
index 40630db..f09a33d 100644
--- a/drivers/block/xd.h
+++ b/drivers/block/xd.h
@@ -98,37 +98,4 @@ struct xd_signature {
        const char *name;
 };
 
-#ifndef MODULE
-static int xd_manual_geo_init (char *command);
-#endif /* MODULE */
-static u_char xd_detect (u_char *controller, unsigned int *address);
-static u_char xd_initdrives (void (*init_drive)(u_char drive));
-
-static void do_xd_request (struct request_queue * q);
-static int xd_ioctl (struct block_device *bdev,fmode_t mode,unsigned int 
cmd,unsigned long arg);
-static int xd_readwrite (u_char operation, struct 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);
-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);
-static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long 
timeout);
-static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char 
*outdata,u_char *sense,u_long timeout);
-
-/* card specific setup and geometry gathering code */
-static void xd_dtc_init_controller (unsigned int address);
-static void xd_dtc5150cx_init_drive (u_char drive);
-static void xd_dtc_init_drive (u_char drive);
-static void xd_wd_init_controller (unsigned int address);
-static void xd_wd_init_drive (u_char drive);
-static void xd_seagate_init_controller (unsigned int address);
-static void xd_seagate_init_drive (u_char drive);
-static void xd_omti_init_controller (unsigned int address);
-static void xd_omti_init_drive (u_char drive);
-static void xd_xebec_init_controller (unsigned int address);
-static void xd_xebec_init_drive (u_char drive);
-static void xd_setparam (u_char command,u_char drive,u_char heads,u_short 
cylinders,u_short rwrite,u_short wprecomp,u_char ecc);
-static void xd_override_init_drive (u_char drive);
-
 #endif /* _LINUX_XD_H */
-- 
1.8.1.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to