From a84be5c79bdc5d7dfd285f2361bf205666148306 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik <vojtech@suse.cz> Date: Wed, 12 Feb 2003 12:24:25 +0100 Subject: [PATCH] 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 --- drivers/input/keyboard/atkbd.c | 56 ++++++++++++++++++++-------------- drivers/input/mouse/psmouse.c | 36 ++++++++++++++-------- 2 files changed, 56 insertions(+), 36 deletions(-) diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index b89b74637685..81938c02bd81 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -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,11 +141,15 @@ 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: @@ -227,12 +230,15 @@ 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)) @@ -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 @@ -376,8 +389,8 @@ 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"); + if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT)) + 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); } /* diff --git a/drivers/input/mouse/psmouse.c b/drivers/input/mouse/psmouse.c index e50a4814057a..f1406f55774d 100644 --- a/drivers/input/mouse/psmouse.c +++ b/drivers/input/mouse/psmouse.c @@ -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; -- 2.30.9