| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 1 |  | 
 | 2 | /* | 
 | 3 |  *   pata-isapnp.c - ISA PnP PATA controller driver. | 
| Alan Cox | ab77163 | 2008-10-27 15:09:10 +0000 | [diff] [blame] | 4 |  *   Copyright 2005/2006 Red Hat Inc, all rights reserved. | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 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" | 
| Alan Cox | c96f173 | 2009-03-24 10:23:46 +0000 | [diff] [blame] | 20 | #define DRV_VERSION "0.2.5" | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 21 |  | 
 | 22 | static struct scsi_host_template isapnp_sht = { | 
| Tejun Heo | 68d1d07 | 2008-03-25 12:22:49 +0900 | [diff] [blame] | 23 | 	ATA_PIO_SHT(DRV_NAME), | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 24 | }; | 
 | 25 |  | 
 | 26 | static struct ata_port_operations isapnp_port_ops = { | 
| Tejun Heo | 029cfd6 | 2008-03-25 12:22:49 +0900 | [diff] [blame] | 27 | 	.inherits	= &ata_sff_port_ops, | 
| Jeff Garzik | a73984a | 2007-03-09 08:37:46 -0500 | [diff] [blame] | 28 | 	.cable_detect	= ata_cable_40wire, | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 29 | }; | 
 | 30 |  | 
| Alan Cox | c96f173 | 2009-03-24 10:23:46 +0000 | [diff] [blame] | 31 | static struct ata_port_operations isapnp_noalt_port_ops = { | 
 | 32 | 	.inherits	= &ata_sff_port_ops, | 
 | 33 | 	.cable_detect	= ata_cable_40wire, | 
 | 34 | 	/* No altstatus so we don't want to use the lost interrupt poll */ | 
 | 35 | 	.lost_interrupt = ATA_OP_NULL, | 
 | 36 | }; | 
 | 37 |  | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 38 | /** | 
 | 39 |  *	isapnp_init_one		-	attach an isapnp interface | 
 | 40 |  *	@idev: PnP device | 
 | 41 |  *	@dev_id: matching detect line | 
 | 42 |  * | 
 | 43 |  *	Register an ISA bus IDE interface. Such interfaces are PIO 0 and | 
 | 44 |  *	non shared IRQ. | 
 | 45 |  */ | 
 | 46 |  | 
 | 47 | static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev_id) | 
 | 48 | { | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 49 | 	struct ata_host *host; | 
 | 50 | 	struct ata_port *ap; | 
| Tejun Heo | 0d5ff56 | 2007-02-01 15:06:36 +0900 | [diff] [blame] | 51 | 	void __iomem *cmd_addr, *ctl_addr; | 
| Alan Cox | 91e33d3 | 2007-11-19 14:41:05 +0000 | [diff] [blame] | 52 | 	int irq = 0; | 
 | 53 | 	irq_handler_t handler = NULL; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 54 |  | 
 | 55 | 	if (pnp_port_valid(idev, 0) == 0) | 
 | 56 | 		return -ENODEV; | 
 | 57 |  | 
| Alan Cox | 91e33d3 | 2007-11-19 14:41:05 +0000 | [diff] [blame] | 58 | 	if (pnp_irq_valid(idev, 0)) { | 
 | 59 | 		irq = pnp_irq(idev, 0); | 
| Tejun Heo | 9363c38 | 2008-04-07 22:47:16 +0900 | [diff] [blame] | 60 | 		handler = ata_sff_interrupt; | 
| Alan Cox | 91e33d3 | 2007-11-19 14:41:05 +0000 | [diff] [blame] | 61 | 	} | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 62 |  | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 63 | 	/* allocate host */ | 
 | 64 | 	host = ata_host_alloc(&idev->dev, 1); | 
 | 65 | 	if (!host) | 
 | 66 | 		return -ENOMEM; | 
 | 67 |  | 
 | 68 | 	/* acquire resources and fill host */ | 
| Tejun Heo | 0d5ff56 | 2007-02-01 15:06:36 +0900 | [diff] [blame] | 69 | 	cmd_addr = devm_ioport_map(&idev->dev, pnp_port_start(idev, 0), 8); | 
 | 70 | 	if (!cmd_addr) | 
 | 71 | 		return -ENOMEM; | 
 | 72 |  | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 73 | 	ap = host->ports[0]; | 
 | 74 |  | 
| Alan Cox | c96f173 | 2009-03-24 10:23:46 +0000 | [diff] [blame] | 75 | 	ap->ops = &isapnp_noalt_port_ops; | 
| Erik Inge Bolsø | 14bdef9 | 2009-03-14 21:38:24 +0100 | [diff] [blame] | 76 | 	ap->pio_mask = ATA_PIO0; | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 77 | 	ap->flags |= ATA_FLAG_SLAVE_POSS; | 
 | 78 |  | 
 | 79 | 	ap->ioaddr.cmd_addr = cmd_addr; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 80 |  | 
 | 81 | 	if (pnp_port_valid(idev, 1) == 0) { | 
| Tejun Heo | 0d5ff56 | 2007-02-01 15:06:36 +0900 | [diff] [blame] | 82 | 		ctl_addr = devm_ioport_map(&idev->dev, | 
 | 83 | 					   pnp_port_start(idev, 1), 1); | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 84 | 		ap->ioaddr.altstatus_addr = ctl_addr; | 
 | 85 | 		ap->ioaddr.ctl_addr = ctl_addr; | 
| Alan Cox | c96f173 | 2009-03-24 10:23:46 +0000 | [diff] [blame] | 86 | 		ap->ops = &isapnp_port_ops; | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 87 | 	} | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 88 |  | 
| Tejun Heo | 9363c38 | 2008-04-07 22:47:16 +0900 | [diff] [blame] | 89 | 	ata_sff_std_ports(&ap->ioaddr); | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 90 |  | 
| Tejun Heo | cbcdd87 | 2007-08-18 13:14:55 +0900 | [diff] [blame] | 91 | 	ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx", | 
 | 92 | 		      (unsigned long long)pnp_port_start(idev, 0), | 
 | 93 | 		      (unsigned long long)pnp_port_start(idev, 1)); | 
 | 94 |  | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 95 | 	/* activate */ | 
| Alan Cox | 91e33d3 | 2007-11-19 14:41:05 +0000 | [diff] [blame] | 96 | 	return ata_host_activate(host, irq, handler, 0, | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 97 | 				 &isapnp_sht); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 98 | } | 
 | 99 |  | 
 | 100 | /** | 
 | 101 |  *	isapnp_remove_one	-	unplug an isapnp interface | 
 | 102 |  *	@idev: PnP device | 
 | 103 |  * | 
 | 104 |  *	Remove a previously configured PnP ATA port. Called only on module | 
 | 105 |  *	unload events as the core does not currently deal with ISAPnP docking. | 
 | 106 |  */ | 
 | 107 |  | 
 | 108 | static void isapnp_remove_one(struct pnp_dev *idev) | 
 | 109 | { | 
 | 110 | 	struct device *dev = &idev->dev; | 
 | 111 | 	struct ata_host *host = dev_get_drvdata(dev); | 
 | 112 |  | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 113 | 	ata_host_detach(host); | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 114 | } | 
 | 115 |  | 
 | 116 | static struct pnp_device_id isapnp_devices[] = { | 
 | 117 |   	/* Generic ESDI/IDE/ATA compatible hard disk controller */ | 
 | 118 | 	{.id = "PNP0600", .driver_data = 0}, | 
 | 119 | 	{.id = ""} | 
 | 120 | }; | 
 | 121 |  | 
| Jeff Garzik | 6a286a6 | 2007-08-03 11:25:50 -0400 | [diff] [blame] | 122 | MODULE_DEVICE_TABLE(pnp, isapnp_devices); | 
 | 123 |  | 
| Jeff Garzik | 669a5db | 2006-08-29 18:12:40 -0400 | [diff] [blame] | 124 | static struct pnp_driver isapnp_driver = { | 
 | 125 | 	.name		= DRV_NAME, | 
 | 126 | 	.id_table	= isapnp_devices, | 
 | 127 | 	.probe		= isapnp_init_one, | 
 | 128 | 	.remove		= isapnp_remove_one, | 
 | 129 | }; | 
 | 130 |  | 
 | 131 | static int __init isapnp_init(void) | 
 | 132 | { | 
 | 133 | 	return pnp_register_driver(&isapnp_driver); | 
 | 134 | } | 
 | 135 |  | 
 | 136 | static void __exit isapnp_exit(void) | 
 | 137 | { | 
 | 138 | 	pnp_unregister_driver(&isapnp_driver); | 
 | 139 | } | 
 | 140 |  | 
 | 141 | MODULE_AUTHOR("Alan Cox"); | 
 | 142 | MODULE_DESCRIPTION("low-level driver for ISA PnP ATA"); | 
 | 143 | MODULE_LICENSE("GPL"); | 
 | 144 | MODULE_VERSION(DRV_VERSION); | 
 | 145 |  | 
 | 146 | module_init(isapnp_init); | 
 | 147 | module_exit(isapnp_exit); |