diff options
Diffstat (limited to 'drivers/message/i2o/driver.c')
-rw-r--r-- | drivers/message/i2o/driver.c | 382 |
1 files changed, 0 insertions, 382 deletions
diff --git a/drivers/message/i2o/driver.c b/drivers/message/i2o/driver.c deleted file mode 100644 index 1b18a0d1d05b..000000000000 --- a/drivers/message/i2o/driver.c +++ /dev/null | |||
@@ -1,382 +0,0 @@ | |||
1 | /* | ||
2 | * Functions to handle I2O drivers (OSMs) and I2O bus type for sysfs | ||
3 | * | ||
4 | * Copyright (C) 2004 Markus Lidel <Markus.Lidel@shadowconnect.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | * | ||
11 | * Fixes/additions: | ||
12 | * Markus Lidel <Markus.Lidel@shadowconnect.com> | ||
13 | * initial version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/device.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/rwsem.h> | ||
19 | #include <linux/i2o.h> | ||
20 | #include <linux/workqueue.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include "core.h" | ||
24 | |||
25 | #define OSM_NAME "i2o" | ||
26 | |||
27 | /* max_drivers - Maximum I2O drivers (OSMs) which could be registered */ | ||
28 | static unsigned int i2o_max_drivers = I2O_MAX_DRIVERS; | ||
29 | module_param_named(max_drivers, i2o_max_drivers, uint, 0); | ||
30 | MODULE_PARM_DESC(max_drivers, "maximum number of OSM's to support"); | ||
31 | |||
32 | /* I2O drivers lock and array */ | ||
33 | static spinlock_t i2o_drivers_lock; | ||
34 | static struct i2o_driver **i2o_drivers; | ||
35 | |||
36 | /** | ||
37 | * i2o_bus_match - Tell if I2O device class id matches the class ids of the I2O driver (OSM) | ||
38 | * @dev: device which should be verified | ||
39 | * @drv: the driver to match against | ||
40 | * | ||
41 | * Used by the bus to check if the driver wants to handle the device. | ||
42 | * | ||
43 | * Returns 1 if the class ids of the driver match the class id of the | ||
44 | * device, otherwise 0. | ||
45 | */ | ||
46 | static int i2o_bus_match(struct device *dev, struct device_driver *drv) | ||
47 | { | ||
48 | struct i2o_device *i2o_dev = to_i2o_device(dev); | ||
49 | struct i2o_driver *i2o_drv = to_i2o_driver(drv); | ||
50 | struct i2o_class_id *ids = i2o_drv->classes; | ||
51 | |||
52 | if (ids) | ||
53 | while (ids->class_id != I2O_CLASS_END) { | ||
54 | if (ids->class_id == i2o_dev->lct_data.class_id) | ||
55 | return 1; | ||
56 | ids++; | ||
57 | } | ||
58 | return 0; | ||
59 | }; | ||
60 | |||
61 | /* I2O bus type */ | ||
62 | struct bus_type i2o_bus_type = { | ||
63 | .name = "i2o", | ||
64 | .match = i2o_bus_match, | ||
65 | .dev_groups = i2o_device_groups, | ||
66 | }; | ||
67 | |||
68 | /** | ||
69 | * i2o_driver_register - Register a I2O driver (OSM) in the I2O core | ||
70 | * @drv: I2O driver which should be registered | ||
71 | * | ||
72 | * Registers the OSM drv in the I2O core and creates an event queues if | ||
73 | * necessary. | ||
74 | * | ||
75 | * Returns 0 on success or negative error code on failure. | ||
76 | */ | ||
77 | int i2o_driver_register(struct i2o_driver *drv) | ||
78 | { | ||
79 | struct i2o_controller *c; | ||
80 | int i; | ||
81 | int rc = 0; | ||
82 | unsigned long flags; | ||
83 | |||
84 | osm_debug("Register driver %s\n", drv->name); | ||
85 | |||
86 | if (drv->event) { | ||
87 | drv->event_queue = alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, | ||
88 | drv->name); | ||
89 | if (!drv->event_queue) { | ||
90 | osm_err("Could not initialize event queue for driver " | ||
91 | "%s\n", drv->name); | ||
92 | return -EFAULT; | ||
93 | } | ||
94 | osm_debug("Event queue initialized for driver %s\n", drv->name); | ||
95 | } else | ||
96 | drv->event_queue = NULL; | ||
97 | |||
98 | drv->driver.name = drv->name; | ||
99 | drv->driver.bus = &i2o_bus_type; | ||
100 | |||
101 | spin_lock_irqsave(&i2o_drivers_lock, flags); | ||
102 | |||
103 | for (i = 0; i2o_drivers[i]; i++) | ||
104 | if (i >= i2o_max_drivers) { | ||
105 | osm_err("too many drivers registered, increase " | ||
106 | "max_drivers\n"); | ||
107 | spin_unlock_irqrestore(&i2o_drivers_lock, flags); | ||
108 | rc = -EFAULT; | ||
109 | goto out; | ||
110 | } | ||
111 | |||
112 | drv->context = i; | ||
113 | i2o_drivers[i] = drv; | ||
114 | |||
115 | spin_unlock_irqrestore(&i2o_drivers_lock, flags); | ||
116 | |||
117 | osm_debug("driver %s gets context id %d\n", drv->name, drv->context); | ||
118 | |||
119 | list_for_each_entry(c, &i2o_controllers, list) { | ||
120 | struct i2o_device *i2o_dev; | ||
121 | |||
122 | i2o_driver_notify_controller_add(drv, c); | ||
123 | list_for_each_entry(i2o_dev, &c->devices, list) | ||
124 | i2o_driver_notify_device_add(drv, i2o_dev); | ||
125 | } | ||
126 | |||
127 | rc = driver_register(&drv->driver); | ||
128 | if (rc) | ||
129 | goto out; | ||
130 | |||
131 | return 0; | ||
132 | out: | ||
133 | if (drv->event_queue) { | ||
134 | destroy_workqueue(drv->event_queue); | ||
135 | drv->event_queue = NULL; | ||
136 | } | ||
137 | |||
138 | return rc; | ||
139 | }; | ||
140 | |||
141 | /** | ||
142 | * i2o_driver_unregister - Unregister a I2O driver (OSM) from the I2O core | ||
143 | * @drv: I2O driver which should be unregistered | ||
144 | * | ||
145 | * Unregisters the OSM drv from the I2O core and cleanup event queues if | ||
146 | * necessary. | ||
147 | */ | ||
148 | void i2o_driver_unregister(struct i2o_driver *drv) | ||
149 | { | ||
150 | struct i2o_controller *c; | ||
151 | unsigned long flags; | ||
152 | |||
153 | osm_debug("unregister driver %s\n", drv->name); | ||
154 | |||
155 | driver_unregister(&drv->driver); | ||
156 | |||
157 | list_for_each_entry(c, &i2o_controllers, list) { | ||
158 | struct i2o_device *i2o_dev; | ||
159 | |||
160 | list_for_each_entry(i2o_dev, &c->devices, list) | ||
161 | i2o_driver_notify_device_remove(drv, i2o_dev); | ||
162 | |||
163 | i2o_driver_notify_controller_remove(drv, c); | ||
164 | } | ||
165 | |||
166 | spin_lock_irqsave(&i2o_drivers_lock, flags); | ||
167 | i2o_drivers[drv->context] = NULL; | ||
168 | spin_unlock_irqrestore(&i2o_drivers_lock, flags); | ||
169 | |||
170 | if (drv->event_queue) { | ||
171 | destroy_workqueue(drv->event_queue); | ||
172 | drv->event_queue = NULL; | ||
173 | osm_debug("event queue removed for %s\n", drv->name); | ||
174 | } | ||
175 | }; | ||
176 | |||
177 | /** | ||
178 | * i2o_driver_dispatch - dispatch an I2O reply message | ||
179 | * @c: I2O controller of the message | ||
180 | * @m: I2O message number | ||
181 | * | ||
182 | * The reply is delivered to the driver from which the original message | ||
183 | * was. This function is only called from interrupt context. | ||
184 | * | ||
185 | * Returns 0 on success and the message should not be flushed. Returns > 0 | ||
186 | * on success and if the message should be flushed afterwords. Returns | ||
187 | * negative error code on failure (the message will be flushed too). | ||
188 | */ | ||
189 | int i2o_driver_dispatch(struct i2o_controller *c, u32 m) | ||
190 | { | ||
191 | struct i2o_driver *drv; | ||
192 | struct i2o_message *msg = i2o_msg_out_to_virt(c, m); | ||
193 | u32 context = le32_to_cpu(msg->u.s.icntxt); | ||
194 | unsigned long flags; | ||
195 | |||
196 | if (unlikely(context >= i2o_max_drivers)) { | ||
197 | osm_warn("%s: Spurious reply to unknown driver %d\n", c->name, | ||
198 | context); | ||
199 | return -EIO; | ||
200 | } | ||
201 | |||
202 | spin_lock_irqsave(&i2o_drivers_lock, flags); | ||
203 | drv = i2o_drivers[context]; | ||
204 | spin_unlock_irqrestore(&i2o_drivers_lock, flags); | ||
205 | |||
206 | if (unlikely(!drv)) { | ||
207 | osm_warn("%s: Spurious reply to unknown driver %d\n", c->name, | ||
208 | context); | ||
209 | return -EIO; | ||
210 | } | ||
211 | |||
212 | if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_UTIL_EVT_REGISTER) { | ||
213 | struct i2o_device *dev, *tmp; | ||
214 | struct i2o_event *evt; | ||
215 | u16 size; | ||
216 | u16 tid = le32_to_cpu(msg->u.head[1]) & 0xfff; | ||
217 | |||
218 | osm_debug("event received from device %d\n", tid); | ||
219 | |||
220 | if (!drv->event) | ||
221 | return -EIO; | ||
222 | |||
223 | /* cut of header from message size (in 32-bit words) */ | ||
224 | size = (le32_to_cpu(msg->u.head[0]) >> 16) - 5; | ||
225 | |||
226 | evt = kzalloc(size * 4 + sizeof(*evt), GFP_ATOMIC); | ||
227 | if (!evt) | ||
228 | return -ENOMEM; | ||
229 | |||
230 | evt->size = size; | ||
231 | evt->tcntxt = le32_to_cpu(msg->u.s.tcntxt); | ||
232 | evt->event_indicator = le32_to_cpu(msg->body[0]); | ||
233 | memcpy(&evt->data, &msg->body[1], size * 4); | ||
234 | |||
235 | list_for_each_entry_safe(dev, tmp, &c->devices, list) | ||
236 | if (dev->lct_data.tid == tid) { | ||
237 | evt->i2o_dev = dev; | ||
238 | break; | ||
239 | } | ||
240 | |||
241 | INIT_WORK(&evt->work, drv->event); | ||
242 | queue_work(drv->event_queue, &evt->work); | ||
243 | return 1; | ||
244 | } | ||
245 | |||
246 | if (unlikely(!drv->reply)) { | ||
247 | osm_debug("%s: Reply to driver %s, but no reply function" | ||
248 | " defined!\n", c->name, drv->name); | ||
249 | return -EIO; | ||
250 | } | ||
251 | |||
252 | return drv->reply(c, m, msg); | ||
253 | } | ||
254 | |||
255 | /** | ||
256 | * i2o_driver_notify_controller_add_all - Send notify of added controller | ||
257 | * @c: newly added controller | ||
258 | * | ||
259 | * Send notifications to all registered drivers that a new controller was | ||
260 | * added. | ||
261 | */ | ||
262 | void i2o_driver_notify_controller_add_all(struct i2o_controller *c) | ||
263 | { | ||
264 | int i; | ||
265 | struct i2o_driver *drv; | ||
266 | |||
267 | for (i = 0; i < i2o_max_drivers; i++) { | ||
268 | drv = i2o_drivers[i]; | ||
269 | |||
270 | if (drv) | ||
271 | i2o_driver_notify_controller_add(drv, c); | ||
272 | } | ||
273 | } | ||
274 | |||
275 | /** | ||
276 | * i2o_driver_notify_controller_remove_all - Send notify of removed controller | ||
277 | * @c: controller that is being removed | ||
278 | * | ||
279 | * Send notifications to all registered drivers that a controller was | ||
280 | * removed. | ||
281 | */ | ||
282 | void i2o_driver_notify_controller_remove_all(struct i2o_controller *c) | ||
283 | { | ||
284 | int i; | ||
285 | struct i2o_driver *drv; | ||
286 | |||
287 | for (i = 0; i < i2o_max_drivers; i++) { | ||
288 | drv = i2o_drivers[i]; | ||
289 | |||
290 | if (drv) | ||
291 | i2o_driver_notify_controller_remove(drv, c); | ||
292 | } | ||
293 | } | ||
294 | |||
295 | /** | ||
296 | * i2o_driver_notify_device_add_all - Send notify of added device | ||
297 | * @i2o_dev: newly added I2O device | ||
298 | * | ||
299 | * Send notifications to all registered drivers that a device was added. | ||
300 | */ | ||
301 | void i2o_driver_notify_device_add_all(struct i2o_device *i2o_dev) | ||
302 | { | ||
303 | int i; | ||
304 | struct i2o_driver *drv; | ||
305 | |||
306 | for (i = 0; i < i2o_max_drivers; i++) { | ||
307 | drv = i2o_drivers[i]; | ||
308 | |||
309 | if (drv) | ||
310 | i2o_driver_notify_device_add(drv, i2o_dev); | ||
311 | } | ||
312 | } | ||
313 | |||
314 | /** | ||
315 | * i2o_driver_notify_device_remove_all - Send notify of removed device | ||
316 | * @i2o_dev: device that is being removed | ||
317 | * | ||
318 | * Send notifications to all registered drivers that a device was removed. | ||
319 | */ | ||
320 | void i2o_driver_notify_device_remove_all(struct i2o_device *i2o_dev) | ||
321 | { | ||
322 | int i; | ||
323 | struct i2o_driver *drv; | ||
324 | |||
325 | for (i = 0; i < i2o_max_drivers; i++) { | ||
326 | drv = i2o_drivers[i]; | ||
327 | |||
328 | if (drv) | ||
329 | i2o_driver_notify_device_remove(drv, i2o_dev); | ||
330 | } | ||
331 | } | ||
332 | |||
333 | /** | ||
334 | * i2o_driver_init - initialize I2O drivers (OSMs) | ||
335 | * | ||
336 | * Registers the I2O bus and allocate memory for the array of OSMs. | ||
337 | * | ||
338 | * Returns 0 on success or negative error code on failure. | ||
339 | */ | ||
340 | int __init i2o_driver_init(void) | ||
341 | { | ||
342 | int rc = 0; | ||
343 | |||
344 | spin_lock_init(&i2o_drivers_lock); | ||
345 | |||
346 | if ((i2o_max_drivers < 2) || (i2o_max_drivers > 64)) { | ||
347 | osm_warn("max_drivers set to %d, but must be >=2 and <= 64\n", | ||
348 | i2o_max_drivers); | ||
349 | i2o_max_drivers = I2O_MAX_DRIVERS; | ||
350 | } | ||
351 | osm_info("max drivers = %d\n", i2o_max_drivers); | ||
352 | |||
353 | i2o_drivers = | ||
354 | kcalloc(i2o_max_drivers, sizeof(*i2o_drivers), GFP_KERNEL); | ||
355 | if (!i2o_drivers) | ||
356 | return -ENOMEM; | ||
357 | |||
358 | rc = bus_register(&i2o_bus_type); | ||
359 | |||
360 | if (rc < 0) | ||
361 | kfree(i2o_drivers); | ||
362 | |||
363 | return rc; | ||
364 | }; | ||
365 | |||
366 | /** | ||
367 | * i2o_driver_exit - clean up I2O drivers (OSMs) | ||
368 | * | ||
369 | * Unregisters the I2O bus and frees driver array. | ||
370 | */ | ||
371 | void i2o_driver_exit(void) | ||
372 | { | ||
373 | bus_unregister(&i2o_bus_type); | ||
374 | kfree(i2o_drivers); | ||
375 | }; | ||
376 | |||
377 | EXPORT_SYMBOL(i2o_driver_register); | ||
378 | EXPORT_SYMBOL(i2o_driver_unregister); | ||
379 | EXPORT_SYMBOL(i2o_driver_notify_controller_add_all); | ||
380 | EXPORT_SYMBOL(i2o_driver_notify_controller_remove_all); | ||
381 | EXPORT_SYMBOL(i2o_driver_notify_device_add_all); | ||
382 | EXPORT_SYMBOL(i2o_driver_notify_device_remove_all); | ||