aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2010-01-30 02:59:12 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-01-30 04:47:41 -0500
commitef7995f4e46b1677f3eaaf547316e1a910b38dcb (patch)
tree9d3fe13ae7a288f77dbc0e1b07813ce23f9106d3 /drivers
parent45cdba4d376adfd30cfbda1b7d43110818d967cc (diff)
Input: implement input filters
Sometimes it is desirable to suppress certain events from reaching input handlers and thus user space. One such example is Mac mouse button emulation code which catches certain key presses and converts them into button clicks as if they were emitted by a virtual mouse. The original key press events should be completely suppressed, otherwise user space will be confused, and while keyboard driver does it on its own evdev is blissfully unaware of this arrangement. This patch adds notion of 'filter' to the standard input handlers, which may flag event as filtered thus preventing it from reaching other input handlers. Filters don't (nor will they ever) have a notion of priority relative to each other, input core will run all of them first and any one of them may mark event as filtered. This patch is inspired by similar patch by Matthew Garret but the implementation and intended usage are quite different. Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/input.c41
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 */
92static void input_pass_event(struct input_dev *dev, 93static 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 /*