diff options
author | Dmitry Torokhov <dtor_core@ameritech.net> | 2005-05-29 03:29:52 -0400 |
---|---|---|
committer | Dmitry Torokhov <dtor_core@ameritech.net> | 2005-05-29 03:29:52 -0400 |
commit | 8b1a198bf14d59b67e47dc7b133ec5ea443fb40d (patch) | |
tree | 11d80109ddc2f61de6a75a37941346100a67a0d1 /drivers/input/joystick/gamecon.c | |
parent | af246041277674854383cf91b8f0b01217b521e8 (diff) |
Input: fix open/close races in joystick drivers - add a semaphore
to the ones that register more than one input device.
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/joystick/gamecon.c')
-rw-r--r-- | drivers/input/joystick/gamecon.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index 462fc38f026e..95bbdd302aad 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c | |||
@@ -81,6 +81,7 @@ struct gc { | |||
81 | struct timer_list timer; | 81 | struct timer_list timer; |
82 | unsigned char pads[GC_MAX + 1]; | 82 | unsigned char pads[GC_MAX + 1]; |
83 | int used; | 83 | int used; |
84 | struct semaphore sem; | ||
84 | char phys[5][32]; | 85 | char phys[5][32]; |
85 | }; | 86 | }; |
86 | 87 | ||
@@ -503,22 +504,33 @@ static void gc_timer(unsigned long private) | |||
503 | static int gc_open(struct input_dev *dev) | 504 | static int gc_open(struct input_dev *dev) |
504 | { | 505 | { |
505 | struct gc *gc = dev->private; | 506 | struct gc *gc = dev->private; |
507 | int err; | ||
508 | |||
509 | err = down_interruptible(&gc->sem); | ||
510 | if (err) | ||
511 | return err; | ||
512 | |||
506 | if (!gc->used++) { | 513 | if (!gc->used++) { |
507 | parport_claim(gc->pd); | 514 | parport_claim(gc->pd); |
508 | parport_write_control(gc->pd->port, 0x04); | 515 | parport_write_control(gc->pd->port, 0x04); |
509 | mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME); | 516 | mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME); |
510 | } | 517 | } |
518 | |||
519 | up(&gc->sem); | ||
511 | return 0; | 520 | return 0; |
512 | } | 521 | } |
513 | 522 | ||
514 | static void gc_close(struct input_dev *dev) | 523 | static void gc_close(struct input_dev *dev) |
515 | { | 524 | { |
516 | struct gc *gc = dev->private; | 525 | struct gc *gc = dev->private; |
526 | |||
527 | down(&gc->sem); | ||
517 | if (!--gc->used) { | 528 | if (!--gc->used) { |
518 | del_timer(&gc->timer); | 529 | del_timer_sync(&gc->timer); |
519 | parport_write_control(gc->pd->port, 0x00); | 530 | parport_write_control(gc->pd->port, 0x00); |
520 | parport_release(gc->pd); | 531 | parport_release(gc->pd); |
521 | } | 532 | } |
533 | up(&gc->sem); | ||
522 | } | 534 | } |
523 | 535 | ||
524 | static struct gc __init *gc_probe(int *config, int nargs) | 536 | static struct gc __init *gc_probe(int *config, int nargs) |
@@ -542,11 +554,12 @@ static struct gc __init *gc_probe(int *config, int nargs) | |||
542 | return NULL; | 554 | return NULL; |
543 | } | 555 | } |
544 | 556 | ||
545 | if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL))) { | 557 | if (!(gc = kcalloc(1, sizeof(struct gc), GFP_KERNEL))) { |
546 | parport_put_port(pp); | 558 | parport_put_port(pp); |
547 | return NULL; | 559 | return NULL; |
548 | } | 560 | } |
549 | memset(gc, 0, sizeof(struct gc)); | 561 | |
562 | init_MUTEX(&gc->sem); | ||
550 | 563 | ||
551 | gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); | 564 | gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); |
552 | 565 | ||