#include <linux/mm.h>
#include <linux/bio.h>
#include <linux/string.h>
-#include <linux/jiffies.h>
#include <linux/fcntl.h>
#include <linux/delay.h>
#include <linux/mc146818rtc.h> /* CMOS defines */
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/platform_device.h>
#include <linux/buffer_head.h> /* for invalidate_buffers() */
-#include <linux/mutex.h>
/*
* PS/2 floppies have much slower step rates than regular floppies.
static unsigned short virtual_dma_port = 0x3f0;
irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int set_dor(int fdc, char mask, char data);
+static void register_devfs_entries(int drive) __init;
#define K_64 0x10000 /* 64KB */
static struct timer_list motor_off_timer[N_DRIVE];
static struct gendisk *disks[N_DRIVE];
static struct block_device *opened_bdev[N_DRIVE];
-static DEFINE_MUTEX(open_lock);
+static DECLARE_MUTEX(open_lock);
static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
/*
{
int fdc = FDC(drive);
#ifdef FLOPPY_SANITY_CHECK
- if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
+ if (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)) {
UDRS->select_date = jiffies;
}
}
+ /*
+ * We should propagate failures to grab the resources back
+ * nicely from here. Actually we ought to rewrite the fd
+ * driver some day too.
+ */
+ if (newdor & FLOPPY_MOTOR_MASK)
+ floppy_grab_irq_and_dma();
+ if (olddor & FLOPPY_MOTOR_MASK)
+ floppy_release_irq_and_dma();
return olddor;
}
line);
return -1;
}
+ if (floppy_grab_irq_and_dma() == -1)
+ return -EBUSY;
if (test_and_set_bit(0, &fdc_busy)) {
DECLARE_WAITQUEUE(wait, current);
set_current_state(TASK_RUNNING);
remove_wait_queue(&fdc_wait, &wait);
-
- flush_scheduled_work();
}
command_status = FD_COMMAND_NONE;
if (elv_next_request(floppy_queue))
do_fd_request(floppy_queue);
spin_unlock_irqrestore(&floppy_lock, flags);
+ floppy_release_irq_and_dma();
wake_up(&fdc_wait);
}
return 1;
}
- if (time_before(jiffies, delay)) {
+ if ((signed)(jiffies - delay) < 0) {
del_timer(&fd_timer);
fd_timer.function = function;
fd_timer.expires = delay;
* again just before spinup completion. Beware that
* after scandrives, we must again wait for selection.
*/
- if (time_after(ready_date, jiffies + DP->select_delay)) {
+ if ((signed)(ready_date - jiffies) > DP->select_delay) {
ready_date -= DP->select_delay;
function = (timeout_fn) floppy_start;
} else
if (type) {
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- mutex_lock(&open_lock);
+ down(&open_lock);
LOCK_FDC(drive, 1);
floppy_type[type] = *g;
floppy_type[type].name = "user format";
continue;
__invalidate_device(bdev);
}
- mutex_unlock(&open_lock);
+ up(&open_lock);
} else {
int oldStretch;
LOCK_FDC(drive, 1);
first = 0;
}
printk("%s fd%d is %s", prepend, drive, name);
+ register_devfs_entries(drive);
}
*UDP = *params;
}
{
int drive = (long)inode->i_bdev->bd_disk->private_data;
- mutex_lock(&open_lock);
+ down(&open_lock);
if (UDRS->fd_ref < 0)
UDRS->fd_ref = 0;
else if (!UDRS->fd_ref--) {
}
if (!UDRS->fd_ref)
opened_bdev[drive] = NULL;
- mutex_unlock(&open_lock);
-
+ floppy_release_irq_and_dma();
+ up(&open_lock);
return 0;
}
char *tmp;
filp->private_data = (void *)0;
- mutex_lock(&open_lock);
+ down(&open_lock);
old_dev = UDRS->fd_device;
if (opened_bdev[drive] && opened_bdev[drive] != inode->i_bdev)
goto out2;
if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (filp->f_flags & O_EXCL)))
goto out2;
+ if (floppy_grab_irq_and_dma())
+ goto out2;
+
if (filp->f_flags & O_EXCL)
UDRS->fd_ref = -1;
else
if ((filp->f_mode & 2) && !(UTESTF(FD_DISK_WRITABLE)))
goto out;
}
- mutex_unlock(&open_lock);
+ up(&open_lock);
return 0;
out:
if (UDRS->fd_ref < 0)
UDRS->fd_ref--;
if (!UDRS->fd_ref)
opened_bdev[drive] = NULL;
+ floppy_release_irq_and_dma();
out2:
- mutex_unlock(&open_lock);
+ up(&open_lock);
return res;
}
if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
return 1;
- if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
+ if (UDP->checkfreq < (int)(jiffies - UDRS->last_checked)) {
+ if (floppy_grab_irq_and_dma()) {
+ return 1;
+ }
+
lock_fdc(drive, 0);
poll_drive(0, 0);
process_fd_request();
+ floppy_release_irq_and_dma();
}
if (UTESTF(FD_DISK_CHANGED) ||
.media_changed = check_floppy_change,
.revalidate_disk = floppy_revalidate,
};
+static char *table[] = {
+ "", "d360", "h1200", "u360", "u720", "h360", "h720",
+ "u1440", "u2880", "CompaQ", "h1440", "u1680", "h410",
+ "u820", "h1476", "u1722", "h420", "u830", "h1494", "u1743",
+ "h880", "u1040", "u1120", "h1600", "u1760", "u1920",
+ "u3200", "u3520", "u3840", "u1840", "u800", "u1600",
+ NULL
+};
+static int t360[] = { 1, 0 },
+ t1200[] = { 2, 5, 6, 10, 12, 14, 16, 18, 20, 23, 0 },
+ t3in[] = { 8, 9, 26, 27, 28, 7, 11, 15, 19, 24, 25, 29, 31, 3, 4, 13,
+ 17, 21, 22, 30, 0 };
+static int *table_sup[] =
+ { NULL, t360, t1200, t3in + 5 + 8, t3in + 5, t3in, t3in };
+
+static void __init register_devfs_entries(int drive)
+{
+ int base_minor = (drive < 4) ? drive : (124 + drive);
+
+ if (UDP->cmos < ARRAY_SIZE(default_drive_params)) {
+ int i = 0;
+ do {
+ int minor = base_minor + (table_sup[UDP->cmos][i] << 2);
+
+ devfs_mk_bdev(MKDEV(FLOPPY_MAJOR, minor),
+ S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |
+ S_IWGRP, "floppy/%d%s", drive,
+ table[table_sup[UDP->cmos][i]]);
+ } while (table_sup[UDP->cmos][i++]);
+ }
+}
/*
* Floppy Driver initialization
int i, unit, drive;
int err, dr;
-#if defined(CONFIG_PPC_MERGE)
- if (check_legacy_ioport(FDC1))
- return -ENODEV;
-#endif
-
raw_cmd = NULL;
for (dr = 0; dr < N_DRIVE; dr++) {
motor_off_timer[dr].function = motor_off_callback;
}
+ devfs_mk_dir("floppy");
+
err = register_blkdev(FLOPPY_MAJOR, "fd");
if (err)
- goto out_put_disk;
+ goto out_devfs_remove;
floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
if (!floppy_queue) {
}
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);
fdc = 0;
del_timer(&fd_timeout);
current_drive = 0;
+ floppy_release_irq_and_dma();
initialising = 0;
if (have_no_fdc) {
DPRINT("no floppy controllers found\n");
blk_cleanup_queue(floppy_queue);
out_unreg_blkdev:
unregister_blkdev(FLOPPY_MAJOR, "fd");
+out_devfs_remove:
+ devfs_remove("floppy");
out_put_disk:
while (dr--) {
del_timer(&motor_off_timer[dr]);
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);
static char *floppy;
+static void unregister_devfs_entries(int drive)
+{
+ int i;
+
+ if (UDP->cmos < ARRAY_SIZE(default_drive_params)) {
+ i = 0;
+ do {
+ devfs_remove("floppy/%d%s", drive,
+ table[table_sup[UDP->cmos][i]]);
+ } while (table_sup[UDP->cmos][i++]);
+ }
+}
+
static void __init parse_floppy_cfg_string(char *cfg)
{
char *ptr;
}
}
-int __init init_module(void)
+int init_module(void)
{
if (floppy)
parse_floppy_cfg_string(floppy);
if ((allowed_drive_mask & (1 << drive)) &&
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]);
}
+ devfs_remove("floppy");
del_timer_sync(&fd_timeout);
del_timer_sync(&fd_timer);