diff options
Diffstat (limited to 'drivers/input/input.c')
| -rw-r--r-- | drivers/input/input.c | 114 |
1 files changed, 53 insertions, 61 deletions
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 | ||
