| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 1 |  | 
|  | 2 | /* | 
|  | 3 | *   pata-isapnp.c - ISA PnP PATA controller driver. | 
|  | 4 | *   Copyright 2005/2006 Red Hat Inc <alan@redhat.com>, all rights reserved. | 
|  | 5 | * | 
|  | 6 | *   Based in part on ide-pnp.c by Andrey Panin <pazke@donpac.ru> | 
|  | 7 | */ | 
|  | 8 |  | 
|  | 9 | #include <linux/kernel.h> | 
|  | 10 | #include <linux/module.h> | 
|  | 11 | #include <linux/isapnp.h> | 
|  | 12 | #include <linux/init.h> | 
|  | 13 | #include <linux/blkdev.h> | 
|  | 14 | #include <linux/delay.h> | 
|  | 15 | #include <scsi/scsi_host.h> | 
|  | 16 | #include <linux/ata.h> | 
|  | 17 | #include <linux/libata.h> | 
|  | 18 |  | 
|  | 19 | #define DRV_NAME "pata_isapnp" | 
|  | 20 | #define DRV_VERSION "0.1.5" | 
|  | 21 |  | 
|  | 22 | static struct scsi_host_template isapnp_sht = { | 
|  | 23 | .module			= THIS_MODULE, | 
|  | 24 | .name			= DRV_NAME, | 
|  | 25 | .ioctl			= ata_scsi_ioctl, | 
|  | 26 | .queuecommand		= ata_scsi_queuecmd, | 
|  | 27 | .can_queue		= ATA_DEF_QUEUE, | 
|  | 28 | .this_id		= ATA_SHT_THIS_ID, | 
|  | 29 | .sg_tablesize		= LIBATA_MAX_PRD, | 
|  | 30 | .max_sectors		= ATA_MAX_SECTORS, | 
|  | 31 | .cmd_per_lun		= ATA_SHT_CMD_PER_LUN, | 
|  | 32 | .emulated		= ATA_SHT_EMULATED, | 
|  | 33 | .use_clustering		= ATA_SHT_USE_CLUSTERING, | 
|  | 34 | .proc_name		= DRV_NAME, | 
|  | 35 | .dma_boundary		= ATA_DMA_BOUNDARY, | 
|  | 36 | .slave_configure	= ata_scsi_slave_config, | 
|  | 37 | .bios_param		= ata_std_bios_param, | 
|  | 38 | }; | 
|  | 39 |  | 
|  | 40 | static struct ata_port_operations isapnp_port_ops = { | 
|  | 41 | .port_disable	= ata_port_disable, | 
|  | 42 | .tf_load	= ata_tf_load, | 
|  | 43 | .tf_read	= ata_tf_read, | 
|  | 44 | .check_status 	= ata_check_status, | 
|  | 45 | .exec_command	= ata_exec_command, | 
|  | 46 | .dev_select 	= ata_std_dev_select, | 
|  | 47 |  | 
|  | 48 | .freeze		= ata_bmdma_freeze, | 
|  | 49 | .thaw		= ata_bmdma_thaw, | 
|  | 50 | .error_handler	= ata_bmdma_error_handler, | 
|  | 51 | .post_internal_cmd = ata_bmdma_post_internal_cmd, | 
|  | 52 |  | 
|  | 53 | .qc_prep 	= ata_qc_prep, | 
|  | 54 | .qc_issue	= ata_qc_issue_prot, | 
| Jeff Garzik | bda3028 | 2006-09-27 05:41:13 -0400 | [diff] [blame] | 55 |  | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 56 | .data_xfer	= ata_pio_data_xfer, | 
|  | 57 |  | 
|  | 58 | .irq_handler	= ata_interrupt, | 
|  | 59 | .irq_clear	= ata_bmdma_irq_clear, | 
|  | 60 |  | 
|  | 61 | .port_start	= ata_port_start, | 
|  | 62 | .port_stop	= ata_port_stop, | 
|  | 63 | .host_stop	= ata_host_stop | 
|  | 64 | }; | 
|  | 65 |  | 
|  | 66 | /** | 
|  | 67 | *	isapnp_init_one		-	attach an isapnp interface | 
|  | 68 | *	@idev: PnP device | 
|  | 69 | *	@dev_id: matching detect line | 
|  | 70 | * | 
|  | 71 | *	Register an ISA bus IDE interface. Such interfaces are PIO 0 and | 
|  | 72 | *	non shared IRQ. | 
|  | 73 | */ | 
|  | 74 |  | 
|  | 75 | static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev_id) | 
|  | 76 | { | 
|  | 77 | struct ata_probe_ent ae; | 
|  | 78 |  | 
|  | 79 | if (pnp_port_valid(idev, 0) == 0) | 
|  | 80 | return -ENODEV; | 
|  | 81 |  | 
|  | 82 | /* FIXME: Should selected polled PIO here not fail */ | 
|  | 83 | if (pnp_irq_valid(idev, 0) == 0) | 
|  | 84 | return -ENODEV; | 
|  | 85 |  | 
|  | 86 | memset(&ae, 0, sizeof(struct ata_probe_ent)); | 
|  | 87 | INIT_LIST_HEAD(&ae.node); | 
|  | 88 | ae.dev = &idev->dev; | 
|  | 89 | ae.port_ops = &isapnp_port_ops; | 
|  | 90 | ae.sht = &isapnp_sht; | 
|  | 91 | ae.n_ports = 1; | 
|  | 92 | ae.pio_mask = 1;		/* ISA so PIO 0 cycles */ | 
|  | 93 | ae.irq = pnp_irq(idev, 0); | 
|  | 94 | ae.irq_flags = 0; | 
|  | 95 | ae.port_flags = ATA_FLAG_SLAVE_POSS; | 
|  | 96 | ae.port[0].cmd_addr = pnp_port_start(idev, 0); | 
|  | 97 |  | 
|  | 98 | if (pnp_port_valid(idev, 1) == 0) { | 
|  | 99 | ae.port[0].altstatus_addr = pnp_port_start(idev, 1); | 
|  | 100 | ae.port[0].ctl_addr = pnp_port_start(idev, 1); | 
|  | 101 | ae.port_flags |= ATA_FLAG_SRST; | 
|  | 102 | } | 
|  | 103 | ata_std_ports(&ae.port[0]); | 
|  | 104 |  | 
|  | 105 | if (ata_device_add(&ae) == 0) | 
|  | 106 | return -ENODEV; | 
|  | 107 | return 0; | 
|  | 108 | } | 
|  | 109 |  | 
|  | 110 | /** | 
|  | 111 | *	isapnp_remove_one	-	unplug an isapnp interface | 
|  | 112 | *	@idev: PnP device | 
|  | 113 | * | 
|  | 114 | *	Remove a previously configured PnP ATA port. Called only on module | 
|  | 115 | *	unload events as the core does not currently deal with ISAPnP docking. | 
|  | 116 | */ | 
|  | 117 |  | 
|  | 118 | static void isapnp_remove_one(struct pnp_dev *idev) | 
|  | 119 | { | 
|  | 120 | struct device *dev = &idev->dev; | 
|  | 121 | struct ata_host *host = dev_get_drvdata(dev); | 
|  | 122 |  | 
|  | 123 | ata_host_remove(host); | 
|  | 124 | dev_set_drvdata(dev, NULL); | 
|  | 125 | } | 
|  | 126 |  | 
|  | 127 | static struct pnp_device_id isapnp_devices[] = { | 
|  | 128 | /* Generic ESDI/IDE/ATA compatible hard disk controller */ | 
|  | 129 | {.id = "PNP0600", .driver_data = 0}, | 
|  | 130 | {.id = ""} | 
|  | 131 | }; | 
|  | 132 |  | 
|  | 133 | static struct pnp_driver isapnp_driver = { | 
|  | 134 | .name		= DRV_NAME, | 
|  | 135 | .id_table	= isapnp_devices, | 
|  | 136 | .probe		= isapnp_init_one, | 
|  | 137 | .remove		= isapnp_remove_one, | 
|  | 138 | }; | 
|  | 139 |  | 
|  | 140 | static int __init isapnp_init(void) | 
|  | 141 | { | 
|  | 142 | return pnp_register_driver(&isapnp_driver); | 
|  | 143 | } | 
|  | 144 |  | 
|  | 145 | static void __exit isapnp_exit(void) | 
|  | 146 | { | 
|  | 147 | pnp_unregister_driver(&isapnp_driver); | 
|  | 148 | } | 
|  | 149 |  | 
|  | 150 | MODULE_AUTHOR("Alan Cox"); | 
|  | 151 | MODULE_DESCRIPTION("low-level driver for ISA PnP ATA"); | 
|  | 152 | MODULE_LICENSE("GPL"); | 
|  | 153 | MODULE_VERSION(DRV_VERSION); | 
|  | 154 |  | 
|  | 155 | module_init(isapnp_init); | 
|  | 156 | module_exit(isapnp_exit); |