diff options
Diffstat (limited to 'drivers/input/input.c')
-rw-r--r-- | drivers/input/input.c | 90 |
1 files changed, 62 insertions, 28 deletions
diff --git a/drivers/input/input.c b/drivers/input/input.c index d092ef9291da..db409d6bd5d2 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -24,7 +24,6 @@ #include <linux/device.h> #include <linux/mutex.h> #include <linux/rcupdate.h> -#include <linux/smp_lock.h> #include "input-compat.h" MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); @@ -74,6 +73,7 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz) * dev->event_lock held and interrupts disabled. */ static void input_pass_event(struct input_dev *dev, + struct input_handler *src_handler, unsigned int type, unsigned int code, int value) { struct input_handler *handler; @@ -92,6 +92,15 @@ static void input_pass_event(struct input_dev *dev, continue; handler = handle->handler; + + /* + * If this is the handler that injected this + * particular event we want to skip it to avoid + * filters firing again and again. + */ + if (handler == src_handler) + continue; + if (!handler->filter) { if (filtered) break; @@ -121,7 +130,7 @@ static void input_repeat_key(unsigned long data) if (test_bit(dev->repeat_key, dev->key) && is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) { - input_pass_event(dev, EV_KEY, dev->repeat_key, 2); + input_pass_event(dev, NULL, EV_KEY, dev->repeat_key, 2); if (dev->sync) { /* @@ -130,7 +139,7 @@ static void input_repeat_key(unsigned long data) * Otherwise assume that the driver will send * SYN_REPORT once it's done. */ - input_pass_event(dev, EV_SYN, SYN_REPORT, 1); + input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1); } if (dev->rep[REP_PERIOD]) @@ -163,6 +172,7 @@ static void input_stop_autorepeat(struct input_dev *dev) #define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE) static int input_handle_abs_event(struct input_dev *dev, + struct input_handler *src_handler, unsigned int code, int *pval) { bool is_mt_event; @@ -206,13 +216,15 @@ static int input_handle_abs_event(struct input_dev *dev, /* Flush pending "slot" event */ if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) { input_abs_set_val(dev, ABS_MT_SLOT, dev->slot); - input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot); + input_pass_event(dev, src_handler, + EV_ABS, ABS_MT_SLOT, dev->slot); } return INPUT_PASS_TO_HANDLERS; } static void input_handle_event(struct input_dev *dev, + struct input_handler *src_handler, unsigned int type, unsigned int code, int value) { int disposition = INPUT_IGNORE_EVENT; @@ -265,7 +277,8 @@ static void input_handle_event(struct input_dev *dev, case EV_ABS: if (is_event_supported(code, dev->absbit, ABS_MAX)) - disposition = input_handle_abs_event(dev, code, &value); + disposition = input_handle_abs_event(dev, src_handler, + code, &value); break; @@ -323,7 +336,7 @@ static void input_handle_event(struct input_dev *dev, dev->event(dev, type, code, value); if (disposition & INPUT_PASS_TO_HANDLERS) - input_pass_event(dev, type, code, value); + input_pass_event(dev, src_handler, type, code, value); } /** @@ -352,7 +365,7 @@ void input_event(struct input_dev *dev, spin_lock_irqsave(&dev->event_lock, flags); add_input_randomness(type, code, value); - input_handle_event(dev, type, code, value); + input_handle_event(dev, NULL, type, code, value); spin_unlock_irqrestore(&dev->event_lock, flags); } } @@ -382,7 +395,8 @@ void input_inject_event(struct input_handle *handle, rcu_read_lock(); grab = rcu_dereference(dev->grab); if (!grab || grab == handle) - input_handle_event(dev, type, code, value); + input_handle_event(dev, handle->handler, + type, code, value); rcu_read_unlock(); spin_unlock_irqrestore(&dev->event_lock, flags); @@ -595,10 +609,10 @@ static void input_dev_release_keys(struct input_dev *dev) 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, NULL, EV_KEY, code, 0); } } - input_pass_event(dev, EV_SYN, SYN_REPORT, 1); + input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1); } } @@ -738,7 +752,7 @@ static int input_default_setkeycode(struct input_dev *dev, if (index >= dev->keycodemax) return -EINVAL; - if (dev->keycodesize < sizeof(dev->keycode) && + if (dev->keycodesize < sizeof(ke->keycode) && (ke->keycode >> (dev->keycodesize * 8))) return -EINVAL; @@ -873,9 +887,9 @@ int input_set_keycode(struct input_dev *dev, !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && __test_and_clear_bit(old_keycode, dev->key)) { - input_pass_event(dev, EV_KEY, old_keycode, 0); + input_pass_event(dev, NULL, EV_KEY, old_keycode, 0); if (dev->sync) - input_pass_event(dev, EV_SYN, SYN_REPORT, 1); + input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1); } out: @@ -1565,8 +1579,7 @@ static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env) } \ } while (0) -#ifdef CONFIG_PM -static void input_dev_reset(struct input_dev *dev, bool activate) +static void input_dev_toggle(struct input_dev *dev, bool activate) { if (!dev->event) return; @@ -1580,12 +1593,44 @@ static void input_dev_reset(struct input_dev *dev, bool activate) } } +/** + * input_reset_device() - reset/restore the state of input device + * @dev: input device whose state needs to be reset + * + * This function tries to reset the state of an opened input device and + * bring internal state and state if the hardware in sync with each other. + * We mark all keys as released, restore LED state, repeat rate, etc. + */ +void input_reset_device(struct input_dev *dev) +{ + mutex_lock(&dev->mutex); + + if (dev->users) { + input_dev_toggle(dev, true); + + /* + * Keys that have been pressed at suspend time are unlikely + * to be still pressed when we resume. + */ + spin_lock_irq(&dev->event_lock); + input_dev_release_keys(dev); + spin_unlock_irq(&dev->event_lock); + } + + mutex_unlock(&dev->mutex); +} +EXPORT_SYMBOL(input_reset_device); + +#ifdef CONFIG_PM static int input_dev_suspend(struct device *dev) { struct input_dev *input_dev = to_input_dev(dev); mutex_lock(&input_dev->mutex); - input_dev_reset(input_dev, false); + + if (input_dev->users) + input_dev_toggle(input_dev, false); + mutex_unlock(&input_dev->mutex); return 0; @@ -1595,18 +1640,7 @@ static int input_dev_resume(struct device *dev) { struct input_dev *input_dev = to_input_dev(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); + input_reset_device(input_dev); return 0; } |