]> git.neil.brown.name Git - history.git/commitdiff
input: Update AT+PS/2 mouse and keyboard drivers:
authorVojtech Pavlik <vojtech@suse.cz>
Wed, 12 Feb 2003 11:24:25 +0000 (12:24 +0100)
committerVojtech Pavlik <vojtech@suse.cz>
Wed, 12 Feb 2003 11:24:25 +0000 (12:24 +0100)
- 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
drivers/input/mouse/psmouse.c

index b89b74637685ab104f203099c2a7f4ae7d332e4c..81938c02bd81bc834bee36283b58977d670dc19d 100644 (file)
@@ -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);
 }
 
 /*
index e50a4814057a470c3f8eb1dbc276fab987cf9e4a..f1406f55774d770d7c0a2f7e56480f34c7836e87 100644 (file)
@@ -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;