Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+16 −13
Original line number Diff line number Diff line
@@ -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);
		}
+13 −4
Original line number Diff line number Diff line
@@ -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;
+16 −3
Original line number Diff line number Diff line
@@ -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);

+16 −3
Original line number Diff line number Diff line
@@ -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);