diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-16 13:31:44 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-16 13:31:44 -0500 |
commit | 238ccbb050a243e935bb3fc679c2e4bbff7004aa (patch) | |
tree | 3381b895861f625b1524acfd32d4a90eb79108bd /drivers/input/serio/i8042.c | |
parent | c5113e3d66d7c7140fe854c7638a27eb3a23fd7d (diff) | |
parent | 1d9f26262aef6d63ff65eba0fd5f1583f342b69b (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (22 commits)
Input: ALPS - add interleaved protocol support (Dell E6x00 series)
Input: keyboard - don't override beep with a bell
Input: altera_ps2 - fix test of unsigned in altera_ps2_probe()
Input: add mc13783 touchscreen driver
Input: ep93xx_keypad - update driver to new core support
Input: wacom - separate pen from express keys on Graphire
Input: wacom - add defines for data packet report IDs
Input: wacom - add support for new LCD tablets
Input: wacom - add defines for packet lengths of various devices
Input: wacom - ensure the device is initialized properly upon resume
Input: at32psif - do not sleep in atomic context
Input: i8042 - add Gigabyte M1022M to the noloop list
Input: i8042 - allow installing platform filters for incoming data
Input: i8042 - fix locking in interrupt routine
Input: ALPS - do not set REL_X/REL_Y capabilities on the touchpad
Input: document use of input_event() function
Input: sa1111ps2 - annotate probe() and remove() methods
Input: ambakmi - annotate probe() and remove() methods
Input: gscps2 - fix probe() and remove() annotations
Input: altera_ps2 - add annotations to probe and remove methods
...
Diffstat (limited to 'drivers/input/serio/i8042.c')
-rw-r--r-- | drivers/input/serio/i8042.c | 88 |
1 files changed, 79 insertions, 9 deletions
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 1df02d25aca5..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. |
@@ -369,6 +413,31 @@ static void i8042_stop(struct serio *serio) | |||
369 | } | 413 | } |
370 | 414 | ||
371 | /* | 415 | /* |
416 | * i8042_filter() filters out unwanted bytes from the input data stream. | ||
417 | * It is called from i8042_interrupt and thus is running with interrupts | ||
418 | * off and i8042_lock held. | ||
419 | */ | ||
420 | static bool i8042_filter(unsigned char data, unsigned char str, | ||
421 | struct serio *serio) | ||
422 | { | ||
423 | if (unlikely(i8042_suppress_kbd_ack)) { | ||
424 | if ((~str & I8042_STR_AUXDATA) && | ||
425 | (data == 0xfa || data == 0xfe)) { | ||
426 | i8042_suppress_kbd_ack--; | ||
427 | dbg("Extra keyboard ACK - filtered out\n"); | ||
428 | return true; | ||
429 | } | ||
430 | } | ||
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 | |||
437 | return false; | ||
438 | } | ||
439 | |||
440 | /* | ||
372 | * i8042_interrupt() is the most important function in this driver - | 441 | * i8042_interrupt() is the most important function in this driver - |
373 | * it handles the interrupts from the i8042, and sends incoming bytes | 442 | * it handles the interrupts from the i8042, and sends incoming bytes |
374 | * to the upper layers. | 443 | * to the upper layers. |
@@ -377,13 +446,16 @@ static void i8042_stop(struct serio *serio) | |||
377 | static irqreturn_t i8042_interrupt(int irq, void *dev_id) | 446 | static irqreturn_t i8042_interrupt(int irq, void *dev_id) |
378 | { | 447 | { |
379 | struct i8042_port *port; | 448 | struct i8042_port *port; |
449 | struct serio *serio; | ||
380 | unsigned long flags; | 450 | unsigned long flags; |
381 | unsigned char str, data; | 451 | unsigned char str, data; |
382 | unsigned int dfl; | 452 | unsigned int dfl; |
383 | unsigned int port_no; | 453 | unsigned int port_no; |
454 | bool filtered; | ||
384 | int ret = 1; | 455 | int ret = 1; |
385 | 456 | ||
386 | spin_lock_irqsave(&i8042_lock, flags); | 457 | spin_lock_irqsave(&i8042_lock, flags); |
458 | |||
387 | str = i8042_read_status(); | 459 | str = i8042_read_status(); |
388 | if (unlikely(~str & I8042_STR_OBF)) { | 460 | if (unlikely(~str & I8042_STR_OBF)) { |
389 | spin_unlock_irqrestore(&i8042_lock, flags); | 461 | spin_unlock_irqrestore(&i8042_lock, flags); |
@@ -391,8 +463,8 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) | |||
391 | ret = 0; | 463 | ret = 0; |
392 | goto out; | 464 | goto out; |
393 | } | 465 | } |
466 | |||
394 | data = i8042_read_data(); | 467 | data = i8042_read_data(); |
395 | spin_unlock_irqrestore(&i8042_lock, flags); | ||
396 | 468 | ||
397 | if (i8042_mux_present && (str & I8042_STR_AUXDATA)) { | 469 | if (i8042_mux_present && (str & I8042_STR_AUXDATA)) { |
398 | static unsigned long last_transmit; | 470 | static unsigned long last_transmit; |
@@ -441,21 +513,19 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) | |||
441 | } | 513 | } |
442 | 514 | ||
443 | port = &i8042_ports[port_no]; | 515 | port = &i8042_ports[port_no]; |
516 | serio = port->exists ? port->serio : NULL; | ||
444 | 517 | ||
445 | dbg("%02x <- i8042 (interrupt, %d, %d%s%s)", | 518 | dbg("%02x <- i8042 (interrupt, %d, %d%s%s)", |
446 | data, port_no, irq, | 519 | data, port_no, irq, |
447 | dfl & SERIO_PARITY ? ", bad parity" : "", | 520 | dfl & SERIO_PARITY ? ", bad parity" : "", |
448 | dfl & SERIO_TIMEOUT ? ", timeout" : ""); | 521 | dfl & SERIO_TIMEOUT ? ", timeout" : ""); |
449 | 522 | ||
450 | if (unlikely(i8042_suppress_kbd_ack)) | 523 | filtered = i8042_filter(data, str, serio); |
451 | if (port_no == I8042_KBD_PORT_NO && | 524 | |
452 | (data == 0xfa || data == 0xfe)) { | 525 | spin_unlock_irqrestore(&i8042_lock, flags); |
453 | i8042_suppress_kbd_ack--; | ||
454 | goto out; | ||
455 | } | ||
456 | 526 | ||
457 | if (likely(port->exists)) | 527 | if (likely(port->exists && !filtered)) |
458 | serio_interrupt(port->serio, data, dfl); | 528 | serio_interrupt(serio, data, dfl); |
459 | 529 | ||
460 | out: | 530 | out: |
461 | return IRQ_RETVAL(ret); | 531 | return IRQ_RETVAL(ret); |