Message ID | 20090909022718.A177E526EC9@mailhub.coreip.homeip.net (mailing list archive) |
---|---|
State | Accepted |
Commit | 5ddbc77c3eb54336fcd44b7b66b44784d65677e2 |
Headers | show |
* Dmitry Torokhov (dmitry.torokhov@gmail.com) wrote: <snip> > Bah, that one was completely screwed up, please try this one instead. Yep - that works nicely. Thanks. Dave > > Thanks! > > -- > Dmitry > > Input: i8042 - try disabling and re-enabling AUX port at close > > From: Dmitry Torokhov <dmitry.torokhov@gmail.com> > > Ever since we switched from having a polling timer to registering IRQ > handlers for both keyboard and AUX ports at the driver registration > time, on certain boxes probing for a mouse results in keyboard > stopping working. The only real difference between old and new way is > that before we disabled ports after unsuccessful probe whereas now we > leave them as is. Try to emulate the old behavior by disabling and > immediately re-enabling AUX and KBD ports when corresponding serio > port is being closed. > > Signed-off-by: Dmitry Torokhov <dtor@mail.ru> > --- > > drivers/input/serio/i8042.c | 50 ++++++++++++++++++++++++++++++++++++++++++- > 1 files changed, 49 insertions(+), 1 deletions(-) > > > diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c > index b53a015..8aaf8fc 100644 > --- a/drivers/input/serio/i8042.c > +++ b/drivers/input/serio/i8042.c > @@ -264,6 +264,49 @@ static int i8042_aux_write(struct serio *serio, unsigned char c) > I8042_CMD_MUX_SEND + port->mux); > } > > + > +/* > + * i8042_aux_close attempts to clear AUX or KBD port state by disabling > + * and then re-enabling it. > + */ > + > +static void i8042_port_close(struct serio *serio) > +{ > + int irq_bit; > + int disable_bit; > + const char *port_name; > + > + if (serio == i8042_ports[I8042_AUX_PORT_NO].serio) { > + irq_bit = I8042_CTR_AUXINT; > + disable_bit = I8042_CTR_AUXDIS; > + port_name = "AUX"; > + } else { > + irq_bit = I8042_CTR_KBDINT; > + disable_bit = I8042_CTR_KBDDIS; > + port_name = "KBD"; > + } > + > + i8042_ctr &= ~irq_bit; > + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) > + printk(KERN_WARNING > + "i8042.c: Can't write CTR while closing %s port.\n", > + port_name); > + > + udelay(50); > + > + i8042_ctr &= ~disable_bit; > + i8042_ctr |= irq_bit; > + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) > + printk(KERN_ERR "i8042.c: Can't reactivate %s port.\n", > + port_name); > + > + /* > + * See if there is any data appeared while we were messing with > + * port state. > + */ > + i8042_interrupt(0, NULL); > +} > + > /* > * i8042_start() is called by serio core when port is about to finish > * registering. It will mark port as existing so i8042_interrupt can > @@ -393,7 +436,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) > } > > /* > - * i8042_enable_kbd_port enables keybaord port on chip > + * i8042_enable_kbd_port enables keyboard port on chip > */ > > static int i8042_enable_kbd_port(void) > @@ -841,6 +884,9 @@ static void i8042_controller_reset(void) > i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS; > i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT); > > + if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR)) > + printk(KERN_WARNING "i8042.c: Can't write CTR while resetting.\n"); > + > /* > * Disable MUX mode if present. > */ > @@ -1026,6 +1072,7 @@ static int __devinit i8042_create_kbd_port(void) > serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; > serio->start = i8042_start; > serio->stop = i8042_stop; > + serio->close = i8042_port_close; > serio->port_data = port; > serio->dev.parent = &i8042_platform_device->dev; > strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name)); > @@ -1056,6 +1103,7 @@ static int __devinit i8042_create_aux_port(int idx) > if (idx < 0) { > strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name)); > strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); > + serio->close = i8042_port_close; > } else { > snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx); > snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1); > -- > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > Please read the FAQ at http://www.tux.org/lkml/
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index b53a015..8aaf8fc 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -264,6 +264,49 @@ static int i8042_aux_write(struct serio *serio, unsigned char c) I8042_CMD_MUX_SEND + port->mux); } + +/* + * i8042_aux_close attempts to clear AUX or KBD port state by disabling + * and then re-enabling it. + */ + +static void i8042_port_close(struct serio *serio) +{ + int irq_bit; + int disable_bit; + const char *port_name; + + if (serio == i8042_ports[I8042_AUX_PORT_NO].serio) { + irq_bit = I8042_CTR_AUXINT; + disable_bit = I8042_CTR_AUXDIS; + port_name = "AUX"; + } else { + irq_bit = I8042_CTR_KBDINT; + disable_bit = I8042_CTR_KBDDIS; + port_name = "KBD"; + } + + i8042_ctr &= ~irq_bit; + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) + printk(KERN_WARNING + "i8042.c: Can't write CTR while closing %s port.\n", + port_name); + + udelay(50); + + i8042_ctr &= ~disable_bit; + i8042_ctr |= irq_bit; + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) + printk(KERN_ERR "i8042.c: Can't reactivate %s port.\n", + port_name); + + /* + * See if there is any data appeared while we were messing with + * port state. + */ + i8042_interrupt(0, NULL); +} + /* * i8042_start() is called by serio core when port is about to finish * registering. It will mark port as existing so i8042_interrupt can @@ -393,7 +436,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) } /* - * i8042_enable_kbd_port enables keybaord port on chip + * i8042_enable_kbd_port enables keyboard port on chip */ static int i8042_enable_kbd_port(void) @@ -841,6 +884,9 @@ static void i8042_controller_reset(void) i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS; i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT); + if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR)) + printk(KERN_WARNING "i8042.c: Can't write CTR while resetting.\n"); + /* * Disable MUX mode if present. */ @@ -1026,6 +1072,7 @@ static int __devinit i8042_create_kbd_port(void) serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; serio->start = i8042_start; serio->stop = i8042_stop; + serio->close = i8042_port_close; serio->port_data = port; serio->dev.parent = &i8042_platform_device->dev; strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name)); @@ -1056,6 +1103,7 @@ static int __devinit i8042_create_aux_port(int idx) if (idx < 0) { strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name)); strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); + serio->close = i8042_port_close; } else { snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx); snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1);