diff options
| -rw-r--r-- | drivers/input/evdev.c | 99 | ||||
| -rw-r--r-- | drivers/input/input.c | 114 | ||||
| -rw-r--r-- | drivers/input/joydev.c | 88 | ||||
| -rw-r--r-- | drivers/input/mousedev.c | 132 | ||||
| -rw-r--r-- | include/linux/input.h | 10 |
5 files changed, 187 insertions, 256 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 118d0300f1fb..6ae2ac47c9c8 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
| @@ -23,11 +23,11 @@ | |||
| 23 | #include <linux/input/mt.h> | 23 | #include <linux/input/mt.h> |
| 24 | #include <linux/major.h> | 24 | #include <linux/major.h> |
| 25 | #include <linux/device.h> | 25 | #include <linux/device.h> |
| 26 | #include <linux/cdev.h> | ||
| 26 | #include "input-compat.h" | 27 | #include "input-compat.h" |
| 27 | 28 | ||
| 28 | struct evdev { | 29 | struct evdev { |
| 29 | int open; | 30 | int open; |
| 30 | int minor; | ||
| 31 | struct input_handle handle; | 31 | struct input_handle handle; |
| 32 | wait_queue_head_t wait; | 32 | wait_queue_head_t wait; |
| 33 | struct evdev_client __rcu *grab; | 33 | struct evdev_client __rcu *grab; |
| @@ -35,6 +35,7 @@ struct evdev { | |||
| 35 | spinlock_t client_lock; /* protects client_list */ | 35 | spinlock_t client_lock; /* protects client_list */ |
| 36 | struct mutex mutex; | 36 | struct mutex mutex; |
| 37 | struct device dev; | 37 | struct device dev; |
| 38 | struct cdev cdev; | ||
| 38 | bool exist; | 39 | bool exist; |
| 39 | }; | 40 | }; |
| 40 | 41 | ||
| @@ -51,9 +52,6 @@ struct evdev_client { | |||
| 51 | struct input_event buffer[]; | 52 | struct input_event buffer[]; |
| 52 | }; | 53 | }; |
| 53 | 54 | ||
| 54 | static struct evdev *evdev_table[EVDEV_MINORS]; | ||
| 55 | static DEFINE_MUTEX(evdev_table_mutex); | ||
| 56 | |||
| 57 | static void __pass_event(struct evdev_client *client, | 55 | static void __pass_event(struct evdev_client *client, |
| 58 | const struct input_event *event) | 56 | const struct input_event *event) |
| 59 | { | 57 | { |
| @@ -310,35 +308,16 @@ static unsigned int evdev_compute_buffer_size(struct input_dev *dev) | |||
| 310 | 308 | ||
| 311 | static int evdev_open(struct inode *inode, struct file *file) | 309 | static int evdev_open(struct inode *inode, struct file *file) |
| 312 | { | 310 | { |
| 313 | struct evdev *evdev; | 311 | struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev); |
| 312 | unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev); | ||
| 314 | struct evdev_client *client; | 313 | struct evdev_client *client; |
| 315 | int i = iminor(inode) - EVDEV_MINOR_BASE; | ||
| 316 | unsigned int bufsize; | ||
| 317 | int error; | 314 | int error; |
| 318 | 315 | ||
| 319 | if (i >= EVDEV_MINORS) | ||
| 320 | return -ENODEV; | ||
| 321 | |||
| 322 | error = mutex_lock_interruptible(&evdev_table_mutex); | ||
| 323 | if (error) | ||
| 324 | return error; | ||
| 325 | evdev = evdev_table[i]; | ||
| 326 | if (evdev) | ||
| 327 | get_device(&evdev->dev); | ||
| 328 | mutex_unlock(&evdev_table_mutex); | ||
| 329 | |||
| 330 | if (!evdev) | ||
| 331 | return -ENODEV; | ||
| 332 | |||
| 333 | bufsize = evdev_compute_buffer_size(evdev->handle.dev); | ||
| 334 | |||
| 335 | client = kzalloc(sizeof(struct evdev_client) + | 316 | client = kzalloc(sizeof(struct evdev_client) + |
| 336 | bufsize * sizeof(struct input_event), | 317 | bufsize * sizeof(struct input_event), |
| 337 | GFP_KERNEL); | 318 | GFP_KERNEL); |
| 338 | if (!client) { | 319 | if (!client) |
| 339 | error = -ENOMEM; | 320 | return -ENOMEM; |
| 340 | goto err_put_evdev; | ||
| 341 | } | ||
| 342 | 321 | ||
| 343 | client->bufsize = bufsize; | 322 | client->bufsize = bufsize; |
| 344 | spin_lock_init(&client->buffer_lock); | 323 | spin_lock_init(&client->buffer_lock); |
| @@ -352,13 +331,12 @@ static int evdev_open(struct inode *inode, struct file *file) | |||
| 352 | file->private_data = client; | 331 | file->private_data = client; |
| 353 | nonseekable_open(inode, file); | 332 | nonseekable_open(inode, file); |
| 354 | 333 | ||
| 334 | get_device(&evdev->dev); | ||
| 355 | return 0; | 335 | return 0; |
| 356 | 336 | ||
| 357 | err_free_client: | 337 | err_free_client: |
| 358 | evdev_detach_client(evdev, client); | 338 | evdev_detach_client(evdev, client); |
| 359 | kfree(client); | 339 | kfree(client); |
| 360 | err_put_evdev: | ||
| 361 | put_device(&evdev->dev); | ||
| 362 | return error; | 340 | return error; |
| 363 | } | 341 | } |
| 364 | 342 | ||
| @@ -942,26 +920,6 @@ static const struct file_operations evdev_fops = { | |||
| 942 | .llseek = no_llseek, | 920 | .llseek = no_llseek, |
| 943 | }; | 921 | }; |
| 944 | 922 | ||
| 945 | static int evdev_install_chrdev(struct evdev *evdev) | ||
| 946 | { | ||
| 947 | /* | ||
| 948 | * No need to do any locking here as calls to connect and | ||
| 949 | * disconnect are serialized by the input core | ||
| 950 | */ | ||
| 951 | evdev_table[evdev->minor] = evdev; | ||
| 952 | return 0; | ||
| 953 | } | ||
| 954 | |||
| 955 | static void evdev_remove_chrdev(struct evdev *evdev) | ||
| 956 | { | ||
| 957 | /* | ||
| 958 | * Lock evdev table to prevent race with evdev_open() | ||
| 959 | */ | ||
| 960 | mutex_lock(&evdev_table_mutex); | ||
| 961 | evdev_table[evdev->minor] = NULL; | ||
| 962 | mutex_unlock(&evdev_table_mutex); | ||
| 963 | } | ||
| 964 | |||
| 965 | /* | 923 | /* |
| 966 | * Mark device non-existent. This disables writes, ioctls and | 924 | * Mark device non-existent. This disables writes, ioctls and |
| 967 | * prevents new users from opening the device. Already posted | 925 | * prevents new users from opening the device. Already posted |
| @@ -980,7 +938,8 @@ static void evdev_cleanup(struct evdev *evdev) | |||
| 980 | 938 | ||
| 981 | evdev_mark_dead(evdev); | 939 | evdev_mark_dead(evdev); |
| 982 | evdev_hangup(evdev); | 940 | evdev_hangup(evdev); |
| 983 | evdev_remove_chrdev(evdev); | 941 | |
| 942 | cdev_del(&evdev->cdev); | ||
| 984 | 943 | ||
| 985 | /* evdev is marked dead so no one else accesses evdev->open */ | 944 | /* evdev is marked dead so no one else accesses evdev->open */ |
| 986 | if (evdev->open) { | 945 | if (evdev->open) { |
| @@ -991,43 +950,47 @@ static void evdev_cleanup(struct evdev *evdev) | |||
| 991 | 950 | ||
| 992 | /* | 951 | /* |
| 993 | * Create new evdev device. Note that input core serializes calls | 952 | * Create new evdev device. Note that input core serializes calls |
| 994 | * to connect and disconnect so we don't need to lock evdev_table here. | 953 | * to connect and disconnect. |
| 995 | */ | 954 | */ |
| 996 | static int evdev_connect(struct input_handler *handler, struct input_dev *dev, | 955 | static int evdev_connect(struct input_handler *handler, struct input_dev *dev, |
| 997 | const struct input_device_id *id) | 956 | const struct input_device_id *id) |
| 998 | { | 957 | { |
| 999 | struct evdev *evdev; | 958 | struct evdev *evdev; |
| 1000 | int minor; | 959 | int minor; |
| 960 | int dev_no; | ||
| 1001 | int error; | 961 | int error; |
| 1002 | 962 | ||
| 1003 | for (minor = 0; minor < EVDEV_MINORS; minor++) | 963 | minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true); |
| 1004 | if (!evdev_table[minor]) | 964 | if (minor < 0) { |
| 1005 | break; | 965 | error = minor; |
| 1006 | 966 | pr_err("failed to reserve new minor: %d\n", error); | |
| 1007 | if (minor == EVDEV_MINORS) { | 967 | return error; |
| 1008 | pr_err("no more free evdev devices\n"); | ||
| 1009 | return -ENFILE; | ||
| 1010 | } | 968 | } |
| 1011 | 969 | ||
| 1012 | evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); | 970 | evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); |
| 1013 | if (!evdev) | 971 | if (!evdev) { |
| 1014 | return -ENOMEM; | 972 | error = -ENOMEM; |
| 973 | goto err_free_minor; | ||
| 974 | } | ||
| 1015 | 975 | ||
| 1016 | INIT_LIST_HEAD(&evdev->client_list); | 976 | INIT_LIST_HEAD(&evdev->client_list); |
| 1017 | spin_lock_init(&evdev->client_lock); | 977 | spin_lock_init(&evdev->client_lock); |
| 1018 | mutex_init(&evdev->mutex); | 978 | mutex_init(&evdev->mutex); |
| 1019 | init_waitqueue_head(&evdev->wait); | 979 | init_waitqueue_head(&evdev->wait); |
| 1020 | |||
| 1021 | dev_set_name(&evdev->dev, "event%d", minor); | ||
| 1022 | evdev->exist = true; | 980 | evdev->exist = true; |
| 1023 | evdev->minor = minor; | 981 | |
| 982 | dev_no = minor; | ||
| 983 | /* Normalize device number if it falls into legacy range */ | ||
| 984 | if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS) | ||
| 985 | dev_no -= EVDEV_MINOR_BASE; | ||
| 986 | dev_set_name(&evdev->dev, "event%d", dev_no); | ||
| 1024 | 987 | ||
| 1025 | evdev->handle.dev = input_get_device(dev); | 988 | evdev->handle.dev = input_get_device(dev); |
| 1026 | evdev->handle.name = dev_name(&evdev->dev); | 989 | evdev->handle.name = dev_name(&evdev->dev); |
| 1027 | evdev->handle.handler = handler; | 990 | evdev->handle.handler = handler; |
| 1028 | evdev->handle.private = evdev; | 991 | evdev->handle.private = evdev; |
| 1029 | 992 | ||
| 1030 | evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); | 993 | evdev->dev.devt = MKDEV(INPUT_MAJOR, minor); |
| 1031 | evdev->dev.class = &input_class; | 994 | evdev->dev.class = &input_class; |
| 1032 | evdev->dev.parent = &dev->dev; | 995 | evdev->dev.parent = &dev->dev; |
| 1033 | evdev->dev.release = evdev_free; | 996 | evdev->dev.release = evdev_free; |
| @@ -1037,7 +1000,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, | |||
| 1037 | if (error) | 1000 | if (error) |
| 1038 | goto err_free_evdev; | 1001 | goto err_free_evdev; |
| 1039 | 1002 | ||
| 1040 | error = evdev_install_chrdev(evdev); | 1003 | cdev_init(&evdev->cdev, &evdev_fops); |
| 1004 | error = cdev_add(&evdev->cdev, evdev->dev.devt, 1); | ||
| 1041 | if (error) | 1005 | if (error) |
| 1042 | goto err_unregister_handle; | 1006 | goto err_unregister_handle; |
| 1043 | 1007 | ||
| @@ -1053,6 +1017,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, | |||
| 1053 | input_unregister_handle(&evdev->handle); | 1017 | input_unregister_handle(&evdev->handle); |
| 1054 | err_free_evdev: | 1018 | err_free_evdev: |
| 1055 | put_device(&evdev->dev); | 1019 | put_device(&evdev->dev); |
| 1020 | err_free_minor: | ||
| 1021 | input_free_minor(minor); | ||
| 1056 | return error; | 1022 | return error; |
| 1057 | } | 1023 | } |
| 1058 | 1024 | ||
| @@ -1062,6 +1028,7 @@ static void evdev_disconnect(struct input_handle *handle) | |||
| 1062 | 1028 | ||
| 1063 | device_del(&evdev->dev); | 1029 | device_del(&evdev->dev); |
| 1064 | evdev_cleanup(evdev); | 1030 | evdev_cleanup(evdev); |
| 1031 | input_free_minor(MINOR(evdev->dev.devt)); | ||
| 1065 | input_unregister_handle(handle); | 1032 | input_unregister_handle(handle); |
| 1066 | put_device(&evdev->dev); | 1033 | put_device(&evdev->dev); |
| 1067 | } | 1034 | } |
| @@ -1078,7 +1045,7 @@ static struct input_handler evdev_handler = { | |||
| 1078 | .events = evdev_events, | 1045 | .events = evdev_events, |
| 1079 | .connect = evdev_connect, | 1046 | .connect = evdev_connect, |
| 1080 | .disconnect = evdev_disconnect, | 1047 | .disconnect = evdev_disconnect, |
| 1081 | .fops = &evdev_fops, | 1048 | .legacy_minors = true, |
| 1082 | .minor = EVDEV_MINOR_BASE, | 1049 | .minor = EVDEV_MINOR_BASE, |
| 1083 | .name = "evdev", | 1050 | .name = "evdev", |
| 1084 | .id_table = evdev_ids, | 1051 | .id_table = evdev_ids, |
diff --git a/drivers/input/input.c b/drivers/input/input.c index ace3f7c4226d..53a0ddee7872 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | 14 | ||
| 15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
| 16 | #include <linux/types.h> | 16 | #include <linux/types.h> |
| 17 | #include <linux/idr.h> | ||
| 17 | #include <linux/input/mt.h> | 18 | #include <linux/input/mt.h> |
| 18 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
| @@ -32,7 +33,9 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); | |||
| 32 | MODULE_DESCRIPTION("Input core"); | 33 | MODULE_DESCRIPTION("Input core"); |
| 33 | MODULE_LICENSE("GPL"); | 34 | MODULE_LICENSE("GPL"); |
| 34 | 35 | ||
| 35 | #define INPUT_DEVICES 256 | 36 | #define INPUT_MAX_CHAR_DEVICES 1024 |
| 37 | #define INPUT_FIRST_DYNAMIC_DEV 256 | ||
| 38 | static DEFINE_IDA(input_ida); | ||
| 36 | 39 | ||
| 37 | static LIST_HEAD(input_dev_list); | 40 | static LIST_HEAD(input_dev_list); |
| 38 | static LIST_HEAD(input_handler_list); | 41 | static LIST_HEAD(input_handler_list); |
| @@ -45,8 +48,6 @@ static LIST_HEAD(input_handler_list); | |||
| 45 | */ | 48 | */ |
| 46 | static DEFINE_MUTEX(input_mutex); | 49 | static DEFINE_MUTEX(input_mutex); |
| 47 | 50 | ||
| 48 | static struct input_handler *input_table[8]; | ||
| 49 | |||
| 50 | static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 }; | 51 | static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 }; |
| 51 | 52 | ||
| 52 | static inline int is_event_supported(unsigned int code, | 53 | static inline int is_event_supported(unsigned int code, |
| @@ -1218,7 +1219,7 @@ static int input_handlers_seq_show(struct seq_file *seq, void *v) | |||
| 1218 | seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name); | 1219 | seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name); |
| 1219 | if (handler->filter) | 1220 | if (handler->filter) |
| 1220 | seq_puts(seq, " (filter)"); | 1221 | seq_puts(seq, " (filter)"); |
| 1221 | if (handler->fops) | 1222 | if (handler->legacy_minors) |
| 1222 | seq_printf(seq, " Minor=%d", handler->minor); | 1223 | seq_printf(seq, " Minor=%d", handler->minor); |
| 1223 | seq_putc(seq, '\n'); | 1224 | seq_putc(seq, '\n'); |
| 1224 | 1225 | ||
| @@ -2016,22 +2017,14 @@ EXPORT_SYMBOL(input_unregister_device); | |||
| 2016 | int input_register_handler(struct input_handler *handler) | 2017 | int input_register_handler(struct input_handler *handler) |
| 2017 | { | 2018 | { |
| 2018 | struct input_dev *dev; | 2019 | struct input_dev *dev; |
| 2019 | int retval; | 2020 | int error; |
| 2020 | 2021 | ||
| 2021 | retval = mutex_lock_interruptible(&input_mutex); | 2022 | error = mutex_lock_interruptible(&input_mutex); |
| 2022 | if (retval) | 2023 | if (error) |
| 2023 | return retval; | 2024 | return error; |
| 2024 | 2025 | ||
| 2025 | INIT_LIST_HEAD(&handler->h_list); | 2026 | INIT_LIST_HEAD(&handler->h_list); |
| 2026 | 2027 | ||
| 2027 | if (handler->fops != NULL) { | ||
| 2028 | if (input_table[handler->minor >> 5]) { | ||
| 2029 | retval = -EBUSY; | ||
| 2030 | goto out; | ||
| 2031 | } | ||
| 2032 | input_table[handler->minor >> 5] = handler; | ||
| 2033 | } | ||
| 2034 | |||
| 2035 | list_add_tail(&handler->node, &input_handler_list); | 2028 | list_add_tail(&handler->node, &input_handler_list); |
| 2036 | 2029 | ||
| 2037 | list_for_each_entry(dev, &input_dev_list, node) | 2030 | list_for_each_entry(dev, &input_dev_list, node) |
| @@ -2039,9 +2032,8 @@ int input_register_handler(struct input_handler *handler) | |||
| 2039 | 2032 | ||
| 2040 | input_wakeup_procfs_readers(); | 2033 | input_wakeup_procfs_readers(); |
| 2041 | 2034 | ||
| 2042 | out: | ||
| 2043 | mutex_unlock(&input_mutex); | 2035 | mutex_unlock(&input_mutex); |
| 2044 | return retval; | 2036 | return 0; |
| 2045 | } | 2037 | } |
| 2046 | EXPORT_SYMBOL(input_register_handler); | 2038 | EXPORT_SYMBOL(input_register_handler); |
| 2047 | 2039 | ||
| @@ -2064,9 +2056,6 @@ void input_unregister_handler(struct input_handler *handler) | |||
| 2064 | 2056 | ||
| 2065 | list_del_init(&handler->node); | 2057 | list_del_init(&handler->node); |
| 2066 | 2058 | ||
| 2067 | if (handler->fops != NULL) | ||
| 2068 | input_table[handler->minor >> 5] = NULL; | ||
| 2069 | |||
| 2070 | input_wakeup_procfs_readers(); | 2059 | input_wakeup_procfs_readers(); |
| 2071 | 2060 | ||
| 2072 | mutex_unlock(&input_mutex); | 2061 | mutex_unlock(&input_mutex); |
| @@ -2183,51 +2172,52 @@ void input_unregister_handle(struct input_handle *handle) | |||
| 2183 | } | 2172 | } |
| 2184 | EXPORT_SYMBOL(input_unregister_handle); | 2173 | EXPORT_SYMBOL(input_unregister_handle); |
| 2185 | 2174 | ||
| 2186 | static int input_open_file(struct inode *inode, struct file *file) | 2175 | /** |
| 2176 | * input_get_new_minor - allocates a new input minor number | ||
| 2177 | * @legacy_base: beginning or the legacy range to be searched | ||
| 2178 | * @legacy_num: size of legacy range | ||
| 2179 | * @allow_dynamic: whether we can also take ID from the dynamic range | ||
| 2180 | * | ||
| 2181 | * This function allocates a new device minor for from input major namespace. | ||
| 2182 | * Caller can request legacy minor by specifying @legacy_base and @legacy_num | ||
| 2183 | * parameters and whether ID can be allocated from dynamic range if there are | ||
| 2184 | * no free IDs in legacy range. | ||
| 2185 | */ | ||
| 2186 | int input_get_new_minor(int legacy_base, unsigned int legacy_num, | ||
| 2187 | bool allow_dynamic) | ||
| 2187 | { | 2188 | { |
| 2188 | struct input_handler *handler; | ||
| 2189 | const struct file_operations *old_fops, *new_fops = NULL; | ||
| 2190 | int err; | ||
| 2191 | |||
| 2192 | err = mutex_lock_interruptible(&input_mutex); | ||
| 2193 | if (err) | ||
| 2194 | return err; | ||
| 2195 | |||
| 2196 | /* No load-on-demand here? */ | ||
| 2197 | handler = input_table[iminor(inode) >> 5]; | ||
| 2198 | if (handler) | ||
| 2199 | new_fops = fops_get(handler->fops); | ||
| 2200 | |||
| 2201 | mutex_unlock(&input_mutex); | ||
| 2202 | |||
| 2203 | /* | 2189 | /* |
| 2204 | * That's _really_ odd. Usually NULL ->open means "nothing special", | 2190 | * This function should be called from input handler's ->connect() |
| 2205 | * not "no device". Oh, well... | 2191 | * methods, which are serialized with input_mutex, so no additional |
| 2192 | * locking is needed here. | ||
| 2206 | */ | 2193 | */ |
| 2207 | if (!new_fops || !new_fops->open) { | 2194 | if (legacy_base >= 0) { |
| 2208 | fops_put(new_fops); | 2195 | int minor = ida_simple_get(&input_ida, |
| 2209 | err = -ENODEV; | 2196 | legacy_base, |
| 2210 | goto out; | 2197 | legacy_base + legacy_num, |
| 2198 | GFP_KERNEL); | ||
| 2199 | if (minor >= 0 || !allow_dynamic) | ||
| 2200 | return minor; | ||
| 2211 | } | 2201 | } |
| 2212 | 2202 | ||
| 2213 | old_fops = file->f_op; | 2203 | return ida_simple_get(&input_ida, |
| 2214 | file->f_op = new_fops; | 2204 | INPUT_FIRST_DYNAMIC_DEV, INPUT_MAX_CHAR_DEVICES, |
| 2215 | 2205 | GFP_KERNEL); | |
| 2216 | err = new_fops->open(inode, file); | ||
| 2217 | if (err) { | ||
| 2218 | fops_put(file->f_op); | ||
| 2219 | file->f_op = fops_get(old_fops); | ||
| 2220 | } | ||
| 2221 | fops_put(old_fops); | ||
| 2222 | out: | ||
| 2223 | return err; | ||
| 2224 | } | 2206 | } |
| 2207 | EXPORT_SYMBOL(input_get_new_minor); | ||
| 2225 | 2208 | ||
| 2226 | static const struct file_operations input_fops = { | 2209 | /** |
| 2227 | .owner = THIS_MODULE, | 2210 | * input_free_minor - release previously allocated minor |
| 2228 | .open = input_open_file, | 2211 | * @minor: minor to be released |
| 2229 | .llseek = noop_llseek, | 2212 | * |
| 2230 | }; | 2213 | * This function releases previously allocated input minor so that it can be |
| 2214 | * reused later. | ||
| 2215 | */ | ||
| 2216 | void input_free_minor(unsigned int minor) | ||
| 2217 | { | ||
| 2218 | ida_simple_remove(&input_ida, minor); | ||
| 2219 | } | ||
| 2220 | EXPORT_SYMBOL(input_free_minor); | ||
| 2231 | 2221 | ||
| 2232 | static int __init input_init(void) | 2222 | static int __init input_init(void) |
| 2233 | { | 2223 | { |
| @@ -2243,7 +2233,8 @@ static int __init input_init(void) | |||
| 2243 | if (err) | 2233 | if (err) |
| 2244 | goto fail1; | 2234 | goto fail1; |
| 2245 | 2235 | ||
| 2246 | err = register_chrdev(INPUT_MAJOR, "input", &input_fops); | 2236 | err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0), |
| 2237 | INPUT_MAX_CHAR_DEVICES, "input"); | ||
| 2247 | if (err) { | 2238 | if (err) { |
| 2248 | pr_err("unable to register char major %d", INPUT_MAJOR); | 2239 | pr_err("unable to register char major %d", INPUT_MAJOR); |
| 2249 | goto fail2; | 2240 | goto fail2; |
| @@ -2259,7 +2250,8 @@ static int __init input_init(void) | |||
| 2259 | static void __exit input_exit(void) | 2250 | static void __exit input_exit(void) |
| 2260 | { | 2251 | { |
| 2261 | input_proc_exit(); | 2252 | input_proc_exit(); |
| 2262 | unregister_chrdev(INPUT_MAJOR, "input"); | 2253 | unregister_chrdev_region(MKDEV(INPUT_MAJOR, 0), |
| 2254 | INPUT_MAX_CHAR_DEVICES); | ||
| 2263 | class_unregister(&input_class); | 2255 | class_unregister(&input_class); |
| 2264 | } | 2256 | } |
| 2265 | 2257 | ||
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, |
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 88b962aeef13..a1b4c37956b2 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/random.h> | 24 | #include <linux/random.h> |
| 25 | #include <linux/major.h> | 25 | #include <linux/major.h> |
| 26 | #include <linux/device.h> | 26 | #include <linux/device.h> |
| 27 | #include <linux/cdev.h> | ||
| 27 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
| 28 | 29 | ||
| 29 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 30 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
| @@ -58,14 +59,15 @@ struct mousedev_hw_data { | |||
| 58 | 59 | ||
| 59 | struct mousedev { | 60 | struct mousedev { |
| 60 | int open; | 61 | int open; |
| 61 | int minor; | ||
| 62 | struct input_handle handle; | 62 | struct input_handle handle; |
| 63 | wait_queue_head_t wait; | 63 | wait_queue_head_t wait; |
| 64 | struct list_head client_list; | 64 | struct list_head client_list; |
| 65 | spinlock_t client_lock; /* protects client_list */ | 65 | spinlock_t client_lock; /* protects client_list */ |
| 66 | struct mutex mutex; | 66 | struct mutex mutex; |
| 67 | struct device dev; | 67 | struct device dev; |
| 68 | struct cdev cdev; | ||
| 68 | bool exist; | 69 | bool exist; |
| 70 | bool is_mixdev; | ||
| 69 | 71 | ||
| 70 | struct list_head mixdev_node; | 72 | struct list_head mixdev_node; |
| 71 | bool opened_by_mixdev; | 73 | bool opened_by_mixdev; |
| @@ -111,10 +113,6 @@ struct mousedev_client { | |||
| 111 | static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 }; | 113 | static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 }; |
| 112 | static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 }; | 114 | static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 }; |
| 113 | 115 | ||
| 114 | static struct input_handler mousedev_handler; | ||
| 115 | |||
| 116 | static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; | ||
| 117 | static DEFINE_MUTEX(mousedev_table_mutex); | ||
| 118 | static struct mousedev *mousedev_mix; | 116 | static struct mousedev *mousedev_mix; |
| 119 | static LIST_HEAD(mousedev_mix_list); | 117 | static LIST_HEAD(mousedev_mix_list); |
| 120 | 118 | ||
| @@ -430,7 +428,7 @@ static int mousedev_open_device(struct mousedev *mousedev) | |||
| 430 | if (retval) | 428 | if (retval) |
| 431 | return retval; | 429 | return retval; |
| 432 | 430 | ||
| 433 | if (mousedev->minor == MOUSEDEV_MIX) | 431 | if (mousedev->is_mixdev) |
| 434 | mixdev_open_devices(); | 432 | mixdev_open_devices(); |
| 435 | else if (!mousedev->exist) | 433 | else if (!mousedev->exist) |
| 436 | retval = -ENODEV; | 434 | retval = -ENODEV; |
| @@ -448,7 +446,7 @@ static void mousedev_close_device(struct mousedev *mousedev) | |||
| 448 | { | 446 | { |
| 449 | mutex_lock(&mousedev->mutex); | 447 | mutex_lock(&mousedev->mutex); |
| 450 | 448 | ||
| 451 | if (mousedev->minor == MOUSEDEV_MIX) | 449 | if (mousedev->is_mixdev) |
| 452 | mixdev_close_devices(); | 450 | mixdev_close_devices(); |
| 453 | else if (mousedev->exist && !--mousedev->open) | 451 | else if (mousedev->exist && !--mousedev->open) |
| 454 | input_close_device(&mousedev->handle); | 452 | input_close_device(&mousedev->handle); |
| @@ -535,35 +533,17 @@ static int mousedev_open(struct inode *inode, struct file *file) | |||
| 535 | struct mousedev_client *client; | 533 | struct mousedev_client *client; |
| 536 | struct mousedev *mousedev; | 534 | struct mousedev *mousedev; |
| 537 | int error; | 535 | int error; |
| 538 | int i; | ||
| 539 | 536 | ||
| 540 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | 537 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX |
| 541 | if (imajor(inode) == MISC_MAJOR) | 538 | if (imajor(inode) == MISC_MAJOR) |
| 542 | i = MOUSEDEV_MIX; | 539 | mousedev = mousedev_mix; |
| 543 | else | 540 | else |
| 544 | #endif | 541 | #endif |
| 545 | i = iminor(inode) - MOUSEDEV_MINOR_BASE; | 542 | mousedev = container_of(inode->i_cdev, struct mousedev, cdev); |
| 546 | |||
| 547 | if (i >= MOUSEDEV_MINORS) | ||
| 548 | return -ENODEV; | ||
| 549 | |||
| 550 | error = mutex_lock_interruptible(&mousedev_table_mutex); | ||
| 551 | if (error) | ||
| 552 | return error; | ||
| 553 | |||
| 554 | mousedev = mousedev_table[i]; | ||
| 555 | if (mousedev) | ||
| 556 | get_device(&mousedev->dev); | ||
| 557 | mutex_unlock(&mousedev_table_mutex); | ||
| 558 | |||
| 559 | if (!mousedev) | ||
| 560 | return -ENODEV; | ||
| 561 | 543 | ||
| 562 | client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); | 544 | client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); |
| 563 | if (!client) { | 545 | if (!client) |
| 564 | error = -ENOMEM; | 546 | return -ENOMEM; |
| 565 | goto err_put_mousedev; | ||
| 566 | } | ||
| 567 | 547 | ||
| 568 | spin_lock_init(&client->packet_lock); | 548 | spin_lock_init(&client->packet_lock); |
| 569 | client->pos_x = xres / 2; | 549 | client->pos_x = xres / 2; |
| @@ -577,13 +557,13 @@ static int mousedev_open(struct inode *inode, struct file *file) | |||
| 577 | 557 | ||
| 578 | file->private_data = client; | 558 | file->private_data = client; |
| 579 | nonseekable_open(inode, file); | 559 | nonseekable_open(inode, file); |
| 560 | |||
| 561 | get_device(&mousedev->dev); | ||
| 580 | return 0; | 562 | return 0; |
| 581 | 563 | ||
| 582 | err_free_client: | 564 | err_free_client: |
| 583 | mousedev_detach_client(mousedev, client); | 565 | mousedev_detach_client(mousedev, client); |
| 584 | kfree(client); | 566 | kfree(client); |
| 585 | err_put_mousedev: | ||
| 586 | put_device(&mousedev->dev); | ||
| 587 | return error; | 567 | return error; |
| 588 | } | 568 | } |
| 589 | 569 | ||
| @@ -793,19 +773,6 @@ static const struct file_operations mousedev_fops = { | |||
| 793 | .llseek = noop_llseek, | 773 | .llseek = noop_llseek, |
| 794 | }; | 774 | }; |
| 795 | 775 | ||
| 796 | static int mousedev_install_chrdev(struct mousedev *mousedev) | ||
| 797 | { | ||
| 798 | mousedev_table[mousedev->minor] = mousedev; | ||
| 799 | return 0; | ||
| 800 | } | ||
| 801 | |||
| 802 | static void mousedev_remove_chrdev(struct mousedev *mousedev) | ||
| 803 | { | ||
| 804 | mutex_lock(&mousedev_table_mutex); | ||
| 805 | mousedev_table[mousedev->minor] = NULL; | ||
| 806 | mutex_unlock(&mousedev_table_mutex); | ||
| 807 | } | ||
| 808 | |||
| 809 | /* | 776 | /* |
| 810 | * Mark device non-existent. This disables writes, ioctls and | 777 | * Mark device non-existent. This disables writes, ioctls and |
| 811 | * prevents new users from opening the device. Already posted | 778 | * prevents new users from opening the device. Already posted |
| @@ -840,24 +807,50 @@ static void mousedev_cleanup(struct mousedev *mousedev) | |||
| 840 | 807 | ||
| 841 | mousedev_mark_dead(mousedev); | 808 | mousedev_mark_dead(mousedev); |
| 842 | mousedev_hangup(mousedev); | 809 | mousedev_hangup(mousedev); |
| 843 | mousedev_remove_chrdev(mousedev); | 810 | |
| 811 | cdev_del(&mousedev->cdev); | ||
| 844 | 812 | ||
| 845 | /* mousedev is marked dead so no one else accesses mousedev->open */ | 813 | /* mousedev is marked dead so no one else accesses mousedev->open */ |
| 846 | if (mousedev->open) | 814 | if (mousedev->open) |
| 847 | input_close_device(handle); | 815 | input_close_device(handle); |
| 848 | } | 816 | } |
| 849 | 817 | ||
| 818 | static int mousedev_reserve_minor(bool mixdev) | ||
| 819 | { | ||
| 820 | int minor; | ||
| 821 | |||
| 822 | if (mixdev) { | ||
| 823 | minor = input_get_new_minor(MOUSEDEV_MIX, 1, false); | ||
| 824 | if (minor < 0) | ||
| 825 | pr_err("failed to reserve mixdev minor: %d\n", minor); | ||
| 826 | } else { | ||
| 827 | minor = input_get_new_minor(MOUSEDEV_MINOR_BASE, | ||
| 828 | MOUSEDEV_MINORS, true); | ||
| 829 | if (minor < 0) | ||
| 830 | pr_err("failed to reserve new minor: %d\n", minor); | ||
| 831 | } | ||
| 832 | |||
| 833 | return minor; | ||
| 834 | } | ||
| 835 | |||
| 850 | static struct mousedev *mousedev_create(struct input_dev *dev, | 836 | static struct mousedev *mousedev_create(struct input_dev *dev, |
| 851 | struct input_handler *handler, | 837 | struct input_handler *handler, |
| 852 | int minor) | 838 | bool mixdev) |
| 853 | { | 839 | { |
| 854 | struct mousedev *mousedev; | 840 | struct mousedev *mousedev; |
| 841 | int minor; | ||
| 855 | int error; | 842 | int error; |
| 856 | 843 | ||
| 844 | minor = mousedev_reserve_minor(mixdev); | ||
| 845 | if (minor < 0) { | ||
| 846 | error = minor; | ||
| 847 | goto err_out; | ||
| 848 | } | ||
| 849 | |||
| 857 | mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL); | 850 | mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL); |
| 858 | if (!mousedev) { | 851 | if (!mousedev) { |
| 859 | error = -ENOMEM; | 852 | error = -ENOMEM; |
| 860 | goto err_out; | 853 | goto err_free_minor; |
| 861 | } | 854 | } |
| 862 | 855 | ||
| 863 | INIT_LIST_HEAD(&mousedev->client_list); | 856 | INIT_LIST_HEAD(&mousedev->client_list); |
| @@ -865,16 +858,21 @@ static struct mousedev *mousedev_create(struct input_dev *dev, | |||
| 865 | spin_lock_init(&mousedev->client_lock); | 858 | spin_lock_init(&mousedev->client_lock); |
| 866 | mutex_init(&mousedev->mutex); | 859 | mutex_init(&mousedev->mutex); |
| 867 | lockdep_set_subclass(&mousedev->mutex, | 860 | lockdep_set_subclass(&mousedev->mutex, |
| 868 | minor == MOUSEDEV_MIX ? SINGLE_DEPTH_NESTING : 0); | 861 | mixdev ? SINGLE_DEPTH_NESTING : 0); |
| 869 | init_waitqueue_head(&mousedev->wait); | 862 | init_waitqueue_head(&mousedev->wait); |
| 870 | 863 | ||
| 871 | if (minor == MOUSEDEV_MIX) | 864 | if (mixdev) { |
| 872 | dev_set_name(&mousedev->dev, "mice"); | 865 | dev_set_name(&mousedev->dev, "mice"); |
| 873 | else | 866 | } else { |
| 874 | dev_set_name(&mousedev->dev, "mouse%d", minor); | 867 | int dev_no = minor; |
| 868 | /* Normalize device number if it falls into legacy range */ | ||
| 869 | if (dev_no < MOUSEDEV_MINOR_BASE + MOUSEDEV_MINORS) | ||
| 870 | dev_no -= MOUSEDEV_MINOR_BASE; | ||
| 871 | dev_set_name(&mousedev->dev, "mouse%d", dev_no); | ||
| 872 | } | ||
| 875 | 873 | ||
| 876 | mousedev->minor = minor; | ||
| 877 | mousedev->exist = true; | 874 | mousedev->exist = true; |
| 875 | mousedev->is_mixdev = mixdev; | ||
| 878 | mousedev->handle.dev = input_get_device(dev); | 876 | mousedev->handle.dev = input_get_device(dev); |
| 879 | mousedev->handle.name = dev_name(&mousedev->dev); | 877 | mousedev->handle.name = dev_name(&mousedev->dev); |
| 880 | mousedev->handle.handler = handler; | 878 | mousedev->handle.handler = handler; |
| @@ -883,17 +881,18 @@ static struct mousedev *mousedev_create(struct input_dev *dev, | |||
| 883 | mousedev->dev.class = &input_class; | 881 | mousedev->dev.class = &input_class; |
| 884 | if (dev) | 882 | if (dev) |
| 885 | mousedev->dev.parent = &dev->dev; | 883 | mousedev->dev.parent = &dev->dev; |
| 886 | mousedev->dev.devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor); | 884 | mousedev->dev.devt = MKDEV(INPUT_MAJOR, minor); |
| 887 | mousedev->dev.release = mousedev_free; | 885 | mousedev->dev.release = mousedev_free; |
| 888 | device_initialize(&mousedev->dev); | 886 | device_initialize(&mousedev->dev); |
| 889 | 887 | ||
| 890 | if (minor != MOUSEDEV_MIX) { | 888 | if (!mixdev) { |
| 891 | error = input_register_handle(&mousedev->handle); | 889 | error = input_register_handle(&mousedev->handle); |
| 892 | if (error) | 890 | if (error) |
| 893 | goto err_free_mousedev; | 891 | goto err_free_mousedev; |
| 894 | } | 892 | } |
| 895 | 893 | ||
| 896 | error = mousedev_install_chrdev(mousedev); | 894 | cdev_init(&mousedev->cdev, &mousedev_fops); |
| 895 | error = cdev_add(&mousedev->cdev, mousedev->dev.devt, 1); | ||
| 897 | if (error) | 896 | if (error) |
| 898 | goto err_unregister_handle; | 897 | goto err_unregister_handle; |
| 899 | 898 | ||
| @@ -906,10 +905,12 @@ static struct mousedev *mousedev_create(struct input_dev *dev, | |||
| 906 | err_cleanup_mousedev: | 905 | err_cleanup_mousedev: |
| 907 | mousedev_cleanup(mousedev); | 906 | mousedev_cleanup(mousedev); |
| 908 | err_unregister_handle: | 907 | err_unregister_handle: |
| 909 | if (minor != MOUSEDEV_MIX) | 908 | if (!mixdev) |
| 910 | input_unregister_handle(&mousedev->handle); | 909 | input_unregister_handle(&mousedev->handle); |
| 911 | err_free_mousedev: | 910 | err_free_mousedev: |
| 912 | put_device(&mousedev->dev); | 911 | put_device(&mousedev->dev); |
| 912 | err_free_minor: | ||
| 913 | input_free_minor(minor); | ||
| 913 | err_out: | 914 | err_out: |
| 914 | return ERR_PTR(error); | 915 | return ERR_PTR(error); |
| 915 | } | 916 | } |
| @@ -918,7 +919,8 @@ static void mousedev_destroy(struct mousedev *mousedev) | |||
| 918 | { | 919 | { |
| 919 | device_del(&mousedev->dev); | 920 | device_del(&mousedev->dev); |
| 920 | mousedev_cleanup(mousedev); | 921 | mousedev_cleanup(mousedev); |
| 921 | if (mousedev->minor != MOUSEDEV_MIX) | 922 | input_free_minor(MINOR(mousedev->dev.devt)); |
| 923 | if (!mousedev->is_mixdev) | ||
| 922 | input_unregister_handle(&mousedev->handle); | 924 | input_unregister_handle(&mousedev->handle); |
| 923 | put_device(&mousedev->dev); | 925 | put_device(&mousedev->dev); |
| 924 | } | 926 | } |
| @@ -967,19 +969,9 @@ static int mousedev_connect(struct input_handler *handler, | |||
| 967 | const struct input_device_id *id) | 969 | const struct input_device_id *id) |
| 968 | { | 970 | { |
| 969 | struct mousedev *mousedev; | 971 | struct mousedev *mousedev; |
| 970 | int minor; | ||
| 971 | int error; | 972 | int error; |
| 972 | 973 | ||
| 973 | for (minor = 0; minor < MOUSEDEV_MINORS; minor++) | 974 | mousedev = mousedev_create(dev, handler, false); |
| 974 | if (!mousedev_table[minor]) | ||
| 975 | break; | ||
| 976 | |||
| 977 | if (minor == MOUSEDEV_MINORS) { | ||
| 978 | pr_err("no more free mousedev devices\n"); | ||
| 979 | return -ENFILE; | ||
| 980 | } | ||
| 981 | |||
| 982 | mousedev = mousedev_create(dev, handler, minor); | ||
| 983 | if (IS_ERR(mousedev)) | 975 | if (IS_ERR(mousedev)) |
| 984 | return PTR_ERR(mousedev); | 976 | return PTR_ERR(mousedev); |
| 985 | 977 | ||
| @@ -1055,7 +1047,7 @@ static struct input_handler mousedev_handler = { | |||
| 1055 | .event = mousedev_event, | 1047 | .event = mousedev_event, |
| 1056 | .connect = mousedev_connect, | 1048 | .connect = mousedev_connect, |
| 1057 | .disconnect = mousedev_disconnect, | 1049 | .disconnect = mousedev_disconnect, |
| 1058 | .fops = &mousedev_fops, | 1050 | .legacy_minors = true, |
| 1059 | .minor = MOUSEDEV_MINOR_BASE, | 1051 | .minor = MOUSEDEV_MINOR_BASE, |
| 1060 | .name = "mousedev", | 1052 | .name = "mousedev", |
| 1061 | .id_table = mousedev_ids, | 1053 | .id_table = mousedev_ids, |
| @@ -1098,7 +1090,7 @@ static int __init mousedev_init(void) | |||
| 1098 | { | 1090 | { |
| 1099 | int error; | 1091 | int error; |
| 1100 | 1092 | ||
| 1101 | mousedev_mix = mousedev_create(NULL, &mousedev_handler, MOUSEDEV_MIX); | 1093 | mousedev_mix = mousedev_create(NULL, &mousedev_handler, true); |
| 1102 | if (IS_ERR(mousedev_mix)) | 1094 | if (IS_ERR(mousedev_mix)) |
| 1103 | return PTR_ERR(mousedev_mix); | 1095 | return PTR_ERR(mousedev_mix); |
| 1104 | 1096 | ||
diff --git a/include/linux/input.h b/include/linux/input.h index ba4874302939..15464ba6bf53 100644 --- a/include/linux/input.h +++ b/include/linux/input.h | |||
| @@ -1396,8 +1396,8 @@ struct input_handle; | |||
| 1396 | * @start: starts handler for given handle. This function is called by | 1396 | * @start: starts handler for given handle. This function is called by |
| 1397 | * input core right after connect() method and also when a process | 1397 | * input core right after connect() method and also when a process |
| 1398 | * that "grabbed" a device releases it | 1398 | * that "grabbed" a device releases it |
| 1399 | * @fops: file operations this driver implements | 1399 | * @legacy_minors: set to %true by drivers using legacy minor ranges |
| 1400 | * @minor: beginning of range of 32 minors for devices this driver | 1400 | * @minor: beginning of range of 32 legacy minors for devices this driver |
| 1401 | * can provide | 1401 | * can provide |
| 1402 | * @name: name of the handler, to be shown in /proc/bus/input/handlers | 1402 | * @name: name of the handler, to be shown in /proc/bus/input/handlers |
| 1403 | * @id_table: pointer to a table of input_device_ids this driver can | 1403 | * @id_table: pointer to a table of input_device_ids this driver can |
| @@ -1431,7 +1431,7 @@ struct input_handler { | |||
| 1431 | void (*disconnect)(struct input_handle *handle); | 1431 | void (*disconnect)(struct input_handle *handle); |
| 1432 | void (*start)(struct input_handle *handle); | 1432 | void (*start)(struct input_handle *handle); |
| 1433 | 1433 | ||
| 1434 | const struct file_operations *fops; | 1434 | bool legacy_minors; |
| 1435 | int minor; | 1435 | int minor; |
| 1436 | const char *name; | 1436 | const char *name; |
| 1437 | 1437 | ||
| @@ -1499,6 +1499,10 @@ void input_reset_device(struct input_dev *); | |||
| 1499 | int __must_check input_register_handler(struct input_handler *); | 1499 | int __must_check input_register_handler(struct input_handler *); |
| 1500 | void input_unregister_handler(struct input_handler *); | 1500 | void input_unregister_handler(struct input_handler *); |
| 1501 | 1501 | ||
| 1502 | int __must_check input_get_new_minor(int legacy_base, unsigned int legacy_num, | ||
| 1503 | bool allow_dynamic); | ||
| 1504 | void input_free_minor(unsigned int minor); | ||
| 1505 | |||
| 1502 | int input_handler_for_each_handle(struct input_handler *, void *data, | 1506 | int input_handler_for_each_handle(struct input_handler *, void *data, |
| 1503 | int (*fn)(struct input_handle *, void *)); | 1507 | int (*fn)(struct input_handle *, void *)); |
| 1504 | 1508 | ||
