| Rene Herman | a5117ba7 | 2006-06-06 23:54:02 +0200 | [diff] [blame] | 1 | /* | 
 | 2 |  * ISA bus. | 
 | 3 |  */ | 
 | 4 |  | 
 | 5 | #include <linux/device.h> | 
 | 6 | #include <linux/kernel.h> | 
 | 7 | #include <linux/slab.h> | 
 | 8 | #include <linux/module.h> | 
 | 9 | #include <linux/init.h> | 
| Rene Herman | 00412be | 2008-07-25 19:44:45 -0700 | [diff] [blame] | 10 | #include <linux/dma-mapping.h> | 
| Rene Herman | a5117ba7 | 2006-06-06 23:54:02 +0200 | [diff] [blame] | 11 | #include <linux/isa.h> | 
 | 12 |  | 
 | 13 | static struct device isa_bus = { | 
| Kay Sievers | 1e0b2cf | 2008-10-30 01:36:48 +0100 | [diff] [blame] | 14 | 	.init_name	= "isa" | 
| Rene Herman | a5117ba7 | 2006-06-06 23:54:02 +0200 | [diff] [blame] | 15 | }; | 
 | 16 |  | 
 | 17 | struct isa_dev { | 
 | 18 | 	struct device dev; | 
 | 19 | 	struct device *next; | 
 | 20 | 	unsigned int id; | 
 | 21 | }; | 
 | 22 |  | 
 | 23 | #define to_isa_dev(x) container_of((x), struct isa_dev, dev) | 
 | 24 |  | 
 | 25 | static int isa_bus_match(struct device *dev, struct device_driver *driver) | 
 | 26 | { | 
 | 27 | 	struct isa_driver *isa_driver = to_isa_driver(driver); | 
 | 28 |  | 
 | 29 | 	if (dev->platform_data == isa_driver) { | 
 | 30 | 		if (!isa_driver->match || | 
 | 31 | 			isa_driver->match(dev, to_isa_dev(dev)->id)) | 
 | 32 | 			return 1; | 
 | 33 | 		dev->platform_data = NULL; | 
 | 34 | 	} | 
 | 35 | 	return 0; | 
 | 36 | } | 
 | 37 |  | 
 | 38 | static int isa_bus_probe(struct device *dev) | 
 | 39 | { | 
 | 40 | 	struct isa_driver *isa_driver = dev->platform_data; | 
 | 41 |  | 
 | 42 | 	if (isa_driver->probe) | 
 | 43 | 		return isa_driver->probe(dev, to_isa_dev(dev)->id); | 
 | 44 |  | 
 | 45 | 	return 0; | 
 | 46 | } | 
 | 47 |  | 
 | 48 | static int isa_bus_remove(struct device *dev) | 
 | 49 | { | 
 | 50 | 	struct isa_driver *isa_driver = dev->platform_data; | 
 | 51 |  | 
 | 52 | 	if (isa_driver->remove) | 
 | 53 | 		return isa_driver->remove(dev, to_isa_dev(dev)->id); | 
 | 54 |  | 
 | 55 | 	return 0; | 
 | 56 | } | 
 | 57 |  | 
 | 58 | static void isa_bus_shutdown(struct device *dev) | 
 | 59 | { | 
 | 60 | 	struct isa_driver *isa_driver = dev->platform_data; | 
 | 61 |  | 
 | 62 | 	if (isa_driver->shutdown) | 
 | 63 | 		isa_driver->shutdown(dev, to_isa_dev(dev)->id); | 
 | 64 | } | 
 | 65 |  | 
 | 66 | static int isa_bus_suspend(struct device *dev, pm_message_t state) | 
 | 67 | { | 
 | 68 | 	struct isa_driver *isa_driver = dev->platform_data; | 
 | 69 |  | 
 | 70 | 	if (isa_driver->suspend) | 
 | 71 | 		return isa_driver->suspend(dev, to_isa_dev(dev)->id, state); | 
 | 72 |  | 
 | 73 | 	return 0; | 
 | 74 | } | 
 | 75 |  | 
 | 76 | static int isa_bus_resume(struct device *dev) | 
 | 77 | { | 
 | 78 | 	struct isa_driver *isa_driver = dev->platform_data; | 
 | 79 |  | 
 | 80 | 	if (isa_driver->resume) | 
 | 81 | 		return isa_driver->resume(dev, to_isa_dev(dev)->id); | 
 | 82 |  | 
 | 83 | 	return 0; | 
 | 84 | } | 
 | 85 |  | 
 | 86 | static struct bus_type isa_bus_type = { | 
 | 87 | 	.name		= "isa", | 
 | 88 | 	.match		= isa_bus_match, | 
 | 89 | 	.probe		= isa_bus_probe, | 
 | 90 | 	.remove		= isa_bus_remove, | 
 | 91 | 	.shutdown	= isa_bus_shutdown, | 
 | 92 | 	.suspend	= isa_bus_suspend, | 
 | 93 | 	.resume		= isa_bus_resume | 
 | 94 | }; | 
 | 95 |  | 
 | 96 | static void isa_dev_release(struct device *dev) | 
 | 97 | { | 
 | 98 | 	kfree(to_isa_dev(dev)); | 
 | 99 | } | 
 | 100 |  | 
 | 101 | void isa_unregister_driver(struct isa_driver *isa_driver) | 
 | 102 | { | 
 | 103 | 	struct device *dev = isa_driver->devices; | 
 | 104 |  | 
 | 105 | 	while (dev) { | 
 | 106 | 		struct device *tmp = to_isa_dev(dev)->next; | 
 | 107 | 		device_unregister(dev); | 
 | 108 | 		dev = tmp; | 
 | 109 | 	} | 
 | 110 | 	driver_unregister(&isa_driver->driver); | 
 | 111 | } | 
 | 112 | EXPORT_SYMBOL_GPL(isa_unregister_driver); | 
 | 113 |  | 
 | 114 | int isa_register_driver(struct isa_driver *isa_driver, unsigned int ndev) | 
 | 115 | { | 
 | 116 | 	int error; | 
 | 117 | 	unsigned int id; | 
 | 118 |  | 
 | 119 | 	isa_driver->driver.bus	= &isa_bus_type; | 
 | 120 | 	isa_driver->devices	= NULL; | 
 | 121 |  | 
 | 122 | 	error = driver_register(&isa_driver->driver); | 
 | 123 | 	if (error) | 
 | 124 | 		return error; | 
 | 125 |  | 
 | 126 | 	for (id = 0; id < ndev; id++) { | 
 | 127 | 		struct isa_dev *isa_dev; | 
 | 128 |  | 
 | 129 | 		isa_dev = kzalloc(sizeof *isa_dev, GFP_KERNEL); | 
 | 130 | 		if (!isa_dev) { | 
 | 131 | 			error = -ENOMEM; | 
 | 132 | 			break; | 
 | 133 | 		} | 
 | 134 |  | 
 | 135 | 		isa_dev->dev.parent	= &isa_bus; | 
 | 136 | 		isa_dev->dev.bus	= &isa_bus_type; | 
 | 137 |  | 
| Kay Sievers | 1e0b2cf | 2008-10-30 01:36:48 +0100 | [diff] [blame] | 138 | 		dev_set_name(&isa_dev->dev, "%s.%u", | 
 | 139 | 			     isa_driver->driver.name, id); | 
| Rene Herman | a5117ba7 | 2006-06-06 23:54:02 +0200 | [diff] [blame] | 140 | 		isa_dev->dev.platform_data	= isa_driver; | 
 | 141 | 		isa_dev->dev.release		= isa_dev_release; | 
 | 142 | 		isa_dev->id			= id; | 
 | 143 |  | 
| Yang Hongyang | 2f4f27d | 2009-04-06 19:01:18 -0700 | [diff] [blame] | 144 | 		isa_dev->dev.coherent_dma_mask = DMA_BIT_MASK(24); | 
| Rene Herman | 00412be | 2008-07-25 19:44:45 -0700 | [diff] [blame] | 145 | 		isa_dev->dev.dma_mask = &isa_dev->dev.coherent_dma_mask; | 
 | 146 |  | 
| Rene Herman | a5117ba7 | 2006-06-06 23:54:02 +0200 | [diff] [blame] | 147 | 		error = device_register(&isa_dev->dev); | 
 | 148 | 		if (error) { | 
 | 149 | 			put_device(&isa_dev->dev); | 
 | 150 | 			break; | 
 | 151 | 		} | 
 | 152 |  | 
 | 153 | 		if (isa_dev->dev.platform_data) { | 
 | 154 | 			isa_dev->next = isa_driver->devices; | 
 | 155 | 			isa_driver->devices = &isa_dev->dev; | 
 | 156 | 		} else | 
 | 157 | 			device_unregister(&isa_dev->dev); | 
 | 158 | 	} | 
 | 159 |  | 
 | 160 | 	if (!error && !isa_driver->devices) | 
 | 161 | 		error = -ENODEV; | 
 | 162 |  | 
 | 163 | 	if (error) | 
 | 164 | 		isa_unregister_driver(isa_driver); | 
 | 165 |  | 
 | 166 | 	return error; | 
 | 167 | } | 
 | 168 | EXPORT_SYMBOL_GPL(isa_register_driver); | 
 | 169 |  | 
 | 170 | static int __init isa_bus_init(void) | 
 | 171 | { | 
 | 172 | 	int error; | 
 | 173 |  | 
 | 174 | 	error = bus_register(&isa_bus_type); | 
 | 175 | 	if (!error) { | 
 | 176 | 		error = device_register(&isa_bus); | 
 | 177 | 		if (error) | 
 | 178 | 			bus_unregister(&isa_bus_type); | 
 | 179 | 	} | 
 | 180 | 	return error; | 
 | 181 | } | 
 | 182 |  | 
 | 183 | device_initcall(isa_bus_init); |