diff options
Diffstat (limited to 'drivers/input/serio/i8042.c')
-rw-r--r-- | drivers/input/serio/i8042.c | 58 |
1 files changed, 55 insertions, 3 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); |