Commit a84be5c7 authored by Vojtech Pavlik's avatar Vojtech Pavlik

input: Update AT+PS/2 mouse and keyboard drivers:

	- Fix a possible deadlock with 0xfe resend command (atkbd)
	- Make ->ack variables volatile (they're updated from irq)
	- Fix the GETID one/two byte command to avoid any races
	- Fix Logitech PS2++ extended packet detection
	- Use RESET_BAT on reboot to make notebooks happy
parent 92f777ca
...@@ -86,8 +86,7 @@ static unsigned char atkbd_set3_keycode[512] = { ...@@ -86,8 +86,7 @@ static unsigned char atkbd_set3_keycode[512] = {
#define ATKBD_CMD_SETLEDS 0x10ed #define ATKBD_CMD_SETLEDS 0x10ed
#define ATKBD_CMD_GSCANSET 0x11f0 #define ATKBD_CMD_GSCANSET 0x11f0
#define ATKBD_CMD_SSCANSET 0x10f0 #define ATKBD_CMD_SSCANSET 0x10f0
#define ATKBD_CMD_GETID 0x01f2 #define ATKBD_CMD_GETID 0x02f2
#define ATKBD_CMD_GETID2 0x0100
#define ATKBD_CMD_ENABLE 0x00f4 #define ATKBD_CMD_ENABLE 0x00f4
#define ATKBD_CMD_RESET_DIS 0x00f5 #define ATKBD_CMD_RESET_DIS 0x00f5
#define ATKBD_CMD_RESET_BAT 0x01ff #define ATKBD_CMD_RESET_BAT 0x01ff
...@@ -120,12 +119,12 @@ struct atkbd { ...@@ -120,12 +119,12 @@ struct atkbd {
unsigned char cmdbuf[4]; unsigned char cmdbuf[4];
unsigned char cmdcnt; unsigned char cmdcnt;
unsigned char set; unsigned char set;
unsigned char oldset;
unsigned char release; unsigned char release;
signed char ack; volatile signed char ack;
unsigned char emul; unsigned char emul;
unsigned short id; unsigned short id;
unsigned char write; unsigned char write;
unsigned char resend;
}; };
/* /*
...@@ -142,12 +141,16 @@ static void atkbd_interrupt(struct serio *serio, unsigned char data, unsigned in ...@@ -142,12 +141,16 @@ static void atkbd_interrupt(struct serio *serio, unsigned char data, unsigned in
printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags); printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags);
#endif #endif
if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && atkbd->write) { if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) {
printk("atkbd.c: frame/parity error: %02x\n", flags); printk("atkbd.c: frame/parity error: %02x\n", flags);
serio_write(serio, ATKBD_CMD_RESEND); serio_write(serio, ATKBD_CMD_RESEND);
atkbd->resend = 1;
return; return;
} }
if (!flags)
atkbd->resend = 0;
switch (code) { switch (code) {
case ATKBD_RET_ACK: case ATKBD_RET_ACK:
atkbd->ack = 1; atkbd->ack = 1;
...@@ -227,13 +230,16 @@ static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte) ...@@ -227,13 +230,16 @@ static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte)
static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command)
{ {
int timeout = 50000; /* 500 msec */ int timeout = 500000; /* 500 msec */
int send = (command >> 12) & 0xf; int send = (command >> 12) & 0xf;
int receive = (command >> 8) & 0xf; int receive = (command >> 8) & 0xf;
int i; int i;
atkbd->cmdcnt = receive; atkbd->cmdcnt = receive;
if (command == ATKBD_CMD_RESET_BAT)
timeout = 2000000; /* 2 sec */
if (command & 0xff) if (command & 0xff)
if (atkbd_sendbyte(atkbd, command & 0xff)) if (atkbd_sendbyte(atkbd, command & 0xff))
return (atkbd->cmdcnt = 0) - 1; return (atkbd->cmdcnt = 0) - 1;
...@@ -242,14 +248,28 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) ...@@ -242,14 +248,28 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command)
if (atkbd_sendbyte(atkbd, param[i])) if (atkbd_sendbyte(atkbd, param[i]))
return (atkbd->cmdcnt = 0) - 1; return (atkbd->cmdcnt = 0) - 1;
while (atkbd->cmdcnt && timeout--) udelay(10); while (atkbd->cmdcnt && timeout--) {
if (atkbd->cmdcnt == 1 && command == ATKBD_CMD_RESET_BAT)
timeout = 100000;
if (atkbd->cmdcnt == 1 && command == ATKBD_CMD_GETID &&
atkbd->cmdbuf[1] != 0xab && atkbd->cmdbuf[1] != 0xac) {
atkbd->cmdcnt = 0;
break;
}
udelay(1);
}
if (param) if (param)
for (i = 0; i < receive; i++) for (i = 0; i < receive; i++)
param[i] = atkbd->cmdbuf[(receive - 1) - i]; param[i] = atkbd->cmdbuf[(receive - 1) - i];
if (atkbd->cmdcnt) if (atkbd->cmdcnt) {
return (atkbd->cmdcnt = 0) - 1; atkbd->cmdcnt = 0;
return -1;
}
return 0; return 0;
} }
...@@ -302,13 +322,6 @@ static int atkbd_set_3(struct atkbd *atkbd) ...@@ -302,13 +322,6 @@ static int atkbd_set_3(struct atkbd *atkbd)
{ {
unsigned char param[2]; unsigned char param[2];
/*
* Remember original scancode set value, so that we can restore it on exit.
*/
if (atkbd_command(atkbd, &atkbd->oldset, ATKBD_CMD_GSCANSET))
atkbd->oldset = 2;
/* /*
* For known special keyboards we can go ahead and set the correct set. * For known special keyboards we can go ahead and set the correct set.
* We check for NCD PS/2 Sun, NorthGate OmniKey 101 and * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and
...@@ -377,7 +390,7 @@ static int atkbd_probe(struct atkbd *atkbd) ...@@ -377,7 +390,7 @@ static int atkbd_probe(struct atkbd *atkbd)
if (atkbd_reset) if (atkbd_reset)
if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT)) if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT))
printk(KERN_WARNING "atkbd.c: keyboard reset failed\n"); printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", atkbd->serio->phys);
/* /*
* Then we check the keyboard ID. We should get 0xab83 under normal conditions. * Then we check the keyboard ID. We should get 0xab83 under normal conditions.
...@@ -401,10 +414,7 @@ static int atkbd_probe(struct atkbd *atkbd) ...@@ -401,10 +414,7 @@ static int atkbd_probe(struct atkbd *atkbd)
if (param[0] != 0xab && param[0] != 0xac) if (param[0] != 0xab && param[0] != 0xac)
return -1; return -1;
atkbd->id = param[0] << 8; atkbd->id = (param[0] << 8) | param[1];
if (atkbd_command(atkbd, param, ATKBD_CMD_GETID2))
return -1;
atkbd->id |= param[0];
/* /*
* Set the LEDs to a defined state. * Set the LEDs to a defined state.
...@@ -442,7 +452,7 @@ static int atkbd_probe(struct atkbd *atkbd) ...@@ -442,7 +452,7 @@ static int atkbd_probe(struct atkbd *atkbd)
static void atkbd_cleanup(struct serio *serio) static void atkbd_cleanup(struct serio *serio)
{ {
struct atkbd *atkbd = serio->private; struct atkbd *atkbd = serio->private;
atkbd_command(atkbd, &atkbd->oldset, ATKBD_CMD_SSCANSET); atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT);
} }
/* /*
......
...@@ -30,8 +30,7 @@ static int psmouse_noext; ...@@ -30,8 +30,7 @@ static int psmouse_noext;
#define PSMOUSE_CMD_GETINFO 0x03e9 #define PSMOUSE_CMD_GETINFO 0x03e9
#define PSMOUSE_CMD_SETSTREAM 0x00ea #define PSMOUSE_CMD_SETSTREAM 0x00ea
#define PSMOUSE_CMD_POLL 0x03eb #define PSMOUSE_CMD_POLL 0x03eb
#define PSMOUSE_CMD_GETID 0x01f2 #define PSMOUSE_CMD_GETID 0x02f2
#define PSMOUSE_CMD_GETID2 0x0100
#define PSMOUSE_CMD_SETRATE 0x10f3 #define PSMOUSE_CMD_SETRATE 0x10f3
#define PSMOUSE_CMD_ENABLE 0x00f4 #define PSMOUSE_CMD_ENABLE 0x00f4
#define PSMOUSE_CMD_RESET_DIS 0x00f6 #define PSMOUSE_CMD_RESET_DIS 0x00f6
...@@ -54,7 +53,7 @@ struct psmouse { ...@@ -54,7 +53,7 @@ struct psmouse {
unsigned char model; unsigned char model;
unsigned long last; unsigned long last;
char acking; char acking;
char ack; volatile char ack;
char error; char error;
char devname[64]; char devname[64];
char phys[32]; char phys[32];
...@@ -85,9 +84,9 @@ static void psmouse_process_packet(struct psmouse *psmouse) ...@@ -85,9 +84,9 @@ static void psmouse_process_packet(struct psmouse *psmouse)
if (psmouse->type == PSMOUSE_PS2PP || psmouse->type == PSMOUSE_PS2TPP) { if (psmouse->type == PSMOUSE_PS2PP || psmouse->type == PSMOUSE_PS2TPP) {
if ((packet[0] & 0x40) == 0x40 && (int) packet[1] - (int) ((packet[0] & 0x10) << 4) > 191 ) { if ((packet[0] & 0x40) == 0x40 && abs((int)packet[1] - (((int)packet[0] & 0x10) << 4)) > 191 ) {
switch (((packet[1] >> 4) & 0x03) | ((packet[0] >> 2) & 0xc0)) { switch (((packet[1] >> 4) & 0x03) | ((packet[0] >> 2) & 0x0c)) {
case 1: /* Mouse extra info */ case 1: /* Mouse extra info */
...@@ -106,10 +105,11 @@ static void psmouse_process_packet(struct psmouse *psmouse) ...@@ -106,10 +105,11 @@ static void psmouse_process_packet(struct psmouse *psmouse)
break; break;
#ifdef DEBUG
default: default:
printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n", printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n",
((packet[1] >> 4) & 0x03) | ((packet[0] >> 2) & 0xc0)); ((packet[1] >> 4) & 0x03) | ((packet[0] >> 2) & 0x0c));
#endif
} }
...@@ -248,6 +248,9 @@ static int psmouse_command(struct psmouse *psmouse, unsigned char *param, int co ...@@ -248,6 +248,9 @@ static int psmouse_command(struct psmouse *psmouse, unsigned char *param, int co
psmouse->cmdcnt = receive; psmouse->cmdcnt = receive;
if (command == PSMOUSE_CMD_RESET_BAT)
timeout = 2000000; /* 2 sec */
if (command & 0xff) if (command & 0xff)
if (psmouse_sendbyte(psmouse, command & 0xff)) if (psmouse_sendbyte(psmouse, command & 0xff))
return (psmouse->cmdcnt = 0) - 1; return (psmouse->cmdcnt = 0) - 1;
...@@ -256,7 +259,19 @@ static int psmouse_command(struct psmouse *psmouse, unsigned char *param, int co ...@@ -256,7 +259,19 @@ static int psmouse_command(struct psmouse *psmouse, unsigned char *param, int co
if (psmouse_sendbyte(psmouse, param[i])) if (psmouse_sendbyte(psmouse, param[i]))
return (psmouse->cmdcnt = 0) - 1; return (psmouse->cmdcnt = 0) - 1;
while (psmouse->cmdcnt && timeout--) udelay(1); while (psmouse->cmdcnt && timeout--) {
if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_RESET_BAT)
timeout = 100000;
if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_GETID &&
psmouse->cmdbuf[1] != 0xab && psmouse->cmdbuf[1] != 0xac) {
psmouse->cmdcnt = 0;
break;
}
udelay(1);
}
for (i = 0; i < receive; i++) for (i = 0; i < receive; i++)
param[i] = psmouse->cmdbuf[(receive - 1) - i]; param[i] = psmouse->cmdbuf[(receive - 1) - i];
...@@ -498,11 +513,6 @@ static int psmouse_probe(struct psmouse *psmouse) ...@@ -498,11 +513,6 @@ static int psmouse_probe(struct psmouse *psmouse)
if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETID)) if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETID))
return -1; return -1;
if (param[0] == 0xab || param[0] == 0xac) {
psmouse_command(psmouse, param, PSMOUSE_CMD_GETID2);
return -1;
}
if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04) if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04)
return -1; return -1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment