diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/input/serio/serio.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/input/serio/serio.c')
-rw-r--r-- | drivers/input/serio/serio.c | 859 |
1 files changed, 859 insertions, 0 deletions
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c new file mode 100644 index 000000000000..3313e2daeab0 --- /dev/null +++ b/drivers/input/serio/serio.c | |||
@@ -0,0 +1,859 @@ | |||
1 | /* | ||
2 | * The Serio abstraction module | ||
3 | * | ||
4 | * Copyright (c) 1999-2004 Vojtech Pavlik | ||
5 | * Copyright (c) 2004 Dmitry Torokhov | ||
6 | * Copyright (c) 2003 Daniele Bellucci | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | * Should you need to contact me, the author, you can do so either by | ||
25 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
27 | */ | ||
28 | |||
29 | #include <linux/stddef.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/serio.h> | ||
32 | #include <linux/errno.h> | ||
33 | #include <linux/wait.h> | ||
34 | #include <linux/completion.h> | ||
35 | #include <linux/sched.h> | ||
36 | #include <linux/smp_lock.h> | ||
37 | #include <linux/slab.h> | ||
38 | |||
39 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
40 | MODULE_DESCRIPTION("Serio abstraction core"); | ||
41 | MODULE_LICENSE("GPL"); | ||
42 | |||
43 | EXPORT_SYMBOL(serio_interrupt); | ||
44 | EXPORT_SYMBOL(__serio_register_port); | ||
45 | EXPORT_SYMBOL(serio_unregister_port); | ||
46 | EXPORT_SYMBOL(__serio_unregister_port_delayed); | ||
47 | EXPORT_SYMBOL(__serio_register_driver); | ||
48 | EXPORT_SYMBOL(serio_unregister_driver); | ||
49 | EXPORT_SYMBOL(serio_open); | ||
50 | EXPORT_SYMBOL(serio_close); | ||
51 | EXPORT_SYMBOL(serio_rescan); | ||
52 | EXPORT_SYMBOL(serio_reconnect); | ||
53 | |||
54 | /* | ||
55 | * serio_sem protects entire serio subsystem and is taken every time | ||
56 | * serio port or driver registrered or unregistered. | ||
57 | */ | ||
58 | static DECLARE_MUTEX(serio_sem); | ||
59 | |||
60 | static LIST_HEAD(serio_list); | ||
61 | |||
62 | static struct bus_type serio_bus = { | ||
63 | .name = "serio", | ||
64 | }; | ||
65 | |||
66 | static void serio_add_port(struct serio *serio); | ||
67 | static void serio_destroy_port(struct serio *serio); | ||
68 | static void serio_reconnect_port(struct serio *serio); | ||
69 | static void serio_disconnect_port(struct serio *serio); | ||
70 | |||
71 | static int serio_match_port(const struct serio_device_id *ids, struct serio *serio) | ||
72 | { | ||
73 | while (ids->type || ids->proto) { | ||
74 | if ((ids->type == SERIO_ANY || ids->type == serio->id.type) && | ||
75 | (ids->proto == SERIO_ANY || ids->proto == serio->id.proto) && | ||
76 | (ids->extra == SERIO_ANY || ids->extra == serio->id.extra) && | ||
77 | (ids->id == SERIO_ANY || ids->id == serio->id.id)) | ||
78 | return 1; | ||
79 | ids++; | ||
80 | } | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * Basic serio -> driver core mappings | ||
86 | */ | ||
87 | |||
88 | static void serio_bind_driver(struct serio *serio, struct serio_driver *drv) | ||
89 | { | ||
90 | down_write(&serio_bus.subsys.rwsem); | ||
91 | |||
92 | if (serio_match_port(drv->id_table, serio)) { | ||
93 | serio->dev.driver = &drv->driver; | ||
94 | if (drv->connect(serio, drv)) { | ||
95 | serio->dev.driver = NULL; | ||
96 | goto out; | ||
97 | } | ||
98 | device_bind_driver(&serio->dev); | ||
99 | } | ||
100 | out: | ||
101 | up_write(&serio_bus.subsys.rwsem); | ||
102 | } | ||
103 | |||
104 | static void serio_release_driver(struct serio *serio) | ||
105 | { | ||
106 | down_write(&serio_bus.subsys.rwsem); | ||
107 | device_release_driver(&serio->dev); | ||
108 | up_write(&serio_bus.subsys.rwsem); | ||
109 | } | ||
110 | |||
111 | static void serio_find_driver(struct serio *serio) | ||
112 | { | ||
113 | down_write(&serio_bus.subsys.rwsem); | ||
114 | device_attach(&serio->dev); | ||
115 | up_write(&serio_bus.subsys.rwsem); | ||
116 | } | ||
117 | |||
118 | |||
119 | /* | ||
120 | * Serio event processing. | ||
121 | */ | ||
122 | |||
123 | enum serio_event_type { | ||
124 | SERIO_RESCAN, | ||
125 | SERIO_RECONNECT, | ||
126 | SERIO_REGISTER_PORT, | ||
127 | SERIO_UNREGISTER_PORT, | ||
128 | SERIO_REGISTER_DRIVER, | ||
129 | }; | ||
130 | |||
131 | struct serio_event { | ||
132 | enum serio_event_type type; | ||
133 | void *object; | ||
134 | struct module *owner; | ||
135 | struct list_head node; | ||
136 | }; | ||
137 | |||
138 | static DEFINE_SPINLOCK(serio_event_lock); /* protects serio_event_list */ | ||
139 | static LIST_HEAD(serio_event_list); | ||
140 | static DECLARE_WAIT_QUEUE_HEAD(serio_wait); | ||
141 | static DECLARE_COMPLETION(serio_exited); | ||
142 | static int serio_pid; | ||
143 | |||
144 | static void serio_queue_event(void *object, struct module *owner, | ||
145 | enum serio_event_type event_type) | ||
146 | { | ||
147 | unsigned long flags; | ||
148 | struct serio_event *event; | ||
149 | |||
150 | spin_lock_irqsave(&serio_event_lock, flags); | ||
151 | |||
152 | /* | ||
153 | * Scan event list for the other events for the same serio port, | ||
154 | * starting with the most recent one. If event is the same we | ||
155 | * do not need add new one. If event is of different type we | ||
156 | * need to add this event and should not look further because | ||
157 | * we need to preseve sequence of distinct events. | ||
158 | */ | ||
159 | list_for_each_entry_reverse(event, &serio_event_list, node) { | ||
160 | if (event->object == object) { | ||
161 | if (event->type == event_type) | ||
162 | goto out; | ||
163 | break; | ||
164 | } | ||
165 | } | ||
166 | |||
167 | if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) { | ||
168 | if (!try_module_get(owner)) { | ||
169 | printk(KERN_WARNING "serio: Can't get module reference, dropping event %d\n", event_type); | ||
170 | goto out; | ||
171 | } | ||
172 | |||
173 | event->type = event_type; | ||
174 | event->object = object; | ||
175 | event->owner = owner; | ||
176 | |||
177 | list_add_tail(&event->node, &serio_event_list); | ||
178 | wake_up(&serio_wait); | ||
179 | } else { | ||
180 | printk(KERN_ERR "serio: Not enough memory to queue event %d\n", event_type); | ||
181 | } | ||
182 | out: | ||
183 | spin_unlock_irqrestore(&serio_event_lock, flags); | ||
184 | } | ||
185 | |||
186 | static void serio_free_event(struct serio_event *event) | ||
187 | { | ||
188 | module_put(event->owner); | ||
189 | kfree(event); | ||
190 | } | ||
191 | |||
192 | static void serio_remove_duplicate_events(struct serio_event *event) | ||
193 | { | ||
194 | struct list_head *node, *next; | ||
195 | struct serio_event *e; | ||
196 | unsigned long flags; | ||
197 | |||
198 | spin_lock_irqsave(&serio_event_lock, flags); | ||
199 | |||
200 | list_for_each_safe(node, next, &serio_event_list) { | ||
201 | e = list_entry(node, struct serio_event, node); | ||
202 | if (event->object == e->object) { | ||
203 | /* | ||
204 | * If this event is of different type we should not | ||
205 | * look further - we only suppress duplicate events | ||
206 | * that were sent back-to-back. | ||
207 | */ | ||
208 | if (event->type != e->type) | ||
209 | break; | ||
210 | |||
211 | list_del_init(node); | ||
212 | serio_free_event(e); | ||
213 | } | ||
214 | } | ||
215 | |||
216 | spin_unlock_irqrestore(&serio_event_lock, flags); | ||
217 | } | ||
218 | |||
219 | |||
220 | static struct serio_event *serio_get_event(void) | ||
221 | { | ||
222 | struct serio_event *event; | ||
223 | struct list_head *node; | ||
224 | unsigned long flags; | ||
225 | |||
226 | spin_lock_irqsave(&serio_event_lock, flags); | ||
227 | |||
228 | if (list_empty(&serio_event_list)) { | ||
229 | spin_unlock_irqrestore(&serio_event_lock, flags); | ||
230 | return NULL; | ||
231 | } | ||
232 | |||
233 | node = serio_event_list.next; | ||
234 | event = list_entry(node, struct serio_event, node); | ||
235 | list_del_init(node); | ||
236 | |||
237 | spin_unlock_irqrestore(&serio_event_lock, flags); | ||
238 | |||
239 | return event; | ||
240 | } | ||
241 | |||
242 | static void serio_handle_events(void) | ||
243 | { | ||
244 | struct serio_event *event; | ||
245 | struct serio_driver *serio_drv; | ||
246 | |||
247 | down(&serio_sem); | ||
248 | |||
249 | while ((event = serio_get_event())) { | ||
250 | |||
251 | switch (event->type) { | ||
252 | case SERIO_REGISTER_PORT: | ||
253 | serio_add_port(event->object); | ||
254 | break; | ||
255 | |||
256 | case SERIO_UNREGISTER_PORT: | ||
257 | serio_disconnect_port(event->object); | ||
258 | serio_destroy_port(event->object); | ||
259 | break; | ||
260 | |||
261 | case SERIO_RECONNECT: | ||
262 | serio_reconnect_port(event->object); | ||
263 | break; | ||
264 | |||
265 | case SERIO_RESCAN: | ||
266 | serio_disconnect_port(event->object); | ||
267 | serio_find_driver(event->object); | ||
268 | break; | ||
269 | |||
270 | case SERIO_REGISTER_DRIVER: | ||
271 | serio_drv = event->object; | ||
272 | driver_register(&serio_drv->driver); | ||
273 | break; | ||
274 | |||
275 | default: | ||
276 | break; | ||
277 | } | ||
278 | |||
279 | serio_remove_duplicate_events(event); | ||
280 | serio_free_event(event); | ||
281 | } | ||
282 | |||
283 | up(&serio_sem); | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | * Remove all events that have been submitted for a given serio port. | ||
288 | */ | ||
289 | static void serio_remove_pending_events(struct serio *serio) | ||
290 | { | ||
291 | struct list_head *node, *next; | ||
292 | struct serio_event *event; | ||
293 | unsigned long flags; | ||
294 | |||
295 | spin_lock_irqsave(&serio_event_lock, flags); | ||
296 | |||
297 | list_for_each_safe(node, next, &serio_event_list) { | ||
298 | event = list_entry(node, struct serio_event, node); | ||
299 | if (event->object == serio) { | ||
300 | list_del_init(node); | ||
301 | serio_free_event(event); | ||
302 | } | ||
303 | } | ||
304 | |||
305 | spin_unlock_irqrestore(&serio_event_lock, flags); | ||
306 | } | ||
307 | |||
308 | /* | ||
309 | * Destroy child serio port (if any) that has not been fully registered yet. | ||
310 | * | ||
311 | * Note that we rely on the fact that port can have only one child and therefore | ||
312 | * only one child registration request can be pending. Additionally, children | ||
313 | * are registered by driver's connect() handler so there can't be a grandchild | ||
314 | * pending registration together with a child. | ||
315 | */ | ||
316 | static struct serio *serio_get_pending_child(struct serio *parent) | ||
317 | { | ||
318 | struct serio_event *event; | ||
319 | struct serio *serio, *child = NULL; | ||
320 | unsigned long flags; | ||
321 | |||
322 | spin_lock_irqsave(&serio_event_lock, flags); | ||
323 | |||
324 | list_for_each_entry(event, &serio_event_list, node) { | ||
325 | if (event->type == SERIO_REGISTER_PORT) { | ||
326 | serio = event->object; | ||
327 | if (serio->parent == parent) { | ||
328 | child = serio; | ||
329 | break; | ||
330 | } | ||
331 | } | ||
332 | } | ||
333 | |||
334 | spin_unlock_irqrestore(&serio_event_lock, flags); | ||
335 | return child; | ||
336 | } | ||
337 | |||
338 | static int serio_thread(void *nothing) | ||
339 | { | ||
340 | lock_kernel(); | ||
341 | daemonize("kseriod"); | ||
342 | allow_signal(SIGTERM); | ||
343 | |||
344 | do { | ||
345 | serio_handle_events(); | ||
346 | wait_event_interruptible(serio_wait, !list_empty(&serio_event_list)); | ||
347 | try_to_freeze(PF_FREEZE); | ||
348 | } while (!signal_pending(current)); | ||
349 | |||
350 | printk(KERN_DEBUG "serio: kseriod exiting\n"); | ||
351 | |||
352 | unlock_kernel(); | ||
353 | complete_and_exit(&serio_exited, 0); | ||
354 | } | ||
355 | |||
356 | |||
357 | /* | ||
358 | * Serio port operations | ||
359 | */ | ||
360 | |||
361 | static ssize_t serio_show_description(struct device *dev, char *buf) | ||
362 | { | ||
363 | struct serio *serio = to_serio_port(dev); | ||
364 | return sprintf(buf, "%s\n", serio->name); | ||
365 | } | ||
366 | |||
367 | static ssize_t serio_show_id_type(struct device *dev, char *buf) | ||
368 | { | ||
369 | struct serio *serio = to_serio_port(dev); | ||
370 | return sprintf(buf, "%02x\n", serio->id.type); | ||
371 | } | ||
372 | |||
373 | static ssize_t serio_show_id_proto(struct device *dev, char *buf) | ||
374 | { | ||
375 | struct serio *serio = to_serio_port(dev); | ||
376 | return sprintf(buf, "%02x\n", serio->id.proto); | ||
377 | } | ||
378 | |||
379 | static ssize_t serio_show_id_id(struct device *dev, char *buf) | ||
380 | { | ||
381 | struct serio *serio = to_serio_port(dev); | ||
382 | return sprintf(buf, "%02x\n", serio->id.id); | ||
383 | } | ||
384 | |||
385 | static ssize_t serio_show_id_extra(struct device *dev, char *buf) | ||
386 | { | ||
387 | struct serio *serio = to_serio_port(dev); | ||
388 | return sprintf(buf, "%02x\n", serio->id.extra); | ||
389 | } | ||
390 | |||
391 | static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t count) | ||
392 | { | ||
393 | struct serio *serio = to_serio_port(dev); | ||
394 | struct device_driver *drv; | ||
395 | int retval; | ||
396 | |||
397 | retval = down_interruptible(&serio_sem); | ||
398 | if (retval) | ||
399 | return retval; | ||
400 | |||
401 | retval = count; | ||
402 | if (!strncmp(buf, "none", count)) { | ||
403 | serio_disconnect_port(serio); | ||
404 | } else if (!strncmp(buf, "reconnect", count)) { | ||
405 | serio_reconnect_port(serio); | ||
406 | } else if (!strncmp(buf, "rescan", count)) { | ||
407 | serio_disconnect_port(serio); | ||
408 | serio_find_driver(serio); | ||
409 | } else if ((drv = driver_find(buf, &serio_bus)) != NULL) { | ||
410 | serio_disconnect_port(serio); | ||
411 | serio_bind_driver(serio, to_serio_driver(drv)); | ||
412 | put_driver(drv); | ||
413 | } else { | ||
414 | retval = -EINVAL; | ||
415 | } | ||
416 | |||
417 | up(&serio_sem); | ||
418 | |||
419 | return retval; | ||
420 | } | ||
421 | |||
422 | static ssize_t serio_show_bind_mode(struct device *dev, char *buf) | ||
423 | { | ||
424 | struct serio *serio = to_serio_port(dev); | ||
425 | return sprintf(buf, "%s\n", serio->manual_bind ? "manual" : "auto"); | ||
426 | } | ||
427 | |||
428 | static ssize_t serio_set_bind_mode(struct device *dev, const char *buf, size_t count) | ||
429 | { | ||
430 | struct serio *serio = to_serio_port(dev); | ||
431 | int retval; | ||
432 | |||
433 | retval = count; | ||
434 | if (!strncmp(buf, "manual", count)) { | ||
435 | serio->manual_bind = 1; | ||
436 | } else if (!strncmp(buf, "auto", count)) { | ||
437 | serio->manual_bind = 0; | ||
438 | } else { | ||
439 | retval = -EINVAL; | ||
440 | } | ||
441 | |||
442 | return retval; | ||
443 | } | ||
444 | |||
445 | static struct device_attribute serio_device_attrs[] = { | ||
446 | __ATTR(description, S_IRUGO, serio_show_description, NULL), | ||
447 | __ATTR(id_type, S_IRUGO, serio_show_id_type, NULL), | ||
448 | __ATTR(id_proto, S_IRUGO, serio_show_id_proto, NULL), | ||
449 | __ATTR(id_id, S_IRUGO, serio_show_id_id, NULL), | ||
450 | __ATTR(id_extra, S_IRUGO, serio_show_id_extra, NULL), | ||
451 | __ATTR(drvctl, S_IWUSR, NULL, serio_rebind_driver), | ||
452 | __ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode), | ||
453 | __ATTR_NULL | ||
454 | }; | ||
455 | |||
456 | |||
457 | static void serio_release_port(struct device *dev) | ||
458 | { | ||
459 | struct serio *serio = to_serio_port(dev); | ||
460 | |||
461 | kfree(serio); | ||
462 | module_put(THIS_MODULE); | ||
463 | } | ||
464 | |||
465 | /* | ||
466 | * Prepare serio port for registration. | ||
467 | */ | ||
468 | static void serio_init_port(struct serio *serio) | ||
469 | { | ||
470 | static atomic_t serio_no = ATOMIC_INIT(0); | ||
471 | |||
472 | __module_get(THIS_MODULE); | ||
473 | |||
474 | spin_lock_init(&serio->lock); | ||
475 | init_MUTEX(&serio->drv_sem); | ||
476 | device_initialize(&serio->dev); | ||
477 | snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id), | ||
478 | "serio%ld", (long)atomic_inc_return(&serio_no) - 1); | ||
479 | serio->dev.bus = &serio_bus; | ||
480 | serio->dev.release = serio_release_port; | ||
481 | if (serio->parent) | ||
482 | serio->dev.parent = &serio->parent->dev; | ||
483 | } | ||
484 | |||
485 | /* | ||
486 | * Complete serio port registration. | ||
487 | * Driver core will attempt to find appropriate driver for the port. | ||
488 | */ | ||
489 | static void serio_add_port(struct serio *serio) | ||
490 | { | ||
491 | if (serio->parent) { | ||
492 | serio_pause_rx(serio->parent); | ||
493 | serio->parent->child = serio; | ||
494 | serio_continue_rx(serio->parent); | ||
495 | } | ||
496 | |||
497 | list_add_tail(&serio->node, &serio_list); | ||
498 | if (serio->start) | ||
499 | serio->start(serio); | ||
500 | device_add(&serio->dev); | ||
501 | serio->registered = 1; | ||
502 | } | ||
503 | |||
504 | /* | ||
505 | * serio_destroy_port() completes deregistration process and removes | ||
506 | * port from the system | ||
507 | */ | ||
508 | static void serio_destroy_port(struct serio *serio) | ||
509 | { | ||
510 | struct serio *child; | ||
511 | |||
512 | child = serio_get_pending_child(serio); | ||
513 | if (child) { | ||
514 | serio_remove_pending_events(child); | ||
515 | put_device(&child->dev); | ||
516 | } | ||
517 | |||
518 | if (serio->stop) | ||
519 | serio->stop(serio); | ||
520 | |||
521 | if (serio->parent) { | ||
522 | serio_pause_rx(serio->parent); | ||
523 | serio->parent->child = NULL; | ||
524 | serio_continue_rx(serio->parent); | ||
525 | serio->parent = NULL; | ||
526 | } | ||
527 | |||
528 | if (serio->registered) { | ||
529 | device_del(&serio->dev); | ||
530 | list_del_init(&serio->node); | ||
531 | serio->registered = 0; | ||
532 | } | ||
533 | |||
534 | serio_remove_pending_events(serio); | ||
535 | put_device(&serio->dev); | ||
536 | } | ||
537 | |||
538 | /* | ||
539 | * Reconnect serio port and all its children (re-initialize attached devices) | ||
540 | */ | ||
541 | static void serio_reconnect_port(struct serio *serio) | ||
542 | { | ||
543 | do { | ||
544 | if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) { | ||
545 | serio_disconnect_port(serio); | ||
546 | serio_find_driver(serio); | ||
547 | /* Ok, old children are now gone, we are done */ | ||
548 | break; | ||
549 | } | ||
550 | serio = serio->child; | ||
551 | } while (serio); | ||
552 | } | ||
553 | |||
554 | /* | ||
555 | * serio_disconnect_port() unbinds a port from its driver. As a side effect | ||
556 | * all child ports are unbound and destroyed. | ||
557 | */ | ||
558 | static void serio_disconnect_port(struct serio *serio) | ||
559 | { | ||
560 | struct serio *s, *parent; | ||
561 | |||
562 | if (serio->child) { | ||
563 | /* | ||
564 | * Children ports should be disconnected and destroyed | ||
565 | * first, staring with the leaf one, since we don't want | ||
566 | * to do recursion | ||
567 | */ | ||
568 | for (s = serio; s->child; s = s->child) | ||
569 | /* empty */; | ||
570 | |||
571 | do { | ||
572 | parent = s->parent; | ||
573 | |||
574 | serio_release_driver(s); | ||
575 | serio_destroy_port(s); | ||
576 | } while ((s = parent) != serio); | ||
577 | } | ||
578 | |||
579 | /* | ||
580 | * Ok, no children left, now disconnect this port | ||
581 | */ | ||
582 | serio_release_driver(serio); | ||
583 | } | ||
584 | |||
585 | void serio_rescan(struct serio *serio) | ||
586 | { | ||
587 | serio_queue_event(serio, NULL, SERIO_RESCAN); | ||
588 | } | ||
589 | |||
590 | void serio_reconnect(struct serio *serio) | ||
591 | { | ||
592 | serio_queue_event(serio, NULL, SERIO_RECONNECT); | ||
593 | } | ||
594 | |||
595 | /* | ||
596 | * Submits register request to kseriod for subsequent execution. | ||
597 | * Note that port registration is always asynchronous. | ||
598 | */ | ||
599 | void __serio_register_port(struct serio *serio, struct module *owner) | ||
600 | { | ||
601 | serio_init_port(serio); | ||
602 | serio_queue_event(serio, owner, SERIO_REGISTER_PORT); | ||
603 | } | ||
604 | |||
605 | /* | ||
606 | * Synchronously unregisters serio port. | ||
607 | */ | ||
608 | void serio_unregister_port(struct serio *serio) | ||
609 | { | ||
610 | down(&serio_sem); | ||
611 | serio_disconnect_port(serio); | ||
612 | serio_destroy_port(serio); | ||
613 | up(&serio_sem); | ||
614 | } | ||
615 | |||
616 | /* | ||
617 | * Submits register request to kseriod for subsequent execution. | ||
618 | * Can be used when it is not obvious whether the serio_sem is | ||
619 | * taken or not and when delayed execution is feasible. | ||
620 | */ | ||
621 | void __serio_unregister_port_delayed(struct serio *serio, struct module *owner) | ||
622 | { | ||
623 | serio_queue_event(serio, owner, SERIO_UNREGISTER_PORT); | ||
624 | } | ||
625 | |||
626 | |||
627 | /* | ||
628 | * Serio driver operations | ||
629 | */ | ||
630 | |||
631 | static ssize_t serio_driver_show_description(struct device_driver *drv, char *buf) | ||
632 | { | ||
633 | struct serio_driver *driver = to_serio_driver(drv); | ||
634 | return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)"); | ||
635 | } | ||
636 | |||
637 | static ssize_t serio_driver_show_bind_mode(struct device_driver *drv, char *buf) | ||
638 | { | ||
639 | struct serio_driver *serio_drv = to_serio_driver(drv); | ||
640 | return sprintf(buf, "%s\n", serio_drv->manual_bind ? "manual" : "auto"); | ||
641 | } | ||
642 | |||
643 | static ssize_t serio_driver_set_bind_mode(struct device_driver *drv, const char *buf, size_t count) | ||
644 | { | ||
645 | struct serio_driver *serio_drv = to_serio_driver(drv); | ||
646 | int retval; | ||
647 | |||
648 | retval = count; | ||
649 | if (!strncmp(buf, "manual", count)) { | ||
650 | serio_drv->manual_bind = 1; | ||
651 | } else if (!strncmp(buf, "auto", count)) { | ||
652 | serio_drv->manual_bind = 0; | ||
653 | } else { | ||
654 | retval = -EINVAL; | ||
655 | } | ||
656 | |||
657 | return retval; | ||
658 | } | ||
659 | |||
660 | |||
661 | static struct driver_attribute serio_driver_attrs[] = { | ||
662 | __ATTR(description, S_IRUGO, serio_driver_show_description, NULL), | ||
663 | __ATTR(bind_mode, S_IWUSR | S_IRUGO, | ||
664 | serio_driver_show_bind_mode, serio_driver_set_bind_mode), | ||
665 | __ATTR_NULL | ||
666 | }; | ||
667 | |||
668 | static int serio_driver_probe(struct device *dev) | ||
669 | { | ||
670 | struct serio *serio = to_serio_port(dev); | ||
671 | struct serio_driver *drv = to_serio_driver(dev->driver); | ||
672 | |||
673 | return drv->connect(serio, drv); | ||
674 | } | ||
675 | |||
676 | static int serio_driver_remove(struct device *dev) | ||
677 | { | ||
678 | struct serio *serio = to_serio_port(dev); | ||
679 | struct serio_driver *drv = to_serio_driver(dev->driver); | ||
680 | |||
681 | drv->disconnect(serio); | ||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | void __serio_register_driver(struct serio_driver *drv, struct module *owner) | ||
686 | { | ||
687 | drv->driver.bus = &serio_bus; | ||
688 | drv->driver.probe = serio_driver_probe; | ||
689 | drv->driver.remove = serio_driver_remove; | ||
690 | |||
691 | serio_queue_event(drv, owner, SERIO_REGISTER_DRIVER); | ||
692 | } | ||
693 | |||
694 | void serio_unregister_driver(struct serio_driver *drv) | ||
695 | { | ||
696 | struct serio *serio; | ||
697 | |||
698 | down(&serio_sem); | ||
699 | drv->manual_bind = 1; /* so serio_find_driver ignores it */ | ||
700 | |||
701 | start_over: | ||
702 | list_for_each_entry(serio, &serio_list, node) { | ||
703 | if (serio->drv == drv) { | ||
704 | serio_disconnect_port(serio); | ||
705 | serio_find_driver(serio); | ||
706 | /* we could've deleted some ports, restart */ | ||
707 | goto start_over; | ||
708 | } | ||
709 | } | ||
710 | |||
711 | driver_unregister(&drv->driver); | ||
712 | up(&serio_sem); | ||
713 | } | ||
714 | |||
715 | static void serio_set_drv(struct serio *serio, struct serio_driver *drv) | ||
716 | { | ||
717 | down(&serio->drv_sem); | ||
718 | serio_pause_rx(serio); | ||
719 | serio->drv = drv; | ||
720 | serio_continue_rx(serio); | ||
721 | up(&serio->drv_sem); | ||
722 | } | ||
723 | |||
724 | static int serio_bus_match(struct device *dev, struct device_driver *drv) | ||
725 | { | ||
726 | struct serio *serio = to_serio_port(dev); | ||
727 | struct serio_driver *serio_drv = to_serio_driver(drv); | ||
728 | |||
729 | if (serio->manual_bind || serio_drv->manual_bind) | ||
730 | return 0; | ||
731 | |||
732 | return serio_match_port(serio_drv->id_table, serio); | ||
733 | } | ||
734 | |||
735 | #ifdef CONFIG_HOTPLUG | ||
736 | |||
737 | #define PUT_ENVP(fmt, val) \ | ||
738 | do { \ | ||
739 | envp[i++] = buffer; \ | ||
740 | length += snprintf(buffer, buffer_size - length, fmt, val); \ | ||
741 | if (buffer_size - length <= 0 || i >= num_envp) \ | ||
742 | return -ENOMEM; \ | ||
743 | length++; \ | ||
744 | buffer += length; \ | ||
745 | } while (0) | ||
746 | static int serio_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) | ||
747 | { | ||
748 | struct serio *serio; | ||
749 | int i = 0; | ||
750 | int length = 0; | ||
751 | |||
752 | if (!dev) | ||
753 | return -ENODEV; | ||
754 | |||
755 | serio = to_serio_port(dev); | ||
756 | |||
757 | PUT_ENVP("SERIO_TYPE=%02x", serio->id.type); | ||
758 | PUT_ENVP("SERIO_PROTO=%02x", serio->id.proto); | ||
759 | PUT_ENVP("SERIO_ID=%02x", serio->id.id); | ||
760 | PUT_ENVP("SERIO_EXTRA=%02x", serio->id.extra); | ||
761 | |||
762 | envp[i] = NULL; | ||
763 | |||
764 | return 0; | ||
765 | } | ||
766 | #undef PUT_ENVP | ||
767 | |||
768 | #else | ||
769 | |||
770 | static int serio_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) | ||
771 | { | ||
772 | return -ENODEV; | ||
773 | } | ||
774 | |||
775 | #endif /* CONFIG_HOTPLUG */ | ||
776 | |||
777 | static int serio_resume(struct device *dev) | ||
778 | { | ||
779 | struct serio *serio = to_serio_port(dev); | ||
780 | |||
781 | if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) { | ||
782 | serio_disconnect_port(serio); | ||
783 | /* | ||
784 | * Driver re-probing can take a while, so better let kseriod | ||
785 | * deal with it. | ||
786 | */ | ||
787 | serio_rescan(serio); | ||
788 | } | ||
789 | |||
790 | return 0; | ||
791 | } | ||
792 | |||
793 | /* called from serio_driver->connect/disconnect methods under serio_sem */ | ||
794 | int serio_open(struct serio *serio, struct serio_driver *drv) | ||
795 | { | ||
796 | serio_set_drv(serio, drv); | ||
797 | |||
798 | if (serio->open && serio->open(serio)) { | ||
799 | serio_set_drv(serio, NULL); | ||
800 | return -1; | ||
801 | } | ||
802 | return 0; | ||
803 | } | ||
804 | |||
805 | /* called from serio_driver->connect/disconnect methods under serio_sem */ | ||
806 | void serio_close(struct serio *serio) | ||
807 | { | ||
808 | if (serio->close) | ||
809 | serio->close(serio); | ||
810 | |||
811 | serio_set_drv(serio, NULL); | ||
812 | } | ||
813 | |||
814 | irqreturn_t serio_interrupt(struct serio *serio, | ||
815 | unsigned char data, unsigned int dfl, struct pt_regs *regs) | ||
816 | { | ||
817 | unsigned long flags; | ||
818 | irqreturn_t ret = IRQ_NONE; | ||
819 | |||
820 | spin_lock_irqsave(&serio->lock, flags); | ||
821 | |||
822 | if (likely(serio->drv)) { | ||
823 | ret = serio->drv->interrupt(serio, data, dfl, regs); | ||
824 | } else if (!dfl && serio->registered) { | ||
825 | serio_rescan(serio); | ||
826 | ret = IRQ_HANDLED; | ||
827 | } | ||
828 | |||
829 | spin_unlock_irqrestore(&serio->lock, flags); | ||
830 | |||
831 | return ret; | ||
832 | } | ||
833 | |||
834 | static int __init serio_init(void) | ||
835 | { | ||
836 | if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) { | ||
837 | printk(KERN_ERR "serio: Failed to start kseriod\n"); | ||
838 | return -1; | ||
839 | } | ||
840 | |||
841 | serio_bus.dev_attrs = serio_device_attrs; | ||
842 | serio_bus.drv_attrs = serio_driver_attrs; | ||
843 | serio_bus.match = serio_bus_match; | ||
844 | serio_bus.hotplug = serio_hotplug; | ||
845 | serio_bus.resume = serio_resume; | ||
846 | bus_register(&serio_bus); | ||
847 | |||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | static void __exit serio_exit(void) | ||
852 | { | ||
853 | bus_unregister(&serio_bus); | ||
854 | kill_proc(serio_pid, SIGTERM, 1); | ||
855 | wait_for_completion(&serio_exited); | ||
856 | } | ||
857 | |||
858 | module_init(serio_init); | ||
859 | module_exit(serio_exit); | ||