aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Garrett <mjg@redhat.com>2009-12-12 01:00:57 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2009-12-12 02:55:42 -0500
commit967c9ef9b8c3bdec1bd3a380edac19e0b9fbeadc (patch)
tree03a3ba3fec91014adb5afbe78f40ffb429c3753e
parent4e8d340daac46cec8a0f8b3b0f228274fac913ba (diff)
Input: i8042 - allow installing platform filters for incoming data
Some hardware (such as Dell laptops) signal a variety of events through the i8042 controller, even if these don't map to keyboard events. Add support for drivers to filter the i8042 event stream in order to respond to these events and (if appropriate) block them from entering the input stream. Signed-off-by: Matthew Garrett <mjg@redhat.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r--drivers/input/serio/i8042.c58
-rw-r--r--include/linux/i8042.h18
2 files changed, 72 insertions, 4 deletions
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 634da68f7f35..d84a36e545f6 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -126,6 +126,8 @@ static unsigned char i8042_suppress_kbd_ack;
126static struct platform_device *i8042_platform_device; 126static struct platform_device *i8042_platform_device;
127 127
128static irqreturn_t i8042_interrupt(int irq, void *dev_id); 128static irqreturn_t i8042_interrupt(int irq, void *dev_id);
129static bool (*i8042_platform_filter)(unsigned char data, unsigned char str,
130 struct serio *serio);
129 131
130void i8042_lock_chip(void) 132void i8042_lock_chip(void)
131{ 133{
@@ -139,6 +141,48 @@ void i8042_unlock_chip(void)
139} 141}
140EXPORT_SYMBOL(i8042_unlock_chip); 142EXPORT_SYMBOL(i8042_unlock_chip);
141 143
144int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
145 struct serio *serio))
146{
147 unsigned long flags;
148 int ret = 0;
149
150 spin_lock_irqsave(&i8042_lock, flags);
151
152 if (i8042_platform_filter) {
153 ret = -EBUSY;
154 goto out;
155 }
156
157 i8042_platform_filter = filter;
158
159out:
160 spin_unlock_irqrestore(&i8042_lock, flags);
161 return ret;
162}
163EXPORT_SYMBOL(i8042_install_filter);
164
165int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
166 struct serio *port))
167{
168 unsigned long flags;
169 int ret = 0;
170
171 spin_lock_irqsave(&i8042_lock, flags);
172
173 if (i8042_platform_filter != filter) {
174 ret = -EINVAL;
175 goto out;
176 }
177
178 i8042_platform_filter = NULL;
179
180out:
181 spin_unlock_irqrestore(&i8042_lock, flags);
182 return ret;
183}
184EXPORT_SYMBOL(i8042_remove_filter);
185
142/* 186/*
143 * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to 187 * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
144 * be ready for reading values from it / writing values to it. 188 * be ready for reading values from it / writing values to it.
@@ -373,7 +417,8 @@ static void i8042_stop(struct serio *serio)
373 * It is called from i8042_interrupt and thus is running with interrupts 417 * It is called from i8042_interrupt and thus is running with interrupts
374 * off and i8042_lock held. 418 * off and i8042_lock held.
375 */ 419 */
376static bool i8042_filter(unsigned char data, unsigned char str) 420static bool i8042_filter(unsigned char data, unsigned char str,
421 struct serio *serio)
377{ 422{
378 if (unlikely(i8042_suppress_kbd_ack)) { 423 if (unlikely(i8042_suppress_kbd_ack)) {
379 if ((~str & I8042_STR_AUXDATA) && 424 if ((~str & I8042_STR_AUXDATA) &&
@@ -384,6 +429,11 @@ static bool i8042_filter(unsigned char data, unsigned char str)
384 } 429 }
385 } 430 }
386 431
432 if (i8042_platform_filter && i8042_platform_filter(data, str, serio)) {
433 dbg("Filtered out by platfrom filter\n");
434 return true;
435 }
436
387 return false; 437 return false;
388} 438}
389 439
@@ -396,6 +446,7 @@ static bool i8042_filter(unsigned char data, unsigned char str)
396static irqreturn_t i8042_interrupt(int irq, void *dev_id) 446static irqreturn_t i8042_interrupt(int irq, void *dev_id)
397{ 447{
398 struct i8042_port *port; 448 struct i8042_port *port;
449 struct serio *serio;
399 unsigned long flags; 450 unsigned long flags;
400 unsigned char str, data; 451 unsigned char str, data;
401 unsigned int dfl; 452 unsigned int dfl;
@@ -462,18 +513,19 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
462 } 513 }
463 514
464 port = &i8042_ports[port_no]; 515 port = &i8042_ports[port_no];
516 serio = port->exists ? port->serio : NULL;
465 517
466 dbg("%02x <- i8042 (interrupt, %d, %d%s%s)", 518 dbg("%02x <- i8042 (interrupt, %d, %d%s%s)",
467 data, port_no, irq, 519 data, port_no, irq,
468 dfl & SERIO_PARITY ? ", bad parity" : "", 520 dfl & SERIO_PARITY ? ", bad parity" : "",
469 dfl & SERIO_TIMEOUT ? ", timeout" : ""); 521 dfl & SERIO_TIMEOUT ? ", timeout" : "");
470 522
471 filtered = i8042_filter(data, str); 523 filtered = i8042_filter(data, str, serio);
472 524
473 spin_unlock_irqrestore(&i8042_lock, flags); 525 spin_unlock_irqrestore(&i8042_lock, flags);
474 526
475 if (likely(port->exists && !filtered)) 527 if (likely(port->exists && !filtered))
476 serio_interrupt(port->serio, data, dfl); 528 serio_interrupt(serio, data, dfl);
477 529
478 out: 530 out:
479 return IRQ_RETVAL(ret); 531 return IRQ_RETVAL(ret);
diff --git a/include/linux/i8042.h b/include/linux/i8042.h
index 60c3360ef6ad..9bf6870ee5f4 100644
--- a/include/linux/i8042.h
+++ b/include/linux/i8042.h
@@ -39,6 +39,10 @@ void i8042_lock_chip(void);
39void i8042_unlock_chip(void); 39void i8042_unlock_chip(void);
40int i8042_command(unsigned char *param, int command); 40int i8042_command(unsigned char *param, int command);
41bool i8042_check_port_owner(const struct serio *); 41bool i8042_check_port_owner(const struct serio *);
42int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
43 struct serio *serio));
44int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
45 struct serio *serio));
42 46
43#else 47#else
44 48
@@ -52,7 +56,7 @@ void i8042_unlock_chip(void)
52 56
53int i8042_command(unsigned char *param, int command) 57int i8042_command(unsigned char *param, int command)
54{ 58{
55 return -ENOSYS; 59 return -ENODEV;
56} 60}
57 61
58bool i8042_check_port_owner(const struct serio *serio) 62bool i8042_check_port_owner(const struct serio *serio)
@@ -60,6 +64,18 @@ bool i8042_check_port_owner(const struct serio *serio)
60 return false; 64 return false;
61} 65}
62 66
67int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
68 struct serio *serio))
69{
70 return -ENODEV;
71}
72
73int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
74 struct serio *serio))
75{
76 return -ENODEV;
77}
78
63#endif 79#endif
64 80
65#endif 81#endif