kernel - Fix keyboard probe for chromebooks
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 3 Jan 2014 01:14:08 +0000 (17:14 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 3 Jan 2014 02:18:36 +0000 (18:18 -0800)
* Fix a broken conditional that was preventing init_keyboard() from
  ever being called.

* Reorder the sequence of code in init_keyboard(), placing the soft-reset
  command first and adding a SETLEDS command later on.

* My chromebook (Acer C720) required that a SETLEDS command be sent to
  the keyboard before it will send any keystrokes to us, for some reason.

sys/dev/misc/kbd/atkbd.c
sys/dev/misc/kbd/atkbdc.c
sys/dev/misc/kbd/atkbdcreg.h

index 74c7917..c18d598 100644 (file)
 
 static timeout_t       atkbd_timeout;
 
 
 static timeout_t       atkbd_timeout;
 
+#if 0
+static int atkbd_setmuxmode(KBDC kbdc, int value, int *mux_version);
+#endif
+
 int
 atkbd_probe_unit(int unit, int ctlr, int irq, int flags)
 {
 int
 atkbd_probe_unit(int unit, int ctlr, int irq, int flags)
 {
@@ -244,7 +248,7 @@ static int          get_kbd_echo(KBDC kbdc);
 static int             probe_keyboard(KBDC kbdc, int flags);
 static int             init_keyboard(KBDC kbdc, int *type, int flags);
 static int             write_kbd(KBDC kbdc, int command, int data);
 static int             probe_keyboard(KBDC kbdc, int flags);
 static int             init_keyboard(KBDC kbdc, int *type, int flags);
 static int             write_kbd(KBDC kbdc, int command, int data);
-static int             get_kbd_id(KBDC kbdc);
+static int             get_kbd_id(KBDC kbdc, int cmd);
 static int             typematic(int delay, int rate);
 static int             typematic_delay(int delay);
 static int             typematic_rate(int rate);
 static int             typematic(int delay, int rate);
 static int             typematic_delay(int delay);
 static int             typematic_rate(int rate);
@@ -419,7 +423,7 @@ atkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags)
        }
        if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
                kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY;
        }
        if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
                kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY;
-               if (KBD_HAS_DEVICE(kbd)
+               if (!KBD_HAS_DEVICE(kbd)
                    && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config)
                    && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD)) {
                        return ENXIO;
                    && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config)
                    && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD)) {
                        return ENXIO;
@@ -429,6 +433,7 @@ atkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags)
                delay[0] = kbd->kb_delay1;
                delay[1] = kbd->kb_delay2;
                atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
                delay[0] = kbd->kb_delay1;
                delay[1] = kbd->kb_delay2;
                atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
+               KBD_FOUND_DEVICE(kbd);
                KBD_INIT_DONE(kbd);
        }
        if (!KBD_IS_CONFIGURED(kbd)) {
                KBD_INIT_DONE(kbd);
        }
        if (!KBD_IS_CONFIGURED(kbd)) {
@@ -552,7 +557,6 @@ atkbd_check(keyboard_t *kbd)
 {
        int ret;
 
 {
        int ret;
 
-
        if (!KBD_IS_ACTIVE(kbd)) {
                return FALSE;
        }
        if (!KBD_IS_ACTIVE(kbd)) {
                return FALSE;
        }
@@ -1158,6 +1162,9 @@ init_keyboard(KBDC kbdc, int *type, int flags)
        int codeset;
        int id;
        int c;
        int codeset;
        int id;
        int c;
+       int mux_version;
+       int mux_mask;
+       int mux_val;
 
        if (!kbdc_lock(kbdc, TRUE)) {
                /* driver error? */
 
        if (!kbdc_lock(kbdc, TRUE)) {
                /* driver error? */
@@ -1167,6 +1174,17 @@ init_keyboard(KBDC kbdc, int *type, int flags)
        /* temporarily block data transmission from the keyboard */
        write_controller_command(kbdc, KBDC_DISABLE_KBD_PORT);
 
        /* temporarily block data transmission from the keyboard */
        write_controller_command(kbdc, KBDC_DISABLE_KBD_PORT);
 
+#if 0
+       if (atkbd_setmuxmode(kbdc, 1, &mux_version)) {
+               kprintf("atkbd: no mux\n");
+               mux_version = -1;
+       } else {
+               kprintf("atkbd: mux present version %d\n", mux_version);
+       }
+#else
+       mux_version = -1;
+#endif
+
        /* save the current controller command byte */
        empty_both_buffers(kbdc, 200);
        c = get_controller_command_byte(kbdc);
        /* save the current controller command byte */
        empty_both_buffers(kbdc, 200);
        c = get_controller_command_byte(kbdc);
@@ -1192,6 +1210,37 @@ init_keyboard(KBDC kbdc, int *type, int flags)
                return EIO;
        }
 
                return EIO;
        }
 
+       /* default codeset */
+       codeset = -1;
+
+       /* reset keyboard hardware */
+       if (!(flags & KB_CONF_NO_RESET) && !reset_kbd(kbdc)) {
+               /*
+                * KEYBOARD ERROR
+                * Keyboard reset may fail either because the keyboard
+                * doen't exist, or because the keyboard doesn't pass
+                * the self-test, or the keyboard controller on the
+                * motherboard and the keyboard somehow fail to shake hands.
+                * It is just possible, particularly in the last case,
+                * that the keyoard controller may be left in a hung state.
+                * test_controller() and test_kbd_port() appear to bring
+                * the keyboard controller back (I don't know why and how,
+                * though.)
+                */
+               empty_both_buffers(kbdc, 10);
+               test_controller(kbdc);
+               test_kbd_port(kbdc);
+               /*
+                * We could disable the keyboard port and interrupt... but,
+                * the keyboard may still exist (see above).
+                */
+               set_controller_command_byte(kbdc, 0xff, c);
+               kbdc_lock(kbdc, FALSE);
+               if (bootverbose)
+                       kprintf("atkbd: failed to reset the keyboard.\n");
+               return EIO;
+       }
+
        /* 
         * Check if we have an XT keyboard before we attempt to reset it. 
         * The procedure assumes that the keyboard and the controller have 
        /* 
         * Check if we have an XT keyboard before we attempt to reset it. 
         * The procedure assumes that the keyboard and the controller have 
@@ -1209,12 +1258,15 @@ init_keyboard(KBDC kbdc, int *type, int flags)
                        == KBD_ACK) 
                        codeset = read_kbd_data(kbdc);
        }
                        == KBD_ACK) 
                        codeset = read_kbd_data(kbdc);
        }
+#endif /* KBD_DETECT_XT_KEYBOARD */
        if (bootverbose)
                kprintf("atkbd: scancode set %d\n", codeset);
        if (bootverbose)
                kprintf("atkbd: scancode set %d\n", codeset);
-#endif /* KBD_DETECT_XT_KEYBOARD */
  
  
+       /*
+        * Get the keyboard id.
+        */
        *type = KB_OTHER;
        *type = KB_OTHER;
-       id = get_kbd_id(kbdc);
+       id = get_kbd_id(kbdc, ATKBD_CMD_GETID);
        switch(id) {
        case 0x41ab:    /* 101/102/... Enhanced */
        case 0x83ab:    /* ditto */
        switch(id) {
        case 0x41ab:    /* 101/102/... Enhanced */
        case 0x83ab:    /* ditto */
@@ -1236,34 +1288,6 @@ init_keyboard(KBDC kbdc, int *type, int flags)
        if (bootverbose)
                kprintf("atkbd: keyboard ID 0x%x (%d)\n", id, *type);
 
        if (bootverbose)
                kprintf("atkbd: keyboard ID 0x%x (%d)\n", id, *type);
 
-       /* reset keyboard hardware */
-       if (!(flags & KB_CONF_NO_RESET) && !reset_kbd(kbdc)) {
-               /*
-                * KEYBOARD ERROR
-                * Keyboard reset may fail either because the keyboard
-                * doen't exist, or because the keyboard doesn't pass
-                * the self-test, or the keyboard controller on the
-                * motherboard and the keyboard somehow fail to shake hands.
-                * It is just possible, particularly in the last case,
-                * that the keyoard controller may be left in a hung state.
-                * test_controller() and test_kbd_port() appear to bring
-                * the keyboard controller back (I don't know why and how,
-                * though.)
-                */
-               empty_both_buffers(kbdc, 10);
-               test_controller(kbdc);
-               test_kbd_port(kbdc);
-               /*
-                * We could disable the keyboard port and interrupt... but, 
-                * the keyboard may still exist (see above). 
-                */
-               set_controller_command_byte(kbdc, 0xff, c);
-               kbdc_lock(kbdc, FALSE);
-               if (bootverbose)
-                       kprintf("atkbd: failed to reset the keyboard.\n");
-               return EIO;
-       }
-
        /*
         * Allow us to set the XT_KEYBD flag in UserConfig so that keyboards
         * such as those on the IBM ThinkPad laptop computers can be used
        /*
         * Allow us to set the XT_KEYBD flag in UserConfig so that keyboards
         * such as those on the IBM ThinkPad laptop computers can be used
@@ -1287,11 +1311,71 @@ init_keyboard(KBDC kbdc, int *type, int flags)
                }
        }
 
                }
        }
 
+#if 0
+       if (send_kbd_command_and_data(kbdc, ATKBD_CMD_EX_ENABLE, 0x71) != KBD_ACK)
+               kprintf("atkbd: can't CMD_EX_ENABLE\n");
+
+       if (send_kbd_command(kbdc, ATKBD_CMD_SETALL_MB) != KBD_ACK)
+               kprintf("atkbd: can't SETALL_MB\n");
+       if (send_kbd_command(kbdc, ATKBD_CMD_SETALL_MBR) != KBD_ACK)
+               kprintf("atkbd: can't SETALL_MBR\n");
+#endif
+#if 0
+       if (send_kbd_command_and_data(kbdc, ATKBD_CMD_SSCANSET, 2) != KBD_ACK)
+               kprintf("atkbd: can't SSCANSET\n");
+       if (send_kbd_command_and_data(kbdc, ATKBD_CMD_GSCANSET, 0) != KBD_ACK)
+               kprintf("atkbd: can't SSCANSET\n");
+       else
+               kprintf("atkbd: scanset %d\n", read_kbd_data(kbdc));
+#endif
+#if 0
+       kprintf("atkbd: id %04x\n", get_kbd_id(kbdc, ATKBD_CMD_OK_GETID));
+       if (send_kbd_command_and_data(kbdc, ATKBD_CMD_SETLEDS, 0) != KBD_ACK)
+               kprintf("atkbd: setleds failed\n");
+       if (send_kbd_command_and_data(kbdc, ATKBD_CMD_SETREP, 255) != KBD_ACK)
+               kprintf("atkbd: setrep failed\n");
+       if (send_kbd_command(kbdc, ATKBD_CMD_RESEND) != KBD_ACK)
+               kprintf("atkbd: resend failed\n");
+#endif
+       /*
+        * Some keyboards require a SETLEDS command to be sent after
+        * the reset command before they will send keystrokes to us
+        * (Acer C720).
+        */
+       if (send_kbd_command_and_data(kbdc, ATKBD_CMD_SETLEDS, 0) != KBD_ACK)
+               kprintf("atkbd: setleds failed\n");
+       send_kbd_command(kbdc, ATKBD_CMD_ENABLE);
+
+#if 0
+       /* DEBUGGING */
+       {
+               int retry;
+               int c;
+               kprintf("atkbd: waiting for keypress");
+               for (retry = 0; retry < 10; ++retry) {
+                       c = read_kbd_data_no_wait(kbdc);
+                       kprintf(" %d", c);
+                       tsleep(&c, 0, "wait", hz);
+               }
+               kprintf("\n");
+       }
+#endif
+
+       if (mux_version == -1) {
+               mux_mask = 0;
+               mux_val = 0;
+       } else {
+               mux_mask = KBD_AUX_CONTROL_BITS;
+               mux_val = 0;
+               kprintf("atkbd: setaux for multiplexer\n");
+       }
+
        /* enable the keyboard port and intr. */
        if (!set_controller_command_byte(kbdc, 
        /* enable the keyboard port and intr. */
        if (!set_controller_command_byte(kbdc, 
-               KBD_KBD_CONTROL_BITS | KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK,
+               KBD_KBD_CONTROL_BITS | KBD_TRANSLATION |
+               KBD_OVERRIDE_KBD_LOCK | mux_mask,
                (c & (KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK))
                (c & (KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK))
-                   | KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) {
+                   | KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT | mux_val)) {
                /*
                 * CONTROLLER ERROR 
                 * This is serious; we are left with the disabled
                /*
                 * CONTROLLER ERROR 
                 * This is serious; we are left with the disabled
@@ -1307,6 +1391,54 @@ init_keyboard(KBDC kbdc, int *type, int flags)
        return 0;
 }
 
        return 0;
 }
 
+#if 0
+
+static
+int
+atkbd_setmuxmode(KBDC kbdc, int enable, int *mux_version)
+{
+       int param;
+       int val;
+       int i;
+
+       kbdc->mux_active = 0;
+       empty_both_buffers(kbdc, 100);
+       val = 0xf0;
+       if ((param = write_controller_w1r1(kbdc, KBDC_AUX_LOOP, val)) != val) {
+               kprintf("setmuxmode: fail1\n");
+               return(-1);
+       }
+       val = enable ? 0x56 : 0xf6;
+       if ((param = write_controller_w1r1(kbdc, KBDC_AUX_LOOP, val)) != val) {
+               kprintf("setmuxmode: fail2\n");
+               return(-1);
+       }
+       val = enable ? 0xa4 : 0xa5;
+       if ((param = write_controller_w1r1(kbdc, KBDC_AUX_LOOP, val)) != val) {
+               kprintf("setmuxmode: fail3\n");
+               return(-1);
+       }
+       kprintf("mux version %02x\n", param);
+       if (param == 0xac) {
+               kprintf("setmuxmode: fail4\n");
+               return(-1);
+       }
+
+       if (enable) {
+               for (i = 0; i < KBD_NUM_MUX_PORTS; ++i) {
+                       write_controller_command(kbdc, KBDC_MUX_PFX + i);
+                       write_controller_command(kbdc, KBDC_ENABLE_AUX_PORT);
+
+               }
+       }
+       kbdc->mux_active = 1;
+       if (mux_version)
+               *mux_version = param;
+       return 0;
+}
+
+#endif
+
 static int
 write_kbd(KBDC kbdc, int command, int data)
 {
 static int
 write_kbd(KBDC kbdc, int command, int data)
 {
@@ -1357,13 +1489,13 @@ write_kbd(KBDC kbdc, int command, int data)
 }
 
 static int
 }
 
 static int
-get_kbd_id(KBDC kbdc)
+get_kbd_id(KBDC kbdc, int cmd)
 {
        int id1, id2;
 
        empty_both_buffers(kbdc, 10);
        id1 = id2 = -1;
 {
        int id1, id2;
 
        empty_both_buffers(kbdc, 10);
        id1 = id2 = -1;
-       if (send_kbd_command(kbdc, KBDC_SEND_DEV_ID) != KBD_ACK)
+       if (send_kbd_command(kbdc, cmd) != KBD_ACK)
                return -1;
 
        DELAY(10000);   /* 10 msec delay */
                return -1;
 
        DELAY(10000);   /* 10 msec delay */
index a178c3a..e8d69fa 100644 (file)
@@ -335,14 +335,17 @@ wait_while_controller_busy(struct atkbdc_softc *kbdc)
     /* CPU will stay inside the loop for 100msec at most */
     TOTALDELAY retry = { .us = 70000, .last_clock =0 };        /* 70ms */
     int f;
     /* CPU will stay inside the loop for 100msec at most */
     TOTALDELAY retry = { .us = 70000, .last_clock =0 };        /* 70ms */
     int f;
+    unsigned char c;
 
     while ((f = read_status(kbdc)) & KBDS_INPUT_BUFFER_FULL) {
        if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) {
            DELAY(KBDD_DELAYTIME);
 
     while ((f = read_status(kbdc)) & KBDS_INPUT_BUFFER_FULL) {
        if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) {
            DELAY(KBDD_DELAYTIME);
-           addq(&kbdc->kbd, read_data(kbdc));
+           c = read_data(kbdc);
+           addq(&kbdc->kbd, c);
        } else if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) {
            DELAY(KBDD_DELAYTIME);
        } else if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) {
            DELAY(KBDD_DELAYTIME);
-           addq(&kbdc->aux, read_data(kbdc));
+           c = read_data(kbdc);
+           addq(&kbdc->aux, c);
        }
         DELAY(KBDC_DELAYTIME);
        if (CHECKTIMEOUT(&retry))
        }
         DELAY(KBDC_DELAYTIME);
        if (CHECKTIMEOUT(&retry))
@@ -378,12 +381,14 @@ wait_for_kbd_data(struct atkbdc_softc *kbdc)
     /* CPU will stay inside the loop for 200msec at most */
     TOTALDELAY retry = { 200000, 0 };  /* 200ms */
     int f;
     /* CPU will stay inside the loop for 200msec at most */
     TOTALDELAY retry = { 200000, 0 };  /* 200ms */
     int f;
+    unsigned char c;
 
     while ((f = read_status(kbdc) & KBDS_BUFFER_FULL)
            != KBDS_KBD_BUFFER_FULL) {
         if (f == KBDS_AUX_BUFFER_FULL) {
            DELAY(KBDD_DELAYTIME);
 
     while ((f = read_status(kbdc) & KBDS_BUFFER_FULL)
            != KBDS_KBD_BUFFER_FULL) {
         if (f == KBDS_AUX_BUFFER_FULL) {
            DELAY(KBDD_DELAYTIME);
-           addq(&kbdc->aux, read_data(kbdc));
+           c = read_data(kbdc);
+           addq(&kbdc->aux, c);
        }
         DELAY(KBDC_DELAYTIME);
         if (CHECKTIMEOUT(&retry))
        }
         DELAY(KBDC_DELAYTIME);
         if (CHECKTIMEOUT(&retry))
@@ -430,12 +435,14 @@ wait_for_aux_data(struct atkbdc_softc *kbdc)
     /* CPU will stay inside the loop for 200msec at most */
     TOTALDELAY retry = { 200000, 0 };  /* 200ms */
     int f;
     /* CPU will stay inside the loop for 200msec at most */
     TOTALDELAY retry = { 200000, 0 };  /* 200ms */
     int f;
+    unsigned char b;
 
     while ((f = read_status(kbdc) & KBDS_BUFFER_FULL)
            != KBDS_AUX_BUFFER_FULL) {
         if (f == KBDS_KBD_BUFFER_FULL) {
            DELAY(KBDD_DELAYTIME);
 
     while ((f = read_status(kbdc) & KBDS_BUFFER_FULL)
            != KBDS_AUX_BUFFER_FULL) {
         if (f == KBDS_KBD_BUFFER_FULL) {
            DELAY(KBDD_DELAYTIME);
-           addq(&kbdc->kbd, read_data(kbdc));
+           b = read_data(kbdc);
+           addq(&kbdc->kbd, b);
        }
         DELAY(KBDC_DELAYTIME);
        if (CHECKTIMEOUT(&retry))
        }
         DELAY(KBDC_DELAYTIME);
        if (CHECKTIMEOUT(&retry))
@@ -475,6 +482,19 @@ wait_for_aux_ack(struct atkbdc_softc *kbdc)
     return -1;
 }
 
     return -1;
 }
 
+/*
+ * Returns read-back data or -1 on failure
+ */
+int
+write_controller_w1r1(KBDC p, int c, int d)
+{
+    if (!write_controller_command(p, c))
+       return(-1);
+    if (!write_controller_data(p, d))
+       return(-1);
+    return (read_controller_data(p));
+}
+
 /* write a one byte command to the controller */
 int
 write_controller_command(KBDC p, int c)
 /* write a one byte command to the controller */
 int
 write_controller_command(KBDC p, int c)
@@ -641,6 +661,8 @@ static int call = 0;
 int
 read_kbd_data(KBDC p)
 {
 int
 read_kbd_data(KBDC p)
 {
+    unsigned char b;
+
 #if KBDIO_DEBUG >= 2
     if (++call > 2000) {
        call = 0;
 #if KBDIO_DEBUG >= 2
     if (++call > 2000) {
        call = 0;
@@ -655,7 +677,8 @@ read_kbd_data(KBDC p)
         return removeq(&kbdcp(p)->kbd);
     if (!wait_for_kbd_data(kbdcp(p)))
         return -1;             /* timeout */
         return removeq(&kbdcp(p)->kbd);
     if (!wait_for_kbd_data(kbdcp(p)))
         return -1;             /* timeout */
-    return read_data(kbdcp(p));
+    b = read_data(kbdcp(p));
+    return b;
 }
 
 /* read one byte from the keyboard, but return immediately if 
 }
 
 /* read one byte from the keyboard, but return immediately if 
@@ -665,6 +688,7 @@ int
 read_kbd_data_no_wait(KBDC p)
 {
     int f;
 read_kbd_data_no_wait(KBDC p)
 {
     int f;
+    unsigned char b;
 
 #if KBDIO_DEBUG >= 2
     if (++call > 2000) {
 
 #if KBDIO_DEBUG >= 2
     if (++call > 2000) {
@@ -679,14 +703,16 @@ read_kbd_data_no_wait(KBDC p)
     if (availq(&kbdcp(p)->kbd)) 
         return removeq(&kbdcp(p)->kbd);
     f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
     if (availq(&kbdcp(p)->kbd)) 
         return removeq(&kbdcp(p)->kbd);
     f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
-    if (f == KBDS_AUX_BUFFER_FULL) {
+    while (f == KBDS_AUX_BUFFER_FULL) {
         DELAY(KBDD_DELAYTIME);
         DELAY(KBDD_DELAYTIME);
-        addq(&kbdcp(p)->aux, read_data(kbdcp(p)));
+       b = read_data(kbdcp(p));
+        addq(&kbdcp(p)->aux, b);
         f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
     }
     if (f == KBDS_KBD_BUFFER_FULL) {
         DELAY(KBDD_DELAYTIME);
         f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
     }
     if (f == KBDS_KBD_BUFFER_FULL) {
         DELAY(KBDD_DELAYTIME);
-        return read_data(kbdcp(p));
+       b = read_data(kbdcp(p));
+        return (int)b;
     }
     return -1;         /* no data */
 }
     }
     return -1;         /* no data */
 }
@@ -695,11 +721,13 @@ read_kbd_data_no_wait(KBDC p)
 int
 read_aux_data(KBDC p)
 {
 int
 read_aux_data(KBDC p)
 {
+    unsigned char b;
     if (availq(&kbdcp(p)->aux)) 
         return removeq(&kbdcp(p)->aux);
     if (!wait_for_aux_data(kbdcp(p)))
         return -1;             /* timeout */
     if (availq(&kbdcp(p)->aux)) 
         return removeq(&kbdcp(p)->aux);
     if (!wait_for_aux_data(kbdcp(p)))
         return -1;             /* timeout */
-    return read_data(kbdcp(p));
+    b = read_data(kbdcp(p));
+    return b;
 }
 
 /* read one byte from the aux device, but return immediately if 
 }
 
 /* read one byte from the aux device, but return immediately if 
@@ -708,19 +736,22 @@ read_aux_data(KBDC p)
 int
 read_aux_data_no_wait(KBDC p)
 {
 int
 read_aux_data_no_wait(KBDC p)
 {
+    unsigned char b;
     int f;
 
     if (availq(&kbdcp(p)->aux)) 
         return removeq(&kbdcp(p)->aux);
     f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
     int f;
 
     if (availq(&kbdcp(p)->aux)) 
         return removeq(&kbdcp(p)->aux);
     f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
-    if (f == KBDS_KBD_BUFFER_FULL) {
+    while (f == KBDS_KBD_BUFFER_FULL) {
         DELAY(KBDD_DELAYTIME);
         DELAY(KBDD_DELAYTIME);
-        addq(&kbdcp(p)->kbd, read_data(kbdcp(p)));
+       b = read_data(kbdcp(p));
+        addq(&kbdcp(p)->kbd, b);
         f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
     }
     if (f == KBDS_AUX_BUFFER_FULL) {
         DELAY(KBDD_DELAYTIME);
         f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
     }
     if (f == KBDS_AUX_BUFFER_FULL) {
         DELAY(KBDD_DELAYTIME);
-        return read_data(kbdcp(p));
+       b = read_data(kbdcp(p));
+        return b;
     }
     return -1;         /* no data */
 }
     }
     return -1;         /* no data */
 }
@@ -1043,14 +1074,26 @@ set_controller_command_byte(KBDC p, int mask, int command)
        return FALSE;
 
     command = (kbdcp(p)->command_byte & ~mask) | (command & mask);
        return FALSE;
 
     command = (kbdcp(p)->command_byte & ~mask) | (command & mask);
-    if (command & KBD_DISABLE_KBD_PORT) {
-       if (!write_controller_command(p, KBDC_DISABLE_KBD_PORT))
-           return FALSE;
+#if 1
+    if (mask & KBD_DISABLE_KBD_PORT) {
+           if (command & KBD_DISABLE_KBD_PORT) {
+               if (!write_controller_command(p, KBDC_DISABLE_KBD_PORT))
+                   return FALSE;
+           }
     }
     }
+#endif
     if (!write_controller_command(p, KBDC_SET_COMMAND_BYTE))
        return FALSE;
     if (!write_controller_data(p, command))
        return FALSE;
     if (!write_controller_command(p, KBDC_SET_COMMAND_BYTE))
        return FALSE;
     if (!write_controller_data(p, command))
        return FALSE;
+#if 0
+    if (mask & KBD_DISABLE_KBD_PORT) {
+           if ((command & KBD_DISABLE_KBD_PORT) == 0) {
+               if (!write_controller_command(p, KBDC_ENABLE_KBD_PORT))
+                   return FALSE;
+           }
+    }
+#endif
     kbdcp(p)->command_byte = command;
 
     if (verbose)
     kbdcp(p)->command_byte = command;
 
     if (verbose)
index 07383ec..767171a 100644 (file)
@@ -45,6 +45,9 @@
                                         * and mouse command port 
                                         */
 
                                         * and mouse command port 
                                         */
 
+/* misc */
+#define KBD_NUM_MUX_PORTS      4
+
 /* controller commands (sent to KBD_COMMAND_PORT) */
 #define KBDC_SET_COMMAND_BYTE  0x0060
 #define KBDC_GET_COMMAND_BYTE  0x0020
 /* controller commands (sent to KBD_COMMAND_PORT) */
 #define KBDC_SET_COMMAND_BYTE  0x0060
 #define KBDC_GET_COMMAND_BYTE  0x0020
@@ -56,6 +59,9 @@
 #define KBDC_TEST_KBD_PORT     0x00ab
 #define KBDC_DISABLE_KBD_PORT  0x00ad
 #define KBDC_ENABLE_KBD_PORT   0x00ae
 #define KBDC_TEST_KBD_PORT     0x00ab
 #define KBDC_DISABLE_KBD_PORT  0x00ad
 #define KBDC_ENABLE_KBD_PORT   0x00ae
+#define KBDC_AUX_LOOP          0x00d3  /* mux test w+1, r+1 */
+#define KBDC_MUX_PFX           0x0090
+#define KBDC_MUX_SEND          0x0090
 
 /* controller command byte (set by KBDC_SET_COMMAND_BYTE) */
 #define KBD_TRANSLATION                0x0040
 
 /* controller command byte (set by KBDC_SET_COMMAND_BYTE) */
 #define KBD_TRANSLATION                0x0040
 #define KBDC_SET_SCANCODE_SET  0x00f0
 #define KBDC_SET_TYPEMATIC     0x00f3
 
 #define KBDC_SET_SCANCODE_SET  0x00f0
 #define KBDC_SET_TYPEMATIC     0x00f3
 
+#define ATKBD_CMD_SETLEDS       0x10ed
+#define ATKBD_CMD_GSCANSET      0x11f0
+#define ATKBD_CMD_SSCANSET      0x10f0
+#define ATKBD_CMD_GETID         0x02f2
+#define ATKBD_CMD_SETREP        0x10f3
+#define ATKBD_CMD_ENABLE        0x00f4
+#define ATKBD_CMD_RESET_DIS     0x00f5  /* Reset to defaults and disable */
+#define ATKBD_CMD_RESET_DEF     0x00f6  /* Reset to defaults */
+#define ATKBD_CMD_SETALL_MB     0x00f8  /* Set all keys to give break codes */
+#define ATKBD_CMD_SETALL_MBR    0x00fa  /* ... and repeat */
+#define ATKBD_CMD_RESET_BAT     0x02ff
+#define ATKBD_CMD_RESEND        0x00fe
+#define ATKBD_CMD_EX_ENABLE     0x10ea
+#define ATKBD_CMD_EX_SETLEDS    0x20eb
+#define ATKBD_CMD_OK_GETID      0x02e8
+
 /* aux device commands (sent to KBD_DATA_PORT) */
 #define PSMC_RESET_DEV         0x00ff
 #define PSMC_ENABLE_DEV        0x00f4
 /* aux device commands (sent to KBD_DATA_PORT) */
 #define PSMC_RESET_DEV         0x00ff
 #define PSMC_ENABLE_DEV        0x00f4
 
 /* status bits (KBD_STATUS_PORT) */
 #define KBDS_BUFFER_FULL       0x0021
 
 /* status bits (KBD_STATUS_PORT) */
 #define KBDS_BUFFER_FULL       0x0021
-#define KBDS_ANY_BUFFER_FULL   0x0001
-#define KBDS_KBD_BUFFER_FULL   0x0001
-#define KBDS_AUX_BUFFER_FULL   0x0021
-#define KBDS_INPUT_BUFFER_FULL 0x0002
+#define KBDS_ANY_BUFFER_FULL   0x0001  /* (data from controller pending) */
+#define KBDS_KBD_BUFFER_FULL   0x0001  /* mask/match KBDS_BUFFER_FULL */
+#define KBDS_AUX_BUFFER_FULL   0x0021  /* mask/match KBDS_BUFFER_FULL */
+#define KBDS_INPUT_BUFFER_FULL 0x0002  /* (cmd/data to controller pending) */
+
+#define I8042_STR_PARITY       0x80    /* Also MUX data address bit */
+#define I8042_STR_TIMEOUT      0x40    /* Also MUX data address bit */
+#define I8042_STR_AUXDATA      0x20
+#define I8042_STR_KEYLOCK      0x10
+#define I8042_STR_CMDDAT       0x08
+#define I8042_STR_MUXERR       0x04
+#define I8042_STR_IBF          0x02    /* write pending (outgoing) */
+#define I8042_STR_OBF          0x01    /* read pending (incoming) */
+
+#define I8042_STR_MUX_SHIFT    6
+#define I8042_STR_MUX_MASK     3
 
 /* return code */
 #define KBD_ACK                0x00fa
 
 /* return code */
 #define KBD_ACK                0x00fa
@@ -196,6 +230,7 @@ typedef struct atkbdc_softc {
     bus_space_handle_t ioh1;
     int command_byte;          /* current command byte value */
     int command_mask;          /* command byte mask bits for kbd/aux devices */
     bus_space_handle_t ioh1;
     int command_byte;          /* current command byte value */
     int command_mask;          /* command byte mask bits for kbd/aux devices */
+    int mux_active;            /* multiplexer is active */
     int lock;                  /* FIXME: XXX not quite a semaphore... */
     kbdkqueue kbd;             /* keyboard data queue */
     kbdkqueue aux;             /* auxiliary data queue */
     int lock;                  /* FIXME: XXX not quite a semaphore... */
     kbdkqueue kbd;             /* keyboard data queue */
     kbdkqueue aux;             /* auxiliary data queue */
@@ -210,7 +245,7 @@ enum kbdc_device_ivar {
        KBDC_IVAR_COMPATID, 
 };
 
        KBDC_IVAR_COMPATID, 
 };
 
-typedef caddr_t KBDC;
+typedef struct atkbdc_softc *KBDC;
 
 #define KBDC_RID_KBD    0
 #define KBDC_RID_AUX    1
 
 #define KBDC_RID_KBD    0
 #define KBDC_RID_AUX    1
@@ -228,7 +263,8 @@ int kbdc_lock(KBDC kbdc, int lock);
 int kbdc_data_ready(KBDC kbdc);
 
 int write_controller_command(KBDC kbdc,int c);
 int kbdc_data_ready(KBDC kbdc);
 
 int write_controller_command(KBDC kbdc,int c);
-int write_controller_data(KBDC kbdc,int c);
+int write_controller_data(KBDC kbdc, int c);
+int write_controller_w1r1(KBDC kbdc, int c, int d);
 
 int write_kbd_command(KBDC kbdc,int c);
 int write_aux_command(KBDC kbdc,int c);
 
 int write_kbd_command(KBDC kbdc,int c);
 int write_aux_command(KBDC kbdc,int c);