diff options
author | Mike Larkin <mlarkin@cvs.openbsd.org> | 2012-07-07 09:25:46 +0000 |
---|---|---|
committer | Mike Larkin <mlarkin@cvs.openbsd.org> | 2012-07-07 09:25:46 +0000 |
commit | 6af2ad94f914393f306a3f07c5ff7710f58da14c (patch) | |
tree | d050ffdfea98d4b5c45fae41cb04e35de962ce85 /sys | |
parent | b36e5c82c2fe95f183385cea37c852acf4641746 (diff) |
Support for USB keyboards that use a variable for each separate key in the
HID report. Fixes certain gaming-style USB keyboards.
ok miod@ deraadt@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/usb/hidkbd.c | 92 | ||||
-rw-r--r-- | sys/dev/usb/hidkbdsc.h | 22 |
2 files changed, 71 insertions, 43 deletions
diff --git a/sys/dev/usb/hidkbd.c b/sys/dev/usb/hidkbd.c index cba08e54dc1..d02a5b49cb2 100644 --- a/sys/dev/usb/hidkbd.c +++ b/sys/dev/usb/hidkbd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hidkbd.c,v 1.5 2011/11/09 14:22:38 shadchin Exp $ */ +/* $OpenBSD: hidkbd.c,v 1.6 2012/07/07 09:25:45 mlarkin Exp $ */ /* $NetBSD: ukbd.c,v 1.85 2003/03/11 16:44:00 augustss Exp $ */ /* @@ -41,6 +41,7 @@ #include <sys/kernel.h> #include <sys/device.h> #include <sys/ioctl.h> +#include <sys/malloc.h> #include <dev/usb/usb.h> #include <dev/usb/usbhid.h> @@ -164,6 +165,8 @@ hidkbd_attach(struct device *self, struct hidkbd *kbd, int console, { const char *parserr; + kbd->sc_var = NULL; + parserr = hidkbd_parse_desc(kbd, id, desc, dlen); if (parserr != NULL) { printf(": %s\n", parserr); @@ -171,8 +174,8 @@ hidkbd_attach(struct device *self, struct hidkbd *kbd, int console, } #ifdef DIAGNOSTIC - printf(": %d modifier keys, %d key codes", - kbd->sc_nmod, kbd->sc_nkeycode); + printf(": %d variable keys, %d key codes", + kbd->sc_nvar, kbd->sc_nkeycode); #endif kbd->sc_device = self; @@ -245,6 +248,9 @@ hidkbd_detach(struct hidkbd *kbd, int flags) if (kbd->sc_wskbddev != NULL) rv = config_detach(kbd->sc_wskbddev, flags); + if (kbd->sc_var != NULL) + free(kbd->sc_var, M_DEVBUF); + return (rv); } @@ -263,11 +269,9 @@ hidkbd_input(struct hidkbd *kbd, uint8_t *data, u_int len) } #endif - /* extract key modifiers */ - ud->modifiers = 0; - for (i = 0; i < kbd->sc_nmod; i++) - if (hid_get_data(data, &kbd->sc_modloc[i])) - ud->modifiers |= kbd->sc_mods[i].mask; + /* extract variable keys */ + for (i = 0; i < kbd->sc_nvar; i++) + ud->var[i] = (u_int8_t)hid_get_data(data, &kbd->sc_var[i].loc); /* extract keycodes */ memcpy(ud->keycode, data + kbd->sc_keycodeloc.pos / 8, @@ -311,7 +315,6 @@ hidkbd_delayed_decode(void *addr) void hidkbd_decode(struct hidkbd *kbd, struct hidkbd_data *ud) { - uint32_t mod, omod; u_int16_t ibuf[MAXKEYS]; /* chars events */ int s; int nkeys, i, j; @@ -347,15 +350,15 @@ hidkbd_decode(struct hidkbd *kbd, struct hidkbd_data *ud) return; /* ignore */ } nkeys = 0; - mod = ud->modifiers; - omod = kbd->sc_odata.modifiers; - if (mod != omod) - for (i = 0; i < kbd->sc_nmod; i++) - if (( mod & kbd->sc_mods[i].mask) != - (omod & kbd->sc_mods[i].mask)) - ADDKEY(kbd->sc_mods[i].key | - (mod & kbd->sc_mods[i].mask - ? PRESS : RELEASE)); + + for (i = 0; i < kbd->sc_nvar; i++) + if ((kbd->sc_odata.var[i] & kbd->sc_var[i].mask) != + (ud->var[i] & kbd->sc_var[i].mask)) { + ADDKEY(kbd->sc_var[i].key | + ((ud->var[i] & kbd->sc_var[i].mask) ? + PRESS : RELEASE)); + } + if (memcmp(ud->keycode, kbd->sc_odata.keycode, kbd->sc_nkeycode) != 0) { /* Check for released keys. */ for (i = 0; i < kbd->sc_nkeycode; i++) { @@ -547,10 +550,36 @@ hidkbd_parse_desc(struct hidkbd *kbd, int id, void *desc, int dlen) { struct hid_data *d; struct hid_item h; - int imod; + int i, ivar = 0; - imod = 0; kbd->sc_nkeycode = 0; + + d = hid_start_parse(desc, dlen, hid_input); + while (hid_get_item(d, &h)) { + if (h.kind != hid_input || (h.flags & HIO_CONST) || + HID_GET_USAGE_PAGE(h.usage) != HUP_KEYBOARD || + h.report_ID != id) + continue; + if (h.flags & HIO_VARIABLE) + ivar++; + } + hid_end_parse(d); + + if (ivar > MAXVARS) { + DPRINTF((": too many variable keys\n")); + ivar = MAXVARS; + } + + kbd->sc_nvar = ivar; + kbd->sc_var = (struct hidkbd_variable *)malloc( + sizeof(struct hidkbd_variable) * ivar, M_DEVBUF, + M_NOWAIT); + + if (!kbd->sc_var) + return NULL; + + i = 0; + d = hid_start_parse(desc, dlen, hid_input); while (hid_get_item(d, &h)) { if (h.kind != hid_input || (h.flags & HIO_CONST) || @@ -562,20 +591,18 @@ hidkbd_parse_desc(struct hidkbd *kbd, int id, void *desc, int dlen) "cnt=%d", imod, h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count)); if (h.flags & HIO_VARIABLE) { - /* modifier reports should be one bit each */ + /* variable reports should be one bit each */ if (h.loc.size != 1) { - DPRINTF((": bad modifier size\n")); + DPRINTF((": bad variable size\n")); continue; } - /* single item */ - if (imod < MAXMOD) { - kbd->sc_modloc[imod] = h.loc; - kbd->sc_mods[imod].mask = 1 << imod; - kbd->sc_mods[imod].key = HID_GET_USAGE(h.usage); - imod++; - } else { - /* ignore extra modifiers */ - DPRINTF((": too many modifier keys\n")); + + /* variable report */ + if (ivar < MAXVARS) { + kbd->sc_var[i].loc = h.loc; + kbd->sc_var[i].mask = 1 << (i % 8); + kbd->sc_var[i].key = HID_GET_USAGE(h.usage); + i++; } } else { /* keys array should be in bytes, on a byte boundary */ @@ -600,11 +627,10 @@ hidkbd_parse_desc(struct hidkbd *kbd, int id, void *desc, int dlen) } DPRINTF(("\n")); } - kbd->sc_nmod = imod; hid_end_parse(d); /* don't attach if no keys... */ - if (kbd->sc_nkeycode == 0) + if (kbd->sc_nkeycode == 0 && ivar == 0) return "no usable key codes array"; hid_locate(desc, dlen, HID_USAGE2(HUP_LEDS, HUD_LED_NUM_LOCK), diff --git a/sys/dev/usb/hidkbdsc.h b/sys/dev/usb/hidkbdsc.h index b83a68d71be..6a993aa1856 100644 --- a/sys/dev/usb/hidkbdsc.h +++ b/sys/dev/usb/hidkbdsc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hidkbdsc.h,v 1.2 2011/11/09 14:22:38 shadchin Exp $ */ +/* $OpenBSD: hidkbdsc.h,v 1.3 2012/07/07 09:25:45 mlarkin Exp $ */ /* $NetBSD: ukbd.c,v 1.85 2003/03/11 16:44:00 augustss Exp $ */ /* @@ -32,13 +32,19 @@ */ #define MAXKEYCODE 6 -#define MAXMOD 8 /* max 32 */ +#define MAXVARS 128 -#define MAXKEYS (MAXMOD+2*MAXKEYCODE) +#define MAXKEYS (MAXVARS+2*MAXKEYCODE) + +struct hidkbd_variable { + struct hid_location loc; + u_int8_t mask; + u_int8_t key; +}; struct hidkbd_data { - u_int32_t modifiers; u_int8_t keycode[MAXKEYCODE]; + u_int8_t var[MAXVARS]; }; struct hidkbd { @@ -47,12 +53,8 @@ struct hidkbd { struct hidkbd_data sc_odata; /* input reports */ - struct hid_location sc_modloc[MAXMOD]; - u_int sc_nmod; - struct { - u_int32_t mask; - u_int8_t key; - } sc_mods[MAXMOD]; + u_int sc_nvar; + struct hidkbd_variable *sc_var; struct hid_location sc_keycodeloc; u_int sc_nkeycode; |