Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/usb Support for Apple notebook keyboards, which have...



details:   https://anonhg.NetBSD.org/src/rev/4a7f9ddcf3cb
branches:  trunk
changeset: 759139:4a7f9ddcf3cb
user:      phx <phx%NetBSD.org@localhost>
date:      Tue Nov 30 11:35:30 2010 +0000

description:
Support for Apple notebook keyboards, which have a few quirks.
1. On ISO-keyboard the keycodes for the key left of '1' and right of Shift
   are swapped.
2. Find the Apple FN key in the report descriptor and do the translations
   needed, before passing the keycodes to wscons.
3. Those keyboards only have the left Alt key. AltGr is missing. So it is
   emulated when holding down FN together with Alt.

diffstat:

 sys/dev/usb/ukbd.c       |  171 +++++++++++++++++++++++++++++++++++++++++-----
 sys/dev/usb/usb_quirks.c |   12 ++-
 sys/dev/usb/usb_quirks.h |    3 +-
 3 files changed, 162 insertions(+), 24 deletions(-)

diffs (truncated from 369 to 300 lines):

diff -r 760dd9682aba -r 4a7f9ddcf3cb sys/dev/usb/ukbd.c
--- a/sys/dev/usb/ukbd.c        Tue Nov 30 11:28:44 2010 +0000
+++ b/sys/dev/usb/ukbd.c        Tue Nov 30 11:35:30 2010 +0000
@@ -1,4 +1,4 @@
-/*      $NetBSD: ukbd.c,v 1.108 2010/11/03 22:34:24 dyoung Exp $        */
+/*      $NetBSD: ukbd.c,v 1.109 2010/11/30 11:35:30 phx Exp $        */
 
 /*
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ukbd.c,v 1.108 2010/11/03 22:34:24 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ukbd.c,v 1.109 2010/11/30 11:35:30 phx Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -92,6 +92,57 @@
 #define RELEASE  0x100
 #define CODEMASK 0x0ff
 
+struct ukbd_keycodetrans {
+       u_int8_t        from;
+       u_int8_t        to;
+};
+
+Static const struct ukbd_keycodetrans trtab_apple_fn[] = {
+       { 0x0c, 0x5d }, /* i -> KP 5 */
+       { 0x0d, 0x59 }, /* j -> KP 1 */
+       { 0x0e, 0x5a }, /* k -> KP 2 */
+       { 0x0f, 0x5b }, /* l -> KP 3 */
+       { 0x10, 0x62 }, /* m -> KP 0 */
+       { 0x12, 0x5e }, /* o -> KP 6 */
+       { 0x13, 0x55 }, /* o -> KP * */
+       { 0x18, 0x5c }, /* u -> KP 4 */
+       { 0x0c, 0x5d }, /* i -> KP 5 */
+       { 0x2a, 0x4c }, /* Backspace -> Delete */
+       { 0x28, 0x49 }, /* Return -> Insert */
+       { 0x24, 0x5f }, /* 7 -> KP 7 */
+       { 0x25, 0x60 }, /* 8 -> KP 8 */
+       { 0x26, 0x61 }, /* 9 -> KP 9 */
+       { 0x27, 0x54 }, /* 0 -> KP / */
+       { 0x2d, 0x67 }, /* - -> KP = */
+       { 0x33, 0x56 }, /* ; -> KP - */
+       { 0x37, 0x63 }, /* . -> KP . */
+       { 0x38, 0x57 }, /* / -> KP + */
+       { 0x3a, 0xd1 }, /* F1..F12 mapped to reserved codes 0xd1..0xdc */
+       { 0x3b, 0xd2 },
+       { 0x3c, 0xd3 },
+       { 0x3d, 0xd4 },
+       { 0x3e, 0xd5 },
+       { 0x3f, 0xd6 },
+       { 0x40, 0xd7 },
+       { 0x41, 0xd8 },
+       { 0x42, 0xd9 },
+       { 0x43, 0xda },
+       { 0x44, 0xdb },
+       { 0x45, 0xdc },
+       { 0x4f, 0x4d }, /* Right -> End */
+       { 0x50, 0x4a }, /* Left -> Home */
+       { 0x51, 0x4e }, /* Down -> PageDown */
+       { 0x52, 0x4b }, /* Up -> PageUp */
+       { 0x00, 0x00 }
+};
+
+Static const struct ukbd_keycodetrans trtab_apple_iso[] = {
+       { 0x35, 0x64 }, /* swap the key above tab with key right of shift */
+       { 0x64, 0x35 },
+       { 0x31, 0x32 }, /* key left of return is Europe1, not "\|" */
+       { 0x00, 0x00 }
+};
+
 #if defined(__NetBSD__) && defined(WSDISPLAY_COMPAT_RAWKBD)
 #define NN 0                   /* no translation */
 /*
@@ -160,14 +211,21 @@
        struct hid_location sc_keycodeloc;
        u_int sc_nkeycode;
 
-       char sc_enabled;
+       u_int sc_flags;                 /* flags */
+#define FLAG_ENABLED           0x0001
+#define FLAG_POLLING           0x0002
+#define FLAG_DEBOUNCE          0x0004  /* for quirk handling */
+#define FLAG_APPLE_FIX_ISO     0x0008
+#define FLAG_APPLE_FN          0x0010
+#define FLAG_FN_PRESSED                0x0100  /* FN key is held down */
+#define FLAG_FN_ALT            0x0200  /* Last Alt key was FN-Alt = AltGr */
 
        int sc_console_keyboard;        /* we are the console keyboard */
 
-       char sc_debounce;               /* for quirk handling */
-       struct callout sc_delay;                /* for quirk handling */
+       struct callout sc_delay;        /* for quirk handling */
        struct ukbd_data sc_data;       /* for quirk handling */
 
+       struct hid_location sc_apple_fn;
        struct hid_location sc_numloc;
        struct hid_location sc_capsloc;
        struct hid_location sc_scroloc;
@@ -187,7 +245,6 @@
 #endif /* defined(WSDISPLAY_COMPAT_RAWKBD) */
 
        int sc_spl;
-       int sc_polling;
        int sc_npollchar;
        u_int16_t sc_pollchars[MAXKEYS];
 #endif /* defined(__NetBSD__) */
@@ -317,6 +374,7 @@
        sc->sc_hdev.sc_intr = ukbd_intr;
        sc->sc_hdev.sc_parent = uha->parent;
        sc->sc_hdev.sc_report_id = uha->reportid;
+       sc->sc_flags = 0;
 
        if (!pmf_device_register(self, NULL, NULL)) {
                aprint_normal("\n");
@@ -330,15 +388,23 @@
                return;
        }
 
+       /* Quirks */
+       qflags = usbd_get_quirks(uha->parent->sc_udev)->uq_flags;
+       if (qflags & UQ_SPUR_BUT_UP)
+               sc->sc_flags |= FLAG_DEBOUNCE;
+       if (qflags & UQ_APPLE_ISO)
+               sc->sc_flags |= FLAG_APPLE_FIX_ISO;
+
 #ifdef DIAGNOSTIC
        aprint_normal(": %d modifier keys, %d key codes", sc->sc_nmod,
               sc->sc_nkeycode);
+       if (sc->sc_flags & FLAG_APPLE_FN)
+               aprint_normal(", apple fn key");
+       if (sc->sc_flags & FLAG_APPLE_FIX_ISO)
+               aprint_normal(", fix apple iso");
 #endif
        aprint_normal("\n");
 
-       qflags = usbd_get_quirks(uha->parent->sc_udev)->uq_flags;
-       sc->sc_debounce = (qflags & UQ_SPUR_BUT_UP) != 0;
-
        /*
         * Remember if we're the console keyboard.
         *
@@ -388,7 +454,7 @@
                return (EIO);
 
        /* Should only be called to change state */
-       if (sc->sc_enabled == on) {
+       if ((sc->sc_flags & FLAG_ENABLED) != 0 && on != 0) {
 #ifdef DIAGNOSTIC
                printf("ukbd_enable: %s: bad call on=%d\n",
                       device_xname(sc->sc_hdev.sc_dev), on);
@@ -397,10 +463,11 @@
        }
 
        DPRINTF(("ukbd_enable: sc=%p on=%d\n", sc, on));
-       sc->sc_enabled = on;
        if (on) {
+               sc->sc_flags |= FLAG_ENABLED;
                return (uhidev_open(&sc->sc_hdev));
        } else {
+               sc->sc_flags &= ~FLAG_ENABLED;
                uhidev_close(&sc->sc_hdev);
                return (0);
        }
@@ -476,6 +543,46 @@
        return (rv);
 }
 
+static void
+ukbd_translate_keycodes(struct ukbd_softc *sc, struct ukbd_data *ud,
+    const struct ukbd_keycodetrans *tab)
+{
+       const struct ukbd_keycodetrans *tp;
+       int i;
+       u_int8_t key;
+
+       for (i = 0; i < sc->sc_nkeycode; i++) {
+               key = ud->keycode[i];
+               if (key)
+                       for (tp = tab; tp->from; tp++)
+                               if (tp->from == key) {
+                                       ud->keycode[i] = tp->to;
+                                       break;
+                               }
+       }
+}
+
+static u_int16_t
+ukbd_translate_modifier(struct ukbd_softc *sc, u_int16_t key)
+{
+       if ((sc->sc_flags & FLAG_APPLE_FN) && (key & CODEMASK) == 0x00e2) {
+               if ((key & ~CODEMASK) == PRESS) {
+                       if (sc->sc_flags & FLAG_FN_PRESSED) {
+                               /* pressed FN-Alt, translate to AltGr */
+                               key = 0x00e6 | PRESS;
+                               sc->sc_flags |= FLAG_FN_ALT;
+                       }
+               } else {
+                       if (sc->sc_flags & FLAG_FN_ALT) {
+                               /* released Alt, which was treated as FN-Alt */
+                               key = 0x00e6 | RELEASE;
+                               sc->sc_flags &= ~FLAG_FN_ALT;
+                       }
+               }
+       }
+       return key;
+}
+
 void
 ukbd_intr(struct uhidev *addr, void *ibuf, u_int len)
 {
@@ -499,7 +606,16 @@
        memcpy(ud->keycode, (char *)ibuf + sc->sc_keycodeloc.pos / 8,
               sc->sc_nkeycode);
 
-       if (sc->sc_debounce && !sc->sc_polling) {
+       if (sc->sc_flags & FLAG_APPLE_FN) {
+               if (hid_get_data(ibuf, &sc->sc_apple_fn)) {
+                       sc->sc_flags |= FLAG_FN_PRESSED;
+                       ukbd_translate_keycodes(sc, ud, trtab_apple_fn);
+               }
+               else
+                       sc->sc_flags &= ~FLAG_FN_PRESSED;
+       }
+
+       if ((sc->sc_flags & FLAG_DEBOUNCE) && !(sc->sc_flags & FLAG_POLLING)) {
                /*
                 * Some keyboards have a peculiar quirk.  They sometimes
                 * generate a key up followed by a key down for the same
@@ -509,7 +625,7 @@
                sc->sc_data = *ud;
                callout_reset(&sc->sc_delay, hz / 50, ukbd_delayed_decode, sc);
 #ifdef DDB
-       } else if (sc->sc_console_keyboard && !sc->sc_polling) {
+       } else if (sc->sc_console_keyboard && !(sc->sc_flags & FLAG_POLLING)) {
                /*
                 * For the console keyboard we can't deliver CTL-ALT-ESC
                 * from the interrupt routine.  Doing so would start
@@ -570,16 +686,22 @@
                DPRINTF(("ukbd_intr: KEY_ERROR\n"));
                return;         /* ignore  */
        }
+
+       if (sc->sc_flags & FLAG_APPLE_FIX_ISO)
+               ukbd_translate_keycodes(sc, ud, trtab_apple_iso);
+
        nkeys = 0;
        mod = ud->modifiers;
        omod = sc->sc_odata.modifiers;
        if (mod != omod)
                for (i = 0; i < sc->sc_nmod; i++)
                        if (( mod & sc->sc_mods[i].mask) !=
-                           (omod & sc->sc_mods[i].mask))
-                               ADDKEY(sc->sc_mods[i].key |
-                                      (mod & sc->sc_mods[i].mask
-                                         ? PRESS : RELEASE));
+                           (omod & sc->sc_mods[i].mask)) {
+                               key = sc->sc_mods[i].key |
+                                   ((mod & sc->sc_mods[i].mask) ?
+                                   PRESS : RELEASE);
+                               ADDKEY(ukbd_translate_modifier(sc, key));
+                       }
        if (memcmp(ud->keycode, sc->sc_odata.keycode, sc->sc_nkeycode) != 0) {
                /* Check for released keys. */
                for (i = 0; i < sc->sc_nkeycode; i++) {
@@ -614,7 +736,7 @@
        if (nkeys == 0)
                return;
 
-       if (sc->sc_polling) {
+       if (sc->sc_flags & FLAG_POLLING) {
                DPRINTFN(1,("ukbd_intr: pollchar = 0x%03x\n", ibuf[0]));
                memcpy(sc->sc_pollchars, ibuf, nkeys * sizeof(u_int16_t));
                sc->sc_npollchar = nkeys;
@@ -779,10 +901,10 @@
                broken = 0;
 
        DPRINTFN(0,("ukbd_cngetc: enter\n"));
-       sc->sc_polling = 1;
+       sc->sc_flags |= FLAG_POLLING;
        while(sc->sc_npollchar <= 0)
                usbd_dopoll(sc->sc_hdev.sc_parent->sc_iface);
-       sc->sc_polling = 0;
+       sc->sc_flags &= ~FLAG_POLLING;
        c = sc->sc_pollchars[0];
        sc->sc_npollchar--;
        memcpy(sc->sc_pollchars, sc->sc_pollchars+1,
@@ -842,6 +964,15 @@
        while (hid_get_item(d, &h)) {
                /*printf("ukbd: id=%d kind=%d usage=0x%x flags=0x%x pos=%d size=%d cnt=%d\n",
                  h.report_ID, h.kind, h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count);*/
+
+               /* Check for special Apple notebook FN key */
+               if (HID_GET_USAGE_PAGE(h.usage) == 0x00ff &&
+                   HID_GET_USAGE(h.usage) == 0x0003 &&
+                   h.kind == hid_input && (h.flags & HIO_VARIABLE)) {
+                       sc->sc_flags |= FLAG_APPLE_FN;
+                       sc->sc_apple_fn = h.loc;



Home | Main Index | Thread Index | Old Index