Input: fix open/close races in joystick drivers - add a semaphore
authorDmitry Torokhov <dtor_core@ameritech.net>
Sun, 29 May 2005 07:29:52 +0000 (02:29 -0500)
committerDmitry Torokhov <dtor_core@ameritech.net>
Sun, 29 May 2005 07:29:52 +0000 (02:29 -0500)
       to the ones that register more than one input device.

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
drivers/input/joystick/amijoy.c
drivers/input/joystick/db9.c
drivers/input/joystick/gamecon.c
drivers/input/joystick/turbografx.c

index cf36ca9b92f3f3e703edb5b93c3e2d9ee76033e9..033456bb9fe0d70faa00ea0fa0fced045d9b6a02 100644 (file)
@@ -51,7 +51,8 @@ MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is
 
 __obsolete_setup("amijoy=");
 
-static int amijoy_used[2] = { 0, 0 };
+static int amijoy_used;
+static DECLARE_MUTEX(amijoy_sem);
 static struct input_dev amijoy_dev[2];
 static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" };
 
@@ -84,26 +85,30 @@ static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp)
 
 static int amijoy_open(struct input_dev *dev)
 {
-       int *used = dev->private;
+       int err;
 
-       if ((*used)++)
-               return 0;
+       err = down_interruptible(&amijoy_sem);
+       if (err)
+               return err;
 
-       if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
-               (*used)--;
+       if (!amijoy_used && request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
                printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
-               return -EBUSY;
+               err = -EBUSY;
+               goto out;
        }
 
-       return 0;
+       amijoy_used++;
+out:
+       up(&amijoy_sem);
+       return err;
 }
 
 static void amijoy_close(struct input_dev *dev)
 {
-       int *used = dev->private;
-
-       if (!--(*used))
+       down(&amijoysem);
+       if (!--amijoy_used)
                free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
+       up(&amijoy_sem);
 }
 
 static int __init amijoy_init(void)
@@ -138,8 +143,6 @@ static int __init amijoy_init(void)
                        amijoy_dev[i].id.product = 0x0003;
                        amijoy_dev[i].id.version = 0x0100;
 
-                       amijoy_dev[i].private = amijoy_used + i;
-
                        input_register_device(amijoy_dev + i);
                        printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i);
                }
index cfdd3acf06a1cbb4a2584ca697ff6ca518a19643..fbd3eed07f90403806e1bce3212781a638e35241 100644 (file)
@@ -87,7 +87,7 @@ __obsolete_setup("db9_3=");
 #define DB9_NORMAL             0x0a
 #define DB9_NOSELECT           0x08
 
-#define DB9_MAX_DEVICES 2
+#define DB9_MAX_DEVICES                2
 
 #define DB9_GENESIS6_DELAY     14
 #define DB9_REFRESH_TIME       HZ/100
@@ -98,6 +98,7 @@ struct db9 {
        struct pardevice *pd;
        int mode;
        int used;
+       struct semaphore sem;
        char phys[2][32];
 };
 
@@ -503,6 +504,11 @@ static int db9_open(struct input_dev *dev)
 {
        struct db9 *db9 = dev->private;
        struct parport *port = db9->pd->port;
+       int err;
+
+       err = down_interruptible(&db9->sem);
+       if (err)
+               return err;
 
        if (!db9->used++) {
                parport_claim(db9->pd);
@@ -514,6 +520,7 @@ static int db9_open(struct input_dev *dev)
                mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
        }
 
+       up(&db9->sem);
        return 0;
 }
 
@@ -522,12 +529,14 @@ static void db9_close(struct input_dev *dev)
        struct db9 *db9 = dev->private;
        struct parport *port = db9->pd->port;
 
+       down(&db9->sem);
        if (!--db9->used) {
-               del_timer(&db9->timer);
+               del_timer_sync(&db9->timer);
                parport_write_control(port, 0x00);
                parport_data_forward(port);
                parport_release(db9->pd);
        }
+       up(&db9->sem);
 }
 
 static struct db9 __init *db9_probe(int *config, int nargs)
@@ -563,12 +572,12 @@ static struct db9 __init *db9_probe(int *config, int nargs)
                }
        }
 
-       if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL))) {
+       if (!(db9 = kcalloc(1, sizeof(struct db9), GFP_KERNEL))) {
                parport_put_port(pp);
                return NULL;
        }
-       memset(db9, 0, sizeof(struct db9));
 
+       init_MUTEX(&db9->sem);
        db9->mode = config[1];
        init_timer(&db9->timer);
        db9->timer.data = (long) db9;
index 462fc38f026e287d08daf5b8054d4d6cc6cb4893..95bbdd302aad8639bacc4817e6f49b472e749211 100644 (file)
@@ -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);
 
index 316c4bebfed27a5b67237adee3ce3fefbe158efd..28100d461cb751c1c1d8b34f4fb5001b970e1b2c 100644 (file)
@@ -84,6 +84,7 @@ static struct tgfx {
        char phys[7][32];
        int sticks;
        int used;
+       struct semaphore sem;
 } *tgfx_base[3];
 
 /*
@@ -123,22 +124,33 @@ static void tgfx_timer(unsigned long private)
 static int tgfx_open(struct input_dev *dev)
 {
        struct tgfx *tgfx = dev->private;
+       int err;
+
+       err = down_interruptible(&tgfx->sem);
+       if (err)
+               return err;
+
        if (!tgfx->used++) {
                parport_claim(tgfx->pd);
                parport_write_control(tgfx->pd->port, 0x04);
                mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
        }
+
+       up(&tgfx->sem);
        return 0;
 }
 
 static void tgfx_close(struct input_dev *dev)
 {
        struct tgfx *tgfx = dev->private;
+
+       down(&tgfx->sem);
        if (!--tgfx->used) {
-               del_timer(&tgfx->timer);
+               del_timer_sync(&tgfx->timer);
                parport_write_control(tgfx->pd->port, 0x00);
                parport_release(tgfx->pd);
        }
+       up(&tgfx->sem);
 }
 
 /*
@@ -166,11 +178,12 @@ static struct tgfx __init *tgfx_probe(int *config, int nargs)
                return NULL;
        }
 
-       if (!(tgfx = kmalloc(sizeof(struct tgfx), GFP_KERNEL))) {
+       if (!(tgfx = kcalloc(1, sizeof(struct tgfx), GFP_KERNEL))) {
                parport_put_port(pp);
                return NULL;
        }
-       memset(tgfx, 0, sizeof(struct tgfx));
+
+       init_MUTEX(&tgfx->sem);
 
        tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);