#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/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 int irqdma_allocated;
-#define LOCAL_END_REQUEST
#define DEVICE_NAME "floppy"
#include <linux/blkdev.h>
#include <linux/cdrom.h> /* for the compatibility eject ioctl */
#include <linux/completion.h>
+/*
+ * 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);
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;
/*
{ 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. */
{
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)) {
return 1;
}
- if ((signed)(jiffies - delay) < 0) {
+ if (time_before(jiffies, delay)) {
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 ((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
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;
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";
continue;
__invalidate_device(bdev);
}
- up(&open_lock);
+ mutex_unlock(&open_lock);
} else {
int oldStretch;
LOCK_FDC(drive, 1);
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)
{
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));
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;
{
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--) {
if (!UDRS->fd_ref)
opened_bdev[drive] = NULL;
floppy_release_irq_and_dma();
- up(&open_lock);
+ mutex_unlock(&open_lock);
return 0;
}
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;
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)
opened_bdev[drive] = NULL;
floppy_release_irq_and_dma();
out2:
- up(&open_lock);
+ mutex_unlock(&open_lock);
return res;
}
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;
}
.open = floppy_open,
.release = floppy_release,
.ioctl = fd_ioctl,
+ .getgeo = fd_getgeo,
.media_changed = check_floppy_change,
.revalidate_disk = floppy_revalidate,
};
{
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);
!(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]);
}
use_virtual_dma = can_use_virtual_dma & 1;
-#if defined(CONFIG_PPC64)
+#if defined(CONFIG_PPC_MERGE)
if (check_legacy_ioport(FDC1)) {
del_timer(&fd_timeout);
err = -ENODEV;
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);
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);
{
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,
}
}
-int init_module(void)
+int __init init_module(void)
{
if (floppy)
parse_floppy_cfg_string(floppy);
/* eject disk, if any */
fd_eject(0);
+ flush_scheduled_work(); /* fd_free_irq() might be pending */
+
wait_for_completion(&device_release);
}