Skip to content

Commit

Permalink
Input: i8042 - try disabling and re-enabling AUX port at close
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
dtor committed Sep 11, 2009
1 parent bd96f37 commit 5ddbc77
Showing 1 changed file with 49 additions and 1 deletion.
50 changes: 49 additions & 1 deletion drivers/input/serio/i8042.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 5ddbc77

Please sign in to comment.