diff options
author | Dmitry Torokhov <dtor@insightbb.com> | 2006-11-23 23:34:49 -0500 |
---|---|---|
committer | Dmitry Torokhov <dtor@insightbb.com> | 2006-11-23 23:34:49 -0500 |
commit | ed7b1f6d6ea1054ea4fe293a7fd8015fc3803d93 (patch) | |
tree | eb4d4f4e0eb07e7ae923f654ea09297b437409cc /drivers/input/serio/serio.c | |
parent | 9d92fe17b652f5496c97bc83fdfe925f3182f602 (diff) |
Input: serio - make serio_register_driver() return errors
Perform actual driver registration right in serio_register_driver()
instead of offloading it to kseriod and return proper error code to
callers if driver registration fails.
Note that driver <-> port matching is still done by kseriod to
speed up boot process since probing for PS/2 mice and keyboards
is pretty slow.
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/serio/serio.c')
-rw-r--r-- | drivers/input/serio/serio.c | 107 |
1 files changed, 74 insertions, 33 deletions
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index cd55ddb7df4f..8c717042f611 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c | |||
@@ -44,7 +44,7 @@ EXPORT_SYMBOL(serio_interrupt); | |||
44 | EXPORT_SYMBOL(__serio_register_port); | 44 | EXPORT_SYMBOL(__serio_register_port); |
45 | EXPORT_SYMBOL(serio_unregister_port); | 45 | EXPORT_SYMBOL(serio_unregister_port); |
46 | EXPORT_SYMBOL(serio_unregister_child_port); | 46 | EXPORT_SYMBOL(serio_unregister_child_port); |
47 | EXPORT_SYMBOL(__serio_register_driver); | 47 | EXPORT_SYMBOL(serio_register_driver); |
48 | EXPORT_SYMBOL(serio_unregister_driver); | 48 | EXPORT_SYMBOL(serio_unregister_driver); |
49 | EXPORT_SYMBOL(serio_open); | 49 | EXPORT_SYMBOL(serio_open); |
50 | EXPORT_SYMBOL(serio_close); | 50 | EXPORT_SYMBOL(serio_close); |
@@ -61,10 +61,10 @@ static LIST_HEAD(serio_list); | |||
61 | 61 | ||
62 | static struct bus_type serio_bus; | 62 | static struct bus_type serio_bus; |
63 | 63 | ||
64 | static void serio_add_driver(struct serio_driver *drv); | ||
65 | static void serio_add_port(struct serio *serio); | 64 | static void serio_add_port(struct serio *serio); |
66 | static void serio_reconnect_port(struct serio *serio); | 65 | static void serio_reconnect_port(struct serio *serio); |
67 | static void serio_disconnect_port(struct serio *serio); | 66 | static void serio_disconnect_port(struct serio *serio); |
67 | static void serio_attach_driver(struct serio_driver *drv); | ||
68 | 68 | ||
69 | static int serio_connect_driver(struct serio *serio, struct serio_driver *drv) | 69 | static int serio_connect_driver(struct serio *serio, struct serio_driver *drv) |
70 | { | 70 | { |
@@ -168,10 +168,10 @@ static void serio_find_driver(struct serio *serio) | |||
168 | */ | 168 | */ |
169 | 169 | ||
170 | enum serio_event_type { | 170 | enum serio_event_type { |
171 | SERIO_RESCAN, | 171 | SERIO_RESCAN_PORT, |
172 | SERIO_RECONNECT, | 172 | SERIO_RECONNECT_PORT, |
173 | SERIO_REGISTER_PORT, | 173 | SERIO_REGISTER_PORT, |
174 | SERIO_REGISTER_DRIVER, | 174 | SERIO_ATTACH_DRIVER, |
175 | }; | 175 | }; |
176 | 176 | ||
177 | struct serio_event { | 177 | struct serio_event { |
@@ -186,11 +186,12 @@ static LIST_HEAD(serio_event_list); | |||
186 | static DECLARE_WAIT_QUEUE_HEAD(serio_wait); | 186 | static DECLARE_WAIT_QUEUE_HEAD(serio_wait); |
187 | static struct task_struct *serio_task; | 187 | static struct task_struct *serio_task; |
188 | 188 | ||
189 | static void serio_queue_event(void *object, struct module *owner, | 189 | static int serio_queue_event(void *object, struct module *owner, |
190 | enum serio_event_type event_type) | 190 | enum serio_event_type event_type) |
191 | { | 191 | { |
192 | unsigned long flags; | 192 | unsigned long flags; |
193 | struct serio_event *event; | 193 | struct serio_event *event; |
194 | int retval = 0; | ||
194 | 195 | ||
195 | spin_lock_irqsave(&serio_event_lock, flags); | 196 | spin_lock_irqsave(&serio_event_lock, flags); |
196 | 197 | ||
@@ -209,24 +210,34 @@ static void serio_queue_event(void *object, struct module *owner, | |||
209 | } | 210 | } |
210 | } | 211 | } |
211 | 212 | ||
212 | if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) { | 213 | event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC); |
213 | if (!try_module_get(owner)) { | 214 | if (!event) { |
214 | printk(KERN_WARNING "serio: Can't get module reference, dropping event %d\n", event_type); | 215 | printk(KERN_ERR |
215 | kfree(event); | 216 | "serio: Not enough memory to queue event %d\n", |
216 | goto out; | 217 | event_type); |
217 | } | 218 | retval = -ENOMEM; |
218 | 219 | goto out; | |
219 | event->type = event_type; | 220 | } |
220 | event->object = object; | ||
221 | event->owner = owner; | ||
222 | 221 | ||
223 | list_add_tail(&event->node, &serio_event_list); | 222 | if (!try_module_get(owner)) { |
224 | wake_up(&serio_wait); | 223 | printk(KERN_WARNING |
225 | } else { | 224 | "serio: Can't get module reference, dropping event %d\n", |
226 | printk(KERN_ERR "serio: Not enough memory to queue event %d\n", event_type); | 225 | event_type); |
226 | kfree(event); | ||
227 | retval = -EINVAL; | ||
228 | goto out; | ||
227 | } | 229 | } |
230 | |||
231 | event->type = event_type; | ||
232 | event->object = object; | ||
233 | event->owner = owner; | ||
234 | |||
235 | list_add_tail(&event->node, &serio_event_list); | ||
236 | wake_up(&serio_wait); | ||
237 | |||
228 | out: | 238 | out: |
229 | spin_unlock_irqrestore(&serio_event_lock, flags); | 239 | spin_unlock_irqrestore(&serio_event_lock, flags); |
240 | return retval; | ||
230 | } | 241 | } |
231 | 242 | ||
232 | static void serio_free_event(struct serio_event *event) | 243 | static void serio_free_event(struct serio_event *event) |
@@ -304,17 +315,17 @@ static void serio_handle_event(void) | |||
304 | serio_add_port(event->object); | 315 | serio_add_port(event->object); |
305 | break; | 316 | break; |
306 | 317 | ||
307 | case SERIO_RECONNECT: | 318 | case SERIO_RECONNECT_PORT: |
308 | serio_reconnect_port(event->object); | 319 | serio_reconnect_port(event->object); |
309 | break; | 320 | break; |
310 | 321 | ||
311 | case SERIO_RESCAN: | 322 | case SERIO_RESCAN_PORT: |
312 | serio_disconnect_port(event->object); | 323 | serio_disconnect_port(event->object); |
313 | serio_find_driver(event->object); | 324 | serio_find_driver(event->object); |
314 | break; | 325 | break; |
315 | 326 | ||
316 | case SERIO_REGISTER_DRIVER: | 327 | case SERIO_ATTACH_DRIVER: |
317 | serio_add_driver(event->object); | 328 | serio_attach_driver(event->object); |
318 | break; | 329 | break; |
319 | 330 | ||
320 | default: | 331 | default: |
@@ -666,12 +677,12 @@ static void serio_disconnect_port(struct serio *serio) | |||
666 | 677 | ||
667 | void serio_rescan(struct serio *serio) | 678 | void serio_rescan(struct serio *serio) |
668 | { | 679 | { |
669 | serio_queue_event(serio, NULL, SERIO_RESCAN); | 680 | serio_queue_event(serio, NULL, SERIO_RESCAN_PORT); |
670 | } | 681 | } |
671 | 682 | ||
672 | void serio_reconnect(struct serio *serio) | 683 | void serio_reconnect(struct serio *serio) |
673 | { | 684 | { |
674 | serio_queue_event(serio, NULL, SERIO_RECONNECT); | 685 | serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT); |
675 | } | 686 | } |
676 | 687 | ||
677 | /* | 688 | /* |
@@ -766,22 +777,52 @@ static int serio_driver_remove(struct device *dev) | |||
766 | return 0; | 777 | return 0; |
767 | } | 778 | } |
768 | 779 | ||
769 | static void serio_add_driver(struct serio_driver *drv) | 780 | static void serio_attach_driver(struct serio_driver *drv) |
770 | { | 781 | { |
771 | int error; | 782 | int error; |
772 | 783 | ||
773 | error = driver_register(&drv->driver); | 784 | error = driver_attach(&drv->driver); |
774 | if (error) | 785 | if (error) |
775 | printk(KERN_ERR | 786 | printk(KERN_WARNING |
776 | "serio: driver_register() failed for %s, error: %d\n", | 787 | "serio: driver_attach() failed for %s with error %d\n", |
777 | drv->driver.name, error); | 788 | drv->driver.name, error); |
778 | } | 789 | } |
779 | 790 | ||
780 | void __serio_register_driver(struct serio_driver *drv, struct module *owner) | 791 | int serio_register_driver(struct serio_driver *drv) |
781 | { | 792 | { |
793 | int manual_bind = drv->manual_bind; | ||
794 | int error; | ||
795 | |||
782 | drv->driver.bus = &serio_bus; | 796 | drv->driver.bus = &serio_bus; |
783 | 797 | ||
784 | serio_queue_event(drv, owner, SERIO_REGISTER_DRIVER); | 798 | /* |
799 | * Temporarily disable automatic binding because probing | ||
800 | * takes long time and we are better off doing it in kseriod | ||
801 | */ | ||
802 | drv->manual_bind = 1; | ||
803 | |||
804 | error = driver_register(&drv->driver); | ||
805 | if (error) { | ||
806 | printk(KERN_ERR | ||
807 | "serio: driver_register() failed for %s, error: %d\n", | ||
808 | drv->driver.name, error); | ||
809 | return error; | ||
810 | } | ||
811 | |||
812 | /* | ||
813 | * Restore original bind mode and let kseriod bind the | ||
814 | * driver to free ports | ||
815 | */ | ||
816 | if (!manual_bind) { | ||
817 | drv->manual_bind = 0; | ||
818 | error = serio_queue_event(drv, NULL, SERIO_ATTACH_DRIVER); | ||
819 | if (error) { | ||
820 | driver_unregister(&drv->driver); | ||
821 | return error; | ||
822 | } | ||
823 | } | ||
824 | |||
825 | return 0; | ||
785 | } | 826 | } |
786 | 827 | ||
787 | void serio_unregister_driver(struct serio_driver *drv) | 828 | void serio_unregister_driver(struct serio_driver *drv) |