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] = {
#define ATKBD_CMD_SETLEDS 0x10ed
#define ATKBD_CMD_GSCANSET 0x11f0
#define ATKBD_CMD_SSCANSET 0x10f0
#define ATKBD_CMD_GETID 0x01f2
#define ATKBD_CMD_GETID2 0x0100
#define ATKBD_CMD_GETID 0x02f2
#define ATKBD_CMD_ENABLE 0x00f4
#define ATKBD_CMD_RESET_DIS 0x00f5
#define ATKBD_CMD_RESET_BAT 0x01ff
......@@ -120,12 +119,12 @@ struct atkbd {
unsigned char cmdbuf[4];
unsigned char cmdcnt;
unsigned char set;
unsigned char oldset;
unsigned char release;
signed char ack;
volatile signed char ack;
unsigned char emul;
unsigned short id;
unsigned char write;
unsigned char resend;
};
/*
......@@ -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);
#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);
serio_write(serio, ATKBD_CMD_RESEND);
atkbd->resend = 1;
return;
}
if (!flags)
atkbd->resend = 0;
switch (code) {
case ATKBD_RET_ACK:
atkbd->ack = 1;
......@@ -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)
{
int timeout = 50000; /* 500 msec */
int timeout = 500000; /* 500 msec */
int send = (command >> 12) & 0xf;
int receive = (command >> 8) & 0xf;
int i;
atkbd->cmdcnt = receive;
if (command == ATKBD_CMD_RESET_BAT)
timeout = 2000000; /* 2 sec */
if (command & 0xff)
if (atkbd_sendbyte(atkbd, command & 0xff))
return (atkbd->cmdcnt = 0) - 1;
......@@ -242,14 +248,28 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command)
if (atkbd_sendbyte(atkbd, param[i]))
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)
for (i = 0; i < receive; i++)
param[i] = atkbd->cmdbuf[(receive - 1) - i];
if (atkbd->cmdcnt)
return (atkbd->cmdcnt = 0) - 1;
if (atkbd->cmdcnt) {
atkbd->cmdcnt = 0;
return -1;
}
return 0;
}
......@@ -302,13 +322,6 @@ static int atkbd_set_3(struct atkbd *atkbd)
{
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.
* We check for NCD PS/2 Sun, NorthGate OmniKey 101 and
......@@ -377,7 +390,7 @@ static int atkbd_probe(struct atkbd *atkbd)
if (atkbd_reset)
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.
......@@ -401,10 +414,7 @@ static int atkbd_probe(struct atkbd *atkbd)
if (param[0] != 0xab && param[0] != 0xac)
return -1;
atkbd->id = param[0] << 8;
if (atkbd_command(atkbd, param, ATKBD_CMD_GETID2))
return -1;
atkbd->id |= param[0];
atkbd->id = (param[0] << 8) | param[1];
/*
* Set the LEDs to a defined state.
......@@ -442,7 +452,7 @@ static int atkbd_probe(struct atkbd *atkbd)
static void atkbd_cleanup(struct serio *serio)
{
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;
#define PSMOUSE_CMD_GETINFO 0x03e9
#define PSMOUSE_CMD_SETSTREAM 0x00ea
#define PSMOUSE_CMD_POLL 0x03eb
#define PSMOUSE_CMD_GETID 0x01f2
#define PSMOUSE_CMD_GETID2 0x0100
#define PSMOUSE_CMD_GETID 0x02f2
#define PSMOUSE_CMD_SETRATE 0x10f3
#define PSMOUSE_CMD_ENABLE 0x00f4
#define PSMOUSE_CMD_RESET_DIS 0x00f6
......@@ -54,7 +53,7 @@ struct psmouse {
unsigned char model;
unsigned long last;
char acking;
char ack;
volatile char ack;
char error;
char devname[64];
char phys[32];
......@@ -85,9 +84,9 @@ static void psmouse_process_packet(struct psmouse *psmouse)
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 */
......@@ -106,10 +105,11 @@ static void psmouse_process_packet(struct psmouse *psmouse)
break;
#ifdef DEBUG
default:
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
psmouse->cmdcnt = receive;
if (command == PSMOUSE_CMD_RESET_BAT)
timeout = 2000000; /* 2 sec */
if (command & 0xff)
if (psmouse_sendbyte(psmouse, command & 0xff))
return (psmouse->cmdcnt = 0) - 1;
......@@ -256,7 +259,19 @@ static int psmouse_command(struct psmouse *psmouse, unsigned char *param, int co
if (psmouse_sendbyte(psmouse, param[i]))
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++)
param[i] = psmouse->cmdbuf[(receive - 1) - i];
......@@ -498,11 +513,6 @@ static int psmouse_probe(struct psmouse *psmouse)
if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETID))
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)
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