diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/input/input.c | 41 |
1 files changed, 34 insertions, 7 deletions
diff --git a/drivers/input/input.c b/drivers/input/input.c index 6c161e220868..7080a9d4b840 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
@@ -86,12 +86,14 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz) | |||
86 | } | 86 | } |
87 | 87 | ||
88 | /* | 88 | /* |
89 | * Pass event through all open handles. This function is called with | 89 | * Pass event first through all filters and then, if event has not been |
90 | * filtered out, through all open handles. This function is called with | ||
90 | * dev->event_lock held and interrupts disabled. | 91 | * dev->event_lock held and interrupts disabled. |
91 | */ | 92 | */ |
92 | static void input_pass_event(struct input_dev *dev, | 93 | static void input_pass_event(struct input_dev *dev, |
93 | unsigned int type, unsigned int code, int value) | 94 | unsigned int type, unsigned int code, int value) |
94 | { | 95 | { |
96 | struct input_handler *handler; | ||
95 | struct input_handle *handle; | 97 | struct input_handle *handle; |
96 | 98 | ||
97 | rcu_read_lock(); | 99 | rcu_read_lock(); |
@@ -99,11 +101,25 @@ static void input_pass_event(struct input_dev *dev, | |||
99 | handle = rcu_dereference(dev->grab); | 101 | handle = rcu_dereference(dev->grab); |
100 | if (handle) | 102 | if (handle) |
101 | handle->handler->event(handle, type, code, value); | 103 | handle->handler->event(handle, type, code, value); |
102 | else | 104 | else { |
103 | list_for_each_entry_rcu(handle, &dev->h_list, d_node) | 105 | bool filtered = false; |
104 | if (handle->open) | 106 | |
105 | handle->handler->event(handle, | 107 | list_for_each_entry_rcu(handle, &dev->h_list, d_node) { |
106 | type, code, value); | 108 | if (!handle->open) |
109 | continue; | ||
110 | |||
111 | handler = handle->handler; | ||
112 | if (!handler->filter) { | ||
113 | if (filtered) | ||
114 | break; | ||
115 | |||
116 | handler->event(handle, type, code, value); | ||
117 | |||
118 | } else if (handler->filter(handle, type, code, value)) | ||
119 | filtered = true; | ||
120 | } | ||
121 | } | ||
122 | |||
107 | rcu_read_unlock(); | 123 | rcu_read_unlock(); |
108 | } | 124 | } |
109 | 125 | ||
@@ -990,6 +1006,8 @@ static int input_handlers_seq_show(struct seq_file *seq, void *v) | |||
990 | union input_seq_state *state = (union input_seq_state *)&seq->private; | 1006 | union input_seq_state *state = (union input_seq_state *)&seq->private; |
991 | 1007 | ||
992 | seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name); | 1008 | seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name); |
1009 | if (handler->filter) | ||
1010 | seq_puts(seq, " (filter)"); | ||
993 | if (handler->fops) | 1011 | if (handler->fops) |
994 | seq_printf(seq, " Minor=%d", handler->minor); | 1012 | seq_printf(seq, " Minor=%d", handler->minor); |
995 | seq_putc(seq, '\n'); | 1013 | seq_putc(seq, '\n'); |
@@ -1803,7 +1821,16 @@ int input_register_handle(struct input_handle *handle) | |||
1803 | error = mutex_lock_interruptible(&dev->mutex); | 1821 | error = mutex_lock_interruptible(&dev->mutex); |
1804 | if (error) | 1822 | if (error) |
1805 | return error; | 1823 | return error; |
1806 | list_add_tail_rcu(&handle->d_node, &dev->h_list); | 1824 | |
1825 | /* | ||
1826 | * Filters go to the head of the list, normal handlers | ||
1827 | * to the tail. | ||
1828 | */ | ||
1829 | if (handler->filter) | ||
1830 | list_add_rcu(&handle->d_node, &dev->h_list); | ||
1831 | else | ||
1832 | list_add_tail_rcu(&handle->d_node, &dev->h_list); | ||
1833 | |||
1807 | mutex_unlock(&dev->mutex); | 1834 | mutex_unlock(&dev->mutex); |
1808 | 1835 | ||
1809 | /* | 1836 | /* |