1 /*
2  * linux/drivers/ide/ide-pnp.c
3  *
4  * This file provides autodetection for ISA PnP IDE interfaces.
5  * It was tested with "ESS ES1868 Plug and Play AudioDrive" IDE interface.
6  *
7  * Copyright (C) 2000 Andrey Panin <pazke@orbita.don.sitek.net>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2, or (at your option)
12  * any later version.
13  *
14  * You should have received a copy of the GNU General Public License
15  * (for example /usr/src/linux/COPYING); if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 
19 #include <linux/module.h>
20 #include <linux/ide.h>
21 #include <linux/init.h>
22 
23 #include <linux/isapnp.h>
24 
25 #define DEV_IO(dev, index) (dev->resource[index].start)
26 #define DEV_IRQ(dev, index) (dev->irq_resource[index].start)
27 
28 #define DEV_NAME(dev) (dev->bus->name ? dev->bus->name : "ISA PnP")
29 
30 #define GENERIC_HD_DATA		0
31 #define GENERIC_HD_ERROR	1
32 #define GENERIC_HD_NSECTOR	2
33 #define GENERIC_HD_SECTOR	3
34 #define GENERIC_HD_LCYL		4
35 #define GENERIC_HD_HCYL		5
36 #define GENERIC_HD_SELECT	6
37 #define GENERIC_HD_STATUS	7
38 
39 static int generic_ide_offsets[IDE_NR_PORTS] __initdata = {
40 	GENERIC_HD_DATA, GENERIC_HD_ERROR, GENERIC_HD_NSECTOR,
41 	GENERIC_HD_SECTOR, GENERIC_HD_LCYL, GENERIC_HD_HCYL,
42 	GENERIC_HD_SELECT, GENERIC_HD_STATUS, -1, -1
43 };
44 
45 /* ISA PnP device table entry */
46 struct pnp_dev_t {
47 	unsigned short card_vendor, card_device, vendor, device;
48 	int (*init_fn)(struct pci_dev *dev, int enable);
49 };
50 
51 /* Generic initialisation function for ISA PnP IDE interface */
52 
pnpide_generic_init(struct pci_dev * dev,int enable)53 static int __init pnpide_generic_init(struct pci_dev *dev, int enable)
54 {
55 	hw_regs_t hw;
56 	int index;
57 
58 	if (!enable)
59 		return 0;
60 
61 	if (!(DEV_IO(dev, 0) && DEV_IO(dev, 1) && DEV_IRQ(dev, 0)))
62 		return 1;
63 
64 	ide_setup_ports(&hw, (ide_ioreg_t) DEV_IO(dev, 0),
65 			generic_ide_offsets,
66 			(ide_ioreg_t) DEV_IO(dev, 1),
67 			0, NULL,
68 //			generic_pnp_ide_iops,
69 			DEV_IRQ(dev, 0));
70 
71 	index = ide_register_hw(&hw, NULL);
72 
73 	if (index != -1) {
74 	    	printk(KERN_INFO "ide%d: %s IDE interface\n", index, DEV_NAME(dev));
75 		return 0;
76 	}
77 
78 	return 1;
79 }
80 
81 /* Add your devices here :)) */
82 struct pnp_dev_t idepnp_devices[] __initdata = {
83   	/* Generic ESDI/IDE/ATA compatible hard disk controller */
84 	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
85 		ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0600),
86 		pnpide_generic_init },
87 	{	0 }
88 };
89 
90 #define NR_PNP_DEVICES 8
91 struct pnp_dev_inst {
92 	struct pci_dev *dev;
93 	struct pnp_dev_t *dev_type;
94 };
95 static struct pnp_dev_inst devices[NR_PNP_DEVICES];
96 static int pnp_ide_dev_idx = 0;
97 
98 /*
99  * Probe for ISA PnP IDE interfaces.
100  */
101 
pnpide_init(int enable)102 static void pnpide_init(int enable)
103 {
104 	struct pci_dev *dev = NULL;
105 	struct pnp_dev_t *dev_type;
106 
107 	if (!isapnp_present())
108 		return;
109 
110 	/* Module unload, deactivate all registered devices. */
111 	if (!enable) {
112 		int i;
113 		for (i = 0; i < pnp_ide_dev_idx; i++) {
114 			dev = devices[i].dev;
115 			devices[i].dev_type->init_fn(dev, 0);
116 			if (dev->deactivate)
117 				dev->deactivate(dev);
118 		}
119 		return;
120 	}
121 
122 	for (dev_type = idepnp_devices; dev_type->vendor; dev_type++) {
123 		while ((dev = isapnp_find_dev(NULL, dev_type->vendor,
124 			dev_type->device, dev))) {
125 
126 			if (dev->active)
127 				continue;
128 
129        			if (dev->prepare && dev->prepare(dev) < 0) {
130 				printk(KERN_ERR"ide-pnp: %s prepare failed\n", DEV_NAME(dev));
131 				continue;
132 			}
133 
134 			if (dev->activate && dev->activate(dev) < 0) {
135 				printk(KERN_ERR"ide: %s activate failed\n", DEV_NAME(dev));
136 				continue;
137 			}
138 
139 			/* Call device initialization function */
140 			if (dev_type->init_fn(dev, 1)) {
141 				if (dev->deactivate(dev))
142 					dev->deactivate(dev);
143 			} else {
144 #ifdef MODULE
145 				/*
146 				 * Register device in the array to
147 				 * deactivate it on a module unload.
148 				 */
149 				if (pnp_ide_dev_idx >= NR_PNP_DEVICES)
150 					return;
151 				devices[pnp_ide_dev_idx].dev = dev;
152 				devices[pnp_ide_dev_idx].dev_type = dev_type;
153 				pnp_ide_dev_idx++;
154 #endif
155 			}
156 		}
157 	}
158 }
159 
pnpide_begin(void)160 static void __init pnpide_begin(void)
161 {
162 	pnpide_init(1);
163 }
164 
pnpide_init_module(void)165 static int pnpide_init_module(void)
166 {
167 	ide_register_driver(pnpide_begin);
168 	return 0;
169 }
170 
pnpide_unload(void)171 static void pnpide_unload(void)
172 {
173 	pnpide_init(0);
174 }
175 
176 module_init(pnpide_init_module);
177 module_exit(pnpide_unload);
178 
179 MODULE_AUTHOR("Andrey Panin");
180 MODULE_DESCRIPTION("Enabler for ISAPNP IDE devices");
181 MODULE_LICENSE("GPL");
182