Re: Diff to support so-called "gaming" USB keyboards

2012-07-06 Thread Stuart Henderson
On 2012/07/03 15:23, Mike Larkin wrote:
> Many low-cost USB keyboards have a limit of either 3 or 6 simultaneous
> keypresses before they wedge and stop supplying any more keypress events
> (at least until you release one of the pressed keys).

No regressions with my HHKB lite 2.

uhub4 at uhub2 port 2 "Chicony Generic USB Hub" rev 1.10/1.00 addr 3
uhidev0 at uhub4 port 1 configuration 1 interface 0 "Chicony PFU-65 USB 
Keyboard" rev 1.10/1.00 addr 4
uhidev0: iclass 3/1
ukbd0 at uhidev0: 8 variable keys, 6 key codes
wskbd1 at ukbd0 mux 1
wskbd1: connecting to wsdisplay0

Also works fine with an adderlink ipeps 1-port KVM/IP (nice
little box, you can just use normal vnc to connect to it)

uhub3: port 2, set config at addr 3 failed
uhub3: device problem, disabling port 2
uhidev0 at uhub3 port 2 configuration 1 interface 0 "RealVNC Mouse, Keyboard & 
Mass Storage" rev 2.00/1.01 addr 3
uhidev0: iclass 3/1
ukbd0 at uhidev0: 8 variable keys, 6 key codes
wskbd1 at ukbd0 mux 1
wskbd1: connecting to wsdisplay0
uhidev1 at uhub3 port 2 configuration 1 interface 1 "RealVNC Mouse, Keyboard & 
Mass Storage" rev 2.00/1.01 addr 3
uhidev1: iclass 3/0
ums0 at uhidev1: 3 buttons, Z dir
wsmouse1 at ums0 mux 0
uhidev2 at uhub3 port 2 configuration 1 interface 2 "RealVNC Mouse, Keyboard & 
Mass Storage" rev 2.00/1.01 addr 3
uhidev2: iclass 3/0
ums1 at uhidev2: 3 buttons, Z dir
wsmouse2 at ums1 mux 0



Re: Diff to support so-called "gaming" USB keyboards

2012-07-04 Thread Jasper Lievisse Adriaanse
On Tue, Jul 03, 2012 at 03:23:16PM -0700, Mike Larkin wrote:
> Many low-cost USB keyboards have a limit of either 3 or 6 simultaneous
> keypresses before they wedge and stop supplying any more keypress events
> (at least until you release one of the pressed keys).
> 
> Some newer (usually called "gaming") keyboards use a different way of
> reporting keypress events in order to support an arbitrary number of
> simultaneous keypresses (likely under the assumption that in certain
> games, you might need more than 3 or 6 keys pressed at the same time).
> 
> Our USB HID keyboard code had some bad assumptions in it - namely, that
> every key reported in this fashion was a 'modifier' key like shift,
> alt, or control, and that there would only be 8 such keys maximum.
> 
> The diff below reworks the HID keyboard code a bit to remove these
> assumptions and support these newer style USB keyboards. It also
> changes the term 'modifier' to 'variable' which is a more proper
> description of these keys (as per the HID spec), in various 
> comments and printfs.
> 
> If you have a USB keyboard (whether or not it is a "gaming" variety),
> please test this diff to ensure that it does not break you. I've tested
> on i386 and amd64 on a variety of keyboards and haven't seen any
> problems, so it's time to turn it loose to a wider audience.
> 
> -ml
This keyboard is still working fine:

uhidev2 at uhub2 port 1 configuration 1 interface 0 "Microsoft Natural\M-. 
Ergonomic Keyboard 4000" rev 2.00/1.73 addr 2
uhidev2: iclass 3/1
ukbd1 at uhidev2: 8 variable keys, 6 key codes
wskbd2 at ukbd1 mux 1
wskbd2: connecting to wsdisplay0
uhidev3 at uhub2 port 1 configuration 1 interface 1 "Microsoft Natural\M-. 
Ergonomic Keyboard 4000" rev 2.00/1.73 addr 2
uhidev3: iclass 3/0, 1 report id
uhid0 at uhidev3 reportid 1: input=7, output=0, feature=0

Although it's still suffering from the fact I need to detach/attach the cables
upon every boot/suspend otherwise it just sits there playing dead. But that's
unrelated to this diff.

> Index: hidkbd.c
> ===
> RCS file: /cvs/src/sys/dev/usb/hidkbd.c,v
> retrieving revision 1.5
> diff -a -u -r1.5 hidkbd.c
> --- hidkbd.c  9 Nov 2011 14:22:38 -   1.5
> +++ hidkbd.c  29 Jun 2012 06:45:59 -
> @@ -41,6 +41,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  #include 
>  #include 
> @@ -164,6 +165,8 @@
>  {
>   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 @@
>   }
>  
>  #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 @@
>   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 @@
>   }
>  #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 @@
>  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 @@
>   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 <

Re: Diff to support so-called "gaming" USB keyboards

2012-07-03 Thread Loganaden Velvindron
Yep. I had a similar keyboard. I'll test the diff when I'll get home.

I submitted a diff to get it to work & miod committed it along with other
stuff.

http://archives.neohapsis.com/archives/openbsd/cvs/2010-08/0017.html


On Wed, Jul 4, 2012 at 2:23 AM, Mike Larkin  wrote:
> Many low-cost USB keyboards have a limit of either 3 or 6 simultaneous
> keypresses before they wedge and stop supplying any more keypress events
> (at least until you release one of the pressed keys).
>
> Some newer (usually called "gaming") keyboards use a different way of
> reporting keypress events in order to support an arbitrary number of
> simultaneous keypresses (likely under the assumption that in certain
> games, you might need more than 3 or 6 keys pressed at the same time).
>
> Our USB HID keyboard code had some bad assumptions in it - namely, that
> every key reported in this fashion was a 'modifier' key like shift,
> alt, or control, and that there would only be 8 such keys maximum.
>
> The diff below reworks the HID keyboard code a bit to remove these
> assumptions and support these newer style USB keyboards. It also
> changes the term 'modifier' to 'variable' which is a more proper
> description of these keys (as per the HID spec), in various
> comments and printfs.
>
> If you have a USB keyboard (whether or not it is a "gaming" variety),
> please test this diff to ensure that it does not break you. I've tested
> on i386 and amd64 on a variety of keyboards and haven't seen any
> problems, so it's time to turn it loose to a wider audience.
>
> -ml
>
>
> Index: hidkbd.c
> ===
> RCS file: /cvs/src/sys/dev/usb/hidkbd.c,v
> retrieving revision 1.5
> diff -a -u -r1.5 hidkbd.c
> --- hidkbd.c9 Nov 2011 14:22:38 -   1.5
> +++ hidkbd.c29 Jun 2012 06:45:59 -
> @@ -41,6 +41,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>
>  #include 
>  #include 
> @@ -164,6 +165,8 @@
>  {
> 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 @@
> }
>
>  #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 @@
> 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 @@
> }
>  #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 @@
>  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 @@
> 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 @@
>  {
> 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

Diff to support so-called "gaming" USB keyboards

2012-07-03 Thread Mike Larkin
Many low-cost USB keyboards have a limit of either 3 or 6 simultaneous
keypresses before they wedge and stop supplying any more keypress events
(at least until you release one of the pressed keys).

Some newer (usually called "gaming") keyboards use a different way of
reporting keypress events in order to support an arbitrary number of
simultaneous keypresses (likely under the assumption that in certain
games, you might need more than 3 or 6 keys pressed at the same time).

Our USB HID keyboard code had some bad assumptions in it - namely, that
every key reported in this fashion was a 'modifier' key like shift,
alt, or control, and that there would only be 8 such keys maximum.

The diff below reworks the HID keyboard code a bit to remove these
assumptions and support these newer style USB keyboards. It also
changes the term 'modifier' to 'variable' which is a more proper
description of these keys (as per the HID spec), in various 
comments and printfs.

If you have a USB keyboard (whether or not it is a "gaming" variety),
please test this diff to ensure that it does not break you. I've tested
on i386 and amd64 on a variety of keyboards and haven't seen any
problems, so it's time to turn it loose to a wider audience.

-ml


Index: hidkbd.c
===
RCS file: /cvs/src/sys/dev/usb/hidkbd.c,v
retrieving revision 1.5
diff -a -u -r1.5 hidkbd.c
--- hidkbd.c9 Nov 2011 14:22:38 -   1.5
+++ hidkbd.c29 Jun 2012 06:45:59 -
@@ -41,6 +41,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -164,6 +165,8 @@
 {
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 @@
}
 
 #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 @@
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 @@
}
 #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 @@
 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 @@
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 @@
 {
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(str