X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Finput%2Fjoystick%2Fturbografx.c;h=5570fd5487c730bc973b29736033942c00c1c560;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=0e620cb882cdbf0e20b799f5b44d2a73a532ac52;hpb=6a77f38946aaee1cd85eeec6cf4229b204c15071;p=linux-2.6.git diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index 0e620cb88..5570fd548 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -37,24 +37,27 @@ #include #include #include +#include MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("TurboGraFX parallel port interface driver"); MODULE_LICENSE("GPL"); -static int tgfx[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; -static int tgfx_nargs __initdata = 0; -module_param_array_named(map, tgfx, int, &tgfx_nargs, 0); -MODULE_PARM_DESC(map, "Describes first set of devices (,,,.."); +#define TGFX_MAX_PORTS 3 +#define TGFX_MAX_DEVICES 7 -static int tgfx_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; -static int tgfx_nargs_2 __initdata = 0; -module_param_array_named(map2, tgfx_2, int, &tgfx_nargs_2, 0); -MODULE_PARM_DESC(map2, "Describes second set of devices"); +struct tgfx_config { + int args[TGFX_MAX_DEVICES + 1]; + int nargs; +}; + +static struct tgfx_config tgfx[TGFX_MAX_PORTS] __initdata; -static int tgfx_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; -static int tgfx_nargs_3 __initdata = 0; -module_param_array_named(map3, tgfx_3, int, &tgfx_nargs_3, 0); +module_param_array_named(map, tgfx[0].args, int, &tgfx[0].nargs, 0); +MODULE_PARM_DESC(map, "Describes first set of devices (,,,.."); +module_param_array_named(map2, tgfx[1].args, int, &tgfx[1].nargs, 0); +MODULE_PARM_DESC(map2, "Describes second set of devices"); +module_param_array_named(map3, tgfx[2].args, int, &tgfx[2].nargs, 0); MODULE_PARM_DESC(map3, "Describes third set of devices"); __obsolete_setup("tgfx="); @@ -75,16 +78,17 @@ __obsolete_setup("tgfx_3="); #define TGFX_TOP2 0x08 static int tgfx_buttons[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2 }; -static char *tgfx_name = "TurboGraFX Multisystem joystick"; -struct tgfx { +static struct tgfx { struct pardevice *pd; struct timer_list timer; - struct input_dev dev[7]; - char phys[7][32]; + struct input_dev *dev[TGFX_MAX_DEVICES]; + char name[TGFX_MAX_DEVICES][64]; + char phys[TGFX_MAX_DEVICES][32]; int sticks; int used; -} *tgfx_base[3]; + struct mutex sem; +} *tgfx_base[TGFX_MAX_PORTS]; /* * tgfx_timer() reads and analyzes TurboGraFX joystick data. @@ -99,7 +103,7 @@ static void tgfx_timer(unsigned long private) for (i = 0; i < 7; i++) if (tgfx->sticks & (1 << i)) { - dev = tgfx->dev + i; + dev = tgfx->dev[i]; parport_write_data(tgfx->pd->port, ~(1 << i)); data1 = parport_read_status(tgfx->pd->port) ^ 0x7f; @@ -122,136 +126,201 @@ static void tgfx_timer(unsigned long private) static int tgfx_open(struct input_dev *dev) { - struct tgfx *tgfx = dev->private; - if (!tgfx->used++) { + struct tgfx *tgfx = dev->private; + int err; + + err = mutex_lock_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); + mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME); } - return 0; + + mutex_unlock(&tgfx->sem); + return 0; } static void tgfx_close(struct input_dev *dev) { - struct tgfx *tgfx = dev->private; - if (!--tgfx->used) { - del_timer(&tgfx->timer); + struct tgfx *tgfx = dev->private; + + mutex_lock(&tgfx->sem); + if (!--tgfx->used) { + del_timer_sync(&tgfx->timer); parport_write_control(tgfx->pd->port, 0x00); - parport_release(tgfx->pd); + parport_release(tgfx->pd); } + mutex_unlock(&tgfx->sem); } + + /* * tgfx_probe() probes for tg gamepads. */ -static struct tgfx __init *tgfx_probe(int *config, int nargs) +static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs) { struct tgfx *tgfx; + struct input_dev *input_dev; struct parport *pp; + struct pardevice *pd; int i, j; + int err; - if (config[0] < 0) - return NULL; - - if (nargs < 2) { - printk(KERN_ERR "turbografx.c: at least one joystick must be specified\n"); - return NULL; - } - - pp = parport_find_number(config[0]); - + pp = parport_find_number(parport); if (!pp) { printk(KERN_ERR "turbografx.c: no such parport\n"); - return NULL; + err = -EINVAL; + goto err_out; } - if (!(tgfx = kmalloc(sizeof(struct tgfx), GFP_KERNEL))) { - parport_put_port(pp); - return NULL; + pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); + if (!pd) { + printk(KERN_ERR "turbografx.c: parport busy already - lp.o loaded?\n"); + err = -EBUSY; + goto err_put_pp; } - memset(tgfx, 0, sizeof(struct tgfx)); - tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); - - parport_put_port(pp); - - if (!tgfx->pd) { - printk(KERN_ERR "turbografx.c: parport busy already - lp.o loaded?\n"); - kfree(tgfx); - return NULL; + tgfx = kzalloc(sizeof(struct tgfx), GFP_KERNEL); + if (!tgfx) { + printk(KERN_ERR "turbografx.c: Not enough memory\n"); + err = -ENOMEM; + goto err_unreg_pardev; } + mutex_init(&tgfx->sem); + tgfx->pd = pd; init_timer(&tgfx->timer); tgfx->timer.data = (long) tgfx; tgfx->timer.function = tgfx_timer; - tgfx->sticks = 0; + for (i = 0; i < n_devs; i++) { + if (n_buttons[i] < 1) + continue; - for (i = 0; i < nargs - 1; i++) - if (config[i+1] > 0 && config[i+1] < 6) { + if (n_buttons[i] > 6) { + printk(KERN_ERR "turbografx.c: Invalid number of buttons %d\n", n_buttons[i]); + err = -EINVAL; + goto err_unreg_devs; + } - tgfx->sticks |= (1 << i); + tgfx->dev[i] = input_dev = input_allocate_device(); + if (!input_dev) { + printk(KERN_ERR "turbografx.c: Not enough memory for input device\n"); + err = -ENOMEM; + goto err_unreg_devs; + } - tgfx->dev[i].private = tgfx; - tgfx->dev[i].open = tgfx_open; - tgfx->dev[i].close = tgfx_close; + tgfx->sticks |= (1 << i); + snprintf(tgfx->name[i], sizeof(tgfx->name[i]), + "TurboGraFX %d-button Multisystem joystick", n_buttons[i]); + snprintf(tgfx->phys[i], sizeof(tgfx->phys[i]), + "%s/input%d", tgfx->pd->port->name, i); + + input_dev->name = tgfx->name[i]; + input_dev->phys = tgfx->phys[i]; + input_dev->id.bustype = BUS_PARPORT; + input_dev->id.vendor = 0x0003; + input_dev->id.product = n_buttons[i]; + input_dev->id.version = 0x0100; + + input_dev->private = tgfx; + input_dev->open = tgfx_open; + input_dev->close = tgfx_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_set_abs_params(input_dev, ABS_X, -1, 1, 0, 0); + input_set_abs_params(input_dev, ABS_Y, -1, 1, 0, 0); + + for (j = 0; j < n_buttons[i]; j++) + set_bit(tgfx_buttons[j], input_dev->keybit); + + err = input_register_device(tgfx->dev[i]); + if (err) + goto err_free_dev; + } - sprintf(tgfx->phys[i], "%s/input0", tgfx->pd->port->name); + if (!tgfx->sticks) { + printk(KERN_ERR "turbografx.c: No valid devices specified\n"); + err = -EINVAL; + goto err_free_tgfx; + } - tgfx->dev[i].name = tgfx_name; - tgfx->dev[i].phys = tgfx->phys[i]; - tgfx->dev[i].id.bustype = BUS_PARPORT; - tgfx->dev[i].id.vendor = 0x0003; - tgfx->dev[i].id.product = config[i+1]; - tgfx->dev[i].id.version = 0x0100; + return tgfx; - tgfx->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - tgfx->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + err_free_dev: + input_free_device(tgfx->dev[i]); + err_unreg_devs: + while (--i >= 0) + if (tgfx->dev[i]) + input_unregister_device(tgfx->dev[i]); + err_free_tgfx: + kfree(tgfx); + err_unreg_pardev: + parport_unregister_device(pd); + err_put_pp: + parport_put_port(pp); + err_out: + return ERR_PTR(err); +} - for (j = 0; j < config[i+1]; j++) - set_bit(tgfx_buttons[j], tgfx->dev[i].keybit); +static void tgfx_remove(struct tgfx *tgfx) +{ + int i; - tgfx->dev[i].absmin[ABS_X] = -1; tgfx->dev[i].absmax[ABS_X] = 1; - tgfx->dev[i].absmin[ABS_Y] = -1; tgfx->dev[i].absmax[ABS_Y] = 1; + for (i = 0; i < TGFX_MAX_DEVICES; i++) + if (tgfx->dev[i]) + input_unregister_device(tgfx->dev[i]); + parport_unregister_device(tgfx->pd); + kfree(tgfx); +} - input_register_device(tgfx->dev + i); - printk(KERN_INFO "input: %d-button Multisystem joystick on %s\n", - config[i+1], tgfx->pd->port->name); +static int __init tgfx_init(void) +{ + int i; + int have_dev = 0; + int err = 0; + + for (i = 0; i < TGFX_MAX_PORTS; i++) { + if (tgfx[i].nargs == 0 || tgfx[i].args[0] < 0) + continue; + + if (tgfx[i].nargs < 2) { + printk(KERN_ERR "turbografx.c: at least one joystick must be specified\n"); + err = -EINVAL; + break; } - if (!tgfx->sticks) { - parport_unregister_device(tgfx->pd); - kfree(tgfx); - return NULL; - } - - return tgfx; -} + tgfx_base[i] = tgfx_probe(tgfx[i].args[0], tgfx[i].args + 1, tgfx[i].nargs - 1); + if (IS_ERR(tgfx_base[i])) { + err = PTR_ERR(tgfx_base[i]); + break; + } -int __init tgfx_init(void) -{ - tgfx_base[0] = tgfx_probe(tgfx, tgfx_nargs); - tgfx_base[1] = tgfx_probe(tgfx_2, tgfx_nargs_2); - tgfx_base[2] = tgfx_probe(tgfx_3, tgfx_nargs_3); + have_dev = 1; + } - if (tgfx_base[0] || tgfx_base[1] || tgfx_base[2]) - return 0; + if (err) { + while (--i >= 0) + if (tgfx_base[i]) + tgfx_remove(tgfx_base[i]); + return err; + } - return -ENODEV; + return have_dev ? 0 : -ENODEV; } -void __exit tgfx_exit(void) +static void __exit tgfx_exit(void) { - int i, j; + int i; - for (i = 0; i < 3; i++) - if (tgfx_base[i]) { - for (j = 0; j < 7; j++) - if (tgfx_base[i]->sticks & (1 << j)) - input_unregister_device(tgfx_base[i]->dev + j); - parport_unregister_device(tgfx_base[i]->pd); - } + for (i = 0; i < TGFX_MAX_PORTS; i++) + if (tgfx_base[i]) + tgfx_remove(tgfx_base[i]); } module_init(tgfx_init);