|
@@ -368,6 +368,25 @@ static void i8042_stop(struct serio *serio)
|
|
|
port->serio = NULL;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * i8042_filter() filters out unwanted bytes from the input data stream.
|
|
|
+ * It is called from i8042_interrupt and thus is running with interrupts
|
|
|
+ * off and i8042_lock held.
|
|
|
+ */
|
|
|
+static bool i8042_filter(unsigned char data, unsigned char str)
|
|
|
+{
|
|
|
+ if (unlikely(i8042_suppress_kbd_ack)) {
|
|
|
+ if ((~str & I8042_STR_AUXDATA) &&
|
|
|
+ (data == 0xfa || data == 0xfe)) {
|
|
|
+ i8042_suppress_kbd_ack--;
|
|
|
+ dbg("Extra keyboard ACK - filtered out\n");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* i8042_interrupt() is the most important function in this driver -
|
|
|
* it handles the interrupts from the i8042, and sends incoming bytes
|
|
@@ -381,9 +400,11 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
|
|
|
unsigned char str, data;
|
|
|
unsigned int dfl;
|
|
|
unsigned int port_no;
|
|
|
+ bool filtered;
|
|
|
int ret = 1;
|
|
|
|
|
|
spin_lock_irqsave(&i8042_lock, flags);
|
|
|
+
|
|
|
str = i8042_read_status();
|
|
|
if (unlikely(~str & I8042_STR_OBF)) {
|
|
|
spin_unlock_irqrestore(&i8042_lock, flags);
|
|
@@ -391,8 +412,8 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
|
|
|
ret = 0;
|
|
|
goto out;
|
|
|
}
|
|
|
+
|
|
|
data = i8042_read_data();
|
|
|
- spin_unlock_irqrestore(&i8042_lock, flags);
|
|
|
|
|
|
if (i8042_mux_present && (str & I8042_STR_AUXDATA)) {
|
|
|
static unsigned long last_transmit;
|
|
@@ -447,14 +468,11 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
|
|
|
dfl & SERIO_PARITY ? ", bad parity" : "",
|
|
|
dfl & SERIO_TIMEOUT ? ", timeout" : "");
|
|
|
|
|
|
- if (unlikely(i8042_suppress_kbd_ack))
|
|
|
- if (port_no == I8042_KBD_PORT_NO &&
|
|
|
- (data == 0xfa || data == 0xfe)) {
|
|
|
- i8042_suppress_kbd_ack--;
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ filtered = i8042_filter(data, str);
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&i8042_lock, flags);
|
|
|
|
|
|
- if (likely(port->exists))
|
|
|
+ if (likely(port->exists && !filtered))
|
|
|
serio_interrupt(port->serio, data, dfl);
|
|
|
|
|
|
out:
|