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, |