diff options
Diffstat (limited to 'drivers/input/joydev.c')
| -rw-r--r-- | drivers/input/joydev.c | 88 |
1 files changed, 32 insertions, 56 deletions
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 78f323ea1e4b..b62b5891f399 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/poll.h> | 27 | #include <linux/poll.h> |
| 28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
| 29 | #include <linux/device.h> | 29 | #include <linux/device.h> |
| 30 | #include <linux/cdev.h> | ||
| 30 | 31 | ||
| 31 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 32 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
| 32 | MODULE_DESCRIPTION("Joystick device interfaces"); | 33 | MODULE_DESCRIPTION("Joystick device interfaces"); |
| @@ -39,13 +40,13 @@ MODULE_LICENSE("GPL"); | |||
| 39 | 40 | ||
| 40 | struct joydev { | 41 | struct joydev { |
| 41 | int open; | 42 | int open; |
| 42 | int minor; | ||
| 43 | struct input_handle handle; | 43 | struct input_handle handle; |
| 44 | wait_queue_head_t wait; | 44 | wait_queue_head_t wait; |
| 45 | struct list_head client_list; | 45 | struct list_head client_list; |
| 46 | spinlock_t client_lock; /* protects client_list */ | 46 | spinlock_t client_lock; /* protects client_list */ |
| 47 | struct mutex mutex; | 47 | struct mutex mutex; |
| 48 | struct device dev; | 48 | struct device dev; |
| 49 | struct cdev cdev; | ||
| 49 | bool exist; | 50 | bool exist; |
| 50 | 51 | ||
| 51 | struct js_corr corr[ABS_CNT]; | 52 | struct js_corr corr[ABS_CNT]; |
| @@ -70,9 +71,6 @@ struct joydev_client { | |||
| 70 | struct list_head node; | 71 | struct list_head node; |
| 71 | }; | 72 | }; |
| 72 | 73 | ||
| 73 | static struct joydev *joydev_table[JOYDEV_MINORS]; | ||
| 74 | static DEFINE_MUTEX(joydev_table_mutex); | ||
| 75 | |||
| 76 | static int joydev_correct(int value, struct js_corr *corr) | 74 | static int joydev_correct(int value, struct js_corr *corr) |
| 77 | { | 75 | { |
| 78 | switch (corr->type) { | 76 | switch (corr->type) { |
| @@ -252,30 +250,14 @@ static int joydev_release(struct inode *inode, struct file *file) | |||
| 252 | 250 | ||
| 253 | static int joydev_open(struct inode *inode, struct file *file) | 251 | static int joydev_open(struct inode *inode, struct file *file) |
| 254 | { | 252 | { |
| 253 | struct joydev *joydev = | ||
| 254 | container_of(inode->i_cdev, struct joydev, cdev); | ||
| 255 | struct joydev_client *client; | 255 | struct joydev_client *client; |
| 256 | struct joydev *joydev; | ||
| 257 | int i = iminor(inode) - JOYDEV_MINOR_BASE; | ||
| 258 | int error; | 256 | int error; |
| 259 | 257 | ||
| 260 | if (i >= JOYDEV_MINORS) | ||
| 261 | return -ENODEV; | ||
| 262 | |||
| 263 | error = mutex_lock_interruptible(&joydev_table_mutex); | ||
| 264 | if (error) | ||
| 265 | return error; | ||
| 266 | joydev = joydev_table[i]; | ||
| 267 | if (joydev) | ||
| 268 | get_device(&joydev->dev); | ||
| 269 | mutex_unlock(&joydev_table_mutex); | ||
| 270 | |||
| 271 | if (!joydev) | ||
| 272 | return -ENODEV; | ||
| 273 | |||
| 274 | client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); | 258 | client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); |
| 275 | if (!client) { | 259 | if (!client) |
| 276 | error = -ENOMEM; | 260 | return -ENOMEM; |
| 277 | goto err_put_joydev; | ||
| 278 | } | ||
| 279 | 261 | ||
| 280 | spin_lock_init(&client->buffer_lock); | 262 | spin_lock_init(&client->buffer_lock); |
| 281 | client->joydev = joydev; | 263 | client->joydev = joydev; |
| @@ -288,13 +270,12 @@ static int joydev_open(struct inode *inode, struct file *file) | |||
| 288 | file->private_data = client; | 270 | file->private_data = client; |
| 289 | nonseekable_open(inode, file); | 271 | nonseekable_open(inode, file); |
| 290 | 272 | ||
| 273 | get_device(&joydev->dev); | ||
| 291 | return 0; | 274 | return 0; |
| 292 | 275 | ||
| 293 | err_free_client: | 276 | err_free_client: |
| 294 | joydev_detach_client(joydev, client); | 277 | joydev_detach_client(joydev, client); |
| 295 | kfree(client); | 278 | kfree(client); |
| 296 | err_put_joydev: | ||
| 297 | put_device(&joydev->dev); | ||
| 298 | return error; | 279 | return error; |
| 299 | } | 280 | } |
| 300 | 281 | ||
| @@ -742,19 +723,6 @@ static const struct file_operations joydev_fops = { | |||
| 742 | .llseek = no_llseek, | 723 | .llseek = no_llseek, |
| 743 | }; | 724 | }; |
| 744 | 725 | ||
| 745 | static int joydev_install_chrdev(struct joydev *joydev) | ||
| 746 | { | ||
| 747 | joydev_table[joydev->minor] = joydev; | ||
| 748 | return 0; | ||
| 749 | } | ||
| 750 | |||
| 751 | static void joydev_remove_chrdev(struct joydev *joydev) | ||
| 752 | { | ||
| 753 | mutex_lock(&joydev_table_mutex); | ||
| 754 | joydev_table[joydev->minor] = NULL; | ||
| 755 | mutex_unlock(&joydev_table_mutex); | ||
| 756 | } | ||
| 757 | |||
| 758 | /* | 726 | /* |
| 759 | * Mark device non-existent. This disables writes, ioctls and | 727 | * Mark device non-existent. This disables writes, ioctls and |
| 760 | * prevents new users from opening the device. Already posted | 728 | * prevents new users from opening the device. Already posted |
| @@ -773,7 +741,8 @@ static void joydev_cleanup(struct joydev *joydev) | |||
| 773 | 741 | ||
| 774 | joydev_mark_dead(joydev); | 742 | joydev_mark_dead(joydev); |
| 775 | joydev_hangup(joydev); | 743 | joydev_hangup(joydev); |
| 776 | joydev_remove_chrdev(joydev); | 744 | |
| 745 | cdev_del(&joydev->cdev); | ||
| 777 | 746 | ||
| 778 | /* joydev is marked dead so no one else accesses joydev->open */ | 747 | /* joydev is marked dead so no one else accesses joydev->open */ |
| 779 | if (joydev->open) | 748 | if (joydev->open) |
| @@ -798,30 +767,33 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
| 798 | const struct input_device_id *id) | 767 | const struct input_device_id *id) |
| 799 | { | 768 | { |
| 800 | struct joydev *joydev; | 769 | struct joydev *joydev; |
| 801 | int i, j, t, minor; | 770 | int i, j, t, minor, dev_no; |
| 802 | int error; | 771 | int error; |
| 803 | 772 | ||
| 804 | for (minor = 0; minor < JOYDEV_MINORS; minor++) | 773 | minor = input_get_new_minor(JOYDEV_MINOR_BASE, JOYDEV_MINORS, true); |
| 805 | if (!joydev_table[minor]) | 774 | if (minor < 0) { |
| 806 | break; | 775 | error = minor; |
| 807 | 776 | pr_err("failed to reserve new minor: %d\n", error); | |
| 808 | if (minor == JOYDEV_MINORS) { | 777 | return error; |
| 809 | pr_err("no more free joydev devices\n"); | ||
| 810 | return -ENFILE; | ||
| 811 | } | 778 | } |
| 812 | 779 | ||
| 813 | joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL); | 780 | joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL); |
| 814 | if (!joydev) | 781 | if (!joydev) { |
| 815 | return -ENOMEM; | 782 | error = -ENOMEM; |
| 783 | goto err_free_minor; | ||
| 784 | } | ||
| 816 | 785 | ||
| 817 | INIT_LIST_HEAD(&joydev->client_list); | 786 | INIT_LIST_HEAD(&joydev->client_list); |
| 818 | spin_lock_init(&joydev->client_lock); | 787 | spin_lock_init(&joydev->client_lock); |
| 819 | mutex_init(&joydev->mutex); | 788 | mutex_init(&joydev->mutex); |
| 820 | init_waitqueue_head(&joydev->wait); | 789 | init_waitqueue_head(&joydev->wait); |
| 821 | |||
| 822 | dev_set_name(&joydev->dev, "js%d", minor); | ||
| 823 | joydev->exist = true; | 790 | joydev->exist = true; |
| 824 | joydev->minor = minor; | 791 | |
| 792 | dev_no = minor; | ||
| 793 | /* Normalize device number if it falls into legacy range */ | ||
| 794 | if (dev_no < JOYDEV_MINOR_BASE + JOYDEV_MINORS) | ||
| 795 | dev_no -= JOYDEV_MINOR_BASE; | ||
| 796 | dev_set_name(&joydev->dev, "js%d", dev_no); | ||
| 825 | 797 | ||
| 826 | joydev->handle.dev = input_get_device(dev); | 798 | joydev->handle.dev = input_get_device(dev); |
| 827 | joydev->handle.name = dev_name(&joydev->dev); | 799 | joydev->handle.name = dev_name(&joydev->dev); |
| @@ -875,7 +847,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
| 875 | } | 847 | } |
| 876 | } | 848 | } |
| 877 | 849 | ||
| 878 | joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor); | 850 | joydev->dev.devt = MKDEV(INPUT_MAJOR, minor); |
| 879 | joydev->dev.class = &input_class; | 851 | joydev->dev.class = &input_class; |
| 880 | joydev->dev.parent = &dev->dev; | 852 | joydev->dev.parent = &dev->dev; |
| 881 | joydev->dev.release = joydev_free; | 853 | joydev->dev.release = joydev_free; |
| @@ -885,7 +857,8 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
| 885 | if (error) | 857 | if (error) |
| 886 | goto err_free_joydev; | 858 | goto err_free_joydev; |
| 887 | 859 | ||
| 888 | error = joydev_install_chrdev(joydev); | 860 | cdev_init(&joydev->cdev, &joydev_fops); |
| 861 | error = cdev_add(&joydev->cdev, joydev->dev.devt, 1); | ||
| 889 | if (error) | 862 | if (error) |
| 890 | goto err_unregister_handle; | 863 | goto err_unregister_handle; |
| 891 | 864 | ||
| @@ -901,6 +874,8 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
| 901 | input_unregister_handle(&joydev->handle); | 874 | input_unregister_handle(&joydev->handle); |
| 902 | err_free_joydev: | 875 | err_free_joydev: |
| 903 | put_device(&joydev->dev); | 876 | put_device(&joydev->dev); |
| 877 | err_free_minor: | ||
| 878 | input_free_minor(minor); | ||
| 904 | return error; | 879 | return error; |
| 905 | } | 880 | } |
| 906 | 881 | ||
| @@ -910,6 +885,7 @@ static void joydev_disconnect(struct input_handle *handle) | |||
| 910 | 885 | ||
| 911 | device_del(&joydev->dev); | 886 | device_del(&joydev->dev); |
| 912 | joydev_cleanup(joydev); | 887 | joydev_cleanup(joydev); |
| 888 | input_free_minor(MINOR(joydev->dev.devt)); | ||
| 913 | input_unregister_handle(handle); | 889 | input_unregister_handle(handle); |
| 914 | put_device(&joydev->dev); | 890 | put_device(&joydev->dev); |
| 915 | } | 891 | } |
| @@ -961,7 +937,7 @@ static struct input_handler joydev_handler = { | |||
| 961 | .match = joydev_match, | 937 | .match = joydev_match, |
| 962 | .connect = joydev_connect, | 938 | .connect = joydev_connect, |
| 963 | .disconnect = joydev_disconnect, | 939 | .disconnect = joydev_disconnect, |
| 964 | .fops = &joydev_fops, | 940 | .legacy_minors = true, |
| 965 | .minor = JOYDEV_MINOR_BASE, | 941 | .minor = JOYDEV_MINOR_BASE, |
| 966 | .name = "joydev", | 942 | .name = "joydev", |
| 967 | .id_table = joydev_ids, | 943 | .id_table = joydev_ids, |
