aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/joydev.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2012-10-08 12:07:24 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2012-10-08 12:37:55 -0400
commit7f8d4cad1e4e11a45d02bd6e024cc2812963c38a (patch)
treeac592d99a390f1aecf9944e10d05abe4ec0f1b76 /drivers/input/joydev.c
parent0124be49770469cfb258d7df4693e70b4c5fb013 (diff)
Input: extend the number of event (and other) devices
Extend the amount of character devices, such as eventX, mouseX and jsX, from a hard limit of 32 per input handler to about 1024 shared across all handlers. To be compatible with legacy installations input handlers will start creating char devices with minors in their legacy range, however once legacy range is exhausted they will start allocating minors from the dynamic range 256-1024. Reviewed-by: David Herrmann <dh.herrmann@googlemail.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/joydev.c')
-rw-r--r--drivers/input/joydev.c88
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
31MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 32MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
32MODULE_DESCRIPTION("Joystick device interfaces"); 33MODULE_DESCRIPTION("Joystick device interfaces");
@@ -39,13 +40,13 @@ MODULE_LICENSE("GPL");
39 40
40struct joydev { 41struct 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
73static struct joydev *joydev_table[JOYDEV_MINORS];
74static DEFINE_MUTEX(joydev_table_mutex);
75
76static int joydev_correct(int value, struct js_corr *corr) 74static 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
253static int joydev_open(struct inode *inode, struct file *file) 251static 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
745static int joydev_install_chrdev(struct joydev *joydev)
746{
747 joydev_table[joydev->minor] = joydev;
748 return 0;
749}
750
751static 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,