Commit 8b1a198b authored by Dmitry Torokhov's avatar Dmitry Torokhov

Input: fix open/close races in joystick drivers - add a semaphore

       to the ones that register more than one input device.
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent af246041
...@@ -51,7 +51,8 @@ MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is ...@@ -51,7 +51,8 @@ MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is
__obsolete_setup("amijoy="); __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 struct input_dev amijoy_dev[2];
static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" }; 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) ...@@ -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) static int amijoy_open(struct input_dev *dev)
{ {
int *used = dev->private; int err;
if ((*used)++) err = down_interruptible(&amijoy_sem);
return 0; if (err)
return err;
if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) { if (!amijoy_used && request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
(*used)--;
printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB); 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) static void amijoy_close(struct input_dev *dev)
{ {
int *used = dev->private; down(&amijoysem);
if (!--amijoy_used)
if (!--(*used))
free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt); free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
up(&amijoy_sem);
} }
static int __init amijoy_init(void) static int __init amijoy_init(void)
...@@ -138,8 +143,6 @@ 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.product = 0x0003;
amijoy_dev[i].id.version = 0x0100; amijoy_dev[i].id.version = 0x0100;
amijoy_dev[i].private = amijoy_used + i;
input_register_device(amijoy_dev + i); input_register_device(amijoy_dev + i);
printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i); printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i);
} }
......
...@@ -98,6 +98,7 @@ struct db9 { ...@@ -98,6 +98,7 @@ struct db9 {
struct pardevice *pd; struct pardevice *pd;
int mode; int mode;
int used; int used;
struct semaphore sem;
char phys[2][32]; char phys[2][32];
}; };
...@@ -503,6 +504,11 @@ static int db9_open(struct input_dev *dev) ...@@ -503,6 +504,11 @@ static int db9_open(struct input_dev *dev)
{ {
struct db9 *db9 = dev->private; struct db9 *db9 = dev->private;
struct parport *port = db9->pd->port; struct parport *port = db9->pd->port;
int err;
err = down_interruptible(&db9->sem);
if (err)
return err;
if (!db9->used++) { if (!db9->used++) {
parport_claim(db9->pd); parport_claim(db9->pd);
...@@ -514,6 +520,7 @@ static int db9_open(struct input_dev *dev) ...@@ -514,6 +520,7 @@ static int db9_open(struct input_dev *dev)
mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME); mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
} }
up(&db9->sem);
return 0; return 0;
} }
...@@ -522,12 +529,14 @@ static void db9_close(struct input_dev *dev) ...@@ -522,12 +529,14 @@ static void db9_close(struct input_dev *dev)
struct db9 *db9 = dev->private; struct db9 *db9 = dev->private;
struct parport *port = db9->pd->port; struct parport *port = db9->pd->port;
down(&db9->sem);
if (!--db9->used) { if (!--db9->used) {
del_timer(&db9->timer); del_timer_sync(&db9->timer);
parport_write_control(port, 0x00); parport_write_control(port, 0x00);
parport_data_forward(port); parport_data_forward(port);
parport_release(db9->pd); parport_release(db9->pd);
} }
up(&db9->sem);
} }
static struct db9 __init *db9_probe(int *config, int nargs) static struct db9 __init *db9_probe(int *config, int nargs)
...@@ -563,12 +572,12 @@ 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); parport_put_port(pp);
return NULL; return NULL;
} }
memset(db9, 0, sizeof(struct db9));
init_MUTEX(&db9->sem);
db9->mode = config[1]; db9->mode = config[1];
init_timer(&db9->timer); init_timer(&db9->timer);
db9->timer.data = (long) db9; db9->timer.data = (long) db9;
......
...@@ -81,6 +81,7 @@ struct gc { ...@@ -81,6 +81,7 @@ struct gc {
struct timer_list timer; struct timer_list timer;
unsigned char pads[GC_MAX + 1]; unsigned char pads[GC_MAX + 1];
int used; int used;
struct semaphore sem;
char phys[5][32]; char phys[5][32];
}; };
...@@ -503,22 +504,33 @@ static void gc_timer(unsigned long private) ...@@ -503,22 +504,33 @@ static void gc_timer(unsigned long private)
static int gc_open(struct input_dev *dev) static int gc_open(struct input_dev *dev)
{ {
struct gc *gc = dev->private; struct gc *gc = dev->private;
int err;
err = down_interruptible(&gc->sem);
if (err)
return err;
if (!gc->used++) { if (!gc->used++) {
parport_claim(gc->pd); parport_claim(gc->pd);
parport_write_control(gc->pd->port, 0x04); parport_write_control(gc->pd->port, 0x04);
mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME); mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
} }
up(&gc->sem);
return 0; return 0;
} }
static void gc_close(struct input_dev *dev) static void gc_close(struct input_dev *dev)
{ {
struct gc *gc = dev->private; struct gc *gc = dev->private;
down(&gc->sem);
if (!--gc->used) { if (!--gc->used) {
del_timer(&gc->timer); del_timer_sync(&gc->timer);
parport_write_control(gc->pd->port, 0x00); parport_write_control(gc->pd->port, 0x00);
parport_release(gc->pd); parport_release(gc->pd);
} }
up(&gc->sem);
} }
static struct gc __init *gc_probe(int *config, int nargs) 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,11 +554,12 @@ static struct gc __init *gc_probe(int *config, int nargs)
return NULL; return NULL;
} }
if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL))) { if (!(gc = kcalloc(1, sizeof(struct gc), GFP_KERNEL))) {
parport_put_port(pp); parport_put_port(pp);
return NULL; 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); gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
......
...@@ -84,6 +84,7 @@ static struct tgfx { ...@@ -84,6 +84,7 @@ static struct tgfx {
char phys[7][32]; char phys[7][32];
int sticks; int sticks;
int used; int used;
struct semaphore sem;
} *tgfx_base[3]; } *tgfx_base[3];
/* /*
...@@ -123,22 +124,33 @@ static void tgfx_timer(unsigned long private) ...@@ -123,22 +124,33 @@ static void tgfx_timer(unsigned long private)
static int tgfx_open(struct input_dev *dev) static int tgfx_open(struct input_dev *dev)
{ {
struct tgfx *tgfx = dev->private; struct tgfx *tgfx = dev->private;
int err;
err = down_interruptible(&tgfx->sem);
if (err)
return err;
if (!tgfx->used++) { if (!tgfx->used++) {
parport_claim(tgfx->pd); parport_claim(tgfx->pd);
parport_write_control(tgfx->pd->port, 0x04); parport_write_control(tgfx->pd->port, 0x04);
mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME); mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
} }
up(&tgfx->sem);
return 0; return 0;
} }
static void tgfx_close(struct input_dev *dev) static void tgfx_close(struct input_dev *dev)
{ {
struct tgfx *tgfx = dev->private; struct tgfx *tgfx = dev->private;
down(&tgfx->sem);
if (!--tgfx->used) { if (!--tgfx->used) {
del_timer(&tgfx->timer); del_timer_sync(&tgfx->timer);
parport_write_control(tgfx->pd->port, 0x00); parport_write_control(tgfx->pd->port, 0x00);
parport_release(tgfx->pd); parport_release(tgfx->pd);
} }
up(&tgfx->sem);
} }
/* /*
...@@ -166,11 +178,12 @@ static struct tgfx __init *tgfx_probe(int *config, int nargs) ...@@ -166,11 +178,12 @@ static struct tgfx __init *tgfx_probe(int *config, int nargs)
return NULL; return NULL;
} }
if (!(tgfx = kmalloc(sizeof(struct tgfx), GFP_KERNEL))) { if (!(tgfx = kcalloc(1, sizeof(struct tgfx), GFP_KERNEL))) {
parport_put_port(pp); parport_put_port(pp);
return NULL; 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); tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment