diff options
Diffstat (limited to 'drivers/input/serio/serio.c')
-rw-r--r-- | drivers/input/serio/serio.c | 89 |
1 files changed, 62 insertions, 27 deletions
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 341824c48529..f367695e69b5 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c | |||
@@ -31,10 +31,9 @@ | |||
31 | #include <linux/serio.h> | 31 | #include <linux/serio.h> |
32 | #include <linux/errno.h> | 32 | #include <linux/errno.h> |
33 | #include <linux/wait.h> | 33 | #include <linux/wait.h> |
34 | #include <linux/completion.h> | ||
35 | #include <linux/sched.h> | 34 | #include <linux/sched.h> |
36 | #include <linux/smp_lock.h> | ||
37 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/kthread.h> | ||
38 | 37 | ||
39 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 38 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
40 | MODULE_DESCRIPTION("Serio abstraction core"); | 39 | MODULE_DESCRIPTION("Serio abstraction core"); |
@@ -43,6 +42,7 @@ MODULE_LICENSE("GPL"); | |||
43 | EXPORT_SYMBOL(serio_interrupt); | 42 | EXPORT_SYMBOL(serio_interrupt); |
44 | EXPORT_SYMBOL(__serio_register_port); | 43 | EXPORT_SYMBOL(__serio_register_port); |
45 | EXPORT_SYMBOL(serio_unregister_port); | 44 | EXPORT_SYMBOL(serio_unregister_port); |
45 | EXPORT_SYMBOL(serio_unregister_child_port); | ||
46 | EXPORT_SYMBOL(__serio_unregister_port_delayed); | 46 | EXPORT_SYMBOL(__serio_unregister_port_delayed); |
47 | EXPORT_SYMBOL(__serio_register_driver); | 47 | EXPORT_SYMBOL(__serio_register_driver); |
48 | EXPORT_SYMBOL(serio_unregister_driver); | 48 | EXPORT_SYMBOL(serio_unregister_driver); |
@@ -68,6 +68,37 @@ static void serio_destroy_port(struct serio *serio); | |||
68 | static void serio_reconnect_port(struct serio *serio); | 68 | static void serio_reconnect_port(struct serio *serio); |
69 | static void serio_disconnect_port(struct serio *serio); | 69 | static void serio_disconnect_port(struct serio *serio); |
70 | 70 | ||
71 | static int serio_connect_driver(struct serio *serio, struct serio_driver *drv) | ||
72 | { | ||
73 | int retval; | ||
74 | |||
75 | down(&serio->drv_sem); | ||
76 | retval = drv->connect(serio, drv); | ||
77 | up(&serio->drv_sem); | ||
78 | |||
79 | return retval; | ||
80 | } | ||
81 | |||
82 | static int serio_reconnect_driver(struct serio *serio) | ||
83 | { | ||
84 | int retval = -1; | ||
85 | |||
86 | down(&serio->drv_sem); | ||
87 | if (serio->drv && serio->drv->reconnect) | ||
88 | retval = serio->drv->reconnect(serio); | ||
89 | up(&serio->drv_sem); | ||
90 | |||
91 | return retval; | ||
92 | } | ||
93 | |||
94 | static void serio_disconnect_driver(struct serio *serio) | ||
95 | { | ||
96 | down(&serio->drv_sem); | ||
97 | if (serio->drv) | ||
98 | serio->drv->disconnect(serio); | ||
99 | up(&serio->drv_sem); | ||
100 | } | ||
101 | |||
71 | static int serio_match_port(const struct serio_device_id *ids, struct serio *serio) | 102 | static int serio_match_port(const struct serio_device_id *ids, struct serio *serio) |
72 | { | 103 | { |
73 | while (ids->type || ids->proto) { | 104 | while (ids->type || ids->proto) { |
@@ -91,7 +122,7 @@ static void serio_bind_driver(struct serio *serio, struct serio_driver *drv) | |||
91 | 122 | ||
92 | if (serio_match_port(drv->id_table, serio)) { | 123 | if (serio_match_port(drv->id_table, serio)) { |
93 | serio->dev.driver = &drv->driver; | 124 | serio->dev.driver = &drv->driver; |
94 | if (drv->connect(serio, drv)) { | 125 | if (serio_connect_driver(serio, drv)) { |
95 | serio->dev.driver = NULL; | 126 | serio->dev.driver = NULL; |
96 | goto out; | 127 | goto out; |
97 | } | 128 | } |
@@ -138,8 +169,7 @@ struct serio_event { | |||
138 | static DEFINE_SPINLOCK(serio_event_lock); /* protects serio_event_list */ | 169 | static DEFINE_SPINLOCK(serio_event_lock); /* protects serio_event_list */ |
139 | static LIST_HEAD(serio_event_list); | 170 | static LIST_HEAD(serio_event_list); |
140 | static DECLARE_WAIT_QUEUE_HEAD(serio_wait); | 171 | static DECLARE_WAIT_QUEUE_HEAD(serio_wait); |
141 | static DECLARE_COMPLETION(serio_exited); | 172 | static struct task_struct *serio_task; |
142 | static int serio_pid; | ||
143 | 173 | ||
144 | static void serio_queue_event(void *object, struct module *owner, | 174 | static void serio_queue_event(void *object, struct module *owner, |
145 | enum serio_event_type event_type) | 175 | enum serio_event_type event_type) |
@@ -150,12 +180,12 @@ static void serio_queue_event(void *object, struct module *owner, | |||
150 | spin_lock_irqsave(&serio_event_lock, flags); | 180 | spin_lock_irqsave(&serio_event_lock, flags); |
151 | 181 | ||
152 | /* | 182 | /* |
153 | * Scan event list for the other events for the same serio port, | 183 | * 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 | 184 | * 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 | 185 | * 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 | 186 | * need to add this event and should not look further because |
157 | * we need to preseve sequence of distinct events. | 187 | * we need to preseve sequence of distinct events. |
158 | */ | 188 | */ |
159 | list_for_each_entry_reverse(event, &serio_event_list, node) { | 189 | list_for_each_entry_reverse(event, &serio_event_list, node) { |
160 | if (event->object == object) { | 190 | if (event->object == object) { |
161 | if (event->type == event_type) | 191 | if (event->type == event_type) |
@@ -337,20 +367,15 @@ static struct serio *serio_get_pending_child(struct serio *parent) | |||
337 | 367 | ||
338 | static int serio_thread(void *nothing) | 368 | static int serio_thread(void *nothing) |
339 | { | 369 | { |
340 | lock_kernel(); | ||
341 | daemonize("kseriod"); | ||
342 | allow_signal(SIGTERM); | ||
343 | |||
344 | do { | 370 | do { |
345 | serio_handle_events(); | 371 | serio_handle_events(); |
346 | wait_event_interruptible(serio_wait, !list_empty(&serio_event_list)); | 372 | wait_event_interruptible(serio_wait, |
373 | kthread_should_stop() || !list_empty(&serio_event_list)); | ||
347 | try_to_freeze(); | 374 | try_to_freeze(); |
348 | } while (!signal_pending(current)); | 375 | } while (!kthread_should_stop()); |
349 | 376 | ||
350 | printk(KERN_DEBUG "serio: kseriod exiting\n"); | 377 | printk(KERN_DEBUG "serio: kseriod exiting\n"); |
351 | 378 | return 0; | |
352 | unlock_kernel(); | ||
353 | complete_and_exit(&serio_exited, 0); | ||
354 | } | 379 | } |
355 | 380 | ||
356 | 381 | ||
@@ -557,7 +582,7 @@ static void serio_destroy_port(struct serio *serio) | |||
557 | static void serio_reconnect_port(struct serio *serio) | 582 | static void serio_reconnect_port(struct serio *serio) |
558 | { | 583 | { |
559 | do { | 584 | do { |
560 | if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) { | 585 | if (serio_reconnect_driver(serio)) { |
561 | serio_disconnect_port(serio); | 586 | serio_disconnect_port(serio); |
562 | serio_find_driver(serio); | 587 | serio_find_driver(serio); |
563 | /* Ok, old children are now gone, we are done */ | 588 | /* Ok, old children are now gone, we are done */ |
@@ -630,6 +655,19 @@ void serio_unregister_port(struct serio *serio) | |||
630 | } | 655 | } |
631 | 656 | ||
632 | /* | 657 | /* |
658 | * Safely unregisters child port if one is present. | ||
659 | */ | ||
660 | void serio_unregister_child_port(struct serio *serio) | ||
661 | { | ||
662 | down(&serio_sem); | ||
663 | if (serio->child) { | ||
664 | serio_disconnect_port(serio->child); | ||
665 | serio_destroy_port(serio->child); | ||
666 | } | ||
667 | up(&serio_sem); | ||
668 | } | ||
669 | |||
670 | /* | ||
633 | * Submits register request to kseriod for subsequent execution. | 671 | * Submits register request to kseriod for subsequent execution. |
634 | * Can be used when it is not obvious whether the serio_sem is | 672 | * Can be used when it is not obvious whether the serio_sem is |
635 | * taken or not and when delayed execution is feasible. | 673 | * taken or not and when delayed execution is feasible. |
@@ -686,15 +724,14 @@ static int serio_driver_probe(struct device *dev) | |||
686 | struct serio *serio = to_serio_port(dev); | 724 | struct serio *serio = to_serio_port(dev); |
687 | struct serio_driver *drv = to_serio_driver(dev->driver); | 725 | struct serio_driver *drv = to_serio_driver(dev->driver); |
688 | 726 | ||
689 | return drv->connect(serio, drv); | 727 | return serio_connect_driver(serio, drv); |
690 | } | 728 | } |
691 | 729 | ||
692 | static int serio_driver_remove(struct device *dev) | 730 | static int serio_driver_remove(struct device *dev) |
693 | { | 731 | { |
694 | struct serio *serio = to_serio_port(dev); | 732 | struct serio *serio = to_serio_port(dev); |
695 | struct serio_driver *drv = to_serio_driver(dev->driver); | ||
696 | 733 | ||
697 | drv->disconnect(serio); | 734 | serio_disconnect_driver(serio); |
698 | return 0; | 735 | return 0; |
699 | } | 736 | } |
700 | 737 | ||
@@ -730,11 +767,9 @@ start_over: | |||
730 | 767 | ||
731 | static void serio_set_drv(struct serio *serio, struct serio_driver *drv) | 768 | static void serio_set_drv(struct serio *serio, struct serio_driver *drv) |
732 | { | 769 | { |
733 | down(&serio->drv_sem); | ||
734 | serio_pause_rx(serio); | 770 | serio_pause_rx(serio); |
735 | serio->drv = drv; | 771 | serio->drv = drv; |
736 | serio_continue_rx(serio); | 772 | serio_continue_rx(serio); |
737 | up(&serio->drv_sem); | ||
738 | } | 773 | } |
739 | 774 | ||
740 | static int serio_bus_match(struct device *dev, struct device_driver *drv) | 775 | static int serio_bus_match(struct device *dev, struct device_driver *drv) |
@@ -794,7 +829,7 @@ static int serio_resume(struct device *dev) | |||
794 | { | 829 | { |
795 | struct serio *serio = to_serio_port(dev); | 830 | struct serio *serio = to_serio_port(dev); |
796 | 831 | ||
797 | if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) { | 832 | if (serio_reconnect_driver(serio)) { |
798 | /* | 833 | /* |
799 | * Driver re-probing can take a while, so better let kseriod | 834 | * Driver re-probing can take a while, so better let kseriod |
800 | * deal with it. | 835 | * deal with it. |
@@ -848,9 +883,10 @@ irqreturn_t serio_interrupt(struct serio *serio, | |||
848 | 883 | ||
849 | static int __init serio_init(void) | 884 | static int __init serio_init(void) |
850 | { | 885 | { |
851 | if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) { | 886 | serio_task = kthread_run(serio_thread, NULL, "kseriod"); |
887 | if (IS_ERR(serio_task)) { | ||
852 | printk(KERN_ERR "serio: Failed to start kseriod\n"); | 888 | printk(KERN_ERR "serio: Failed to start kseriod\n"); |
853 | return -1; | 889 | return PTR_ERR(serio_task); |
854 | } | 890 | } |
855 | 891 | ||
856 | serio_bus.dev_attrs = serio_device_attrs; | 892 | serio_bus.dev_attrs = serio_device_attrs; |
@@ -866,8 +902,7 @@ static int __init serio_init(void) | |||
866 | static void __exit serio_exit(void) | 902 | static void __exit serio_exit(void) |
867 | { | 903 | { |
868 | bus_unregister(&serio_bus); | 904 | bus_unregister(&serio_bus); |
869 | kill_proc(serio_pid, SIGTERM, 1); | 905 | kthread_stop(serio_task); |
870 | wait_for_completion(&serio_exited); | ||
871 | } | 906 | } |
872 | 907 | ||
873 | module_init(serio_init); | 908 | module_init(serio_init); |