diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/input/joydev.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/input/joydev.c')
-rw-r--r-- | drivers/input/joydev.c | 92 |
1 files changed, 59 insertions, 33 deletions
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index f362883c94e..c24ec2d5f92 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
14 | 14 | ||
15 | #include <asm/io.h> | 15 | #include <asm/io.h> |
16 | #include <asm/system.h> | ||
16 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
17 | #include <linux/errno.h> | 18 | #include <linux/errno.h> |
18 | #include <linux/joystick.h> | 19 | #include <linux/joystick.h> |
@@ -27,7 +28,6 @@ | |||
27 | #include <linux/poll.h> | 28 | #include <linux/poll.h> |
28 | #include <linux/init.h> | 29 | #include <linux/init.h> |
29 | #include <linux/device.h> | 30 | #include <linux/device.h> |
30 | #include <linux/cdev.h> | ||
31 | 31 | ||
32 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 32 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
33 | MODULE_DESCRIPTION("Joystick device interfaces"); | 33 | MODULE_DESCRIPTION("Joystick device interfaces"); |
@@ -40,13 +40,13 @@ MODULE_LICENSE("GPL"); | |||
40 | 40 | ||
41 | struct joydev { | 41 | struct joydev { |
42 | int open; | 42 | int open; |
43 | int minor; | ||
43 | struct input_handle handle; | 44 | struct input_handle handle; |
44 | wait_queue_head_t wait; | 45 | wait_queue_head_t wait; |
45 | struct list_head client_list; | 46 | struct list_head client_list; |
46 | spinlock_t client_lock; /* protects client_list */ | 47 | spinlock_t client_lock; /* protects client_list */ |
47 | struct mutex mutex; | 48 | struct mutex mutex; |
48 | struct device dev; | 49 | struct device dev; |
49 | struct cdev cdev; | ||
50 | bool exist; | 50 | bool exist; |
51 | 51 | ||
52 | struct js_corr corr[ABS_CNT]; | 52 | struct js_corr corr[ABS_CNT]; |
@@ -71,6 +71,9 @@ struct joydev_client { | |||
71 | struct list_head node; | 71 | struct list_head node; |
72 | }; | 72 | }; |
73 | 73 | ||
74 | static struct joydev *joydev_table[JOYDEV_MINORS]; | ||
75 | static DEFINE_MUTEX(joydev_table_mutex); | ||
76 | |||
74 | static int joydev_correct(int value, struct js_corr *corr) | 77 | static int joydev_correct(int value, struct js_corr *corr) |
75 | { | 78 | { |
76 | switch (corr->type) { | 79 | switch (corr->type) { |
@@ -243,20 +246,37 @@ static int joydev_release(struct inode *inode, struct file *file) | |||
243 | kfree(client); | 246 | kfree(client); |
244 | 247 | ||
245 | joydev_close_device(joydev); | 248 | joydev_close_device(joydev); |
249 | put_device(&joydev->dev); | ||
246 | 250 | ||
247 | return 0; | 251 | return 0; |
248 | } | 252 | } |
249 | 253 | ||
250 | static int joydev_open(struct inode *inode, struct file *file) | 254 | static int joydev_open(struct inode *inode, struct file *file) |
251 | { | 255 | { |
252 | struct joydev *joydev = | ||
253 | container_of(inode->i_cdev, struct joydev, cdev); | ||
254 | struct joydev_client *client; | 256 | struct joydev_client *client; |
257 | struct joydev *joydev; | ||
258 | int i = iminor(inode) - JOYDEV_MINOR_BASE; | ||
255 | int error; | 259 | int error; |
256 | 260 | ||
261 | if (i >= JOYDEV_MINORS) | ||
262 | return -ENODEV; | ||
263 | |||
264 | error = mutex_lock_interruptible(&joydev_table_mutex); | ||
265 | if (error) | ||
266 | return error; | ||
267 | joydev = joydev_table[i]; | ||
268 | if (joydev) | ||
269 | get_device(&joydev->dev); | ||
270 | mutex_unlock(&joydev_table_mutex); | ||
271 | |||
272 | if (!joydev) | ||
273 | return -ENODEV; | ||
274 | |||
257 | client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); | 275 | client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); |
258 | if (!client) | 276 | if (!client) { |
259 | return -ENOMEM; | 277 | error = -ENOMEM; |
278 | goto err_put_joydev; | ||
279 | } | ||
260 | 280 | ||
261 | spin_lock_init(&client->buffer_lock); | 281 | spin_lock_init(&client->buffer_lock); |
262 | client->joydev = joydev; | 282 | client->joydev = joydev; |
@@ -274,6 +294,8 @@ static int joydev_open(struct inode *inode, struct file *file) | |||
274 | err_free_client: | 294 | err_free_client: |
275 | joydev_detach_client(joydev, client); | 295 | joydev_detach_client(joydev, client); |
276 | kfree(client); | 296 | kfree(client); |
297 | err_put_joydev: | ||
298 | put_device(&joydev->dev); | ||
277 | return error; | 299 | return error; |
278 | } | 300 | } |
279 | 301 | ||
@@ -690,7 +712,7 @@ static long joydev_ioctl(struct file *file, | |||
690 | 712 | ||
691 | case JS_SET_ALL: | 713 | case JS_SET_ALL: |
692 | retval = copy_from_user(&joydev->glue, argp, | 714 | retval = copy_from_user(&joydev->glue, argp, |
693 | sizeof(joydev->glue)) ? -EFAULT : 0; | 715 | sizeof(joydev->glue)) ? -EFAULT: 0; |
694 | break; | 716 | break; |
695 | 717 | ||
696 | case JS_GET_ALL: | 718 | case JS_GET_ALL: |
@@ -721,6 +743,19 @@ static const struct file_operations joydev_fops = { | |||
721 | .llseek = no_llseek, | 743 | .llseek = no_llseek, |
722 | }; | 744 | }; |
723 | 745 | ||
746 | static int joydev_install_chrdev(struct joydev *joydev) | ||
747 | { | ||
748 | joydev_table[joydev->minor] = joydev; | ||
749 | return 0; | ||
750 | } | ||
751 | |||
752 | static void joydev_remove_chrdev(struct joydev *joydev) | ||
753 | { | ||
754 | mutex_lock(&joydev_table_mutex); | ||
755 | joydev_table[joydev->minor] = NULL; | ||
756 | mutex_unlock(&joydev_table_mutex); | ||
757 | } | ||
758 | |||
724 | /* | 759 | /* |
725 | * Mark device non-existent. This disables writes, ioctls and | 760 | * Mark device non-existent. This disables writes, ioctls and |
726 | * prevents new users from opening the device. Already posted | 761 | * prevents new users from opening the device. Already posted |
@@ -739,8 +774,7 @@ static void joydev_cleanup(struct joydev *joydev) | |||
739 | 774 | ||
740 | joydev_mark_dead(joydev); | 775 | joydev_mark_dead(joydev); |
741 | joydev_hangup(joydev); | 776 | joydev_hangup(joydev); |
742 | 777 | joydev_remove_chrdev(joydev); | |
743 | cdev_del(&joydev->cdev); | ||
744 | 778 | ||
745 | /* joydev is marked dead so no one else accesses joydev->open */ | 779 | /* joydev is marked dead so no one else accesses joydev->open */ |
746 | if (joydev->open) | 780 | if (joydev->open) |
@@ -765,33 +799,30 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
765 | const struct input_device_id *id) | 799 | const struct input_device_id *id) |
766 | { | 800 | { |
767 | struct joydev *joydev; | 801 | struct joydev *joydev; |
768 | int i, j, t, minor, dev_no; | 802 | int i, j, t, minor; |
769 | int error; | 803 | int error; |
770 | 804 | ||
771 | minor = input_get_new_minor(JOYDEV_MINOR_BASE, JOYDEV_MINORS, true); | 805 | for (minor = 0; minor < JOYDEV_MINORS; minor++) |
772 | if (minor < 0) { | 806 | if (!joydev_table[minor]) |
773 | error = minor; | 807 | break; |
774 | pr_err("failed to reserve new minor: %d\n", error); | 808 | |
775 | return error; | 809 | if (minor == JOYDEV_MINORS) { |
810 | pr_err("no more free joydev devices\n"); | ||
811 | return -ENFILE; | ||
776 | } | 812 | } |
777 | 813 | ||
778 | joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL); | 814 | joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL); |
779 | if (!joydev) { | 815 | if (!joydev) |
780 | error = -ENOMEM; | 816 | return -ENOMEM; |
781 | goto err_free_minor; | ||
782 | } | ||
783 | 817 | ||
784 | INIT_LIST_HEAD(&joydev->client_list); | 818 | INIT_LIST_HEAD(&joydev->client_list); |
785 | spin_lock_init(&joydev->client_lock); | 819 | spin_lock_init(&joydev->client_lock); |
786 | mutex_init(&joydev->mutex); | 820 | mutex_init(&joydev->mutex); |
787 | init_waitqueue_head(&joydev->wait); | 821 | init_waitqueue_head(&joydev->wait); |
788 | joydev->exist = true; | ||
789 | 822 | ||
790 | dev_no = minor; | 823 | dev_set_name(&joydev->dev, "js%d", minor); |
791 | /* Normalize device number if it falls into legacy range */ | 824 | joydev->exist = true; |
792 | if (dev_no < JOYDEV_MINOR_BASE + JOYDEV_MINORS) | 825 | joydev->minor = minor; |
793 | dev_no -= JOYDEV_MINOR_BASE; | ||
794 | dev_set_name(&joydev->dev, "js%d", dev_no); | ||
795 | 826 | ||
796 | joydev->handle.dev = input_get_device(dev); | 827 | joydev->handle.dev = input_get_device(dev); |
797 | joydev->handle.name = dev_name(&joydev->dev); | 828 | joydev->handle.name = dev_name(&joydev->dev); |
@@ -845,7 +876,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
845 | } | 876 | } |
846 | } | 877 | } |
847 | 878 | ||
848 | joydev->dev.devt = MKDEV(INPUT_MAJOR, minor); | 879 | joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor); |
849 | joydev->dev.class = &input_class; | 880 | joydev->dev.class = &input_class; |
850 | joydev->dev.parent = &dev->dev; | 881 | joydev->dev.parent = &dev->dev; |
851 | joydev->dev.release = joydev_free; | 882 | joydev->dev.release = joydev_free; |
@@ -855,9 +886,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
855 | if (error) | 886 | if (error) |
856 | goto err_free_joydev; | 887 | goto err_free_joydev; |
857 | 888 | ||
858 | cdev_init(&joydev->cdev, &joydev_fops); | 889 | error = joydev_install_chrdev(joydev); |
859 | joydev->cdev.kobj.parent = &joydev->dev.kobj; | ||
860 | error = cdev_add(&joydev->cdev, joydev->dev.devt, 1); | ||
861 | if (error) | 890 | if (error) |
862 | goto err_unregister_handle; | 891 | goto err_unregister_handle; |
863 | 892 | ||
@@ -873,8 +902,6 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
873 | input_unregister_handle(&joydev->handle); | 902 | input_unregister_handle(&joydev->handle); |
874 | err_free_joydev: | 903 | err_free_joydev: |
875 | put_device(&joydev->dev); | 904 | put_device(&joydev->dev); |
876 | err_free_minor: | ||
877 | input_free_minor(minor); | ||
878 | return error; | 905 | return error; |
879 | } | 906 | } |
880 | 907 | ||
@@ -884,7 +911,6 @@ static void joydev_disconnect(struct input_handle *handle) | |||
884 | 911 | ||
885 | device_del(&joydev->dev); | 912 | device_del(&joydev->dev); |
886 | joydev_cleanup(joydev); | 913 | joydev_cleanup(joydev); |
887 | input_free_minor(MINOR(joydev->dev.devt)); | ||
888 | input_unregister_handle(handle); | 914 | input_unregister_handle(handle); |
889 | put_device(&joydev->dev); | 915 | put_device(&joydev->dev); |
890 | } | 916 | } |
@@ -936,7 +962,7 @@ static struct input_handler joydev_handler = { | |||
936 | .match = joydev_match, | 962 | .match = joydev_match, |
937 | .connect = joydev_connect, | 963 | .connect = joydev_connect, |
938 | .disconnect = joydev_disconnect, | 964 | .disconnect = joydev_disconnect, |
939 | .legacy_minors = true, | 965 | .fops = &joydev_fops, |
940 | .minor = JOYDEV_MINOR_BASE, | 966 | .minor = JOYDEV_MINOR_BASE, |
941 | .name = "joydev", | 967 | .name = "joydev", |
942 | .id_table = joydev_ids, | 968 | .id_table = joydev_ids, |