diff options
Diffstat (limited to 'drivers/usb/joydev.c')
-rw-r--r-- | drivers/usb/joydev.c | 91 |
1 files changed, 48 insertions, 43 deletions
diff --git a/drivers/usb/joydev.c b/drivers/usb/joydev.c index 9b54300e2..585740db9 100644 --- a/drivers/usb/joydev.c +++ b/drivers/usb/joydev.c @@ -45,15 +45,18 @@ #include <linux/poll.h> #include <linux/init.h> -#define JOYDEV_MAJOR 15 +#define JOYDEV_MINOR_BASE 0 +#define JOYDEV_MINORS 32 #define JOYDEV_BUFFER_SIZE 64 struct joydev { - char name[32]; int used; - struct input_handle handle; + int open; int minor; + char name[32]; + struct input_handle handle; wait_queue_head_t wait; + devfs_handle_t devfs; struct joydev *next; struct joydev_list *list; struct js_corr corr[ABS_MAX]; @@ -76,11 +79,10 @@ struct joydev_list { struct joydev_list *next; }; -static unsigned long joydev_minors = 0; -static struct joydev *joydev_base[BITS_PER_LONG]; +static struct joydev *joydev_table[JOYDEV_MINORS]; MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); -MODULE_SUPPORTED_DEVICE("js"); +MODULE_SUPPORTED_DEVICE("input/js"); static int joydev_correct(int value, struct js_corr *corr) { @@ -164,9 +166,13 @@ static int joydev_release(struct inode * inode, struct file * file) while (*listptr && (*listptr != list)) listptr = &((*listptr)->next); *listptr = (*listptr)->next; + + if (!--list->joydev->open) + input_close_device(&list->joydev->handle); if (!--list->joydev->used) { - clear_bit(list->joydev->minor, &joydev_minors); + input_unregister_minor(list->joydev->devfs); + joydev_table[list->joydev->minor] = NULL; kfree(list->joydev); } @@ -179,28 +185,30 @@ static int joydev_release(struct inode * inode, struct file * file) static int joydev_open(struct inode *inode, struct file *file) { struct joydev_list *list; - int i = MINOR(inode->i_rdev); + int i = MINOR(inode->i_rdev) - JOYDEV_MINOR_BASE; - if (MAJOR(inode->i_rdev) != JOYSTICK_MAJOR) - return -EINVAL; - - if (i > BITS_PER_LONG || !test_bit(i, &joydev_minors)) + if (i > JOYDEV_MINORS || !joydev_table[i]) return -ENODEV; - if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL))) - return -ENOMEM; + MOD_INC_USE_COUNT; + if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL))) { + MOD_DEC_USE_COUNT; + return -ENOMEM; + } memset(list, 0, sizeof(struct joydev_list)); - list->joydev = joydev_base[i]; - list->next = joydev_base[i]->list; - joydev_base[i]->list = list; + list->joydev = joydev_table[i]; + list->next = joydev_table[i]->list; + joydev_table[i]->list = list; file->private_data = list; list->joydev->used++; - MOD_INC_USE_COUNT; + if (!list->joydev->open++) + input_open_device(&list->joydev->handle); + return 0; } @@ -370,30 +378,33 @@ static struct file_operations joydev_fops = { fasync: joydev_fasync, }; -static int joydev_connect(struct input_handler *handler, struct input_dev *dev) +static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev) { struct joydev *joydev; - int i, j; + int i, j, minor; if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_ABS, dev->evbit) && test_bit(ABS_X, dev->absbit) && test_bit(ABS_Y, dev->absbit) && (test_bit(BTN_TRIGGER, dev->keybit) || test_bit(BTN_A, dev->keybit) - || test_bit(BTN_1, dev->keybit)))) return -1; + || test_bit(BTN_1, dev->keybit)))) return NULL; - if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL))) - return -1; + for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++); + if (joydev_table[minor]) { + printk(KERN_ERR "joydev: no more free joydev devices\n"); + return NULL; + } + if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL))) + return NULL; memset(joydev, 0, sizeof(struct joydev)); init_waitqueue_head(&joydev->wait); - if (joydev_minors == -1) { - printk("Can't register new joystick - 32 devices already taken.\n"); - return -1; - } - sprintf(joydev->name, "joydev%d", joydev->minor); + joydev->minor = minor; + joydev_table[minor] = joydev; + joydev->handle.dev = dev; joydev->handle.handler = handler; joydev->handle.private = joydev; @@ -421,10 +432,6 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev) joydev->nkey++; } - joydev->minor = ffz(joydev_minors); - set_bit(joydev->minor, &joydev_minors); - joydev_base[joydev->minor] = joydev; - for (i = 0; i < joydev->nabs; i++) { j = joydev->abspam[i]; if (dev->absmax[j] == dev->absmin[j]) { @@ -439,21 +446,23 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev) joydev->corr[i].coef[3] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]); } - input_open_device(&joydev->handle); + joydev->devfs = input_register_minor("js%d", minor, JOYDEV_MINOR_BASE); - printk("%s: Joystick device for input%d on /dev/js%d\n", joydev->name, dev->number, joydev->minor); + printk("js%d: Joystick device for input%d\n", minor, dev->number); - return 0; + return &joydev->handle; } static void joydev_disconnect(struct input_handle *handle) { struct joydev *joydev = handle->private; - input_close_device(handle); + if (joydev->open) + input_close_device(handle); if (!--joydev->used) { - clear_bit(joydev->minor, &joydev_minors); + input_unregister_minor(joydev->devfs); + joydev_table[joydev->minor] = NULL; kfree(joydev); } } @@ -462,14 +471,12 @@ static struct input_handler joydev_handler = { event: joydev_event, connect: joydev_connect, disconnect: joydev_disconnect, + fops: &joydev_fops, + minor: JOYDEV_MINOR_BASE, }; static int __init joydev_init(void) { - if (register_chrdev(JOYDEV_MAJOR, "js", &joydev_fops)) { - printk(KERN_ERR "joydev: unable to get major %d for joystick\n", JOYDEV_MAJOR); - return -EBUSY; - } input_register_handler(&joydev_handler); return 0; } @@ -477,8 +484,6 @@ static int __init joydev_init(void) static void __exit joydev_exit(void) { input_unregister_handler(&joydev_handler); - if (unregister_chrdev(JOYSTICK_MAJOR, "js")) - printk(KERN_ERR "js: can't unregister device\n"); } module_init(joydev_init); |