diff options
-rw-r--r-- | drivers/base/Makefile | 1 | ||||
-rw-r--r-- | drivers/base/isa.c | 180 | ||||
-rw-r--r-- | include/linux/isa.h | 28 |
3 files changed, 209 insertions, 0 deletions
diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 659cde6c2fb..b539e5e75b5 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile | |||
@@ -5,6 +5,7 @@ obj-y := core.o sys.o bus.o dd.o \ | |||
5 | cpu.o firmware.o init.o map.o dmapool.o \ | 5 | cpu.o firmware.o init.o map.o dmapool.o \ |
6 | attribute_container.o transport_class.o | 6 | attribute_container.o transport_class.o |
7 | obj-y += power/ | 7 | obj-y += power/ |
8 | obj-$(CONFIG_ISA) += isa.o | ||
8 | obj-$(CONFIG_FW_LOADER) += firmware_class.o | 9 | obj-$(CONFIG_FW_LOADER) += firmware_class.o |
9 | obj-$(CONFIG_NUMA) += node.o | 10 | obj-$(CONFIG_NUMA) += node.o |
10 | obj-$(CONFIG_MEMORY_HOTPLUG) += memory.o | 11 | obj-$(CONFIG_MEMORY_HOTPLUG) += memory.o |
diff --git a/drivers/base/isa.c b/drivers/base/isa.c new file mode 100644 index 00000000000..d2222397a40 --- /dev/null +++ b/drivers/base/isa.c | |||
@@ -0,0 +1,180 @@ | |||
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> | ||
10 | #include <linux/isa.h> | ||
11 | |||
12 | static struct device isa_bus = { | ||
13 | .bus_id = "isa" | ||
14 | }; | ||
15 | |||
16 | struct isa_dev { | ||
17 | struct device dev; | ||
18 | struct device *next; | ||
19 | unsigned int id; | ||
20 | }; | ||
21 | |||
22 | #define to_isa_dev(x) container_of((x), struct isa_dev, dev) | ||
23 | |||
24 | static int isa_bus_match(struct device *dev, struct device_driver *driver) | ||
25 | { | ||
26 | struct isa_driver *isa_driver = to_isa_driver(driver); | ||
27 | |||
28 | if (dev->platform_data == isa_driver) { | ||
29 | if (!isa_driver->match || | ||
30 | isa_driver->match(dev, to_isa_dev(dev)->id)) | ||
31 | return 1; | ||
32 | dev->platform_data = NULL; | ||
33 | } | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | static int isa_bus_probe(struct device *dev) | ||
38 | { | ||
39 | struct isa_driver *isa_driver = dev->platform_data; | ||
40 | |||
41 | if (isa_driver->probe) | ||
42 | return isa_driver->probe(dev, to_isa_dev(dev)->id); | ||
43 | |||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | static int isa_bus_remove(struct device *dev) | ||
48 | { | ||
49 | struct isa_driver *isa_driver = dev->platform_data; | ||
50 | |||
51 | if (isa_driver->remove) | ||
52 | return isa_driver->remove(dev, to_isa_dev(dev)->id); | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static void isa_bus_shutdown(struct device *dev) | ||
58 | { | ||
59 | struct isa_driver *isa_driver = dev->platform_data; | ||
60 | |||
61 | if (isa_driver->shutdown) | ||
62 | isa_driver->shutdown(dev, to_isa_dev(dev)->id); | ||
63 | } | ||
64 | |||
65 | static int isa_bus_suspend(struct device *dev, pm_message_t state) | ||
66 | { | ||
67 | struct isa_driver *isa_driver = dev->platform_data; | ||
68 | |||
69 | if (isa_driver->suspend) | ||
70 | return isa_driver->suspend(dev, to_isa_dev(dev)->id, state); | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static int isa_bus_resume(struct device *dev) | ||
76 | { | ||
77 | struct isa_driver *isa_driver = dev->platform_data; | ||
78 | |||
79 | if (isa_driver->resume) | ||
80 | return isa_driver->resume(dev, to_isa_dev(dev)->id); | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static struct bus_type isa_bus_type = { | ||
86 | .name = "isa", | ||
87 | .match = isa_bus_match, | ||
88 | .probe = isa_bus_probe, | ||
89 | .remove = isa_bus_remove, | ||
90 | .shutdown = isa_bus_shutdown, | ||
91 | .suspend = isa_bus_suspend, | ||
92 | .resume = isa_bus_resume | ||
93 | }; | ||
94 | |||
95 | static void isa_dev_release(struct device *dev) | ||
96 | { | ||
97 | kfree(to_isa_dev(dev)); | ||
98 | } | ||
99 | |||
100 | void isa_unregister_driver(struct isa_driver *isa_driver) | ||
101 | { | ||
102 | struct device *dev = isa_driver->devices; | ||
103 | |||
104 | while (dev) { | ||
105 | struct device *tmp = to_isa_dev(dev)->next; | ||
106 | device_unregister(dev); | ||
107 | dev = tmp; | ||
108 | } | ||
109 | driver_unregister(&isa_driver->driver); | ||
110 | } | ||
111 | EXPORT_SYMBOL_GPL(isa_unregister_driver); | ||
112 | |||
113 | int isa_register_driver(struct isa_driver *isa_driver, unsigned int ndev) | ||
114 | { | ||
115 | int error; | ||
116 | unsigned int id; | ||
117 | |||
118 | isa_driver->driver.bus = &isa_bus_type; | ||
119 | isa_driver->devices = NULL; | ||
120 | |||
121 | error = driver_register(&isa_driver->driver); | ||
122 | if (error) | ||
123 | return error; | ||
124 | |||
125 | for (id = 0; id < ndev; id++) { | ||
126 | struct isa_dev *isa_dev; | ||
127 | |||
128 | isa_dev = kzalloc(sizeof *isa_dev, GFP_KERNEL); | ||
129 | if (!isa_dev) { | ||
130 | error = -ENOMEM; | ||
131 | break; | ||
132 | } | ||
133 | |||
134 | isa_dev->dev.parent = &isa_bus; | ||
135 | isa_dev->dev.bus = &isa_bus_type; | ||
136 | |||
137 | snprintf(isa_dev->dev.bus_id, BUS_ID_SIZE, "%s.%u", | ||
138 | isa_driver->driver.name, id); | ||
139 | |||
140 | isa_dev->dev.platform_data = isa_driver; | ||
141 | isa_dev->dev.release = isa_dev_release; | ||
142 | isa_dev->id = id; | ||
143 | |||
144 | error = device_register(&isa_dev->dev); | ||
145 | if (error) { | ||
146 | put_device(&isa_dev->dev); | ||
147 | break; | ||
148 | } | ||
149 | |||
150 | if (isa_dev->dev.platform_data) { | ||
151 | isa_dev->next = isa_driver->devices; | ||
152 | isa_driver->devices = &isa_dev->dev; | ||
153 | } else | ||
154 | device_unregister(&isa_dev->dev); | ||
155 | } | ||
156 | |||
157 | if (!error && !isa_driver->devices) | ||
158 | error = -ENODEV; | ||
159 | |||
160 | if (error) | ||
161 | isa_unregister_driver(isa_driver); | ||
162 | |||
163 | return error; | ||
164 | } | ||
165 | EXPORT_SYMBOL_GPL(isa_register_driver); | ||
166 | |||
167 | static int __init isa_bus_init(void) | ||
168 | { | ||
169 | int error; | ||
170 | |||
171 | error = bus_register(&isa_bus_type); | ||
172 | if (!error) { | ||
173 | error = device_register(&isa_bus); | ||
174 | if (error) | ||
175 | bus_unregister(&isa_bus_type); | ||
176 | } | ||
177 | return error; | ||
178 | } | ||
179 | |||
180 | device_initcall(isa_bus_init); | ||
diff --git a/include/linux/isa.h b/include/linux/isa.h new file mode 100644 index 00000000000..1b855335cb1 --- /dev/null +++ b/include/linux/isa.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * ISA bus. | ||
3 | */ | ||
4 | |||
5 | #ifndef __LINUX_ISA_H | ||
6 | #define __LINUX_ISA_H | ||
7 | |||
8 | #include <linux/device.h> | ||
9 | #include <linux/kernel.h> | ||
10 | |||
11 | struct isa_driver { | ||
12 | int (*match)(struct device *, unsigned int); | ||
13 | int (*probe)(struct device *, unsigned int); | ||
14 | int (*remove)(struct device *, unsigned int); | ||
15 | void (*shutdown)(struct device *, unsigned int); | ||
16 | int (*suspend)(struct device *, unsigned int, pm_message_t); | ||
17 | int (*resume)(struct device *, unsigned int); | ||
18 | |||
19 | struct device_driver driver; | ||
20 | struct device *devices; | ||
21 | }; | ||
22 | |||
23 | #define to_isa_driver(x) container_of((x), struct isa_driver, driver) | ||
24 | |||
25 | int isa_register_driver(struct isa_driver *, unsigned int); | ||
26 | void isa_unregister_driver(struct isa_driver *); | ||
27 | |||
28 | #endif /* __LINUX_ISA_H */ | ||