ide: add generic ATA/ATAPI disk driver
* Add struct ide_disk_ops containing protocol specific methods.
* Add 'struct ide_disk_ops *' to ide_drive_t.
* Convert ide-{disk,floppy} drivers to use struct ide_disk_ops.
* Merge ide-{disk,floppy} drivers into generic ide-gd driver.
While at it:
- ide_disk_init_capacity() -> ide_disk_get_capacity()
Acked-by: Borislav Petkov <petkovbb@gmail.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
			
			
This commit is contained in:
		
							parent
							
								
									79cb380397
								
							
						
					
					
						commit
						806f80a6fc
					
				| @ -84,21 +84,40 @@ config BLK_DEV_IDE_SATA | |||||||
| 
 | 
 | ||||||
| 	  If unsure, say N. | 	  If unsure, say N. | ||||||
| 
 | 
 | ||||||
| config BLK_DEV_IDEDISK | config IDE_GD | ||||||
| 	tristate "Include IDE/ATA-2 DISK support" | 	tristate "generic ATA/ATAPI disk support" | ||||||
| 	---help--- | 	default y | ||||||
| 	  This will include enhanced support for MFM/RLL/IDE hard disks.  If | 	help | ||||||
| 	  you have a MFM/RLL/IDE disk, and there is no special reason to use | 	  Support for ATA/ATAPI disks (including ATAPI floppy drives). | ||||||
| 	  the old hard disk driver instead, say Y.  If you have an SCSI-only |  | ||||||
| 	  system, you can say N here. |  | ||||||
| 
 | 
 | ||||||
| 	  To compile this driver as a module, choose M here: the | 	  To compile this driver as a module, choose M here. | ||||||
| 	  module will be called ide-disk. | 	  The module will be called ide-gd_mod. | ||||||
| 	  Do not compile this driver as a module if your root file system |  | ||||||
| 	  (the one containing the directory /) is located on the IDE disk. |  | ||||||
| 
 | 
 | ||||||
| 	  If unsure, say Y. | 	  If unsure, say Y. | ||||||
| 
 | 
 | ||||||
|  | config IDE_GD_ATA | ||||||
|  | 	bool "ATA disk support" | ||||||
|  | 	depends on IDE_GD | ||||||
|  | 	default y | ||||||
|  | 	help | ||||||
|  | 	  This will include support for ATA hard disks. | ||||||
|  | 
 | ||||||
|  | 	  If unsure, say Y. | ||||||
|  | 
 | ||||||
|  | config IDE_GD_ATAPI | ||||||
|  | 	bool "ATAPI floppy support" | ||||||
|  | 	depends on IDE_GD | ||||||
|  | 	select IDE_ATAPI | ||||||
|  | 	help | ||||||
|  | 	  This will include support for ATAPI floppy drives | ||||||
|  | 	  (i.e. Iomega ZIP or MKE LS-120). | ||||||
|  | 
 | ||||||
|  | 	  For information about jumper settings and the question | ||||||
|  | 	  of when a ZIP drive uses a partition table, see | ||||||
|  | 	  <http://www.win.tue.nl/~aeb/linux/zip/zip-1.html>. | ||||||
|  | 
 | ||||||
|  | 	  If unsure, say N. | ||||||
|  | 
 | ||||||
| config BLK_DEV_IDECS | config BLK_DEV_IDECS | ||||||
| 	tristate "PCMCIA IDE support" | 	tristate "PCMCIA IDE support" | ||||||
| 	depends on PCMCIA | 	depends on PCMCIA | ||||||
| @ -163,29 +182,6 @@ config BLK_DEV_IDETAPE | |||||||
| 	  To compile this driver as a module, choose M here: the | 	  To compile this driver as a module, choose M here: the | ||||||
| 	  module will be called ide-tape. | 	  module will be called ide-tape. | ||||||
| 
 | 
 | ||||||
| config BLK_DEV_IDEFLOPPY |  | ||||||
| 	tristate "Include IDE/ATAPI FLOPPY support" |  | ||||||
| 	select IDE_ATAPI |  | ||||||
| 	---help--- |  | ||||||
| 	  If you have an IDE floppy drive which uses the ATAPI protocol, |  | ||||||
| 	  answer Y.  ATAPI is a newer protocol used by IDE CD-ROM/tape/floppy |  | ||||||
| 	  drives, similar to the SCSI protocol. |  | ||||||
| 
 |  | ||||||
| 	  The LS-120 and the IDE/ATAPI Iomega ZIP drive are also supported by |  | ||||||
| 	  this driver. For information about jumper settings and the question |  | ||||||
| 	  of when a ZIP drive uses a partition table, see |  | ||||||
| 	  <http://www.win.tue.nl/~aeb/linux/zip/zip-1.html>. |  | ||||||
| 	  (ATAPI PD-CD/CDR drives are not supported by this driver; support |  | ||||||
| 	  for PD-CD/CDR drives is available if you answer Y to |  | ||||||
| 	  "SCSI emulation support", below). |  | ||||||
| 
 |  | ||||||
| 	  If you say Y here, the FLOPPY drive will be identified along with |  | ||||||
| 	  other IDE devices, as "hdb" or "hdc", or something similar (check |  | ||||||
| 	  the boot messages with dmesg). |  | ||||||
| 
 |  | ||||||
| 	  To compile this driver as a module, choose M here: the |  | ||||||
| 	  module will be called ide-floppy. |  | ||||||
| 
 |  | ||||||
| config BLK_DEV_IDESCSI | config BLK_DEV_IDESCSI | ||||||
| 	tristate "SCSI emulation support (DEPRECATED)" | 	tristate "SCSI emulation support (DEPRECATED)" | ||||||
| 	depends on SCSI | 	depends on SCSI | ||||||
|  | |||||||
| @ -37,18 +37,25 @@ obj-$(CONFIG_IDE_H8300)			+= h8300/ | |||||||
| obj-$(CONFIG_IDE_GENERIC)		+= ide-generic.o | obj-$(CONFIG_IDE_GENERIC)		+= ide-generic.o | ||||||
| obj-$(CONFIG_BLK_DEV_IDEPNP)		+= ide-pnp.o | obj-$(CONFIG_BLK_DEV_IDEPNP)		+= ide-pnp.o | ||||||
| 
 | 
 | ||||||
| ide-disk_mod-y += ide-gd.o ide-disk.o ide-disk_ioctl.o | ide-gd_mod-y += ide-gd.o | ||||||
| ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o | ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o | ||||||
| ide-floppy_mod-y += ide-gd-floppy.o ide-floppy.o ide-floppy_ioctl.o |  | ||||||
| 
 | 
 | ||||||
|  | ifeq ($(CONFIG_IDE_GD_ATA), y) | ||||||
|  | 	ide-gd_mod-y += ide-disk.o ide-disk_ioctl.o | ||||||
| ifeq ($(CONFIG_IDE_PROC_FS), y) | ifeq ($(CONFIG_IDE_PROC_FS), y) | ||||||
| 	ide-disk_mod-y += ide-disk_proc.o | 	ide-gd_mod-y += ide-disk_proc.o | ||||||
| 	ide-floppy_mod-y += ide-floppy_proc.o | endif | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| obj-$(CONFIG_BLK_DEV_IDEDISK)		+= ide-disk_mod.o | ifeq ($(CONFIG_IDE_GD_ATAPI), y) | ||||||
|  | 	ide-gd_mod-y += ide-floppy.o ide-floppy_ioctl.o | ||||||
|  | ifeq ($(CONFIG_IDE_PROC_FS), y) | ||||||
|  | 	ide-gd_mod-y += ide-floppy_proc.o | ||||||
|  | endif | ||||||
|  | endif | ||||||
|  | 
 | ||||||
|  | obj-$(CONFIG_IDE_GD)			+= ide-gd_mod.o | ||||||
| obj-$(CONFIG_BLK_DEV_IDECD)		+= ide-cd_mod.o | obj-$(CONFIG_BLK_DEV_IDECD)		+= ide-cd_mod.o | ||||||
| obj-$(CONFIG_BLK_DEV_IDEFLOPPY)		+= ide-floppy_mod.o |  | ||||||
| obj-$(CONFIG_BLK_DEV_IDETAPE)		+= ide-tape.o | obj-$(CONFIG_BLK_DEV_IDETAPE)		+= ide-tape.o | ||||||
| 
 | 
 | ||||||
| ifeq ($(CONFIG_BLK_DEV_IDECS), y) | ifeq ($(CONFIG_BLK_DEV_IDECS), y) | ||||||
|  | |||||||
| @ -184,8 +184,8 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, | |||||||
|  * 1073741822 == 549756 MB or 48bit addressing fake drive |  * 1073741822 == 549756 MB or 48bit addressing fake drive | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq, | static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq, | ||||||
| 			       sector_t block) | 				      sector_t block) | ||||||
| { | { | ||||||
| 	ide_hwif_t *hwif = HWIF(drive); | 	ide_hwif_t *hwif = HWIF(drive); | ||||||
| 
 | 
 | ||||||
| @ -333,7 +333,7 @@ static void idedisk_check_hpa(ide_drive_t *drive) | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ide_disk_init_capacity(ide_drive_t *drive) | static int ide_disk_get_capacity(ide_drive_t *drive) | ||||||
| { | { | ||||||
| 	u16 *id = drive->id; | 	u16 *id = drive->id; | ||||||
| 	int lba; | 	int lba; | ||||||
| @ -382,6 +382,8 @@ void ide_disk_init_capacity(ide_drive_t *drive) | |||||||
| 		} else | 		} else | ||||||
| 			drive->dev_flags &= ~IDE_DFLAG_LBA48; | 			drive->dev_flags &= ~IDE_DFLAG_LBA48; | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void idedisk_prepare_flush(struct request_queue *q, struct request *rq) | static void idedisk_prepare_flush(struct request_queue *q, struct request *rq) | ||||||
| @ -590,7 +592,12 @@ ide_ext_devset_rw(wcache, wcache); | |||||||
| 
 | 
 | ||||||
| ide_ext_devset_rw_sync(nowerr, nowerr); | ide_ext_devset_rw_sync(nowerr, nowerr); | ||||||
| 
 | 
 | ||||||
| void ide_disk_setup(ide_drive_t *drive) | static int ide_disk_check(ide_drive_t *drive, const char *s) | ||||||
|  | { | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void ide_disk_setup(ide_drive_t *drive) | ||||||
| { | { | ||||||
| 	struct ide_disk_obj *idkp = drive->driver_data; | 	struct ide_disk_obj *idkp = drive->driver_data; | ||||||
| 	ide_hwif_t *hwif = drive->hwif; | 	ide_hwif_t *hwif = drive->hwif; | ||||||
| @ -626,7 +633,7 @@ void ide_disk_setup(ide_drive_t *drive) | |||||||
| 			 drive->queue->max_sectors / 2); | 			 drive->queue->max_sectors / 2); | ||||||
| 
 | 
 | ||||||
| 	/* calculate drive capacity, and select LBA if possible */ | 	/* calculate drive capacity, and select LBA if possible */ | ||||||
| 	ide_disk_init_capacity(drive); | 	ide_disk_get_capacity(drive); | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * if possible, give fdisk access to more of the drive, | 	 * if possible, give fdisk access to more of the drive, | ||||||
| @ -682,7 +689,7 @@ void ide_disk_setup(ide_drive_t *drive) | |||||||
| 		drive->dev_flags |= IDE_DFLAG_ATTACH; | 		drive->dev_flags |= IDE_DFLAG_ATTACH; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ide_disk_flush(ide_drive_t *drive) | static void ide_disk_flush(ide_drive_t *drive) | ||||||
| { | { | ||||||
| 	if (ata_id_flush_enabled(drive->id) == 0 || | 	if (ata_id_flush_enabled(drive->id) == 0 || | ||||||
| 	    (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) | 	    (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) | ||||||
| @ -692,7 +699,13 @@ void ide_disk_flush(ide_drive_t *drive) | |||||||
| 		printk(KERN_INFO "%s: wcache flush failed!\n", drive->name); | 		printk(KERN_INFO "%s: wcache flush failed!\n", drive->name); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int ide_disk_set_doorlock(ide_drive_t *drive, int on) | static int ide_disk_init_media(ide_drive_t *drive, struct gendisk *disk) | ||||||
|  | { | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int ide_disk_set_doorlock(ide_drive_t *drive, struct gendisk *disk, | ||||||
|  | 				 int on) | ||||||
| { | { | ||||||
| 	ide_task_t task; | 	ide_task_t task; | ||||||
| 	int ret; | 	int ret; | ||||||
| @ -711,3 +724,15 @@ int ide_disk_set_doorlock(ide_drive_t *drive, int on) | |||||||
| 
 | 
 | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | const struct ide_disk_ops ide_ata_disk_ops = { | ||||||
|  | 	.check		= ide_disk_check, | ||||||
|  | 	.get_capacity	= ide_disk_get_capacity, | ||||||
|  | 	.setup		= ide_disk_setup, | ||||||
|  | 	.flush		= ide_disk_flush, | ||||||
|  | 	.init_media	= ide_disk_init_media, | ||||||
|  | 	.set_doorlock	= ide_disk_set_doorlock, | ||||||
|  | 	.do_request	= ide_do_rw_disk, | ||||||
|  | 	.end_request	= ide_end_request, | ||||||
|  | 	.ioctl		= ide_disk_ioctl, | ||||||
|  | }; | ||||||
|  | |||||||
| @ -1,22 +1,11 @@ | |||||||
| #ifndef __IDE_DISK_H | #ifndef __IDE_DISK_H | ||||||
| #define __IDE_DISK_H | #define __IDE_DISK_H | ||||||
| 
 | 
 | ||||||
| struct ide_disk_obj { | #include "ide-gd.h" | ||||||
| 	ide_drive_t	*drive; |  | ||||||
| 	ide_driver_t	*driver; |  | ||||||
| 	struct gendisk	*disk; |  | ||||||
| 	struct kref	kref; |  | ||||||
| 	unsigned int	openers;	/* protected by BKL for now */ |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| sector_t ide_gd_capacity(ide_drive_t *); |  | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_IDE_GD_ATA | ||||||
| /* ide-disk.c */ | /* ide-disk.c */ | ||||||
| void ide_disk_init_capacity(ide_drive_t *); | extern const struct ide_disk_ops ide_ata_disk_ops; | ||||||
| void ide_disk_setup(ide_drive_t *); |  | ||||||
| void ide_disk_flush(ide_drive_t *); |  | ||||||
| int ide_disk_set_doorlock(ide_drive_t *, int); |  | ||||||
| ide_startstop_t ide_do_rw_disk(ide_drive_t *, struct request *, sector_t); |  | ||||||
| ide_decl_devset(address); | ide_decl_devset(address); | ||||||
| ide_decl_devset(multcount); | ide_decl_devset(multcount); | ||||||
| ide_decl_devset(nowerr); | ide_decl_devset(nowerr); | ||||||
| @ -24,12 +13,17 @@ ide_decl_devset(wcache); | |||||||
| ide_decl_devset(acoustic); | ide_decl_devset(acoustic); | ||||||
| 
 | 
 | ||||||
| /* ide-disk_ioctl.c */ | /* ide-disk_ioctl.c */ | ||||||
| int ide_disk_ioctl(struct inode *, struct file *, unsigned int, unsigned long); | int ide_disk_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int, | ||||||
|  | 		   unsigned long); | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_IDE_PROC_FS | #ifdef CONFIG_IDE_PROC_FS | ||||||
| /* ide-disk_proc.c */ | /* ide-disk_proc.c */ | ||||||
| extern ide_proc_entry_t ide_disk_proc[]; | extern ide_proc_entry_t ide_disk_proc[]; | ||||||
| extern const struct ide_proc_devset ide_disk_settings[]; | extern const struct ide_proc_devset ide_disk_settings[]; | ||||||
| #endif | #endif | ||||||
|  | #else | ||||||
|  | #define ide_disk_proc		NULL | ||||||
|  | #define ide_disk_settings	NULL | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| #endif /* __IDE_DISK_H */ | #endif /* __IDE_DISK_H */ | ||||||
|  | |||||||
| @ -13,12 +13,10 @@ static const struct ide_ioctl_devset ide_disk_ioctl_settings[] = { | |||||||
| { 0 } | { 0 } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| int ide_disk_ioctl(struct inode *inode, struct file *file, | int ide_disk_ioctl(ide_drive_t *drive, struct inode *inode, struct file *file, | ||||||
| 		   unsigned int cmd, unsigned long arg) | 		   unsigned int cmd, unsigned long arg) | ||||||
| { | { | ||||||
| 	struct block_device *bdev = inode->i_bdev; | 	struct block_device *bdev = inode->i_bdev; | ||||||
| 	struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj); |  | ||||||
| 	ide_drive_t *drive = idkp->drive; |  | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
| 	err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_disk_ioctl_settings); | 	err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_disk_ioctl_settings); | ||||||
|  | |||||||
| @ -68,7 +68,7 @@ | |||||||
|  * Used to finish servicing a request. For read/write requests, we will call |  * Used to finish servicing a request. For read/write requests, we will call | ||||||
|  * ide_end_request to pass to the next buffer. |  * ide_end_request to pass to the next buffer. | ||||||
|  */ |  */ | ||||||
| int ide_floppy_end_request(ide_drive_t *drive, int uptodate, int nsecs) | static int ide_floppy_end_request(ide_drive_t *drive, int uptodate, int nsecs) | ||||||
| { | { | ||||||
| 	idefloppy_floppy_t *floppy = drive->driver_data; | 	idefloppy_floppy_t *floppy = drive->driver_data; | ||||||
| 	struct request *rq = HWGROUP(drive)->rq; | 	struct request *rq = HWGROUP(drive)->rq; | ||||||
| @ -280,13 +280,12 @@ static void idefloppy_blockpc_cmd(idefloppy_floppy_t *floppy, | |||||||
| 	pc->req_xfer = pc->buf_size = rq->data_len; | 	pc->req_xfer = pc->buf_size = rq->data_len; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, struct request *rq, | static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, | ||||||
| 				      sector_t block_s) | 					     struct request *rq, sector_t block) | ||||||
| { | { | ||||||
| 	idefloppy_floppy_t *floppy = drive->driver_data; | 	idefloppy_floppy_t *floppy = drive->driver_data; | ||||||
| 	ide_hwif_t *hwif = drive->hwif; | 	ide_hwif_t *hwif = drive->hwif; | ||||||
| 	struct ide_atapi_pc *pc; | 	struct ide_atapi_pc *pc; | ||||||
| 	unsigned long block = (unsigned long)block_s; |  | ||||||
| 
 | 
 | ||||||
| 	ide_debug_log(IDE_DBG_FUNC, "%s: dev: %s, cmd: 0x%x, cmd_type: %x, " | 	ide_debug_log(IDE_DBG_FUNC, "%s: dev: %s, cmd: 0x%x, cmd_type: %x, " | ||||||
| 		      "errors: %d\n", | 		      "errors: %d\n", | ||||||
| @ -316,7 +315,7 @@ ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, struct request *rq, | |||||||
| 			return ide_stopped; | 			return ide_stopped; | ||||||
| 		} | 		} | ||||||
| 		pc = &floppy->queued_pc; | 		pc = &floppy->queued_pc; | ||||||
| 		idefloppy_create_rw_cmd(drive, pc, rq, block); | 		idefloppy_create_rw_cmd(drive, pc, rq, (unsigned long)block); | ||||||
| 	} else if (blk_special_request(rq)) { | 	} else if (blk_special_request(rq)) { | ||||||
| 		pc = (struct ide_atapi_pc *) rq->buffer; | 		pc = (struct ide_atapi_pc *) rq->buffer; | ||||||
| 	} else if (blk_pc_request(rq)) { | 	} else if (blk_pc_request(rq)) { | ||||||
| @ -406,7 +405,7 @@ static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive) | |||||||
|  * Determine if a media is present in the floppy drive, and if so, its LBA |  * Determine if a media is present in the floppy drive, and if so, its LBA | ||||||
|  * capacity. |  * capacity. | ||||||
|  */ |  */ | ||||||
| int ide_floppy_get_capacity(ide_drive_t *drive) | static int ide_floppy_get_capacity(ide_drive_t *drive) | ||||||
| { | { | ||||||
| 	idefloppy_floppy_t *floppy = drive->driver_data; | 	idefloppy_floppy_t *floppy = drive->driver_data; | ||||||
| 	struct gendisk *disk = floppy->disk; | 	struct gendisk *disk = floppy->disk; | ||||||
| @ -505,9 +504,9 @@ int ide_floppy_get_capacity(ide_drive_t *drive) | |||||||
| 	return rc; | 	return rc; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ide_floppy_setup(ide_drive_t *drive) | static void ide_floppy_setup(ide_drive_t *drive) | ||||||
| { | { | ||||||
| 	struct ide_floppy_obj *floppy = drive->driver_data; | 	struct ide_disk_obj *floppy = drive->driver_data; | ||||||
| 	u16 *id = drive->id; | 	u16 *id = drive->id; | ||||||
| 
 | 
 | ||||||
| 	drive->pc_callback	 = ide_floppy_callback; | 	drive->pc_callback	 = ide_floppy_callback; | ||||||
| @ -547,3 +546,33 @@ void ide_floppy_setup(ide_drive_t *drive) | |||||||
| 
 | 
 | ||||||
| 	drive->dev_flags |= IDE_DFLAG_ATTACH; | 	drive->dev_flags |= IDE_DFLAG_ATTACH; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | static void ide_floppy_flush(ide_drive_t *drive) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int ide_floppy_init_media(ide_drive_t *drive, struct gendisk *disk) | ||||||
|  | { | ||||||
|  | 	int ret = 0; | ||||||
|  | 
 | ||||||
|  | 	if (ide_do_test_unit_ready(drive, disk)) | ||||||
|  | 		ide_do_start_stop(drive, disk, 1); | ||||||
|  | 
 | ||||||
|  | 	ret = ide_floppy_get_capacity(drive); | ||||||
|  | 
 | ||||||
|  | 	set_capacity(disk, ide_gd_capacity(drive)); | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const struct ide_disk_ops ide_atapi_disk_ops = { | ||||||
|  | 	.check		= ide_check_atapi_device, | ||||||
|  | 	.get_capacity	= ide_floppy_get_capacity, | ||||||
|  | 	.setup		= ide_floppy_setup, | ||||||
|  | 	.flush		= ide_floppy_flush, | ||||||
|  | 	.init_media	= ide_floppy_init_media, | ||||||
|  | 	.set_doorlock	= ide_set_media_lock, | ||||||
|  | 	.do_request	= ide_floppy_do_request, | ||||||
|  | 	.end_request	= ide_floppy_end_request, | ||||||
|  | 	.ioctl		= ide_floppy_ioctl, | ||||||
|  | }; | ||||||
|  | |||||||
| @ -1,48 +1,10 @@ | |||||||
| #ifndef __IDE_FLOPPY_H | #ifndef __IDE_FLOPPY_H | ||||||
| #define __IDE_FLOPPY_H | #define __IDE_FLOPPY_H | ||||||
| 
 | 
 | ||||||
| #define DRV_NAME "ide-floppy" | #include "ide-gd.h" | ||||||
| #define PFX DRV_NAME ": " |  | ||||||
| 
 | 
 | ||||||
| /* define to see debug info */ | #ifdef CONFIG_IDE_GD_ATAPI | ||||||
| #define IDEFLOPPY_DEBUG_LOG	0 | typedef struct ide_disk_obj idefloppy_floppy_t; | ||||||
| 
 |  | ||||||
| #if IDEFLOPPY_DEBUG_LOG |  | ||||||
| #define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, args) |  | ||||||
| #else |  | ||||||
| #define ide_debug_log(lvl, fmt, args...) do {} while (0) |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
|  * Most of our global data which we need to save even as we leave the driver |  | ||||||
|  * due to an interrupt or a timer event is stored in a variable of type |  | ||||||
|  * idefloppy_floppy_t, defined below. |  | ||||||
|  */ |  | ||||||
| typedef struct ide_floppy_obj { |  | ||||||
| 	ide_drive_t	*drive; |  | ||||||
| 	ide_driver_t	*driver; |  | ||||||
| 	struct gendisk	*disk; |  | ||||||
| 	struct kref	kref; |  | ||||||
| 	unsigned int	openers;	/* protected by BKL for now */ |  | ||||||
| 
 |  | ||||||
| 	/* Last failed packet command */ |  | ||||||
| 	struct ide_atapi_pc *failed_pc; |  | ||||||
| 	/* used for blk_{fs,pc}_request() requests */ |  | ||||||
| 	struct ide_atapi_pc queued_pc; |  | ||||||
| 
 |  | ||||||
| 	/* Last error information */ |  | ||||||
| 	u8 sense_key, asc, ascq; |  | ||||||
| 
 |  | ||||||
| 	int progress_indication; |  | ||||||
| 
 |  | ||||||
| 	/* Device information */ |  | ||||||
| 	/* Current format */ |  | ||||||
| 	int blocks, block_size, bs_factor; |  | ||||||
| 	/* Last format capacity descriptor */ |  | ||||||
| 	u8 cap_desc[8]; |  | ||||||
| 	/* Copy of the flexible disk page */ |  | ||||||
| 	u8 flexible_disk_page[32]; |  | ||||||
| } idefloppy_floppy_t; |  | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Pages of the SELECT SENSE / MODE SENSE packet commands. |  * Pages of the SELECT SENSE / MODE SENSE packet commands. | ||||||
| @ -57,23 +19,23 @@ typedef struct ide_floppy_obj { | |||||||
| #define	IDEFLOPPY_IOCTL_FORMAT_START		0x4602 | #define	IDEFLOPPY_IOCTL_FORMAT_START		0x4602 | ||||||
| #define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS	0x4603 | #define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS	0x4603 | ||||||
| 
 | 
 | ||||||
| sector_t ide_gd_capacity(ide_drive_t *); |  | ||||||
| 
 |  | ||||||
| /* ide-floppy.c */ | /* ide-floppy.c */ | ||||||
|  | extern const struct ide_disk_ops ide_atapi_disk_ops; | ||||||
| void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *, u8); | void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *, u8); | ||||||
| void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *); | void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *); | ||||||
| int ide_floppy_get_capacity(ide_drive_t *); |  | ||||||
| void ide_floppy_setup(ide_drive_t *); |  | ||||||
| ide_startstop_t ide_floppy_do_request(ide_drive_t *, struct request *, sector_t); |  | ||||||
| int ide_floppy_end_request(ide_drive_t *, int, int); |  | ||||||
| 
 | 
 | ||||||
| /* ide-floppy_ioctl.c */ | /* ide-floppy_ioctl.c */ | ||||||
| int ide_floppy_ioctl(struct inode *, struct file *, unsigned, unsigned long); | int ide_floppy_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int, | ||||||
|  | 		     unsigned long); | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_IDE_PROC_FS | #ifdef CONFIG_IDE_PROC_FS | ||||||
| /* ide-floppy_proc.c */ | /* ide-floppy_proc.c */ | ||||||
| extern ide_proc_entry_t ide_floppy_proc[]; | extern ide_proc_entry_t ide_floppy_proc[]; | ||||||
| extern const struct ide_proc_devset ide_floppy_settings[]; | extern const struct ide_proc_devset ide_floppy_settings[]; | ||||||
| #endif | #endif | ||||||
|  | #else | ||||||
|  | #define ide_floppy_proc		NULL | ||||||
|  | #define ide_floppy_settings	NULL | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| #endif /*__IDE_FLOPPY_H */ | #endif /*__IDE_FLOPPY_H */ | ||||||
|  | |||||||
| @ -33,7 +33,7 @@ | |||||||
| 
 | 
 | ||||||
| static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg) | static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg) | ||||||
| { | { | ||||||
| 	struct ide_floppy_obj *floppy = drive->driver_data; | 	struct ide_disk_obj *floppy = drive->driver_data; | ||||||
| 	struct ide_atapi_pc pc; | 	struct ide_atapi_pc pc; | ||||||
| 	u8 header_len, desc_cnt; | 	u8 header_len, desc_cnt; | ||||||
| 	int i, blocks, length, u_array_size, u_index; | 	int i, blocks, length, u_array_size, u_index; | ||||||
| @ -260,13 +260,10 @@ static int ide_floppy_format_ioctl(ide_drive_t *drive, struct file *file, | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int ide_floppy_ioctl(struct inode *inode, struct file *file, | int ide_floppy_ioctl(ide_drive_t *drive, struct inode *inode, | ||||||
| 		    unsigned int cmd, unsigned long arg) | 		     struct file *file, unsigned int cmd, unsigned long arg) | ||||||
| { | { | ||||||
| 	struct block_device *bdev = inode->i_bdev; | 	struct block_device *bdev = inode->i_bdev; | ||||||
| 	struct ide_floppy_obj *floppy = ide_drv_g(bdev->bd_disk, |  | ||||||
| 						     ide_floppy_obj); |  | ||||||
| 	ide_drive_t *drive = floppy->drive; |  | ||||||
| 	struct ide_atapi_pc pc; | 	struct ide_atapi_pc pc; | ||||||
| 	void __user *argp = (void __user *)arg; | 	void __user *argp = (void __user *)arg; | ||||||
| 	int err; | 	int err; | ||||||
|  | |||||||
| @ -1,309 +0,0 @@ | |||||||
| #include <linux/module.h> |  | ||||||
| #include <linux/types.h> |  | ||||||
| #include <linux/string.h> |  | ||||||
| #include <linux/kernel.h> |  | ||||||
| #include <linux/errno.h> |  | ||||||
| #include <linux/genhd.h> |  | ||||||
| #include <linux/mutex.h> |  | ||||||
| #include <linux/ide.h> |  | ||||||
| #include <linux/hdreg.h> |  | ||||||
| 
 |  | ||||||
| #include "ide-floppy.h" |  | ||||||
| 
 |  | ||||||
| #define IDEFLOPPY_VERSION "1.00" |  | ||||||
| 
 |  | ||||||
| /* module parameters */ |  | ||||||
| static unsigned long debug_mask; |  | ||||||
| module_param(debug_mask, ulong, 0644); |  | ||||||
| 
 |  | ||||||
| static DEFINE_MUTEX(ide_disk_ref_mutex); |  | ||||||
| 
 |  | ||||||
| static void ide_disk_release(struct kref *); |  | ||||||
| 
 |  | ||||||
| static struct ide_floppy_obj *ide_disk_get(struct gendisk *disk) |  | ||||||
| { |  | ||||||
| 	struct ide_floppy_obj *idkp = NULL; |  | ||||||
| 
 |  | ||||||
| 	mutex_lock(&ide_disk_ref_mutex); |  | ||||||
| 	idkp = ide_drv_g(disk, ide_floppy_obj); |  | ||||||
| 	if (idkp) { |  | ||||||
| 		if (ide_device_get(idkp->drive)) |  | ||||||
| 			idkp = NULL; |  | ||||||
| 		else |  | ||||||
| 			kref_get(&idkp->kref); |  | ||||||
| 	} |  | ||||||
| 	mutex_unlock(&ide_disk_ref_mutex); |  | ||||||
| 	return idkp; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void ide_disk_put(struct ide_floppy_obj *idkp) |  | ||||||
| { |  | ||||||
| 	ide_drive_t *drive = idkp->drive; |  | ||||||
| 
 |  | ||||||
| 	mutex_lock(&ide_disk_ref_mutex); |  | ||||||
| 	kref_put(&idkp->kref, ide_disk_release); |  | ||||||
| 	ide_device_put(drive); |  | ||||||
| 	mutex_unlock(&ide_disk_ref_mutex); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| sector_t ide_gd_capacity(ide_drive_t *drive) |  | ||||||
| { |  | ||||||
| 	return drive->capacity64; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int ide_gd_probe(ide_drive_t *); |  | ||||||
| 
 |  | ||||||
| static void ide_gd_remove(ide_drive_t *drive) |  | ||||||
| { |  | ||||||
| 	struct ide_floppy_obj *idkp = drive->driver_data; |  | ||||||
| 	struct gendisk *g = idkp->disk; |  | ||||||
| 
 |  | ||||||
| 	ide_proc_unregister_driver(drive, idkp->driver); |  | ||||||
| 
 |  | ||||||
| 	del_gendisk(g); |  | ||||||
| 
 |  | ||||||
| 	ide_disk_put(idkp); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void ide_disk_release(struct kref *kref) |  | ||||||
| { |  | ||||||
| 	struct ide_floppy_obj *idkp = to_ide_drv(kref, ide_floppy_obj); |  | ||||||
| 	ide_drive_t *drive = idkp->drive; |  | ||||||
| 	struct gendisk *g = idkp->disk; |  | ||||||
| 
 |  | ||||||
| 	drive->driver_data = NULL; |  | ||||||
| 	g->private_data = NULL; |  | ||||||
| 	put_disk(g); |  | ||||||
| 	kfree(idkp); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #ifdef CONFIG_IDE_PROC_FS |  | ||||||
| static ide_proc_entry_t *ide_floppy_proc_entries(ide_drive_t *drive) |  | ||||||
| { |  | ||||||
| 	return ide_floppy_proc; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static const struct ide_proc_devset *ide_floppy_proc_devsets(ide_drive_t *drive) |  | ||||||
| { |  | ||||||
| 	return ide_floppy_settings; |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| static ide_driver_t ide_gd_driver = { |  | ||||||
| 	.gen_driver = { |  | ||||||
| 		.owner		= THIS_MODULE, |  | ||||||
| 		.name		= "ide-floppy", |  | ||||||
| 		.bus		= &ide_bus_type, |  | ||||||
| 	}, |  | ||||||
| 	.probe			= ide_gd_probe, |  | ||||||
| 	.remove			= ide_gd_remove, |  | ||||||
| 	.version		= IDEFLOPPY_VERSION, |  | ||||||
| 	.do_request		= ide_floppy_do_request, |  | ||||||
| 	.end_request		= ide_floppy_end_request, |  | ||||||
| 	.error			= __ide_error, |  | ||||||
| #ifdef CONFIG_IDE_PROC_FS |  | ||||||
| 	.proc_entries		= ide_floppy_proc_entries, |  | ||||||
| 	.proc_devsets		= ide_floppy_proc_devsets, |  | ||||||
| #endif |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static int ide_gd_open(struct inode *inode, struct file *filp) |  | ||||||
| { |  | ||||||
| 	struct gendisk *disk = inode->i_bdev->bd_disk; |  | ||||||
| 	struct ide_floppy_obj *idkp; |  | ||||||
| 	ide_drive_t *drive; |  | ||||||
| 	int ret = 0; |  | ||||||
| 
 |  | ||||||
| 	idkp = ide_disk_get(disk); |  | ||||||
| 	if (idkp == NULL) |  | ||||||
| 		return -ENXIO; |  | ||||||
| 
 |  | ||||||
| 	drive = idkp->drive; |  | ||||||
| 
 |  | ||||||
| 	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__); |  | ||||||
| 
 |  | ||||||
| 	idkp->openers++; |  | ||||||
| 
 |  | ||||||
| 	if (idkp->openers == 1) { |  | ||||||
| 		drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS; |  | ||||||
| 		/* Just in case */ |  | ||||||
| 
 |  | ||||||
| 		if (ide_do_test_unit_ready(drive, disk)) |  | ||||||
| 			ide_do_start_stop(drive, disk, 1); |  | ||||||
| 
 |  | ||||||
| 		ret = ide_floppy_get_capacity(drive); |  | ||||||
| 
 |  | ||||||
| 		set_capacity(disk, ide_gd_capacity(drive)); |  | ||||||
| 
 |  | ||||||
| 		if (ret && (filp->f_flags & O_NDELAY) == 0) { |  | ||||||
| 		    /*
 |  | ||||||
| 		     * Allow O_NDELAY to open a drive without a disk, or with an |  | ||||||
| 		     * unreadable disk, so that we can get the format capacity |  | ||||||
| 		     * of the drive or begin the format - Sam |  | ||||||
| 		     */ |  | ||||||
| 			ret = -EIO; |  | ||||||
| 			goto out_put_idkp; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if ((drive->dev_flags & IDE_DFLAG_WP) && (filp->f_mode & 2)) { |  | ||||||
| 			ret = -EROFS; |  | ||||||
| 			goto out_put_idkp; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		ide_set_media_lock(drive, disk, 1); |  | ||||||
| 		drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED; |  | ||||||
| 		check_disk_change(inode->i_bdev); |  | ||||||
| 	} else if (drive->dev_flags & IDE_DFLAG_FORMAT_IN_PROGRESS) { |  | ||||||
| 		ret = -EBUSY; |  | ||||||
| 		goto out_put_idkp; |  | ||||||
| 	} |  | ||||||
| 	return 0; |  | ||||||
| 
 |  | ||||||
| out_put_idkp: |  | ||||||
| 	idkp->openers--; |  | ||||||
| 	ide_disk_put(idkp); |  | ||||||
| 	return ret; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int ide_gd_release(struct inode *inode, struct file *filp) |  | ||||||
| { |  | ||||||
| 	struct gendisk *disk = inode->i_bdev->bd_disk; |  | ||||||
| 	struct ide_floppy_obj *idkp = ide_drv_g(disk, ide_floppy_obj); |  | ||||||
| 	ide_drive_t *drive = idkp->drive; |  | ||||||
| 
 |  | ||||||
| 	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__); |  | ||||||
| 
 |  | ||||||
| 	if (idkp->openers == 1) { |  | ||||||
| 		ide_set_media_lock(drive, disk, 0); |  | ||||||
| 		drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	idkp->openers--; |  | ||||||
| 
 |  | ||||||
| 	ide_disk_put(idkp); |  | ||||||
| 
 |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int ide_gd_getgeo(struct block_device *bdev, struct hd_geometry *geo) |  | ||||||
| { |  | ||||||
| 	struct ide_floppy_obj *idkp = ide_drv_g(bdev->bd_disk, ide_floppy_obj); |  | ||||||
| 	ide_drive_t *drive = idkp->drive; |  | ||||||
| 
 |  | ||||||
| 	geo->heads = drive->bios_head; |  | ||||||
| 	geo->sectors = drive->bios_sect; |  | ||||||
| 	geo->cylinders = (u16)drive->bios_cyl; /* truncate */ |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int ide_gd_media_changed(struct gendisk *disk) |  | ||||||
| { |  | ||||||
| 	struct ide_floppy_obj *idkp = ide_drv_g(disk, ide_floppy_obj); |  | ||||||
| 	ide_drive_t *drive = idkp->drive; |  | ||||||
| 	int ret; |  | ||||||
| 
 |  | ||||||
| 	/* do not scan partitions twice if this is a removable device */ |  | ||||||
| 	if (drive->dev_flags & IDE_DFLAG_ATTACH) { |  | ||||||
| 		drive->dev_flags &= ~IDE_DFLAG_ATTACH; |  | ||||||
| 		return 0; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	ret = !!(drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED); |  | ||||||
| 	drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED; |  | ||||||
| 
 |  | ||||||
| 	return ret; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int ide_gd_revalidate_disk(struct gendisk *disk) |  | ||||||
| { |  | ||||||
| 	struct ide_floppy_obj *idkp = ide_drv_g(disk, ide_floppy_obj); |  | ||||||
| 	set_capacity(disk, ide_gd_capacity(idkp->drive)); |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static struct block_device_operations ide_gd_ops = { |  | ||||||
| 	.owner			= THIS_MODULE, |  | ||||||
| 	.open			= ide_gd_open, |  | ||||||
| 	.release		= ide_gd_release, |  | ||||||
| 	.ioctl			= ide_floppy_ioctl, |  | ||||||
| 	.getgeo			= ide_gd_getgeo, |  | ||||||
| 	.media_changed		= ide_gd_media_changed, |  | ||||||
| 	.revalidate_disk	= ide_gd_revalidate_disk |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static int ide_gd_probe(ide_drive_t *drive) |  | ||||||
| { |  | ||||||
| 	struct ide_floppy_obj *idkp; |  | ||||||
| 	struct gendisk *g; |  | ||||||
| 
 |  | ||||||
| 	if (!strstr("ide-floppy", drive->driver_req)) |  | ||||||
| 		goto failed; |  | ||||||
| 
 |  | ||||||
| 	if (drive->media != ide_floppy) |  | ||||||
| 		goto failed; |  | ||||||
| 
 |  | ||||||
| 	if (!ide_check_atapi_device(drive, DRV_NAME)) { |  | ||||||
| 		printk(KERN_ERR PFX "%s: not supported by this version of " |  | ||||||
| 		       DRV_NAME "\n", drive->name); |  | ||||||
| 		goto failed; |  | ||||||
| 	} |  | ||||||
| 	idkp = kzalloc(sizeof(*idkp), GFP_KERNEL); |  | ||||||
| 	if (!idkp) { |  | ||||||
| 		printk(KERN_ERR PFX "%s: Can't allocate a floppy structure\n", |  | ||||||
| 		       drive->name); |  | ||||||
| 		goto failed; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	g = alloc_disk_node(1 << PARTN_BITS, hwif_to_node(drive->hwif)); |  | ||||||
| 	if (!g) |  | ||||||
| 		goto out_free_idkp; |  | ||||||
| 
 |  | ||||||
| 	ide_init_disk(g, drive); |  | ||||||
| 
 |  | ||||||
| 	kref_init(&idkp->kref); |  | ||||||
| 
 |  | ||||||
| 	idkp->drive = drive; |  | ||||||
| 	idkp->driver = &ide_gd_driver; |  | ||||||
| 	idkp->disk = g; |  | ||||||
| 
 |  | ||||||
| 	g->private_data = &idkp->driver; |  | ||||||
| 
 |  | ||||||
| 	drive->driver_data = idkp; |  | ||||||
| 
 |  | ||||||
| 	drive->debug_mask = debug_mask; |  | ||||||
| 
 |  | ||||||
| 	ide_floppy_setup(drive); |  | ||||||
| 
 |  | ||||||
| 	set_capacity(g, ide_gd_capacity(drive)); |  | ||||||
| 
 |  | ||||||
| 	g->minors = 1 << PARTN_BITS; |  | ||||||
| 	g->driverfs_dev = &drive->gendev; |  | ||||||
| 	if (drive->dev_flags & IDE_DFLAG_REMOVABLE) |  | ||||||
| 		g->flags = GENHD_FL_REMOVABLE; |  | ||||||
| 	g->fops = &ide_gd_ops; |  | ||||||
| 	add_disk(g); |  | ||||||
| 	return 0; |  | ||||||
| 
 |  | ||||||
| out_free_idkp: |  | ||||||
| 	kfree(idkp); |  | ||||||
| failed: |  | ||||||
| 	return -ENODEV; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int __init ide_gd_init(void) |  | ||||||
| { |  | ||||||
| 	printk(KERN_INFO DRV_NAME " driver " IDEFLOPPY_VERSION "\n"); |  | ||||||
| 	return driver_register(&ide_gd_driver.gen_driver); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void __exit ide_gd_exit(void) |  | ||||||
| { |  | ||||||
| 	driver_unregister(&ide_gd_driver.gen_driver); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| MODULE_ALIAS("ide:*m-floppy*"); |  | ||||||
| MODULE_ALIAS("ide-floppy"); |  | ||||||
| module_init(ide_gd_init); |  | ||||||
| module_exit(ide_gd_exit); |  | ||||||
| MODULE_LICENSE("GPL"); |  | ||||||
| MODULE_DESCRIPTION("ATAPI FLOPPY Driver"); |  | ||||||
| @ -15,9 +15,14 @@ | |||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #include "ide-disk.h" | #include "ide-disk.h" | ||||||
|  | #include "ide-floppy.h" | ||||||
| 
 | 
 | ||||||
| #define IDE_GD_VERSION	"1.18" | #define IDE_GD_VERSION	"1.18" | ||||||
| 
 | 
 | ||||||
|  | /* module parameters */ | ||||||
|  | static unsigned long debug_mask; | ||||||
|  | module_param(debug_mask, ulong, 0644); | ||||||
|  | 
 | ||||||
| static DEFINE_MUTEX(ide_disk_ref_mutex); | static DEFINE_MUTEX(ide_disk_ref_mutex); | ||||||
| 
 | 
 | ||||||
| static void ide_disk_release(struct kref *); | static void ide_disk_release(struct kref *); | ||||||
| @ -64,7 +69,7 @@ static void ide_gd_remove(ide_drive_t *drive) | |||||||
| 
 | 
 | ||||||
| 	del_gendisk(g); | 	del_gendisk(g); | ||||||
| 
 | 
 | ||||||
| 	ide_disk_flush(drive); | 	drive->disk_ops->flush(drive); | ||||||
| 
 | 
 | ||||||
| 	ide_disk_put(idkp); | 	ide_disk_put(idkp); | ||||||
| } | } | ||||||
| @ -75,6 +80,7 @@ static void ide_disk_release(struct kref *kref) | |||||||
| 	ide_drive_t *drive = idkp->drive; | 	ide_drive_t *drive = idkp->drive; | ||||||
| 	struct gendisk *g = idkp->disk; | 	struct gendisk *g = idkp->disk; | ||||||
| 
 | 
 | ||||||
|  | 	drive->disk_ops = NULL; | ||||||
| 	drive->driver_data = NULL; | 	drive->driver_data = NULL; | ||||||
| 	g->private_data = NULL; | 	g->private_data = NULL; | ||||||
| 	put_disk(g); | 	put_disk(g); | ||||||
| @ -89,7 +95,7 @@ static void ide_disk_release(struct kref *kref) | |||||||
| static void ide_gd_resume(ide_drive_t *drive) | static void ide_gd_resume(ide_drive_t *drive) | ||||||
| { | { | ||||||
| 	if (ata_id_hpa_enabled(drive->id)) | 	if (ata_id_hpa_enabled(drive->id)) | ||||||
| 		ide_disk_init_capacity(drive); | 		(void)drive->disk_ops->get_capacity(drive); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void ide_gd_shutdown(ide_drive_t *drive) | static void ide_gd_shutdown(ide_drive_t *drive) | ||||||
| @ -110,7 +116,7 @@ static void ide_gd_shutdown(ide_drive_t *drive) | |||||||
| #else | #else | ||||||
| 	if (system_state == SYSTEM_RESTART) { | 	if (system_state == SYSTEM_RESTART) { | ||||||
| #endif | #endif | ||||||
| 		ide_disk_flush(drive); | 		drive->disk_ops->flush(drive); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -122,19 +128,31 @@ static void ide_gd_shutdown(ide_drive_t *drive) | |||||||
| #ifdef CONFIG_IDE_PROC_FS | #ifdef CONFIG_IDE_PROC_FS | ||||||
| static ide_proc_entry_t *ide_disk_proc_entries(ide_drive_t *drive) | static ide_proc_entry_t *ide_disk_proc_entries(ide_drive_t *drive) | ||||||
| { | { | ||||||
| 	return ide_disk_proc; | 	return (drive->media == ide_disk) ? ide_disk_proc : ide_floppy_proc; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct ide_proc_devset *ide_disk_proc_devsets(ide_drive_t *drive) | static const struct ide_proc_devset *ide_disk_proc_devsets(ide_drive_t *drive) | ||||||
| { | { | ||||||
| 	return ide_disk_settings; | 	return (drive->media == ide_disk) ? ide_disk_settings | ||||||
|  | 					  : ide_floppy_settings; | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | static ide_startstop_t ide_gd_do_request(ide_drive_t *drive, | ||||||
|  | 					 struct request *rq, sector_t sector) | ||||||
|  | { | ||||||
|  | 	return drive->disk_ops->do_request(drive, rq, sector); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int ide_gd_end_request(ide_drive_t *drive, int uptodate, int nrsecs) | ||||||
|  | { | ||||||
|  | 	return drive->disk_ops->end_request(drive, uptodate, nrsecs); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static ide_driver_t ide_gd_driver = { | static ide_driver_t ide_gd_driver = { | ||||||
| 	.gen_driver = { | 	.gen_driver = { | ||||||
| 		.owner		= THIS_MODULE, | 		.owner		= THIS_MODULE, | ||||||
| 		.name		= "ide-disk", | 		.name		= "ide-gd", | ||||||
| 		.bus		= &ide_bus_type, | 		.bus		= &ide_bus_type, | ||||||
| 	}, | 	}, | ||||||
| 	.probe			= ide_gd_probe, | 	.probe			= ide_gd_probe, | ||||||
| @ -142,8 +160,8 @@ static ide_driver_t ide_gd_driver = { | |||||||
| 	.resume			= ide_gd_resume, | 	.resume			= ide_gd_resume, | ||||||
| 	.shutdown		= ide_gd_shutdown, | 	.shutdown		= ide_gd_shutdown, | ||||||
| 	.version		= IDE_GD_VERSION, | 	.version		= IDE_GD_VERSION, | ||||||
| 	.do_request		= ide_do_rw_disk, | 	.do_request		= ide_gd_do_request, | ||||||
| 	.end_request		= ide_end_request, | 	.end_request		= ide_gd_end_request, | ||||||
| 	.error			= __ide_error, | 	.error			= __ide_error, | ||||||
| #ifdef CONFIG_IDE_PROC_FS | #ifdef CONFIG_IDE_PROC_FS | ||||||
| 	.proc_entries		= ide_disk_proc_entries, | 	.proc_entries		= ide_disk_proc_entries, | ||||||
| @ -156,6 +174,7 @@ static int ide_gd_open(struct inode *inode, struct file *filp) | |||||||
| 	struct gendisk *disk = inode->i_bdev->bd_disk; | 	struct gendisk *disk = inode->i_bdev->bd_disk; | ||||||
| 	struct ide_disk_obj *idkp; | 	struct ide_disk_obj *idkp; | ||||||
| 	ide_drive_t *drive; | 	ide_drive_t *drive; | ||||||
|  | 	int ret = 0; | ||||||
| 
 | 
 | ||||||
| 	idkp = ide_disk_get(disk); | 	idkp = ide_disk_get(disk); | ||||||
| 	if (idkp == NULL) | 	if (idkp == NULL) | ||||||
| @ -163,19 +182,49 @@ static int ide_gd_open(struct inode *inode, struct file *filp) | |||||||
| 
 | 
 | ||||||
| 	drive = idkp->drive; | 	drive = idkp->drive; | ||||||
| 
 | 
 | ||||||
|  | 	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__); | ||||||
|  | 
 | ||||||
| 	idkp->openers++; | 	idkp->openers++; | ||||||
| 
 | 
 | ||||||
| 	if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) { | 	if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) { | ||||||
|  | 		drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS; | ||||||
|  | 		/* Just in case */ | ||||||
|  | 
 | ||||||
|  | 		ret = drive->disk_ops->init_media(drive, disk); | ||||||
|  | 
 | ||||||
|  | 		/*
 | ||||||
|  | 		 * Allow O_NDELAY to open a drive without a disk, or with an | ||||||
|  | 		 * unreadable disk, so that we can get the format capacity | ||||||
|  | 		 * of the drive or begin the format - Sam | ||||||
|  | 		 */ | ||||||
|  | 		if (ret && (filp->f_flags & O_NDELAY) == 0) { | ||||||
|  | 			ret = -EIO; | ||||||
|  | 			goto out_put_idkp; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if ((drive->dev_flags & IDE_DFLAG_WP) && (filp->f_mode & 2)) { | ||||||
|  | 			ret = -EROFS; | ||||||
|  | 			goto out_put_idkp; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * Ignore the return code from door_lock, | 		 * Ignore the return code from door_lock, | ||||||
| 		 * since the open() has already succeeded, | 		 * since the open() has already succeeded, | ||||||
| 		 * and the door_lock is irrelevant at this point. | 		 * and the door_lock is irrelevant at this point. | ||||||
| 		 */ | 		 */ | ||||||
| 		ide_disk_set_doorlock(drive, 1); | 		drive->disk_ops->set_doorlock(drive, disk, 1); | ||||||
| 		drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED; | 		drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED; | ||||||
| 		check_disk_change(inode->i_bdev); | 		check_disk_change(inode->i_bdev); | ||||||
|  | 	} else if (drive->dev_flags & IDE_DFLAG_FORMAT_IN_PROGRESS) { | ||||||
|  | 		ret = -EBUSY; | ||||||
|  | 		goto out_put_idkp; | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
|  | 
 | ||||||
|  | out_put_idkp: | ||||||
|  | 	idkp->openers--; | ||||||
|  | 	ide_disk_put(idkp); | ||||||
|  | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int ide_gd_release(struct inode *inode, struct file *filp) | static int ide_gd_release(struct inode *inode, struct file *filp) | ||||||
| @ -184,11 +233,15 @@ static int ide_gd_release(struct inode *inode, struct file *filp) | |||||||
| 	struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); | 	struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); | ||||||
| 	ide_drive_t *drive = idkp->drive; | 	ide_drive_t *drive = idkp->drive; | ||||||
| 
 | 
 | ||||||
| 	if (idkp->openers == 1) | 	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__); | ||||||
| 		ide_disk_flush(drive); |  | ||||||
| 
 | 
 | ||||||
| 	if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) | 	if (idkp->openers == 1) | ||||||
| 		ide_disk_set_doorlock(drive, 0); | 		drive->disk_ops->flush(drive); | ||||||
|  | 
 | ||||||
|  | 	if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) { | ||||||
|  | 		drive->disk_ops->set_doorlock(drive, disk, 0); | ||||||
|  | 		drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	idkp->openers--; | 	idkp->openers--; | ||||||
| 
 | 
 | ||||||
| @ -233,11 +286,21 @@ static int ide_gd_revalidate_disk(struct gendisk *disk) | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int ide_gd_ioctl(struct inode *inode, struct file *file, | ||||||
|  | 			     unsigned int cmd, unsigned long arg) | ||||||
|  | { | ||||||
|  | 	struct block_device *bdev = inode->i_bdev; | ||||||
|  | 	struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj); | ||||||
|  | 	ide_drive_t *drive = idkp->drive; | ||||||
|  | 
 | ||||||
|  | 	return drive->disk_ops->ioctl(drive, inode, file, cmd, arg); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static struct block_device_operations ide_gd_ops = { | static struct block_device_operations ide_gd_ops = { | ||||||
| 	.owner			= THIS_MODULE, | 	.owner			= THIS_MODULE, | ||||||
| 	.open			= ide_gd_open, | 	.open			= ide_gd_open, | ||||||
| 	.release		= ide_gd_release, | 	.release		= ide_gd_release, | ||||||
| 	.ioctl			= ide_disk_ioctl, | 	.ioctl			= ide_gd_ioctl, | ||||||
| 	.getgeo			= ide_gd_getgeo, | 	.getgeo			= ide_gd_getgeo, | ||||||
| 	.media_changed		= ide_gd_media_changed, | 	.media_changed		= ide_gd_media_changed, | ||||||
| 	.revalidate_disk	= ide_gd_revalidate_disk | 	.revalidate_disk	= ide_gd_revalidate_disk | ||||||
| @ -245,19 +308,37 @@ static struct block_device_operations ide_gd_ops = { | |||||||
| 
 | 
 | ||||||
| static int ide_gd_probe(ide_drive_t *drive) | static int ide_gd_probe(ide_drive_t *drive) | ||||||
| { | { | ||||||
|  | 	const struct ide_disk_ops *disk_ops = NULL; | ||||||
| 	struct ide_disk_obj *idkp; | 	struct ide_disk_obj *idkp; | ||||||
| 	struct gendisk *g; | 	struct gendisk *g; | ||||||
| 
 | 
 | ||||||
| 	/* strstr("foo", "") is non-NULL */ | 	/* strstr("foo", "") is non-NULL */ | ||||||
| 	if (!strstr("ide-disk", drive->driver_req)) | 	if (!strstr("ide-gd", drive->driver_req)) | ||||||
| 		goto failed; | 		goto failed; | ||||||
| 
 | 
 | ||||||
| 	if (drive->media != ide_disk) | #ifdef CONFIG_IDE_GD_ATA | ||||||
|  | 	if (drive->media == ide_disk) | ||||||
|  | 		disk_ops = &ide_ata_disk_ops; | ||||||
|  | #endif | ||||||
|  | #ifdef CONFIG_IDE_GD_ATAPI | ||||||
|  | 	if (drive->media == ide_floppy) | ||||||
|  | 		disk_ops = &ide_atapi_disk_ops; | ||||||
|  | #endif | ||||||
|  | 	if (disk_ops == NULL) | ||||||
| 		goto failed; | 		goto failed; | ||||||
| 
 | 
 | ||||||
|  | 	if (disk_ops->check(drive, DRV_NAME) == 0) { | ||||||
|  | 		printk(KERN_ERR PFX "%s: not supported by this driver\n", | ||||||
|  | 			drive->name); | ||||||
|  | 		goto failed; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	idkp = kzalloc(sizeof(*idkp), GFP_KERNEL); | 	idkp = kzalloc(sizeof(*idkp), GFP_KERNEL); | ||||||
| 	if (!idkp) | 	if (!idkp) { | ||||||
|  | 		printk(KERN_ERR PFX "%s: can't allocate a disk structure\n", | ||||||
|  | 			drive->name); | ||||||
| 		goto failed; | 		goto failed; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif)); | 	g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif)); | ||||||
| 	if (!g) | 	if (!g) | ||||||
| @ -274,8 +355,10 @@ static int ide_gd_probe(ide_drive_t *drive) | |||||||
| 	g->private_data = &idkp->driver; | 	g->private_data = &idkp->driver; | ||||||
| 
 | 
 | ||||||
| 	drive->driver_data = idkp; | 	drive->driver_data = idkp; | ||||||
|  | 	drive->debug_mask = debug_mask; | ||||||
|  | 	drive->disk_ops = disk_ops; | ||||||
| 
 | 
 | ||||||
| 	ide_disk_setup(drive); | 	disk_ops->setup(drive); | ||||||
| 
 | 
 | ||||||
| 	set_capacity(g, ide_gd_capacity(drive)); | 	set_capacity(g, ide_gd_capacity(drive)); | ||||||
| 
 | 
 | ||||||
| @ -296,6 +379,7 @@ failed: | |||||||
| 
 | 
 | ||||||
| static int __init ide_gd_init(void) | static int __init ide_gd_init(void) | ||||||
| { | { | ||||||
|  | 	printk(KERN_INFO DRV_NAME " driver " IDE_GD_VERSION "\n"); | ||||||
| 	return driver_register(&ide_gd_driver.gen_driver); | 	return driver_register(&ide_gd_driver.gen_driver); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -306,7 +390,9 @@ static void __exit ide_gd_exit(void) | |||||||
| 
 | 
 | ||||||
| MODULE_ALIAS("ide:*m-disk*"); | MODULE_ALIAS("ide:*m-disk*"); | ||||||
| MODULE_ALIAS("ide-disk"); | MODULE_ALIAS("ide-disk"); | ||||||
|  | MODULE_ALIAS("ide:*m-floppy*"); | ||||||
|  | MODULE_ALIAS("ide-floppy"); | ||||||
| module_init(ide_gd_init); | module_init(ide_gd_init); | ||||||
| module_exit(ide_gd_exit); | module_exit(ide_gd_exit); | ||||||
| MODULE_LICENSE("GPL"); | MODULE_LICENSE("GPL"); | ||||||
| MODULE_DESCRIPTION("ATA DISK Driver"); | MODULE_DESCRIPTION("generic ATA/ATAPI disk driver"); | ||||||
|  | |||||||
							
								
								
									
										44
									
								
								drivers/ide/ide-gd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								drivers/ide/ide-gd.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | |||||||
|  | #ifndef __IDE_GD_H | ||||||
|  | #define __IDE_GD_H | ||||||
|  | 
 | ||||||
|  | #define DRV_NAME "ide-gd" | ||||||
|  | #define PFX DRV_NAME ": " | ||||||
|  | 
 | ||||||
|  | /* define to see debug info */ | ||||||
|  | #define IDE_GD_DEBUG_LOG	0 | ||||||
|  | 
 | ||||||
|  | #if IDE_GD_DEBUG_LOG | ||||||
|  | #define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, args) | ||||||
|  | #else | ||||||
|  | #define ide_debug_log(lvl, fmt, args...) do {} while (0) | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | struct ide_disk_obj { | ||||||
|  | 	ide_drive_t	*drive; | ||||||
|  | 	ide_driver_t	*driver; | ||||||
|  | 	struct gendisk	*disk; | ||||||
|  | 	struct kref	kref; | ||||||
|  | 	unsigned int	openers;	/* protected by BKL for now */ | ||||||
|  | 
 | ||||||
|  | 	/* Last failed packet command */ | ||||||
|  | 	struct ide_atapi_pc *failed_pc; | ||||||
|  | 	/* used for blk_{fs,pc}_request() requests */ | ||||||
|  | 	struct ide_atapi_pc queued_pc; | ||||||
|  | 
 | ||||||
|  | 	/* Last error information */ | ||||||
|  | 	u8 sense_key, asc, ascq; | ||||||
|  | 
 | ||||||
|  | 	int progress_indication; | ||||||
|  | 
 | ||||||
|  | 	/* Device information */ | ||||||
|  | 	/* Current format */ | ||||||
|  | 	int blocks, block_size, bs_factor; | ||||||
|  | 	/* Last format capacity descriptor */ | ||||||
|  | 	u8 cap_desc[8]; | ||||||
|  | 	/* Copy of the flexible disk page */ | ||||||
|  | 	u8 flexible_disk_page[32]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | sector_t ide_gd_capacity(ide_drive_t *); | ||||||
|  | 
 | ||||||
|  | #endif /* __IDE_GD_H */ | ||||||
| @ -179,7 +179,7 @@ config LEDS_TRIGGER_TIMER | |||||||
| 
 | 
 | ||||||
| config LEDS_TRIGGER_IDE_DISK | config LEDS_TRIGGER_IDE_DISK | ||||||
| 	bool "LED IDE Disk Trigger" | 	bool "LED IDE Disk Trigger" | ||||||
| 	depends on LEDS_TRIGGERS && BLK_DEV_IDEDISK | 	depends on LEDS_TRIGGERS && IDE_GD_ATA | ||||||
| 	help | 	help | ||||||
| 	  This allows LEDs to be controlled by IDE disk activity. | 	  This allows LEDs to be controlled by IDE disk activity. | ||||||
| 	  If unsure, say Y. | 	  If unsure, say Y. | ||||||
|  | |||||||
| @ -461,6 +461,23 @@ struct ide_acpi_drive_link; | |||||||
| struct ide_acpi_hwif_link; | struct ide_acpi_hwif_link; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | struct ide_drive_s; | ||||||
|  | 
 | ||||||
|  | struct ide_disk_ops { | ||||||
|  | 	int		(*check)(struct ide_drive_s *, const char *); | ||||||
|  | 	int		(*get_capacity)(struct ide_drive_s *); | ||||||
|  | 	void		(*setup)(struct ide_drive_s *); | ||||||
|  | 	void		(*flush)(struct ide_drive_s *); | ||||||
|  | 	int		(*init_media)(struct ide_drive_s *, struct gendisk *); | ||||||
|  | 	int		(*set_doorlock)(struct ide_drive_s *, struct gendisk *, | ||||||
|  | 					int); | ||||||
|  | 	ide_startstop_t	(*do_request)(struct ide_drive_s *, struct request *, | ||||||
|  | 				      sector_t); | ||||||
|  | 	int		(*end_request)(struct ide_drive_s *, int, int); | ||||||
|  | 	int		(*ioctl)(struct ide_drive_s *, struct inode *, | ||||||
|  | 				 struct file *, unsigned int, unsigned long); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| /* ATAPI device flags */ | /* ATAPI device flags */ | ||||||
| enum { | enum { | ||||||
| 	IDE_AFLAG_DRQ_INTERRUPT		= (1 << 0), | 	IDE_AFLAG_DRQ_INTERRUPT		= (1 << 0), | ||||||
| @ -594,6 +611,8 @@ struct ide_drive_s { | |||||||
| #endif | #endif | ||||||
| 	struct hwif_s		*hwif;	/* actually (ide_hwif_t *) */ | 	struct hwif_s		*hwif;	/* actually (ide_hwif_t *) */ | ||||||
| 
 | 
 | ||||||
|  | 	const struct ide_disk_ops *disk_ops; | ||||||
|  | 
 | ||||||
| 	unsigned long dev_flags; | 	unsigned long dev_flags; | ||||||
| 
 | 
 | ||||||
| 	unsigned long sleep;		/* sleep until this time */ | 	unsigned long sleep;		/* sleep until this time */ | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user