Input: do not pass injected events back to the originating handler
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Tue, 9 Nov 2010 05:51:25 +0000 (21:51 -0800)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Thu, 11 Nov 2010 09:01:26 +0000 (01:01 -0800)
Sometimes input handlers (as opposed to input devices) have a need to
inject (or re-inject) events back into input core. For example sysrq
filter may want to inject previously suppressed Alt-SysRq so that user
can take a screen print. In this case we do not want to pass such events
back to the same same handler that injected them to avoid loops.

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
drivers/input/input.c

index 75bed63..7f26ca6 100644 (file)
@@ -74,6 +74,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 +93,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 +131,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 +140,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 +173,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 +217,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 +278,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 +337,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 +366,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 +396,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 +610,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);
        }
 }
 
@@ -873,9 +888,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: