Module Name:    src
Committed By:   snj
Date:           Mon Sep  4 06:43:15 UTC 2017

Modified Files:
        src/sys/dev/usb [netbsd-8]: uhidev.c ukbd.c

Log Message:
Pull up following revision(s) (requested by jakllsch in ticket #263):
        sys/dev/usb/uhidev.c: revision 1.71
        sys/dev/usb/ukbd.c: revision 1.137-1.138
Fix memory leak in report parsing error paths.
--
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.
--
Always try to set USB HID devices into Report Protocol.  (Unless the
device is known to be quirky.)
Some of the most-widely-compatible methods of implementing USB Keyboard
NKRO depend on this Request to function as designed.
Issuing this Request is recommended by the HID 1.11 spec (7.2.6):
... "the host should not make any assumptions about the device's state
and should set the desired protocol whenever initializing a device."


To generate a diff of this commit:
cvs rdiff -u -r1.70 -r1.70.2.1 src/sys/dev/usb/uhidev.c
cvs rdiff -u -r1.136 -r1.136.6.1 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/uhidev.c
diff -u src/sys/dev/usb/uhidev.c:1.70 src/sys/dev/usb/uhidev.c:1.70.2.1
--- src/sys/dev/usb/uhidev.c:1.70	Thu Jun  1 02:45:12 2017
+++ src/sys/dev/usb/uhidev.c	Mon Sep  4 06:43:14 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: uhidev.c,v 1.70 2017/06/01 02:45:12 chs Exp $	*/
+/*	$NetBSD: uhidev.c,v 1.70.2.1 2017/09/04 06:43:14 snj Exp $	*/
 
 /*
  * Copyright (c) 2001, 2012 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uhidev.c,v 1.70 2017/06/01 02:45:12 chs Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uhidev.c,v 1.70.2.1 2017/09/04 06:43:14 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -153,12 +153,9 @@ uhidev_attach(device_t parent, device_t 
 		aprint_error_dev(self, "couldn't establish power handler\n");
 
 	(void)usbd_set_idle(iface, 0, 0);
-#if 0
 
-	if ((usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_NO_SET_PROTO) == 0 &&
-	    id->bInterfaceSubClass != UISUBCLASS_BOOT)
+	if ((usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_NO_SET_PROTO) == 0)
 		(void)usbd_set_protocol(iface, 1);
-#endif
 
 	maxinpktsize = 0;
 	sc->sc_iep_addr = sc->sc_oep_addr = -1;

Index: src/sys/dev/usb/ukbd.c
diff -u src/sys/dev/usb/ukbd.c:1.136 src/sys/dev/usb/ukbd.c:1.136.6.1
--- src/sys/dev/usb/ukbd.c:1.136	Fri Jan 20 02:25:24 2017
+++ src/sys/dev/usb/ukbd.c	Mon Sep  4 06:43:14 2017
@@ -1,4 +1,4 @@
-/*      $NetBSD: ukbd.c,v 1.136 2017/01/20 02:25:24 maya Exp $        */
+/*      $NetBSD: ukbd.c,v 1.136.6.1 2017/09/04 06:43:14 snj Exp $        */
 
 /*
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ukbd.c,v 1.136 2017/01/20 02:25:24 maya Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ukbd.c,v 1.136.6.1 2017/09/04 06:43:14 snj 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,35 +1039,44 @@ 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)
+			if (h.loc.size != 1) {
+				hid_end_parse(d);
 				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++;
-			} else
-				return "too many modifier keys";
+			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 Variable keys";
+			}
 		} else {
 			/* Array */
-			if (h.loc.size != 8)
+			if (h.loc.size != 8) {
+				hid_end_parse(d);
 				return "key code size != 8";
+			}
 			if (h.loc.count > MAXKEYCODE)
 				h.loc.count = MAXKEYCODE;
-			if (h.loc.pos % 8 != 0)
+			if (h.loc.pos % 8 != 0) {
+				hid_end_parse(d);
 				return "key codes not on byte boundary";
-			if (sc->sc_nkeycode != 0)
+			}
+			if (sc->sc_nkeycode != 0) {
+				hid_end_parse(d);
 				return "multiple key code arrays";
+			}
 			sc->sc_keycodeloc = h.loc;
 			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