linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / block / floppy.c
index 70375a0..d23b543 100644 (file)
  * features to asm/floppy.h.
  */
 
+/*
+ * 1998/1/21 -- Richard Gooch <rgooch@atnf.csiro.au> -- devfs support
+ */
+
 /*
  * 1998/05/07 -- Russell King -- More portability cleanups; moved definition of
  * interrupt and dma channel to asm/floppy.h. Cleaned up some formatting &
@@ -155,14 +159,9 @@ static int print_unex = 1;
 #include <linux/kernel.h>
 #include <linux/timer.h>
 #include <linux/workqueue.h>
-#include <linux/version.h>
 #define FDPATCHES
 #include <linux/fdreg.h>
 
-/*
- * 1998/1/21 -- Richard Gooch <rgooch@atnf.csiro.au> -- devfs support
- */
-
 #include <linux/fd.h>
 #include <linux/hdreg.h>
 
@@ -178,7 +177,7 @@ static int print_unex = 1;
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/devfs_fs_kernel.h>
-#include <linux/device.h>
+#include <linux/platform_device.h>
 #include <linux/buffer_head.h> /* for invalidate_buffers() */
 
 /*
@@ -217,7 +216,7 @@ static int use_virtual_dma;
  * record each buffers capabilities
  */
 
-static spinlock_t floppy_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(floppy_lock);
 static struct completion device_release;
 
 static unsigned short virtual_dma_port = 0x3f0;
@@ -243,7 +242,6 @@ static int allowed_drive_mask = 0x33;
 
 static int irqdma_allocated;
 
-#define LOCAL_END_REQUEST
 #define DEVICE_NAME "floppy"
 
 #include <linux/blkdev.h>
@@ -480,7 +478,6 @@ static struct floppy_struct floppy_type[32] = {
        { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5"    */
 };
 
-#define        NUMBER(x)       (sizeof(x) / sizeof(*(x)))
 #define SECTSIZE (_FD_SECTSIZE(*floppy))
 
 /* Auto-detection: Disk type used until the next media change occurs. */
@@ -494,6 +491,8 @@ static struct floppy_struct user_params[N_DRIVE];
 
 static sector_t floppy_sizes[256];
 
+static char floppy_device_name[] = "floppy";
+
 /*
  * The driver is trying to determine the correct media format
  * while probing is set. rw_interrupt() clears it after a
@@ -627,7 +626,7 @@ static inline void debugt(const char *message) { }
 #endif /* DEBUGT */
 
 typedef void (*timeout_fn) (unsigned long);
-static struct timer_list fd_timeout = TIMER_INITIALIZER(floppy_shutdown, 0, 0);
+static DEFINE_TIMER(fd_timeout, floppy_shutdown, 0, 0);
 
 static const char *timeout_message;
 
@@ -922,7 +921,7 @@ static inline void unlock_fdc(void)
 {
        unsigned long flags;
 
-       raw_cmd = 0;
+       raw_cmd = NULL;
        if (!test_bit(0, &fdc_busy))
                DPRINT("FDC access conflict!\n");
 
@@ -1011,7 +1010,7 @@ static void schedule_bh(void (*handler) (void))
        schedule_work(&floppy_work);
 }
 
-static struct timer_list fd_timer = TIMER_INITIALIZER(NULL, 0, 0);
+static DEFINE_TIMER(fd_timer, NULL, 0, 0);
 
 static void cancel_activity(void)
 {
@@ -1073,7 +1072,7 @@ static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
        return 0;
 }
 
-static spinlock_t floppy_hlt_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(floppy_hlt_lock);
 static int hlt_disabled;
 static void floppy_disable_hlt(void)
 {
@@ -1787,10 +1786,11 @@ irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2
                         && max_sensei);
        }
-       if (handler)
-               schedule_bh(handler);
-       else
+       if (!handler) {
                FDCS->reset = 1;
+               return IRQ_NONE;
+       }
+       schedule_bh(handler);
        is_alive("normal interrupt end");
 
        /* FIXME! Was it really for us? */
@@ -2021,7 +2021,7 @@ static void floppy_start(void)
 static void do_wakeup(void)
 {
        reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
-       cont = 0;
+       cont = NULL;
        command_status += 2;
        wake_up(&command_done);
 }
@@ -2299,7 +2299,7 @@ static void floppy_end_request(struct request *req, int uptodate)
        add_disk_randomness(req->rq_disk);
        floppy_off((long)req->rq_disk->private_data);
        blkdev_dequeue_request(req);
-       end_that_request_last(req);
+       end_that_request_last(req, uptodate);
 
        /* We're done with the request */
        current_req = NULL;
@@ -3191,7 +3191,7 @@ static void raw_cmd_free(struct floppy_raw_cmd **ptr)
        struct floppy_raw_cmd *next, *this;
 
        this = *ptr;
-       *ptr = 0;
+       *ptr = NULL;
        while (this) {
                if (this->buffer_length) {
                        fd_dma_mem_free((unsigned long)this->kernel_data,
@@ -3211,7 +3211,7 @@ static inline int raw_cmd_copyin(int cmd, char __user *param,
        int ret;
        int i;
 
-       *rcmd = 0;
+       *rcmd = NULL;
        while (1) {
                ptr = (struct floppy_raw_cmd *)
                    kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
@@ -3219,7 +3219,7 @@ static inline int raw_cmd_copyin(int cmd, char __user *param,
                        return -ENOMEM;
                *rcmd = ptr;
                COPYIN(*ptr);
-               ptr->next = 0;
+               ptr->next = NULL;
                ptr->buffer_length = 0;
                param += sizeof(struct floppy_raw_cmd);
                if (ptr->cmd_count > 33)
@@ -3236,7 +3236,7 @@ static inline int raw_cmd_copyin(int cmd, char __user *param,
                for (i = 0; i < 16; i++)
                        ptr->reply[i] = 0;
                ptr->resultcode = 0;
-               ptr->kernel_data = 0;
+               ptr->kernel_data = NULL;
 
                if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
                        if (ptr->length <= 0)
@@ -3318,11 +3318,6 @@ static int invalidate_drive(struct block_device *bdev)
        return 0;
 }
 
-static inline void clear_write_error(int drive)
-{
-       CLEARSTRUCT(UDRWE);
-}
-
 static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
                               int drive, int type, struct block_device *bdev)
 {
@@ -3350,7 +3345,7 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
                        struct block_device *bdev = opened_bdev[cnt];
                        if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
                                continue;
-                       __invalidate_device(bdev, 0);
+                       __invalidate_device(bdev);
                }
                up(&open_lock);
        } else {
@@ -3448,6 +3443,23 @@ static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
        return 0;
 }
 
+static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+       int drive = (long)bdev->bd_disk->private_data;
+       int type = ITYPE(drive_state[drive].fd_device);
+       struct floppy_struct *g;
+       int ret;
+
+       ret = get_floppy_geometry(drive, type, &g);
+       if (ret)
+               return ret;
+
+       geo->heads = g->head;
+       geo->sectors = g->sect;
+       geo->cylinders = g->track;
+       return 0;
+}
+
 static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                    unsigned long param)
 {
@@ -3477,23 +3489,6 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                cmd = FDEJECT;
        }
 
-       /* generic block device ioctls */
-       switch (cmd) {
-               /* the following have been inspired by the corresponding
-                * code for other block devices. */
-               struct floppy_struct *g;
-       case HDIO_GETGEO:
-               {
-                       struct hd_geometry loc;
-                       ECALL(get_floppy_geometry(drive, type, &g));
-                       loc.heads = g->head;
-                       loc.sectors = g->sect;
-                       loc.cylinders = g->track;
-                       loc.start = 0;
-                       return _COPYOUT(loc);
-               }
-       }
-
        /* convert the old style command into a new style command */
        if ((cmd & 0xff00) == 0x0200) {
                ECALL(normalize_ioctl(&cmd, &size));
@@ -3648,7 +3643,7 @@ static void __init config_types(void)
                const char *name = NULL;
                static char temparea[32];
 
-               if (type < NUMBER(default_drive_params)) {
+               if (type < ARRAY_SIZE(default_drive_params)) {
                        params = &default_drive_params[type].params;
                        if (type) {
                                name = default_drive_params[type].name;
@@ -3773,8 +3768,7 @@ static int floppy_open(struct inode *inode, struct file *filp)
        /* Allow ioctls if we have write-permissions even if read-only open.
         * Needed so that programs such as fdrawcmd still can work on write
         * protected disks */
-       if (filp->f_mode & 2
-           || permission(filp->f_dentry->d_inode, 2, NULL) == 0)
+       if ((filp->f_mode & FMODE_WRITE) || !file_permission(filp, MAY_WRITE))
                filp->private_data = (void *)8;
 
        if (UFDCS->rawcmd == 1)
@@ -3942,6 +3936,7 @@ static struct block_device_operations floppy_fops = {
        .open           = floppy_open,
        .release        = floppy_release,
        .ioctl          = fd_ioctl,
+       .getgeo         = fd_getgeo,
        .media_changed  = check_floppy_change,
        .revalidate_disk = floppy_revalidate,
 };
@@ -3964,7 +3959,7 @@ static void __init register_devfs_entries(int drive)
 {
        int base_minor = (drive < 4) ? drive : (124 + drive);
 
-       if (UDP->cmos < NUMBER(default_drive_params)) {
+       if (UDP->cmos < ARRAY_SIZE(default_drive_params)) {
                int i = 0;
                do {
                        int minor = base_minor + (table_sup[UDP->cmos][i] << 2);
@@ -4124,33 +4119,33 @@ static struct param_table {
        int *var;
        int def_param;
        int param2;
-} config_params[] = {
-       {"allowed_drive_mask", 0, &allowed_drive_mask, 0xff, 0}, /* obsolete */
-       {"all_drives", 0, &allowed_drive_mask, 0xff, 0},        /* obsolete */
-       {"asus_pci", 0, &allowed_drive_mask, 0x33, 0},
-       {"irq", 0, &FLOPPY_IRQ, 6, 0},
-       {"dma", 0, &FLOPPY_DMA, 2, 0},
-       {"daring", daring, 0, 1, 0},
+} config_params[] __initdata = {
+       {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
+       {"all_drives", NULL, &allowed_drive_mask, 0xff, 0},     /* obsolete */
+       {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
+       {"irq", NULL, &FLOPPY_IRQ, 6, 0},
+       {"dma", NULL, &FLOPPY_DMA, 2, 0},
+       {"daring", daring, NULL, 1, 0},
 #if N_FDC > 1
-       {"two_fdc", 0, &FDC2, 0x370, 0},
-       {"one_fdc", 0, &FDC2, 0, 0},
+       {"two_fdc", NULL, &FDC2, 0x370, 0},
+       {"one_fdc", NULL, &FDC2, 0, 0},
 #endif
-       {"thinkpad", floppy_set_flags, 0, 1, FD_INVERTED_DCL},
-       {"broken_dcl", floppy_set_flags, 0, 1, FD_BROKEN_DCL},
-       {"messages", floppy_set_flags, 0, 1, FTD_MSG},
-       {"silent_dcl_clear", floppy_set_flags, 0, 1, FD_SILENT_DCL_CLEAR},
-       {"debug", floppy_set_flags, 0, 1, FD_DEBUG},
-       {"nodma", 0, &can_use_virtual_dma, 1, 0},
-       {"omnibook", 0, &can_use_virtual_dma, 1, 0},
-       {"yesdma", 0, &can_use_virtual_dma, 0, 0},
-       {"fifo_depth", 0, &fifo_depth, 0xa, 0},
-       {"nofifo", 0, &no_fifo, 0x20, 0},
-       {"usefifo", 0, &no_fifo, 0, 0},
-       {"cmos", set_cmos, 0, 0, 0},
-       {"slow", 0, &slow_floppy, 1, 0},
-       {"unexpected_interrupts", 0, &print_unex, 1, 0},
-       {"no_unexpected_interrupts", 0, &print_unex, 0, 0},
-       {"L40SX", 0, &print_unex, 0, 0}
+       {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
+       {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
+       {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
+       {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
+       {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
+       {"nodma", NULL, &can_use_virtual_dma, 1, 0},
+       {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
+       {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
+       {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
+       {"nofifo", NULL, &no_fifo, 0x20, 0},
+       {"usefifo", NULL, &no_fifo, 0, 0},
+       {"cmos", set_cmos, NULL, 0, 0},
+       {"slow", NULL, &slow_floppy, 1, 0},
+       {"unexpected_interrupts", NULL, &print_unex, 1, 0},
+       {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
+       {"L40SX", NULL, &print_unex, 0, 0}
 
        EXTRA_FLOPPY_PARAMS
 };
@@ -4190,24 +4185,30 @@ static int __init floppy_setup(char *str)
                printk("\n");
        } else
                DPRINT("botched floppy option\n");
-       DPRINT("Read linux/Documentation/floppy.txt\n");
+       DPRINT("Read Documentation/floppy.txt\n");
        return 0;
 }
 
 static int have_no_fdc = -ENODEV;
 
+static ssize_t floppy_cmos_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct platform_device *p;
+       int drive;
+
+       p = container_of(dev, struct platform_device,dev);
+       drive = p->id;
+       return sprintf(buf, "%X\n", UDP->cmos);
+}
+DEVICE_ATTR(cmos,S_IRUGO,floppy_cmos_show,NULL);
+
 static void floppy_device_release(struct device *dev)
 {
        complete(&device_release);
 }
 
-static struct platform_device floppy_device = {
-       .name           = "floppy",
-       .id             = 0,
-       .dev            = {
-                       .release = floppy_device_release,
-                       }
-};
+static struct platform_device floppy_device[N_DRIVE];
 
 static struct kobject *floppy_find(dev_t dev, int *part, void *data)
 {
@@ -4216,19 +4217,18 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data)
            !(allowed_drive_mask & (1 << drive)) ||
            fdc_state[FDC(drive)].version == FDC_NONE)
                return NULL;
-       if (((*part >> 2) & 0x1f) >= NUMBER(floppy_type))
+       if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
                return NULL;
        *part = 0;
        return get_disk(disks[drive]);
 }
 
-int __init floppy_init(void)
+static int __init floppy_init(void)
 {
        int i, unit, drive;
        int err, dr;
 
        raw_cmd = NULL;
-       i = 0;
 
        for (dr = 0; dr < N_DRIVE; dr++) {
                disks[dr] = alloc_disk(1);
@@ -4287,6 +4287,13 @@ int __init floppy_init(void)
        }
 
        use_virtual_dma = can_use_virtual_dma & 1;
+#if defined(CONFIG_PPC64)
+       if (check_legacy_ioport(FDC1)) {
+               del_timer(&fd_timeout);
+               err = -ENODEV;
+               goto out_unreg_region;
+       }
+#endif
        fdc_state[0].address = FDC1;
        if (fdc_state[0].address == -1) {
                del_timer(&fd_timeout);
@@ -4316,6 +4323,12 @@ int __init floppy_init(void)
                floppy_track_buffer = NULL;
                max_buffer_sectors = 0;
        }
+       /*
+        * Small 10 msec delay to let through any interrupt that
+        * initialization might have triggered, to not
+        * confuse detection:
+        */
+       msleep(10);
 
        for (i = 0; i < N_FDC; i++) {
                fdc = i;
@@ -4368,27 +4381,26 @@ int __init floppy_init(void)
                        continue;
                if (fdc_state[FDC(drive)].version == FDC_NONE)
                        continue;
+
+               floppy_device[drive].name = floppy_device_name;
+               floppy_device[drive].id = drive;
+               floppy_device[drive].dev.release = floppy_device_release;
+
+               err = platform_device_register(&floppy_device[drive]);
+               if (err)
+                       goto out_flush_work;
+
+               device_create_file(&floppy_device[drive].dev,&dev_attr_cmos);
                /* to be cleaned up... */
                disks[drive]->private_data = (void *)(long)drive;
                disks[drive]->queue = floppy_queue;
                disks[drive]->flags |= GENHD_FL_REMOVABLE;
+               disks[drive]->driverfs_dev = &floppy_device[drive].dev;
                add_disk(disks[drive]);
        }
 
-       err = platform_device_register(&floppy_device);
-       if (err)
-               goto out_del_disk;
-
        return 0;
 
-out_del_disk:
-       for (drive = 0; drive < N_DRIVE; drive++) {
-               if (!(allowed_drive_mask & (1 << drive)))
-                       continue;
-               if (fdc_state[FDC(drive)].version == FDC_NONE)
-                       continue;
-               del_gendisk(disks[drive]);
-       }
 out_flush_work:
        flush_scheduled_work();
        if (usage_count)
@@ -4408,7 +4420,7 @@ out_put_disk:
        return err;
 }
 
-static spinlock_t floppy_usage_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(floppy_usage_lock);
 
 static int floppy_grab_irq_and_dma(void)
 {
@@ -4551,13 +4563,13 @@ static void floppy_release_irq_and_dma(void)
 
 #ifdef MODULE
 
-char *floppy;
+static char *floppy;
 
 static void unregister_devfs_entries(int drive)
 {
        int i;
 
-       if (UDP->cmos < NUMBER(default_drive_params)) {
+       if (UDP->cmos < ARRAY_SIZE(default_drive_params)) {
                i = 0;
                do {
                        devfs_remove("floppy/%d%s", drive,
@@ -4583,8 +4595,6 @@ static void __init parse_floppy_cfg_string(char *cfg)
 
 int init_module(void)
 {
-       printk(KERN_INFO "inserting floppy driver for " UTS_RELEASE "\n");
-
        if (floppy)
                parse_floppy_cfg_string(floppy);
        return floppy_init();
@@ -4595,7 +4605,6 @@ void cleanup_module(void)
        int drive;
 
        init_completion(&device_release);
-       platform_device_unregister(&floppy_device);
        blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
        unregister_blkdev(FLOPPY_MAJOR, "fd");
 
@@ -4606,6 +4615,8 @@ void cleanup_module(void)
                    fdc_state[FDC(drive)].version != FDC_NONE) {
                        del_gendisk(disks[drive]);
                        unregister_devfs_entries(drive);
+                       device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
+                       platform_device_unregister(&floppy_device[drive]);
                }
                put_disk(disks[drive]);
        }
@@ -4624,9 +4635,9 @@ void cleanup_module(void)
        wait_for_completion(&device_release);
 }
 
-MODULE_PARM(floppy, "s");
-MODULE_PARM(FLOPPY_IRQ, "i");
-MODULE_PARM(FLOPPY_DMA, "i");
+module_param(floppy, charp, 0);
+module_param(FLOPPY_IRQ, int, 0);
+module_param(FLOPPY_DMA, int, 0);
 MODULE_AUTHOR("Alain L. Knaff");
 MODULE_SUPPORTED_DEVICE("fd");
 MODULE_LICENSE("GPL");