diff options
author | Dmitry Torokhov <dtor_core@ameritech.net> | 2005-05-29 02:29:52 -0500 |
---|---|---|
committer | Dmitry Torokhov <dtor_core@ameritech.net> | 2005-05-29 02:29:52 -0500 |
commit | 8b1a198bf14d59b67e47dc7b133ec5ea443fb40d (patch) | |
tree | 11d80109ddc2f61de6a75a37941346100a67a0d1 /drivers/input/joystick/gamecon.c | |
parent | af246041277674854383cf91b8f0b01217b521e8 (diff) | |
download | linux-8b1a198bf14d59b67e47dc7b133ec5ea443fb40d.tar.bz2 |
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 { struct timer_list timer; unsigned char pads[GC_MAX + 1]; int used; + struct semaphore sem; char phys[5][32]; }; @@ -503,22 +504,33 @@ static void gc_timer(unsigned long private) static int gc_open(struct input_dev *dev) { struct gc *gc = dev->private; + int err; + + err = down_interruptible(&gc->sem); + if (err) + return err; + if (!gc->used++) { parport_claim(gc->pd); parport_write_control(gc->pd->port, 0x04); mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME); } + + up(&gc->sem); return 0; } static void gc_close(struct input_dev *dev) { struct gc *gc = dev->private; + + down(&gc->sem); if (!--gc->used) { - del_timer(&gc->timer); + del_timer_sync(&gc->timer); parport_write_control(gc->pd->port, 0x00); parport_release(gc->pd); } + up(&gc->sem); } static struct gc __init *gc_probe(int *config, int nargs) @@ -542,11 +554,12 @@ static struct gc __init *gc_probe(int *config, int nargs) return NULL; } - if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL))) { + if (!(gc = kcalloc(1, sizeof(struct gc), GFP_KERNEL))) { parport_put_port(pp); return NULL; } - memset(gc, 0, sizeof(struct gc)); + + init_MUTEX(&gc->sem); gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); |