Module Name: src Committed By: jakllsch Date: Sun Aug 13 22:19:56 UTC 2017
Modified Files: src/sys/dev/usb: ukbd.c Log Message: Support more varieties of USB keyboard reports. The previous code asssumed reports would closely match the Bootstrap Keyboard Protocol. This is no longer always the case, particularly with higher-end keyboards. To generate a diff of this commit: cvs rdiff -u -r1.137 -r1.138 src/sys/dev/usb/ukbd.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/usb/ukbd.c diff -u src/sys/dev/usb/ukbd.c:1.137 src/sys/dev/usb/ukbd.c:1.138 --- src/sys/dev/usb/ukbd.c:1.137 Sun Aug 13 21:11:45 2017 +++ src/sys/dev/usb/ukbd.c Sun Aug 13 22:19:56 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: ukbd.c,v 1.137 2017/08/13 21:11:45 jakllsch Exp $ */ +/* $NetBSD: ukbd.c,v 1.138 2017/08/13 22:19:56 jakllsch Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ukbd.c,v 1.137 2017/08/13 21:11:45 jakllsch Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ukbd.c,v 1.138 2017/08/13 22:19:56 jakllsch Exp $"); #ifdef _KERNEL_OPT #include "opt_ddb.h" @@ -83,12 +83,11 @@ int ukbddebug = 0; #define DPRINTFN(n,x) #endif -#define MAXKEYCODE 6 -#define MAXMOD 8 /* max 32 */ +#define MAXKEYCODE 32 +#define MAXKEYS 256 struct ukbd_data { - uint32_t modifiers; - uint8_t keycode[MAXKEYCODE]; + uint8_t keys[MAXKEYS/NBBY]; }; #define PRESS 0x000 @@ -234,19 +233,14 @@ Static const uint8_t ukbd_trtab[256] = { #define KEY_ERROR 0x01 -#define MAXKEYS (MAXMOD+2*MAXKEYCODE) - struct ukbd_softc { struct uhidev sc_hdev; struct ukbd_data sc_ndata; struct ukbd_data sc_odata; - struct hid_location sc_modloc[MAXMOD]; - u_int sc_nmod; - struct { - uint32_t mask; - uint8_t key; - } sc_mods[MAXMOD]; + struct hid_location sc_keyloc[MAXKEYS]; + uint8_t sc_keyuse[MAXKEYS]; + u_int sc_nkeyloc; struct hid_location sc_keycodeloc; u_int sc_nkeycode; @@ -307,15 +301,17 @@ void ukbdtracedump(void); void ukbdtracedump(void) { - int i; + size_t i, j; for (i = 0; i < UKBDTRACESIZE; i++) { struct ukbdtraceinfo *p = &ukbdtracedata[(i+ukbdtraceindex)%UKBDTRACESIZE]; - printf("%"PRIu64".%06"PRIu64": mod=0x%02x key0=0x%02x key1=0x%02x " - "key2=0x%02x key3=0x%02x\n", - p->tv.tv_sec, (uint64_t)p->tv.tv_usec, - p->ud.modifiers, p->ud.keycode[0], p->ud.keycode[1], - p->ud.keycode[2], p->ud.keycode[3]); + printf("%"PRIu64".%06"PRIu64":", p->tv.tv_sec, + (uint64_t)p->tv.tv_usec); + for (j = 0; j < MAXKEYS; j++) { + if (isset(p->ud.keys, j)) + printf(" %zu", j); + } + printf(".\n"); } } #endif @@ -438,7 +434,7 @@ ukbd_attach(device_t parent, device_t se #endif #ifdef DIAGNOSTIC - aprint_normal(": %d modifier keys, %d key codes", sc->sc_nmod, + aprint_normal(": %d Variable keys, %d Array codes", sc->sc_nkeyloc, sc->sc_nkeycode); if (sc->sc_flags & FLAG_APPLE_FN) aprint_normal(", apple fn key"); @@ -595,21 +591,22 @@ ukbd_translate_keycodes(struct ukbd_soft const struct ukbd_keycodetrans *tab) { const struct ukbd_keycodetrans *tp; + struct ukbd_data oud; int i; - uint8_t key; - for (i = 0; i < sc->sc_nkeycode; i++) { - key = ud->keycode[i]; - if (key) + oud = *ud; + + for (i = 4; i < MAXKEYS; i++) { + if (isset(oud.keys, i)) for (tp = tab; tp->from; tp++) - if (tp->from == key) { + if (tp->from == i) { if (tp->to & IS_PMF) { pmf_event_inject( sc->sc_hdev.sc_dev, tp->to & 0xff); - ud->keycode[i] = 0; } else - ud->keycode[i] = tp->to; + setbit(ud->keys, tp->to); + clrbit(ud->keys, i); break; } } @@ -652,12 +649,18 @@ ukbd_intr(struct uhidev *addr, void *ibu } #endif - ud->modifiers = 0; - for (i = 0; i < sc->sc_nmod; i++) - if (hid_get_data(ibuf, &sc->sc_modloc[i])) - ud->modifiers |= sc->sc_mods[i].mask; - memcpy(ud->keycode, (char *)ibuf + sc->sc_keycodeloc.pos / 8, - sc->sc_nkeycode); + memset(ud->keys, 0, sizeof(ud->keys)); + + for (i = 0; i < sc->sc_nkeyloc; i++) + if (hid_get_data(ibuf, &sc->sc_keyloc[i])) + setbit(ud->keys, sc->sc_keyuse[i]); + + const uint8_t * const scancode = (char *)ibuf + sc->sc_keycodeloc.pos / 8; + const uint16_t Keyboard_NoEvent = 0x0000; + for (i = 0; i < sc->sc_nkeycode; i++) { + if (scancode[i] != Keyboard_NoEvent) + setbit(ud->keys, scancode[i]); + } if (sc->sc_flags & FLAG_APPLE_FN) { if (hid_get_data(ibuf, &sc->sc_apple_fn)) { @@ -714,10 +717,12 @@ ukbd_delayed_decode(void *addr) void ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud) { - int mod, omod; uint16_t ibuf[MAXKEYS]; /* chars events */ int s; - int nkeys, i, j; + int nkeys, i; +#ifdef WSDISPLAY_COMPAT_RAWKBD + int j; +#endif int key; #define ADDKEY(c) do { \ KASSERT(nkeys < MAXKEYS); \ @@ -740,15 +745,17 @@ ukbd_decode(struct ukbd_softc *sc, struc if (ukbddebug > 5) { struct timeval tv; microtime(&tv); - DPRINTF((" at %"PRIu64".%06"PRIu64" mod=0x%02x key0=0x%02x key1=0x%02x " - "key2=0x%02x key3=0x%02x\n", - tv.tv_sec, (uint64_t)tv.tv_usec, - ud->modifiers, ud->keycode[0], ud->keycode[1], - ud->keycode[2], ud->keycode[3])); + DPRINTF((" at %"PRIu64".%06"PRIu64":", tv.tv_sec, + (uint64_t)tv.tv_usec)); + for (size_t k = 0; k < MAXKEYS; k++) { + if (isset(ud->keys, k)) + DPRINTF((" %zu", k)); + } + DPRINTF((".\n")); } #endif - if (ud->keycode[0] == KEY_ERROR) { + if (isset(ud->keys, KEY_ERROR)) { DPRINTF(("ukbd_intr: KEY_ERROR\n")); return; /* ignore */ } @@ -757,61 +764,19 @@ ukbd_decode(struct ukbd_softc *sc, struc 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)) { - 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++) { - key = sc->sc_odata.keycode[i]; - if (key == 0) - continue; - for (j = 0; j < sc->sc_nkeycode; j++) - if (key == ud->keycode[j]) - goto rfound; - DPRINTFN(3,("ukbd_intr: relse key=0x%02x\n", key)); + for (i = 0; i < MAXKEYS; i++) { #ifdef GDIUM_KEYBOARD_HACK - if (sc->sc_flags & FLAG_GDIUM_FN) { - if (key == 0x82) { + if (sc->sc_flags & FLAG_GDIUM_FN && i == 0x82) { + if (isset(ud->keys, i)) + sc->sc_flags |= FLAG_FN_PRESSED; + else sc->sc_flags &= ~FLAG_FN_PRESSED; - goto rfound; - } } #endif - ADDKEY(key | RELEASE); - rfound: - ; - } - - /* Check for pressed keys. */ - for (i = 0; i < sc->sc_nkeycode; i++) { - key = ud->keycode[i]; - if (key == 0) - continue; - for (j = 0; j < sc->sc_nkeycode; j++) - if (key == sc->sc_odata.keycode[j]) - goto pfound; - DPRINTFN(2,("ukbd_intr: press key=0x%02x\n", key)); -#ifdef GDIUM_KEYBOARD_HACK - if (sc->sc_flags & FLAG_GDIUM_FN) { - if (key == 0x82) { - sc->sc_flags |= FLAG_FN_PRESSED; - goto pfound; - } + if (isset(ud->keys, i) != isset(sc->sc_odata.keys, i)) { + key = i | ((isset(ud->keys, i) ? PRESS : RELEASE)); + ADDKEY(ukbd_translate_modifier(sc, key)); } -#endif - ADDKEY(key | PRESS); - pfound: - ; - } } sc->sc_odata = *ud; @@ -1052,10 +1017,10 @@ ukbd_parse_desc(struct ukbd_softc *sc) struct hid_item h; int size; void *desc; - int imod; + int ikey; uhidev_get_report_desc(sc->sc_hdev.sc_parent, &desc, &size); - imod = 0; + ikey = 0; sc->sc_nkeycode = 0; d = hid_start_parse(desc, size, hid_input); while (hid_get_item(d, &h)) { @@ -1074,8 +1039,8 @@ ukbd_parse_desc(struct ukbd_softc *sc) HID_GET_USAGE_PAGE(h.usage) != HUP_KEYBOARD || h.report_ID != sc->sc_hdev.sc_report_id) continue; - DPRINTF(("ukbd: imod=%d usage=0x%x flags=0x%x pos=%d size=%d " - "cnt=%d\n", imod, + DPRINTF(("ukbd: ikey=%d usage=0x%x flags=0x%x pos=%d size=%d " + "cnt=%d\n", ikey, h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count)); if (h.flags & HIO_VARIABLE) { if (h.loc.size != 1) { @@ -1083,14 +1048,13 @@ ukbd_parse_desc(struct ukbd_softc *sc) return "bad modifier size"; } /* Single item */ - if (imod < MAXMOD) { - sc->sc_modloc[imod] = h.loc; - sc->sc_mods[imod].mask = 1 << imod; - sc->sc_mods[imod].key = HID_GET_USAGE(h.usage); - imod++; + if (ikey < MAXKEYS) { + sc->sc_keyloc[ikey] = h.loc; + sc->sc_keyuse[ikey] = HID_GET_USAGE(h.usage); + ikey++; } else { hid_end_parse(d); - return "too many modifier keys"; + return "too many Variable keys"; } } else { /* Array */ @@ -1112,7 +1076,7 @@ ukbd_parse_desc(struct ukbd_softc *sc) sc->sc_nkeycode = h.loc.count; } } - sc->sc_nmod = imod; + sc->sc_nkeyloc = ikey; hid_end_parse(d); hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_NUM_LOCK),