* driver due to an interrupt or a timer event is stored in a variable
* of type idefloppy_floppy_t, defined below.
*/
-typedef struct {
- ide_drive_t *drive;
+typedef struct ide_floppy_obj {
+ ide_drive_t *drive;
+ ide_driver_t *driver;
+ struct gendisk *disk;
+ struct kref kref;
/* Current packet command */
idefloppy_pc_t *pc;
u8 reserved[4];
} idefloppy_mode_parameter_header_t;
+static DECLARE_MUTEX(idefloppy_ref_sem);
+
+#define to_ide_floppy(obj) container_of(obj, struct ide_floppy_obj, kref)
+
+#define ide_floppy_g(disk) \
+ container_of((disk)->private_data, struct ide_floppy_obj, driver)
+
+static struct ide_floppy_obj *ide_floppy_get(struct gendisk *disk)
+{
+ struct ide_floppy_obj *floppy = NULL;
+
+ down(&idefloppy_ref_sem);
+ floppy = ide_floppy_g(disk);
+ if (floppy)
+ kref_get(&floppy->kref);
+ up(&idefloppy_ref_sem);
+ return floppy;
+}
+
+static void ide_floppy_release(struct kref *);
+
+static void ide_floppy_put(struct ide_floppy_obj *floppy)
+{
+ down(&idefloppy_ref_sem);
+ kref_put(&floppy->kref, ide_floppy_release);
+ up(&idefloppy_ref_sem);
+}
+
/*
* Too bad. The drive wants to send us data which we are not ready to accept.
* Just throw it away.
*/
static void idefloppy_queue_pc_head (ide_drive_t *drive,idefloppy_pc_t *pc,struct request *rq)
{
+ struct ide_floppy_obj *floppy = drive->driver_data;
+
ide_init_drive_cmd(rq);
rq->buffer = (char *) pc;
rq->flags = REQ_SPECIAL; //rq->cmd = IDEFLOPPY_PC_RQ;
+ rq->rq_disk = floppy->disk;
(void) ide_do_drive_cmd(drive, rq, ide_preempt);
}
unsigned long block = (unsigned long)block_s;
debug_log(KERN_INFO "rq_status: %d, dev: %s, flags: %lx, errors: %d\n",
- rq->rq_status, rq->rq_disk->disk_name,
+ rq->rq_status,
+ rq->rq_disk ? rq->rq_disk->disk_name ? "?",
rq->flags, rq->errors);
debug_log(KERN_INFO "sector: %ld, nr_sectors: %ld, "
"current_nr_sectors: %d\n", (long)rq->sector,
*/
static int idefloppy_queue_pc_tail (ide_drive_t *drive,idefloppy_pc_t *pc)
{
+ struct ide_floppy_obj *floppy = drive->driver_data;
struct request rq;
ide_init_drive_cmd (&rq);
rq.buffer = (char *) pc;
rq.flags = REQ_SPECIAL; // rq.cmd = IDEFLOPPY_PC_RQ;
+ rq.rq_disk = floppy->disk;
return ide_do_drive_cmd(drive, &rq, ide_wait);
}
}
header = (idefloppy_mode_parameter_header_t *) pc.buffer;
floppy->wp = header->wp;
- set_disk_ro(drive->disk, floppy->wp);
+ set_disk_ro(floppy->disk, floppy->wp);
page = (idefloppy_flexible_disk_page_t *) (header + 1);
page->transfer_rate = ntohs(page->transfer_rate);
drive->bios_cyl = 0;
drive->bios_head = drive->bios_sect = 0;
floppy->blocks = floppy->bs_factor = 0;
- set_capacity(drive->disk, 0);
+ set_capacity(floppy->disk, 0);
idefloppy_create_read_capacity_cmd(&pc);
if (idefloppy_queue_pc_tail(drive, &pc)) {
(void) idefloppy_get_flexible_disk_page(drive);
}
- set_capacity(drive->disk, floppy->blocks * floppy->bs_factor);
+ set_capacity(floppy->disk, floppy->blocks * floppy->bs_factor);
return rc;
}
struct idefloppy_id_gcw gcw;
*((u16 *) &gcw) = drive->id->config;
- drive->driver_data = floppy;
- drive->ready_stat = 0;
- memset(floppy, 0, sizeof(idefloppy_floppy_t));
- floppy->drive = drive;
floppy->pc = floppy->pc_stack;
if (gcw.drq_type == 1)
set_bit(IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
idefloppy_add_settings(drive);
}
-static int idefloppy_cleanup (ide_drive_t *drive)
+static int ide_floppy_remove(struct device *dev)
{
+ ide_drive_t *drive = to_ide_device(dev);
idefloppy_floppy_t *floppy = drive->driver_data;
- struct gendisk *g = drive->disk;
+ struct gendisk *g = floppy->disk;
+
+ ide_unregister_subdriver(drive, floppy->driver);
- if (ide_unregister_subdriver(drive))
- return 1;
- drive->driver_data = NULL;
- kfree(floppy);
del_gendisk(g);
- g->fops = ide_fops;
+
+ ide_floppy_put(floppy);
+
return 0;
}
+static void ide_floppy_release(struct kref *kref)
+{
+ struct ide_floppy_obj *floppy = to_ide_floppy(kref);
+ ide_drive_t *drive = floppy->drive;
+ struct gendisk *g = floppy->disk;
+
+ drive->driver_data = NULL;
+ g->private_data = NULL;
+ put_disk(g);
+ kfree(floppy);
+}
+
#ifdef CONFIG_PROC_FS
+static int proc_idefloppy_read_capacity
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t*drive = (ide_drive_t *)data;
+ int len;
+
+ len = sprintf(page,"%llu\n", (long long)idefloppy_capacity(drive));
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
static ide_proc_entry_t idefloppy_proc[] = {
+ { "capacity", S_IFREG|S_IRUGO, proc_idefloppy_read_capacity, NULL },
{ "geometry", S_IFREG|S_IRUGO, proc_ide_read_geometry, NULL },
{ NULL, 0, NULL, NULL }
};
#endif /* CONFIG_PROC_FS */
-static int idefloppy_attach(ide_drive_t *drive);
+static int ide_floppy_probe(struct device *);
-/*
- * IDE subdriver functions, registered with ide.c
- */
static ide_driver_t idefloppy_driver = {
.owner = THIS_MODULE,
- .name = "ide-floppy",
+ .gen_driver = {
+ .name = "ide-floppy",
+ .bus = &ide_bus_type,
+ .probe = ide_floppy_probe,
+ .remove = ide_floppy_remove,
+ },
.version = IDEFLOPPY_VERSION,
.media = ide_floppy,
- .busy = 0,
.supports_dsc_overlap = 0,
- .cleanup = idefloppy_cleanup,
.do_request = idefloppy_do_request,
.end_request = idefloppy_do_end_request,
- .capacity = idefloppy_capacity,
+ .error = __ide_error,
+ .abort = __ide_abort,
.proc = idefloppy_proc,
- .attach = idefloppy_attach,
- .drives = LIST_HEAD_INIT(idefloppy_driver.drives),
};
static int idefloppy_open(struct inode *inode, struct file *filp)
{
- ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
- idefloppy_floppy_t *floppy = drive->driver_data;
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct ide_floppy_obj *floppy;
+ ide_drive_t *drive;
idefloppy_pc_t pc;
+ int ret = 0;
- drive->usage++;
-
debug_log(KERN_INFO "Reached idefloppy_open\n");
+ if (!(floppy = ide_floppy_get(disk)))
+ return -ENXIO;
+
+ drive = floppy->drive;
+
+ drive->usage++;
+
if (drive->usage == 1) {
clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
/* Just in case */
*/
) {
drive->usage--;
- return -EIO;
+ ret = -EIO;
+ goto out_put_floppy;
}
if (floppy->wp && (filp->f_mode & 2)) {
drive->usage--;
- return -EROFS;
- }
+ ret = -EROFS;
+ goto out_put_floppy;
+ }
set_bit(IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
/* IOMEGA Clik! drives do not support lock/unlock commands */
if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
check_disk_change(inode->i_bdev);
} else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags)) {
drive->usage--;
- return -EBUSY;
+ ret = -EBUSY;
+ goto out_put_floppy;
}
return 0;
+
+out_put_floppy:
+ ide_floppy_put(floppy);
+ return ret;
}
static int idefloppy_release(struct inode *inode, struct file *filp)
{
- ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct ide_floppy_obj *floppy = ide_floppy_g(disk);
+ ide_drive_t *drive = floppy->drive;
idefloppy_pc_t pc;
debug_log(KERN_INFO "Reached idefloppy_release\n");
if (drive->usage == 1) {
- idefloppy_floppy_t *floppy = drive->driver_data;
-
/* IOMEGA Clik! drives do not support lock/unlock commands */
if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
idefloppy_create_prevent_cmd(&pc, 0);
clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
}
drive->usage--;
+
+ ide_floppy_put(floppy);
+
return 0;
}
unsigned int cmd, unsigned long arg)
{
struct block_device *bdev = inode->i_bdev;
- ide_drive_t *drive = bdev->bd_disk->private_data;
- idefloppy_floppy_t *floppy = drive->driver_data;
+ struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk);
+ ide_drive_t *drive = floppy->drive;
void __user *argp = (void __user *)arg;
- int err = generic_ide_ioctl(file, bdev, cmd, arg);
+ int err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
int prevent = (arg) ? 1 : 0;
idefloppy_pc_t pc;
if (err != -EINVAL)
static int idefloppy_media_changed(struct gendisk *disk)
{
- ide_drive_t *drive = disk->private_data;
- idefloppy_floppy_t *floppy = drive->driver_data;
+ struct ide_floppy_obj *floppy = ide_floppy_g(disk);
+ ide_drive_t *drive = floppy->drive;
/* do not scan partitions twice if this is a removable device */
if (drive->attach) {
static int idefloppy_revalidate_disk(struct gendisk *disk)
{
- ide_drive_t *drive = disk->private_data;
- set_capacity(disk, idefloppy_capacity(drive));
+ struct ide_floppy_obj *floppy = ide_floppy_g(disk);
+ set_capacity(disk, idefloppy_capacity(floppy->drive));
return 0;
}
.revalidate_disk= idefloppy_revalidate_disk
};
-static int idefloppy_attach (ide_drive_t *drive)
+static int ide_floppy_probe(struct device *dev)
{
+ ide_drive_t *drive = to_ide_device(dev);
idefloppy_floppy_t *floppy;
- struct gendisk *g = drive->disk;
+ struct gendisk *g;
+
if (!strstr("ide-floppy", drive->driver_req))
goto failed;
if (!drive->present)
printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
goto failed;
}
- if (ide_register_subdriver(drive, &idefloppy_driver)) {
- printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
- kfree (floppy);
- goto failed;
- }
- DRIVER(drive)->busy++;
+
+ g = alloc_disk(1 << PARTN_BITS);
+ if (!g)
+ goto out_free_floppy;
+
+ ide_init_disk(g, drive);
+
+ ide_register_subdriver(drive, &idefloppy_driver);
+
+ memset(floppy, 0, sizeof(*floppy));
+
+ kref_init(&floppy->kref);
+
+ floppy->drive = drive;
+ floppy->driver = &idefloppy_driver;
+ floppy->disk = g;
+
+ g->private_data = &floppy->driver;
+
+ drive->driver_data = floppy;
+
idefloppy_setup (drive, floppy);
- DRIVER(drive)->busy--;
+
g->minors = 1 << PARTN_BITS;
g->driverfs_dev = &drive->gendev;
strcpy(g->devfs_name, drive->devfs_name);
drive->attach = 1;
add_disk(g);
return 0;
+
+out_free_floppy:
+ kfree(floppy);
failed:
- return 1;
+ return -ENODEV;
}
MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
static void __exit idefloppy_exit (void)
{
- ide_unregister_driver(&idefloppy_driver);
+ driver_unregister(&idefloppy_driver.gen_driver);
}
/*
static int idefloppy_init (void)
{
printk("ide-floppy driver " IDEFLOPPY_VERSION "\n");
- ide_register_driver(&idefloppy_driver);
- return 0;
+ return driver_register(&idefloppy_driver.gen_driver);
}
module_init(idefloppy_init);