diff options
Diffstat (limited to 'drivers/input/input.c')
-rw-r--r-- | drivers/input/input.c | 192 |
1 files changed, 134 insertions, 58 deletions
diff --git a/drivers/input/input.c b/drivers/input/input.c index e2aad0a5182..e1243b4b32a 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -14,6 +14,7 @@ #include <linux/types.h> #include <linux/input.h> #include <linux/module.h> +#include <linux/slab.h> #include <linux/random.h> #include <linux/major.h> #include <linux/proc_fs.h> @@ -32,25 +33,6 @@ MODULE_LICENSE("GPL"); #define INPUT_DEVICES 256 -/* - * EV_ABS events which should not be cached are listed here. - */ -static unsigned int input_abs_bypass_init_data[] __initdata = { - ABS_MT_TOUCH_MAJOR, - ABS_MT_TOUCH_MINOR, - ABS_MT_WIDTH_MAJOR, - ABS_MT_WIDTH_MINOR, - ABS_MT_ORIENTATION, - ABS_MT_POSITION_X, - ABS_MT_POSITION_Y, - ABS_MT_TOOL_TYPE, - ABS_MT_BLOB_ID, - ABS_MT_TRACKING_ID, - ABS_MT_PRESSURE, - 0 -}; -static unsigned long input_abs_bypass[BITS_TO_LONGS(ABS_CNT)]; - static LIST_HEAD(input_dev_list); static LIST_HEAD(input_handler_list); @@ -180,6 +162,56 @@ static void input_stop_autorepeat(struct input_dev *dev) #define INPUT_PASS_TO_DEVICE 2 #define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE) +static int input_handle_abs_event(struct input_dev *dev, + unsigned int code, int *pval) +{ + bool is_mt_event; + int *pold; + + if (code == ABS_MT_SLOT) { + /* + * "Stage" the event; we'll flush it later, when we + * get actiual touch data. + */ + if (*pval >= 0 && *pval < dev->mtsize) + dev->slot = *pval; + + return INPUT_IGNORE_EVENT; + } + + is_mt_event = code >= ABS_MT_FIRST && code <= ABS_MT_LAST; + + if (!is_mt_event) { + pold = &dev->abs[code]; + } else if (dev->mt) { + struct input_mt_slot *mtslot = &dev->mt[dev->slot]; + pold = &mtslot->abs[code - ABS_MT_FIRST]; + } else { + /* + * Bypass filtering for multitouch events when + * not employing slots. + */ + pold = NULL; + } + + if (pold) { + *pval = input_defuzz_abs_event(*pval, *pold, + dev->absfuzz[code]); + if (*pold == *pval) + return INPUT_IGNORE_EVENT; + + *pold = *pval; + } + + /* Flush pending "slot" event */ + if (is_mt_event && dev->slot != dev->abs[ABS_MT_SLOT]) { + dev->abs[ABS_MT_SLOT] = dev->slot; + input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot); + } + + return INPUT_PASS_TO_HANDLERS; +} + static void input_handle_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { @@ -195,12 +227,12 @@ static void input_handle_event(struct input_dev *dev, case SYN_REPORT: if (!dev->sync) { - dev->sync = 1; + dev->sync = true; disposition = INPUT_PASS_TO_HANDLERS; } break; case SYN_MT_REPORT: - dev->sync = 0; + dev->sync = false; disposition = INPUT_PASS_TO_HANDLERS; break; } @@ -232,21 +264,9 @@ static void input_handle_event(struct input_dev *dev, break; case EV_ABS: - if (is_event_supported(code, dev->absbit, ABS_MAX)) { - - if (test_bit(code, input_abs_bypass)) { - disposition = INPUT_PASS_TO_HANDLERS; - break; - } - - value = input_defuzz_abs_event(value, - dev->abs[code], dev->absfuzz[code]); + if (is_event_supported(code, dev->absbit, ABS_MAX)) + disposition = input_handle_abs_event(dev, code, &value); - if (dev->abs[code] != value) { - dev->abs[code] = value; - disposition = INPUT_PASS_TO_HANDLERS; - } - } break; case EV_REL: @@ -297,7 +317,7 @@ static void input_handle_event(struct input_dev *dev, } if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN) - dev->sync = 0; + dev->sync = false; if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) dev->event(dev, type, code, value); @@ -527,12 +547,30 @@ void input_close_device(struct input_handle *handle) EXPORT_SYMBOL(input_close_device); /* + * Simulate keyup events for all keys that are marked as pressed. + * The function must be called with dev->event_lock held. + */ +static void input_dev_release_keys(struct input_dev *dev) +{ + int code; + + if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) { + for (code = 0; code <= KEY_MAX; code++) { + if (is_event_supported(code, dev->keybit, KEY_MAX) && + __test_and_clear_bit(code, dev->key)) { + input_pass_event(dev, EV_KEY, code, 0); + } + } + input_pass_event(dev, EV_SYN, SYN_REPORT, 1); + } +} + +/* * Prepare device for unregistering */ static void input_disconnect_device(struct input_dev *dev) { struct input_handle *handle; - int code; /* * Mark device as going away. Note that we take dev->mutex here @@ -551,15 +589,7 @@ static void input_disconnect_device(struct input_dev *dev) * generate events even after we done here but they will not * reach any handlers. */ - if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) { - for (code = 0; code <= KEY_MAX; code++) { - if (is_event_supported(code, dev->keybit, KEY_MAX) && - __test_and_clear_bit(code, dev->key)) { - input_pass_event(dev, EV_KEY, code, 0); - } - } - input_pass_event(dev, EV_SYN, SYN_REPORT, 1); - } + input_dev_release_keys(dev); list_for_each_entry(handle, &dev->h_list, d_node) handle->open = 0; @@ -659,7 +689,14 @@ static int input_default_setkeycode(struct input_dev *dev, int input_get_keycode(struct input_dev *dev, unsigned int scancode, unsigned int *keycode) { - return dev->getkeycode(dev, scancode, keycode); + unsigned long flags; + int retval; + + spin_lock_irqsave(&dev->event_lock, flags); + retval = dev->getkeycode(dev, scancode, keycode); + spin_unlock_irqrestore(&dev->event_lock, flags); + + return retval; } EXPORT_SYMBOL(input_get_keycode); @@ -676,7 +713,7 @@ int input_set_keycode(struct input_dev *dev, unsigned int scancode, unsigned int keycode) { unsigned long flags; - int old_keycode; + unsigned int old_keycode; int retval; if (keycode > KEY_MAX) @@ -1270,6 +1307,7 @@ static void input_dev_release(struct device *device) struct input_dev *dev = to_input_dev(device); input_ff_destroy(dev); + input_mt_destroy_slots(dev); kfree(dev); module_put(THIS_MODULE); @@ -1425,6 +1463,15 @@ static int input_dev_resume(struct device *dev) mutex_lock(&input_dev->mutex); input_dev_reset(input_dev, true); + + /* + * Keys that have been pressed at suspend time are unlikely + * to be still pressed when we resume. + */ + spin_lock_irq(&input_dev->event_lock); + input_dev_release_keys(input_dev); + spin_unlock_irq(&input_dev->event_lock); + mutex_unlock(&input_dev->mutex); return 0; @@ -1510,6 +1557,45 @@ void input_free_device(struct input_dev *dev) EXPORT_SYMBOL(input_free_device); /** + * input_mt_create_slots() - create MT input slots + * @dev: input device supporting MT events and finger tracking + * @num_slots: number of slots used by the device + * + * This function allocates all necessary memory for MT slot handling + * in the input device, and adds ABS_MT_SLOT to the device capabilities. + */ +int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots) +{ + if (!num_slots) + return 0; + + dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL); + if (!dev->mt) + return -ENOMEM; + + dev->mtsize = num_slots; + input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0); + + return 0; +} +EXPORT_SYMBOL(input_mt_create_slots); + +/** + * input_mt_destroy_slots() - frees the MT slots of the input device + * @dev: input device with allocated MT slots + * + * This function is only needed in error path as the input core will + * automatically free the MT slots when the device is destroyed. + */ +void input_mt_destroy_slots(struct input_dev *dev) +{ + kfree(dev->mt); + dev->mt = NULL; + dev->mtsize = 0; +} +EXPORT_SYMBOL(input_mt_destroy_slots); + +/** * input_set_capability - mark device as capable of a certain event * @dev: device that is capable of emitting or accepting event * @type: type of the event (EV_KEY, EV_REL, etc...) @@ -1918,20 +2004,10 @@ static const struct file_operations input_fops = { .open = input_open_file, }; -static void __init input_init_abs_bypass(void) -{ - const unsigned int *p; - - for (p = input_abs_bypass_init_data; *p; p++) - input_abs_bypass[BIT_WORD(*p)] |= BIT_MASK(*p); -} - static int __init input_init(void) { int err; - input_init_abs_bypass(); - err = class_register(&input_class); if (err) { printk(KERN_ERR "input: unable to register input_dev class\n"); |