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),

Reply via email to