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 |
