diff options
-rw-r--r-- | drivers/input/serio/i8042.c | 58 | ||||
-rw-r--r-- | include/linux/i8042.h | 18 |
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; | |||
126 | static struct platform_device *i8042_platform_device; | 126 | static struct platform_device *i8042_platform_device; |
127 | 127 | ||
128 | static irqreturn_t i8042_interrupt(int irq, void *dev_id); | 128 | static irqreturn_t i8042_interrupt(int irq, void *dev_id); |
129 | static bool (*i8042_platform_filter)(unsigned char data, unsigned char str, | ||
130 | struct serio *serio); | ||
129 | 131 | ||
130 | void i8042_lock_chip(void) | 132 | void i8042_lock_chip(void) |
131 | { | 133 | { |
@@ -139,6 +141,48 @@ void i8042_unlock_chip(void) | |||
139 | } | 141 | } |
140 | EXPORT_SYMBOL(i8042_unlock_chip); | 142 | EXPORT_SYMBOL(i8042_unlock_chip); |
141 | 143 | ||
144 | int 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 | |||
159 | out: | ||
160 | spin_unlock_irqrestore(&i8042_lock, flags); | ||
161 | return ret; | ||
162 | } | ||
163 | EXPORT_SYMBOL(i8042_install_filter); | ||
164 | |||
165 | int 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 | |||
180 | out: | ||
181 | spin_unlock_irqrestore(&i8042_lock, flags); | ||
182 | return ret; | ||
183 | } | ||
184 | EXPORT_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 | */ |
376 | static bool i8042_filter(unsigned char data, unsigned char str) | 420 | static 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) | |||
396 | static irqreturn_t i8042_interrupt(int irq, void *dev_id) | 446 | static 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); | |||
39 | void i8042_unlock_chip(void); | 39 | void i8042_unlock_chip(void); |
40 | int i8042_command(unsigned char *param, int command); | 40 | int i8042_command(unsigned char *param, int command); |
41 | bool i8042_check_port_owner(const struct serio *); | 41 | bool i8042_check_port_owner(const struct serio *); |
42 | int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, | ||
43 | struct serio *serio)); | ||
44 | int 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 | ||
53 | int i8042_command(unsigned char *param, int command) | 57 | int i8042_command(unsigned char *param, int command) |
54 | { | 58 | { |
55 | return -ENOSYS; | 59 | return -ENODEV; |
56 | } | 60 | } |
57 | 61 | ||
58 | bool i8042_check_port_owner(const struct serio *serio) | 62 | bool 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 | ||
67 | int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, | ||
68 | struct serio *serio)) | ||
69 | { | ||
70 | return -ENODEV; | ||
71 | } | ||
72 | |||
73 | int 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 |