diff options
Diffstat (limited to 'drivers/input/joydev.c')
-rw-r--r-- | drivers/input/joydev.c | 89 |
1 files changed, 32 insertions, 57 deletions
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 78f323ea1e4b..f362883c94e3 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) { |
@@ -245,37 +243,20 @@ static int joydev_release(struct inode *inode, struct file *file) | |||
245 | kfree(client); | 243 | kfree(client); |
246 | 244 | ||
247 | joydev_close_device(joydev); | 245 | joydev_close_device(joydev); |
248 | put_device(&joydev->dev); | ||
249 | 246 | ||
250 | return 0; | 247 | return 0; |
251 | } | 248 | } |
252 | 249 | ||
253 | static int joydev_open(struct inode *inode, struct file *file) | 250 | static int joydev_open(struct inode *inode, struct file *file) |
254 | { | 251 | { |
252 | struct joydev *joydev = | ||
253 | container_of(inode->i_cdev, struct joydev, cdev); | ||
255 | struct joydev_client *client; | 254 | struct joydev_client *client; |
256 | struct joydev *joydev; | ||
257 | int i = iminor(inode) - JOYDEV_MINOR_BASE; | ||
258 | int error; | 255 | int error; |
259 | 256 | ||
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); | 257 | client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); |
275 | if (!client) { | 258 | if (!client) |
276 | error = -ENOMEM; | 259 | return -ENOMEM; |
277 | goto err_put_joydev; | ||
278 | } | ||
279 | 260 | ||
280 | spin_lock_init(&client->buffer_lock); | 261 | spin_lock_init(&client->buffer_lock); |
281 | client->joydev = joydev; | 262 | client->joydev = joydev; |
@@ -293,8 +274,6 @@ static int joydev_open(struct inode *inode, struct file *file) | |||
293 | err_free_client: | 274 | err_free_client: |
294 | joydev_detach_client(joydev, client); | 275 | joydev_detach_client(joydev, client); |
295 | kfree(client); | 276 | kfree(client); |
296 | err_put_joydev: | ||
297 | put_device(&joydev->dev); | ||
298 | return error; | 277 | return error; |
299 | } | 278 | } |
300 | 279 | ||
@@ -742,19 +721,6 @@ static const struct file_operations joydev_fops = { | |||
742 | .llseek = no_llseek, | 721 | .llseek = no_llseek, |
743 | }; | 722 | }; |
744 | 723 | ||
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 | /* | 724 | /* |
759 | * Mark device non-existent. This disables writes, ioctls and | 725 | * Mark device non-existent. This disables writes, ioctls and |
760 | * prevents new users from opening the device. Already posted | 726 | * prevents new users from opening the device. Already posted |
@@ -773,7 +739,8 @@ static void joydev_cleanup(struct joydev *joydev) | |||
773 | 739 | ||
774 | joydev_mark_dead(joydev); | 740 | joydev_mark_dead(joydev); |
775 | joydev_hangup(joydev); | 741 | joydev_hangup(joydev); |
776 | joydev_remove_chrdev(joydev); | 742 | |
743 | cdev_del(&joydev->cdev); | ||
777 | 744 | ||
778 | /* joydev is marked dead so no one else accesses joydev->open */ | 745 | /* joydev is marked dead so no one else accesses joydev->open */ |
779 | if (joydev->open) | 746 | if (joydev->open) |
@@ -798,30 +765,33 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
798 | const struct input_device_id *id) | 765 | const struct input_device_id *id) |
799 | { | 766 | { |
800 | struct joydev *joydev; | 767 | struct joydev *joydev; |
801 | int i, j, t, minor; | 768 | int i, j, t, minor, dev_no; |
802 | int error; | 769 | int error; |
803 | 770 | ||
804 | for (minor = 0; minor < JOYDEV_MINORS; minor++) | 771 | minor = input_get_new_minor(JOYDEV_MINOR_BASE, JOYDEV_MINORS, true); |
805 | if (!joydev_table[minor]) | 772 | if (minor < 0) { |
806 | break; | 773 | error = minor; |
807 | 774 | pr_err("failed to reserve new minor: %d\n", error); | |
808 | if (minor == JOYDEV_MINORS) { | 775 | return error; |
809 | pr_err("no more free joydev devices\n"); | ||
810 | return -ENFILE; | ||
811 | } | 776 | } |
812 | 777 | ||
813 | joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL); | 778 | joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL); |
814 | if (!joydev) | 779 | if (!joydev) { |
815 | return -ENOMEM; | 780 | error = -ENOMEM; |
781 | goto err_free_minor; | ||
782 | } | ||
816 | 783 | ||
817 | INIT_LIST_HEAD(&joydev->client_list); | 784 | INIT_LIST_HEAD(&joydev->client_list); |
818 | spin_lock_init(&joydev->client_lock); | 785 | spin_lock_init(&joydev->client_lock); |
819 | mutex_init(&joydev->mutex); | 786 | mutex_init(&joydev->mutex); |
820 | init_waitqueue_head(&joydev->wait); | 787 | init_waitqueue_head(&joydev->wait); |
821 | |||
822 | dev_set_name(&joydev->dev, "js%d", minor); | ||
823 | joydev->exist = true; | 788 | joydev->exist = true; |
824 | joydev->minor = minor; | 789 | |
790 | dev_no = minor; | ||
791 | /* Normalize device number if it falls into legacy range */ | ||
792 | if (dev_no < JOYDEV_MINOR_BASE + JOYDEV_MINORS) | ||
793 | dev_no -= JOYDEV_MINOR_BASE; | ||
794 | dev_set_name(&joydev->dev, "js%d", dev_no); | ||
825 | 795 | ||
826 | joydev->handle.dev = input_get_device(dev); | 796 | joydev->handle.dev = input_get_device(dev); |
827 | joydev->handle.name = dev_name(&joydev->dev); | 797 | joydev->handle.name = dev_name(&joydev->dev); |
@@ -875,7 +845,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
875 | } | 845 | } |
876 | } | 846 | } |
877 | 847 | ||
878 | joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor); | 848 | joydev->dev.devt = MKDEV(INPUT_MAJOR, minor); |
879 | joydev->dev.class = &input_class; | 849 | joydev->dev.class = &input_class; |
880 | joydev->dev.parent = &dev->dev; | 850 | joydev->dev.parent = &dev->dev; |
881 | joydev->dev.release = joydev_free; | 851 | joydev->dev.release = joydev_free; |
@@ -885,7 +855,9 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
885 | if (error) | 855 | if (error) |
886 | goto err_free_joydev; | 856 | goto err_free_joydev; |
887 | 857 | ||
888 | error = joydev_install_chrdev(joydev); | 858 | cdev_init(&joydev->cdev, &joydev_fops); |
859 | joydev->cdev.kobj.parent = &joydev->dev.kobj; | ||
860 | error = cdev_add(&joydev->cdev, joydev->dev.devt, 1); | ||
889 | if (error) | 861 | if (error) |
890 | goto err_unregister_handle; | 862 | goto err_unregister_handle; |
891 | 863 | ||
@@ -901,6 +873,8 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
901 | input_unregister_handle(&joydev->handle); | 873 | input_unregister_handle(&joydev->handle); |
902 | err_free_joydev: | 874 | err_free_joydev: |
903 | put_device(&joydev->dev); | 875 | put_device(&joydev->dev); |
876 | err_free_minor: | ||
877 | input_free_minor(minor); | ||
904 | return error; | 878 | return error; |
905 | } | 879 | } |
906 | 880 | ||
@@ -910,6 +884,7 @@ static void joydev_disconnect(struct input_handle *handle) | |||
910 | 884 | ||
911 | device_del(&joydev->dev); | 885 | device_del(&joydev->dev); |
912 | joydev_cleanup(joydev); | 886 | joydev_cleanup(joydev); |
887 | input_free_minor(MINOR(joydev->dev.devt)); | ||
913 | input_unregister_handle(handle); | 888 | input_unregister_handle(handle); |
914 | put_device(&joydev->dev); | 889 | put_device(&joydev->dev); |
915 | } | 890 | } |
@@ -961,7 +936,7 @@ static struct input_handler joydev_handler = { | |||
961 | .match = joydev_match, | 936 | .match = joydev_match, |
962 | .connect = joydev_connect, | 937 | .connect = joydev_connect, |
963 | .disconnect = joydev_disconnect, | 938 | .disconnect = joydev_disconnect, |
964 | .fops = &joydev_fops, | 939 | .legacy_minors = true, |
965 | .minor = JOYDEV_MINOR_BASE, | 940 | .minor = JOYDEV_MINOR_BASE, |
966 | .name = "joydev", | 941 | .name = "joydev", |
967 | .id_table = joydev_ids, | 942 | .id_table = joydev_ids, |