|
@@ -126,6 +126,8 @@ static unsigned char i8042_suppress_kbd_ack;
|
|
static struct platform_device *i8042_platform_device;
|
|
static struct platform_device *i8042_platform_device;
|
|
|
|
|
|
static irqreturn_t i8042_interrupt(int irq, void *dev_id);
|
|
static irqreturn_t i8042_interrupt(int irq, void *dev_id);
|
|
|
|
+static bool (*i8042_platform_filter)(unsigned char data, unsigned char str,
|
|
|
|
+ struct serio *serio);
|
|
|
|
|
|
void i8042_lock_chip(void)
|
|
void i8042_lock_chip(void)
|
|
{
|
|
{
|
|
@@ -139,6 +141,48 @@ void i8042_unlock_chip(void)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(i8042_unlock_chip);
|
|
EXPORT_SYMBOL(i8042_unlock_chip);
|
|
|
|
|
|
|
|
+int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
|
|
|
|
+ struct serio *serio))
|
|
|
|
+{
|
|
|
|
+ unsigned long flags;
|
|
|
|
+ int ret = 0;
|
|
|
|
+
|
|
|
|
+ spin_lock_irqsave(&i8042_lock, flags);
|
|
|
|
+
|
|
|
|
+ if (i8042_platform_filter) {
|
|
|
|
+ ret = -EBUSY;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ i8042_platform_filter = filter;
|
|
|
|
+
|
|
|
|
+out:
|
|
|
|
+ spin_unlock_irqrestore(&i8042_lock, flags);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL(i8042_install_filter);
|
|
|
|
+
|
|
|
|
+int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
|
|
|
|
+ struct serio *port))
|
|
|
|
+{
|
|
|
|
+ unsigned long flags;
|
|
|
|
+ int ret = 0;
|
|
|
|
+
|
|
|
|
+ spin_lock_irqsave(&i8042_lock, flags);
|
|
|
|
+
|
|
|
|
+ if (i8042_platform_filter != filter) {
|
|
|
|
+ ret = -EINVAL;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ i8042_platform_filter = NULL;
|
|
|
|
+
|
|
|
|
+out:
|
|
|
|
+ spin_unlock_irqrestore(&i8042_lock, flags);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL(i8042_remove_filter);
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
|
|
* The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
|
|
* be ready for reading values from it / writing values to it.
|
|
* be ready for reading values from it / writing values to it.
|
|
@@ -373,7 +417,8 @@ static void i8042_stop(struct serio *serio)
|
|
* It is called from i8042_interrupt and thus is running with interrupts
|
|
* It is called from i8042_interrupt and thus is running with interrupts
|
|
* off and i8042_lock held.
|
|
* off and i8042_lock held.
|
|
*/
|
|
*/
|
|
-static bool i8042_filter(unsigned char data, unsigned char str)
|
|
|
|
|
|
+static bool i8042_filter(unsigned char data, unsigned char str,
|
|
|
|
+ struct serio *serio)
|
|
{
|
|
{
|
|
if (unlikely(i8042_suppress_kbd_ack)) {
|
|
if (unlikely(i8042_suppress_kbd_ack)) {
|
|
if ((~str & I8042_STR_AUXDATA) &&
|
|
if ((~str & I8042_STR_AUXDATA) &&
|
|
@@ -384,6 +429,11 @@ static bool i8042_filter(unsigned char data, unsigned char str)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (i8042_platform_filter && i8042_platform_filter(data, str, serio)) {
|
|
|
|
+ dbg("Filtered out by platfrom filter\n");
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -396,6 +446,7 @@ static bool i8042_filter(unsigned char data, unsigned char str)
|
|
static irqreturn_t i8042_interrupt(int irq, void *dev_id)
|
|
static irqreturn_t i8042_interrupt(int irq, void *dev_id)
|
|
{
|
|
{
|
|
struct i8042_port *port;
|
|
struct i8042_port *port;
|
|
|
|
+ struct serio *serio;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
unsigned char str, data;
|
|
unsigned char str, data;
|
|
unsigned int dfl;
|
|
unsigned int dfl;
|
|
@@ -462,18 +513,19 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
|
|
}
|
|
}
|
|
|
|
|
|
port = &i8042_ports[port_no];
|
|
port = &i8042_ports[port_no];
|
|
|
|
+ serio = port->exists ? port->serio : NULL;
|
|
|
|
|
|
dbg("%02x <- i8042 (interrupt, %d, %d%s%s)",
|
|
dbg("%02x <- i8042 (interrupt, %d, %d%s%s)",
|
|
data, port_no, irq,
|
|
data, port_no, irq,
|
|
dfl & SERIO_PARITY ? ", bad parity" : "",
|
|
dfl & SERIO_PARITY ? ", bad parity" : "",
|
|
dfl & SERIO_TIMEOUT ? ", timeout" : "");
|
|
dfl & SERIO_TIMEOUT ? ", timeout" : "");
|
|
|
|
|
|
- filtered = i8042_filter(data, str);
|
|
|
|
|
|
+ filtered = i8042_filter(data, str, serio);
|
|
|
|
|
|
spin_unlock_irqrestore(&i8042_lock, flags);
|
|
spin_unlock_irqrestore(&i8042_lock, flags);
|
|
|
|
|
|
if (likely(port->exists && !filtered))
|
|
if (likely(port->exists && !filtered))
|
|
- serio_interrupt(port->serio, data, dfl);
|
|
|
|
|
|
+ serio_interrupt(serio, data, dfl);
|
|
|
|
|
|
out:
|
|
out:
|
|
return IRQ_RETVAL(ret);
|
|
return IRQ_RETVAL(ret);
|