aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Torokhov <dtor_core@ameritech.net>2005-05-29 02:29:52 -0500
committerDmitry Torokhov <dtor_core@ameritech.net>2005-05-29 02:29:52 -0500
commit8b1a198bf14d59b67e47dc7b133ec5ea443fb40d (patch)
tree11d80109ddc2f61de6a75a37941346100a67a0d1
parentaf246041277674854383cf91b8f0b01217b521e8 (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>
-rw-r--r--drivers/input/joystick/amijoy.c29
-rw-r--r--drivers/input/joystick/db9.c17
-rw-r--r--drivers/input/joystick/gamecon.c19
-rw-r--r--drivers/input/joystick/turbografx.c19
4 files changed, 61 insertions, 23 deletions
diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
index cf36ca9b92f..033456bb9fe 100644
--- a/drivers/input/joystick/amijoy.c
+++ b/drivers/input/joystick/amijoy.c
@@ -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);
}
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index cfdd3acf06a..fbd3eed07f9 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -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;
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index 462fc38f026..95bbdd302aa 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);
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index 316c4bebfed..28100d461cb 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -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);