mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-06 22:42:10 +00:00
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>
This commit is contained in:
parent
af24604127
commit
8b1a198bf1
4 changed files with 61 additions and 23 deletions
|
@ -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)
|
||||||
|
|
||||||
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)
|
||||||
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 {
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
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)
|
||||||
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)
|
||||||
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 {
|
||||||
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)
|
||||||
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)
|
||||||
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);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue