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