aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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