diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2008-06-06 01:33:22 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2008-07-30 00:41:15 -0400 |
commit | 6902c0bead4ce266226fc0c5b3828b850bdc884a (patch) | |
tree | c3e8e280e56089dc4e9f4410128e17c8de0f8bee /drivers/input/gameport | |
parent | 6e86841d05f371b5b9b86ce76c02aaee83352298 (diff) |
Input: gameport - make gameport_register_driver() return errors
Perform actual driver registration right in gameport_register_driver()
instead of offloading it to kgameportd and return proper error code to
callers if driver registration fails.
Note that driver <-> port matching is still done by kgameportd.
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/gameport')
-rw-r--r-- | drivers/input/gameport/gameport.c | 88 |
1 files changed, 67 insertions, 21 deletions
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 078e4eed0894..2880eaae157a 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c | |||
@@ -231,6 +231,7 @@ static void gameport_find_driver(struct gameport *gameport) | |||
231 | enum gameport_event_type { | 231 | enum gameport_event_type { |
232 | GAMEPORT_REGISTER_PORT, | 232 | GAMEPORT_REGISTER_PORT, |
233 | GAMEPORT_REGISTER_DRIVER, | 233 | GAMEPORT_REGISTER_DRIVER, |
234 | GAMEPORT_ATTACH_DRIVER, | ||
234 | }; | 235 | }; |
235 | 236 | ||
236 | struct gameport_event { | 237 | struct gameport_event { |
@@ -245,11 +246,12 @@ static LIST_HEAD(gameport_event_list); | |||
245 | static DECLARE_WAIT_QUEUE_HEAD(gameport_wait); | 246 | static DECLARE_WAIT_QUEUE_HEAD(gameport_wait); |
246 | static struct task_struct *gameport_task; | 247 | static struct task_struct *gameport_task; |
247 | 248 | ||
248 | static void gameport_queue_event(void *object, struct module *owner, | 249 | static int gameport_queue_event(void *object, struct module *owner, |
249 | enum gameport_event_type event_type) | 250 | enum gameport_event_type event_type) |
250 | { | 251 | { |
251 | unsigned long flags; | 252 | unsigned long flags; |
252 | struct gameport_event *event; | 253 | struct gameport_event *event; |
254 | int retval = 0; | ||
253 | 255 | ||
254 | spin_lock_irqsave(&gameport_event_lock, flags); | 256 | spin_lock_irqsave(&gameport_event_lock, flags); |
255 | 257 | ||
@@ -268,24 +270,34 @@ static void gameport_queue_event(void *object, struct module *owner, | |||
268 | } | 270 | } |
269 | } | 271 | } |
270 | 272 | ||
271 | if ((event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC))) { | 273 | event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC); |
272 | if (!try_module_get(owner)) { | 274 | if (!event) { |
273 | printk(KERN_WARNING "gameport: Can't get module reference, dropping event %d\n", event_type); | 275 | printk(KERN_ERR |
274 | kfree(event); | 276 | "gameport: Not enough memory to queue event %d\n", |
275 | goto out; | 277 | event_type); |
276 | } | 278 | retval = -ENOMEM; |
277 | 279 | goto out; | |
278 | event->type = event_type; | 280 | } |
279 | event->object = object; | ||
280 | event->owner = owner; | ||
281 | 281 | ||
282 | list_add_tail(&event->node, &gameport_event_list); | 282 | if (!try_module_get(owner)) { |
283 | wake_up(&gameport_wait); | 283 | printk(KERN_WARNING |
284 | } else { | 284 | "gameport: Can't get module reference, dropping event %d\n", |
285 | printk(KERN_ERR "gameport: Not enough memory to queue event %d\n", event_type); | 285 | event_type); |
286 | kfree(event); | ||
287 | retval = -EINVAL; | ||
288 | goto out; | ||
286 | } | 289 | } |
290 | |||
291 | event->type = event_type; | ||
292 | event->object = object; | ||
293 | event->owner = owner; | ||
294 | |||
295 | list_add_tail(&event->node, &gameport_event_list); | ||
296 | wake_up(&gameport_wait); | ||
297 | |||
287 | out: | 298 | out: |
288 | spin_unlock_irqrestore(&gameport_event_lock, flags); | 299 | spin_unlock_irqrestore(&gameport_event_lock, flags); |
300 | return retval; | ||
289 | } | 301 | } |
290 | 302 | ||
291 | static void gameport_free_event(struct gameport_event *event) | 303 | static void gameport_free_event(struct gameport_event *event) |
@@ -378,9 +390,10 @@ static void gameport_handle_event(void) | |||
378 | } | 390 | } |
379 | 391 | ||
380 | /* | 392 | /* |
381 | * Remove all events that have been submitted for a given gameport port. | 393 | * Remove all events that have been submitted for a given object, |
394 | * be it a gameport port or a driver. | ||
382 | */ | 395 | */ |
383 | static void gameport_remove_pending_events(struct gameport *gameport) | 396 | static void gameport_remove_pending_events(void *object) |
384 | { | 397 | { |
385 | struct list_head *node, *next; | 398 | struct list_head *node, *next; |
386 | struct gameport_event *event; | 399 | struct gameport_event *event; |
@@ -390,7 +403,7 @@ static void gameport_remove_pending_events(struct gameport *gameport) | |||
390 | 403 | ||
391 | list_for_each_safe(node, next, &gameport_event_list) { | 404 | list_for_each_safe(node, next, &gameport_event_list) { |
392 | event = list_entry(node, struct gameport_event, node); | 405 | event = list_entry(node, struct gameport_event, node); |
393 | if (event->object == gameport) { | 406 | if (event->object == object) { |
394 | list_del_init(node); | 407 | list_del_init(node); |
395 | gameport_free_event(event); | 408 | gameport_free_event(event); |
396 | } | 409 | } |
@@ -705,10 +718,40 @@ static void gameport_add_driver(struct gameport_driver *drv) | |||
705 | drv->driver.name, error); | 718 | drv->driver.name, error); |
706 | } | 719 | } |
707 | 720 | ||
708 | void __gameport_register_driver(struct gameport_driver *drv, struct module *owner) | 721 | int __gameport_register_driver(struct gameport_driver *drv, struct module *owner, |
722 | const char *mod_name) | ||
709 | { | 723 | { |
724 | int error; | ||
725 | |||
710 | drv->driver.bus = &gameport_bus; | 726 | drv->driver.bus = &gameport_bus; |
711 | gameport_queue_event(drv, owner, GAMEPORT_REGISTER_DRIVER); | 727 | drv->driver.owner = owner; |
728 | drv->driver.mod_name = mod_name; | ||
729 | |||
730 | /* | ||
731 | * Temporarily disable automatic binding because probing | ||
732 | * takes long time and we are better off doing it in kgameportd | ||
733 | */ | ||
734 | drv->ignore = 1; | ||
735 | |||
736 | error = driver_register(&drv->driver); | ||
737 | if (error) { | ||
738 | printk(KERN_ERR | ||
739 | "gameport: driver_register() failed for %s, error: %d\n", | ||
740 | drv->driver.name, error); | ||
741 | return error; | ||
742 | } | ||
743 | |||
744 | /* | ||
745 | * Reset ignore flag and let kgameportd bind the driver to free ports | ||
746 | */ | ||
747 | drv->ignore = 0; | ||
748 | error = gameport_queue_event(drv, NULL, GAMEPORT_ATTACH_DRIVER); | ||
749 | if (error) { | ||
750 | driver_unregister(&drv->driver); | ||
751 | return error; | ||
752 | } | ||
753 | |||
754 | return 0; | ||
712 | } | 755 | } |
713 | 756 | ||
714 | void gameport_unregister_driver(struct gameport_driver *drv) | 757 | void gameport_unregister_driver(struct gameport_driver *drv) |
@@ -716,7 +759,9 @@ void gameport_unregister_driver(struct gameport_driver *drv) | |||
716 | struct gameport *gameport; | 759 | struct gameport *gameport; |
717 | 760 | ||
718 | mutex_lock(&gameport_mutex); | 761 | mutex_lock(&gameport_mutex); |
762 | |||
719 | drv->ignore = 1; /* so gameport_find_driver ignores it */ | 763 | drv->ignore = 1; /* so gameport_find_driver ignores it */ |
764 | gameport_remove_pending_events(drv); | ||
720 | 765 | ||
721 | start_over: | 766 | start_over: |
722 | list_for_each_entry(gameport, &gameport_list, node) { | 767 | list_for_each_entry(gameport, &gameport_list, node) { |
@@ -729,6 +774,7 @@ start_over: | |||
729 | } | 774 | } |
730 | 775 | ||
731 | driver_unregister(&drv->driver); | 776 | driver_unregister(&drv->driver); |
777 | |||
732 | mutex_unlock(&gameport_mutex); | 778 | mutex_unlock(&gameport_mutex); |
733 | } | 779 | } |
734 | 780 | ||