X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fblock%2Ffloppy.c;h=dff1e67b1dd4e2768447ac92465caf8e1cceb97a;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=70375a056fa11fe2c972b3a7768394fcaebb5a1e;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 70375a056..dff1e67b1 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -97,6 +97,10 @@ * features to asm/floppy.h. */ +/* + * 1998/1/21 -- Richard Gooch -- 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 #include #include -#include #define FDPATCHES #include -/* - * 1998/1/21 -- Richard Gooch -- devfs support - */ - #include #include @@ -171,6 +170,7 @@ static int print_unex = 1; #include #include #include +#include #include #include #include /* CMOS defines */ @@ -178,8 +178,9 @@ static int print_unex = 1; #include #include #include -#include +#include #include /* for invalidate_buffers() */ +#include /* * PS/2 floppies have much slower step rates than regular floppies. @@ -217,7 +218,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 +244,6 @@ static int allowed_drive_mask = 0x33; static int irqdma_allocated; -#define LOCAL_END_REQUEST #define DEVICE_NAME "floppy" #include @@ -251,6 +251,18 @@ static int irqdma_allocated; #include /* for the compatibility eject ioctl */ #include +/* + * Interrupt freeing also means /proc VFS work - dont do it + * from interrupt context. We push this work into keventd: + */ +static void fd_free_irq_fn(void *data) +{ + fd_free_irq(); +} + +static DECLARE_WORK(fd_free_irq_work, fd_free_irq_fn, NULL); + + static struct request *current_req; static struct request_queue *floppy_queue; static void do_fd_request(request_queue_t * q); @@ -415,7 +427,7 @@ static struct floppy_write_errors write_errors[N_DRIVE]; static struct timer_list motor_off_timer[N_DRIVE]; static struct gendisk *disks[N_DRIVE]; static struct block_device *opened_bdev[N_DRIVE]; -static DECLARE_MUTEX(open_lock); +static DEFINE_MUTEX(open_lock); static struct floppy_raw_cmd *raw_cmd, default_raw_cmd; /* @@ -480,7 +492,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 +505,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 +640,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; @@ -735,7 +748,7 @@ static int disk_change(int drive) { int fdc = FDC(drive); #ifdef FLOPPY_SANITY_CHECK - if (jiffies - UDRS->select_date < UDP->select_delay) + if (time_before(jiffies, UDRS->select_date + UDP->select_delay)) DPRINT("WARNING disk change called early\n"); if (!(FDCS->dor & (0x10 << UNIT(drive))) || (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) { @@ -922,7 +935,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 +1024,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) { @@ -1063,7 +1076,7 @@ static int fd_wait_for_completion(unsigned long delay, timeout_fn function) return 1; } - if ((signed)(jiffies - delay) < 0) { + if (time_before(jiffies, delay)) { del_timer(&fd_timer); fd_timer.function = function; fd_timer.expires = delay; @@ -1073,7 +1086,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) { @@ -1523,7 +1536,7 @@ static void setup_rw_floppy(void) * again just before spinup completion. Beware that * after scandrives, we must again wait for selection. */ - if ((signed)(ready_date - jiffies) > DP->select_delay) { + if (time_after(ready_date, jiffies + DP->select_delay)) { ready_date -= DP->select_delay; function = (timeout_fn) floppy_start; } else @@ -1787,10 +1800,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 +2035,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 +2313,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 +3205,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 +3225,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 +3233,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 +3250,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 +3332,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) { @@ -3338,7 +3347,7 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g, if (type) { if (!capable(CAP_SYS_ADMIN)) return -EPERM; - down(&open_lock); + mutex_lock(&open_lock); LOCK_FDC(drive, 1); floppy_type[type] = *g; floppy_type[type].name = "user format"; @@ -3350,9 +3359,9 @@ 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); + mutex_unlock(&open_lock); } else { int oldStretch; LOCK_FDC(drive, 1); @@ -3448,6 +3457,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 +3503,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 +3657,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; @@ -3679,7 +3688,7 @@ static int floppy_release(struct inode *inode, struct file *filp) { int drive = (long)inode->i_bdev->bd_disk->private_data; - down(&open_lock); + mutex_lock(&open_lock); if (UDRS->fd_ref < 0) UDRS->fd_ref = 0; else if (!UDRS->fd_ref--) { @@ -3689,7 +3698,7 @@ static int floppy_release(struct inode *inode, struct file *filp) if (!UDRS->fd_ref) opened_bdev[drive] = NULL; floppy_release_irq_and_dma(); - up(&open_lock); + mutex_unlock(&open_lock); return 0; } @@ -3707,7 +3716,7 @@ static int floppy_open(struct inode *inode, struct file *filp) char *tmp; filp->private_data = (void *)0; - down(&open_lock); + mutex_lock(&open_lock); old_dev = UDRS->fd_device; if (opened_bdev[drive] && opened_bdev[drive] != inode->i_bdev) goto out2; @@ -3773,8 +3782,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) @@ -3791,7 +3799,7 @@ static int floppy_open(struct inode *inode, struct file *filp) if ((filp->f_mode & 2) && !(UTESTF(FD_DISK_WRITABLE))) goto out; } - up(&open_lock); + mutex_unlock(&open_lock); return 0; out: if (UDRS->fd_ref < 0) @@ -3802,7 +3810,7 @@ out: opened_bdev[drive] = NULL; floppy_release_irq_and_dma(); out2: - up(&open_lock); + mutex_unlock(&open_lock); return res; } @@ -3816,7 +3824,7 @@ static int check_floppy_change(struct gendisk *disk) if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY)) return 1; - if (UDP->checkfreq < (int)(jiffies - UDRS->last_checked)) { + if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) { if (floppy_grab_irq_and_dma()) { return 1; } @@ -3942,6 +3950,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 +3973,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 +4133,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 +4199,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 +4231,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 +4301,13 @@ int __init floppy_init(void) } use_virtual_dma = can_use_virtual_dma & 1; +#if defined(CONFIG_PPC_MERGE) + 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 +4337,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 +4395,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 +4434,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) { @@ -4420,6 +4446,13 @@ static int floppy_grab_irq_and_dma(void) return 0; } spin_unlock_irqrestore(&floppy_usage_lock, flags); + + /* + * We might have scheduled a free_irq(), wait it to + * drain first: + */ + flush_scheduled_work(); + if (fd_request_irq()) { DPRINT("Unable to grab IRQ%d for the floppy driver\n", FLOPPY_IRQ); @@ -4509,7 +4542,7 @@ static void floppy_release_irq_and_dma(void) if (irqdma_allocated) { fd_disable_dma(); fd_free_dma(); - fd_free_irq(); + schedule_work(&fd_free_irq_work); irqdma_allocated = 0; } set_dor(0, ~0, 8); @@ -4551,13 +4584,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, @@ -4581,10 +4614,8 @@ static void __init parse_floppy_cfg_string(char *cfg) } } -int init_module(void) +int __init 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 +4626,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 +4636,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]); } @@ -4621,12 +4653,14 @@ void cleanup_module(void) /* eject disk, if any */ fd_eject(0); + flush_scheduled_work(); /* fd_free_irq() might be pending */ + 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");