On 18/08/21(Wed) 17:50, Mark Kettenis wrote:
> > Date: Tue, 17 Aug 2021 20:13:41 +0200
> > From: Anton Lindqvist <an...@openbsd.org>
> > 
> > Hi,
> > 
> > Here's a new driver for USB HID Consumer Control keyboards. Such
> > keyboard is a pseudo device which is used to expose audio and
> > application launch keys. My prime motivation is to get the volume mute,
> > increment and decrement keys to just work on my keyboard without the
> > need to use usbhidaction(1).
> > 
> > ucc(4) attaches a wskbd(4) keyboard "on top" making it appear like an
> > ordinary keyboard, which also makes it possible to inject key
> > press/release input. It supports both translating and raw mode making it
> > compatible with the ordinary console and X11.
> > 
> > My keyboard for instance exposes 42 keys in its input report. I only
> > care about the volume and audio related ones and therefore only added
> > mappings for those. Additional mappings should be trivial to add if
> > desired.
> > 
> > Testing would be much appreciated.
> > 
> > Comments? OK?
> 
> So the downside of this is that you get a separate wskbd(4) device for
> these.  This will be transparent for most users thanks to wsmux(4),
> but it does mean that doing a multi-seat wscons setup becomes a little
> bit more involved.  That's fine with me as I don't think that's an
> important use case for OpenBSD.
>
> This looks reasonable to me.

I agree.  I am also very happy to see a kernel driver that makes things
work out-of-the-box.

Regarding the introduction of a separate wskbd(4) this can be seen as an
intermediate step.  Having this logic in ukbd(4) implies revisiting the
way reportID are mapped to USB drivers, which is still a bit of a hack
when it comes to supporting multiple of them.  Having a simpler driver
like ucc(4) can help us figure out out to support more "special" keys
without having to deal with the HID logic at the same time.

It would be great if users of usbhidaction(1) could tell us if this
introduce any regression and/or if other keys could be supported.

I'm definitively ok with this direction.

> > diff --git share/man/man4/Makefile share/man/man4/Makefile
> > index 6a0ecb20653..63b33660159 100644
> > --- share/man/man4/Makefile
> > +++ share/man/man4/Makefile
> > @@ -84,7 +84,7 @@ MAN=      aac.4 abcrtc.4 abl.4 ac97.4 acphy.4 acrtc.4 \
> >     tlphy.4 thmc.4 tpm.4 tpmr.4 tqphy.4 trm.4 trunk.4 tsl.4 tty.4 \
> >     tun.4 tap.4 twe.4 \
> >     txp.4 txphy.4 uaudio.4 uark.4 uath.4 ubcmtp.4 uberry.4 ubsa.4 \
> > -   ubsec.4 ucom.4 uchcom.4 ucrcom.4 ucycom.4 ukspan.4 uslhcom.4 \
> > +   ubsec.4 ucc.4 ucom.4 uchcom.4 ucrcom.4 ucycom.4 ukspan.4 uslhcom.4 \
> >     udav.4 udcf.4 udl.4 udp.4 udsbr.4 \
> >     uftdi.4 ugen.4 ugl.4 ugold.4 uguru.4 uhci.4 uhid.4 uhidev.4 uhidpp.4 \
> >     uipaq.4 ujoy.4 uk.4 ukbd.4 \
> > diff --git share/man/man4/ucc.4 share/man/man4/ucc.4
> > new file mode 100644
> > index 00000000000..413c88aa6af
> > --- /dev/null
> > +++ share/man/man4/ucc.4
> > @@ -0,0 +1,45 @@
> > +.\"        $OpenBSD$
> > +.\"
> > +.\" Copyright (c) 2021 Anton Lindqvist <an...@openbsd.org>
> > +.\"
> > +.\" Permission to use, copy, modify, and distribute this software for any
> > +.\" purpose with or without fee is hereby granted, provided that the above
> > +.\" copyright notice and this permission notice appear in all copies.
> > +.\"
> > +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 
> > WARRANTIES
> > +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> > +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> > +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> > +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> > +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> > +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> > +.\"
> > +.Dd $Mdocdate$
> > +.Dt UCC 4
> > +.Os
> > +.Sh NAME
> > +.Nm ucc
> > +.Nd Consumer Control keyboards
> > +.Sh SYNOPSIS
> > +.Cd "ucc* at uhidev?"
> > +.Cd "wsbkd* at ucc? mux 1"
> > +.Sh DESCRIPTION
> > +The
> > +.Nm
> > +driver provides support for Consumer Control pseudo keyboards, often used 
> > to
> > +expose audio and application launch keys.
> > +.Sh SEE ALSO
> > +.Xr intro 4 ,
> > +.Xr uhidev 4 ,
> > +.Xr usb 4 ,
> > +.Xr wskbd 4
> > +.Sh HISTORY
> > +The
> > +.Nm
> > +driver first appeared in
> > +.Ox 7.0 .
> > +.Sh AUTHORS
> > +The
> > +.Nm
> > +driver was written by
> > +.An Anton Lindqvist Aq Mt an...@openbsd.org .
> > diff --git share/man/man4/uhidev.4 share/man/man4/uhidev.4
> > index 02252789a3f..d398c564bd5 100644
> > --- share/man/man4/uhidev.4
> > +++ share/man/man4/uhidev.4
> > @@ -37,6 +37,7 @@
> >  .Sh SYNOPSIS
> >  .Cd "uhidev*  at uhub?"
> >  .Cd "fido*    at uhidev?"
> > +.Cd "ucc*     at uhidev?"
> >  .Cd "ucycom*  at uhidev?"
> >  .Cd "ugold*   at uhidev?"
> >  .Cd "uhid*    at uhidev?"
> > @@ -72,6 +73,7 @@ only dispatches data to them based on the report id.
> >  .Sh SEE ALSO
> >  .Xr fido 4 ,
> >  .Xr intro 4 ,
> > +.Xr ucc 4 ,
> >  .Xr ucycom 4 ,
> >  .Xr ugold 4 ,
> >  .Xr uhid 4 ,
> > diff --git share/man/man4/usb.4 share/man/man4/usb.4
> > index dad3d3a97d9..d159d8b27f3 100644
> > --- share/man/man4/usb.4
> > +++ share/man/man4/usb.4
> > @@ -249,6 +249,8 @@ D-Link DSB-R100 USB radio device
> >  FIDO/U2F security keys
> >  .It Xr ubcmtp 4
> >  Broadcom trackpad mouse
> > +.It Xr ucc 4
> > +USB Consumer Control keyboards
> >  .It Xr ugold 4
> >  TEMPer gold HID thermometer and hygrometer
> >  .It Xr uhid 4
> > diff --git sys/arch/alpha/conf/GENERIC sys/arch/alpha/conf/GENERIC
> > index 8af652ce301..54d4a45cd4e 100644
> > --- sys/arch/alpha/conf/GENERIC
> > +++ sys/arch/alpha/conf/GENERIC
> > @@ -107,6 +107,8 @@ uslhcom* at uhidev?                     # Silicon Labs 
> > CP2110 USB HID UART
> >  ucom*      at uslhcom?
> >  uhid*      at uhidev?                      # USB generic HID support
> >  fido*      at uhidev?                      # FIDO/U2F security key support
> > +ucc*       at uhidev?                      # Consumer Control keyboards
> > +wskbd*     at ucc? mux 1
> >  ujoy*      at uhidev?                      # USB joystick/gamecontroller 
> > support
> >  uhidpp*    at uhidev?              # Logitech HID++ Devices
> >  upd*       at uhidev?                      # USB Power Devices sensors
> > diff --git sys/arch/amd64/conf/GENERIC sys/arch/amd64/conf/GENERIC
> > index c0c16f7c986..0d278739ccf 100644
> > --- sys/arch/amd64/conf/GENERIC
> > +++ sys/arch/amd64/conf/GENERIC
> > @@ -286,6 +286,8 @@ uslhcom* at uhidev?             # Silicon Labs CP2110 
> > USB HID UART
> >  ucom*      at uslhcom?
> >  uhid*      at uhidev?              # USB generic HID support
> >  fido*      at uhidev?              # FIDO/U2F security key support
> > +ucc*       at uhidev?              # Consumer Control keyboards
> > +wskbd*     at ucc? mux 1
> >  ujoy*      at uhidev?              # USB joystick/gamecontroller support
> >  uhidpp*    at uhidev?              # Logitech HID++ Devices
> >  upd*       at uhidev?              # USB Power Devices sensors
> > diff --git sys/arch/arm64/conf/GENERIC sys/arch/arm64/conf/GENERIC
> > index ff54bee0a9a..0cb8f4edb05 100644
> > --- sys/arch/arm64/conf/GENERIC
> > +++ sys/arch/arm64/conf/GENERIC
> > @@ -392,6 +392,8 @@ uslhcom*        at uhidev?              # Silicon Labs 
> > CP2110 USB HID UART
> >  ucom*              at uslhcom?
> >  uhid*              at uhidev?              # USB generic HID support
> >  fido*              at uhidev?              # FIDO/U2F security key support
> > +ucc*               at uhidev?              # Consumer Control keyboards
> > +wskbd*             at ucc? mux 1
> >  ujoy*              at uhidev?              # USB joystick/gamecontroller 
> > support
> >  uhidpp*            at uhidev?              # Logitech HID++ Devices
> >  upd*               at uhidev?              # USB Power Devices sensors
> > diff --git sys/arch/armv7/conf/GENERIC sys/arch/armv7/conf/GENERIC
> > index 1af5eb8dd85..271177bf2ab 100644
> > --- sys/arch/armv7/conf/GENERIC
> > +++ sys/arch/armv7/conf/GENERIC
> > @@ -327,6 +327,8 @@ uslhcom* at uhidev?             # Silicon Labs CP2110 
> > USB HID UART
> >  ucom*      at uslhcom?
> >  uhid*      at uhidev?              # USB generic HID support
> >  fido*      at uhidev?              # FIDO/U2F security key support
> > +ucc*       at uhidev?              # Consumer Control keyboards
> > +wskbd*     at ucc? mux 1
> >  ujoy*      at uhidev?              # USB joystick/gamecontroller support
> >  uhidpp*    at uhidev?              # Logitech HID++ Devices
> >  upd*       at uhidev?              # USB Power Devices sensors
> > diff --git sys/arch/hppa/conf/GENERIC sys/arch/hppa/conf/GENERIC
> > index 1a27dbb18c0..91e0888af4c 100644
> > --- sys/arch/hppa/conf/GENERIC
> > +++ sys/arch/hppa/conf/GENERIC
> > @@ -111,6 +111,8 @@ ukbd*   at uhidev?              # USB keyboard
> >  wskbd*     at ukbd? mux 1
> >  uhid*      at uhidev?              # USB generic HID support
> >  fido*      at uhidev?              # FIDO/U2F security key support
> > +ucc*       at uhidev?              # Consumer Control keyboards
> > +wskbd*     at ucc? mux 1
> >  ujoy*      at uhidev?              # USB joystick/gamecontroller support
> >  uhidpp*    at uhidev?              # Logitech HID++ Devices
> >  upd*       at uhidev?              # USB Power Devices sensors
> > diff --git sys/arch/i386/conf/GENERIC sys/arch/i386/conf/GENERIC
> > index b49353a92d0..7e3144dba53 100644
> > --- sys/arch/i386/conf/GENERIC
> > +++ sys/arch/i386/conf/GENERIC
> > @@ -284,6 +284,8 @@ uticom* at uhub?                # TI serial
> >  ucom*      at uticom?
> >  uhid*      at uhidev?              # USB generic HID support
> >  fido*      at uhidev?              # FIDO/U2F security key support
> > +ucc*       at uhidev?              # Consumer Control keyboards
> > +wskbd*     at ucc? mux 1
> >  ujoy*      at uhidev?              # USB joystick/gamecontroller support
> >  uhidpp*    at uhidev?              # Logitech HID++ Devices
> >  upd*       at uhidev?              # USB Power Devices sensors
> > diff --git sys/arch/landisk/conf/GENERIC sys/arch/landisk/conf/GENERIC
> > index a2091413514..133218afe22 100644
> > --- sys/arch/landisk/conf/GENERIC
> > +++ sys/arch/landisk/conf/GENERIC
> > @@ -137,6 +137,8 @@ uslhcom* at uhidev?             # Silicon Labs CP2110 
> > USB HID UART
> >  ucom*      at uslhcom?
> >  uhid*      at uhidev?              # USB generic HID support
> >  fido*      at uhidev?              # FIDO/U2F security key support
> > +ucc*       at uhidev?              # Consumer Control keyboards
> > +wskbd*     at ucc? mux 1
> >  ujoy*      at uhidev?              # USB joystick/gamecontroller support
> >  uhidpp*    at uhidev?              # Logitech HID++ Devices
> >  upd*       at uhidev?              # USB Power Devices sensors
> > diff --git sys/arch/loongson/conf/GENERIC sys/arch/loongson/conf/GENERIC
> > index d213bd976f9..f3ab1b34cf1 100644
> > --- sys/arch/loongson/conf/GENERIC
> > +++ sys/arch/loongson/conf/GENERIC
> > @@ -164,6 +164,8 @@ uslhcom*        at uhidev?      # Silicon Labs CP2110 
> > USB HID UART
> >  ucom*              at uslhcom?
> >  uhid*              at uhidev?      # USB generic HID support
> >  fido*              at uhidev?      # FIDO/U2F security key support
> > +ucc*               at uhidev?      # Consumer Control keyboards
> > +wskbd*             at ucc? mux 1
> >  ujoy*              at uhidev?      # USB joystick/gamecontroller support
> >  uhidpp*            at uhidev?      # Logitech HID++ Devices
> >  upd*               at uhidev?      # USB Power Devices sensors
> > diff --git sys/arch/macppc/conf/GENERIC sys/arch/macppc/conf/GENERIC
> > index 34014204a23..872e74601a2 100644
> > --- sys/arch/macppc/conf/GENERIC
> > +++ sys/arch/macppc/conf/GENERIC
> > @@ -260,6 +260,8 @@ uslhcom* at uhidev?             # Silicon Labs CP2110 
> > USB HID UART
> >  ucom*      at uslhcom?
> >  uhid*      at uhidev?              # USB generic HID support
> >  fido*      at uhidev?              # FIDO/U2F security key support
> > +ucc*       at uhidev?              # Consumer Control keyboards
> > +wskbd*     at ucc? mux 1
> >  ujoy*      at uhidev?              # USB joystick/gamecontroller support
> >  uhidpp*    at uhidev?              # Logitech HID++ Devices
> >  upd*       at uhidev?              # USB Power Devices sensors
> > diff --git sys/arch/octeon/conf/GENERIC sys/arch/octeon/conf/GENERIC
> > index ec5424938cb..260b5fda752 100644
> > --- sys/arch/octeon/conf/GENERIC
> > +++ sys/arch/octeon/conf/GENERIC
> > @@ -156,6 +156,8 @@ uslhcom*        at uhidev?      # Silicon Labs CP2110 
> > USB HID UART
> >  ucom*              at uslhcom?
> >  uhid*              at uhidev?      # USB generic HID support
> >  fido*              at uhidev?      # FIDO/U2F security key support
> > +ucc*               at uhidev?      # Consumer Control keyboards
> > +wskbd*             at ucc? mux 1
> >  ujoy*              at uhidev?      # USB joystick/gamecontroller support
> >  uhidpp*            at uhidev?      # Logitech HID++ Devices
> >  upd*               at uhidev?      # USB Power Devices sensors
> > diff --git sys/arch/powerpc64/conf/GENERIC sys/arch/powerpc64/conf/GENERIC
> > index 5a41fb2ae72..311355bce1a 100644
> > --- sys/arch/powerpc64/conf/GENERIC
> > +++ sys/arch/powerpc64/conf/GENERIC
> > @@ -127,6 +127,8 @@ uslhcom* at uhidev?             # Silicon Labs CP2110 
> > USB HID UART
> >  ucom*      at uslhcom?
> >  uhid*      at uhidev?              # USB generic HID support
> >  fido*      at uhidev?              # FIDO/U2F security key support
> > +ucc*       at uhidev?              # Consumer Control keyboards
> > +wskbd*     at ucc? mux 1
> >  ujoy*      at uhidev?              # USB joystick/gamecontroller support
> >  uhidpp*    at uhidev?              # Logitech HID++ Devices
> >  upd*       at uhidev?              # USB Power Devices sensors
> > diff --git sys/arch/sparc64/conf/GENERIC sys/arch/sparc64/conf/GENERIC
> > index 71e92dc9016..757a637cc09 100644
> > --- sys/arch/sparc64/conf/GENERIC
> > +++ sys/arch/sparc64/conf/GENERIC
> > @@ -224,6 +224,8 @@ umsm*   at uhub?                # Qualcomm MSM EVDO
> >  ucom*      at umsm?
> >  uhid*      at uhidev?              # USB generic HID support
> >  fido*      at uhidev?              # FIDO/U2F security key support
> > +ucc*       at uhidev?              # Consumer Control keyboards
> > +wskbd*     at ucc? mux 1
> >  ujoy*      at uhidev?              # USB joystick/gamecontroller support
> >  uhidpp*    at uhidev?              # Logitech HID++ Devices
> >  upd*       at uhidev?              # USB Power Devices sensors
> > diff --git sys/dev/hid/hid.h sys/dev/hid/hid.h
> > index dd9586d7cc2..23f8f7979ec 100644
> > --- sys/dev/hid/hid.h
> > +++ sys/dev/hid/hid.h
> > @@ -397,6 +397,9 @@ int     hid_is_collection(const void *, int, uint8_t, 
> > int32_t);
> >  
> >  /* Usages, Consumer */
> >  #define HUC_CONTROL                0x0001
> > +#define HUC_TRACK_NEXT             0x00b5
> > +#define HUC_TRACK_PREV             0x00b6
> > +#define HUC_STOP           0x00b7
> >  #define HUC_PLAY_PAUSE             0x00cd
> >  #define HUC_MUTE           0x00e2
> >  #define HUC_VOL_INC                0x00e9
> > diff --git sys/dev/usb/files.usb sys/dev/usb/files.usb
> > index 4d79c5ea21a..c4c4688f00e 100644
> > --- sys/dev/usb/files.usb
> > +++ sys/dev/usb/files.usb
> > @@ -488,3 +488,8 @@ file    dev/usb/umstc.c                 umstc
> >  device     uhidpp: hid
> >  attach     uhidpp at uhidbus
> >  file       dev/usb/uhidpp.c                uhidpp
> > +
> > +# Consumer Control Keyboards
> > +device     ucc: hid, wskbddev
> > +attach     ucc at uhidbus
> > +file       dev/usb/ucc.c                   ucc
> > diff --git sys/dev/usb/ucc.c sys/dev/usb/ucc.c
> > new file mode 100644
> > index 00000000000..8eb82a09cfd
> > --- /dev/null
> > +++ sys/dev/usb/ucc.c
> > @@ -0,0 +1,470 @@
> > +/* $OpenBSD$       */
> > +
> > +/*
> > + * Copyright (c) 2021 Anton Lindqvist <an...@openbsd.org>
> > + *
> > + * Permission to use, copy, modify, and distribute this software for any
> > + * purpose with or without fee is hereby granted, provided that the above
> > + * copyright notice and this permission notice appear in all copies.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> > + */
> > +
> > +#include <sys/param.h>
> > +#include <sys/systm.h>
> > +#include <sys/device.h>
> > +#include <sys/malloc.h>
> > +
> > +#include <dev/usb/usb.h>
> > +#include <dev/usb/usbhid.h>
> > +#include <dev/usb/usbdi.h>
> > +#include <dev/usb/uhidev.h>
> > +
> > +#include <dev/wscons/wsconsio.h>
> > +#include <dev/wscons/wskbdvar.h>
> > +#include <dev/wscons/wsksymdef.h>
> > +#include <dev/wscons/wsksymvar.h>
> > +
> > +/* #define UCC_DEBUG */
> > +#ifdef UCC_DEBUG
> > +#define DPRINTF(x...)      do { if (ucc_debug) printf(x); } while (0)
> > +void       ucc_dump(const char *, u_char *, u_int);
> > +int        ucc_debug = 1;
> > +#else
> > +#define DPRINTF(x...)
> > +#define ucc_dump(prefix, data, len)
> > +#endif
> > +
> > +struct ucc_softc {
> > +   struct uhidev            sc_hdev;
> > +   struct device           *sc_wskbddev;
> > +
> > +   /* Key mappings used in translating mode. */
> > +   keysym_t                *sc_map;
> > +   u_int                    sc_maplen;
> > +   u_int                    sc_mapsiz;
> > +   u_int                    sc_nkeys;
> > +
> > +   /* Key mappings used in raw mode. */
> > +   struct ucc_keyraw       *sc_raw;
> > +   u_int                    sc_rawlen;
> > +   u_int                    sc_rawsiz;
> > +
> > +   int                      sc_mode;
> > +
> > +   /* Last pressed key. */
> > +   union {
> > +           int     sc_last_translate;
> > +           u_char  sc_last_raw;
> > +   };
> > +
> > +   struct wscons_keydesc    sc_keydesc[2];
> > +   struct wskbd_mapdata     sc_keymap;
> > +};
> > +
> > +struct ucc_keysym {
> > +   int32_t         us_usage;
> > +   keysym_t        us_key;
> > +   u_char          us_raw;
> > +};
> > +
> > +struct ucc_keyraw {
> > +   u_int   ur_bit;
> > +   u_char  ur_raw;
> > +};
> > +
> > +int        ucc_match(struct device *, void *, void *);
> > +void       ucc_attach(struct device *, struct device *, void *);
> > +int        ucc_detach(struct device *, int);
> > +void       ucc_intr(struct uhidev *, void *, u_int);
> > +
> > +void       ucc_attach_wskbd(struct ucc_softc *);
> > +int        ucc_enable(void *, int);
> > +void       ucc_set_leds(void *, int);
> > +int        ucc_ioctl(void *, u_long, caddr_t, int, struct proc *);
> > +
> > +int        ucc_parse_hid(struct ucc_softc *, void *, int);
> > +int        ucc_bit_to_raw(struct ucc_softc *, u_int, u_char *);
> > +int        ucc_usage_to_sym(int32_t, const struct ucc_keysym **);
> > +void       ucc_raw_to_scancode(u_char *, int *, u_char, int);
> > +void       ucc_input(struct ucc_softc *, u_int, int);
> > +void       ucc_rawinput(struct ucc_softc *, u_char, int);
> > +int        ucc_setbits(u_char *, int, u_int *);
> > +
> > +struct cfdriver ucc_cd = {
> > +   NULL, "ucc", DV_DULL
> > +};
> > +
> > +const struct cfattach ucc_ca = {
> > +   sizeof(struct ucc_softc),
> > +   ucc_match,
> > +   ucc_attach,
> > +   ucc_detach,
> > +};
> > +
> > +/*
> > + * Mapping of HID consumer control usages to key symbols.
> > + * The raw scan codes are taken from X11, see the media_common symbols in
> > + * dist/xkeyboard-config/symbols/inet.
> > + * Then use dist/xkeyboard-config/keycodes/xfree86 to resolve keys to the
> > + * corrensponding raw scan code.
> > + */
> > +static const struct ucc_keysym ucc_keysyms[] = {
> > +   { HUC_MUTE,             KS_AudioMute,   0 },
> > +   { HUC_VOL_INC,          KS_AudioRaise,  0 },
> > +   { HUC_VOL_DEC,          KS_AudioLower,  0 },
> > +   { HUC_TRACK_NEXT,       0,              153 /* I19 = XF86AudioNext */ },
> > +   { HUC_TRACK_PREV,       0,              144 /* I10 = XF86AudioPrev */ },
> > +   { HUC_STOP,             0,              164 /* I24 = XF86AudioStop */ },
> > +   { HUC_PLAY_PAUSE,       0,              162 /* I22 = XF86AudioPlay, 
> > XF86AudioPause */ },
> > +};
> > +
> > +int
> > +ucc_match(struct device *parent, void *match, void *aux)
> > +{
> > +   struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux;
> > +   void *desc;
> > +   int size;
> > +
> > +   uhidev_get_report_desc(uha->parent, &desc, &size);
> > +   if (!hid_is_collection(desc, size, uha->reportid,
> > +       HID_USAGE2(HUP_CONSUMER, HUC_CONTROL)))
> > +           return UMATCH_NONE;
> > +
> > +   return UMATCH_IFACECLASS;
> > +}
> > +
> > +void
> > +ucc_attach(struct device *parent, struct device *self, void *aux)
> > +{
> > +   struct ucc_softc *sc = (struct ucc_softc *)self;
> > +   struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux;
> > +   void *desc;
> > +   int error, repid, size;
> > +
> > +   sc->sc_mode = WSKBD_TRANSLATED;
> > +   sc->sc_last_translate = -1;
> > +
> > +   sc->sc_hdev.sc_intr = ucc_intr;
> > +   sc->sc_hdev.sc_parent = uha->parent;
> > +   sc->sc_hdev.sc_udev = uha->uaa->device;
> > +   sc->sc_hdev.sc_report_id = uha->reportid;
> > +
> > +   uhidev_get_report_desc(uha->parent, &desc, &size);
> > +   repid = uha->reportid;
> > +   sc->sc_hdev.sc_isize = hid_report_size(desc, size, hid_input, repid);
> > +   sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid);
> > +   sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid);
> > +
> > +   error = ucc_parse_hid(sc, desc, size);
> > +   if (error) {
> > +           printf(" hid error %d\n", error);
> > +           return;
> > +   }
> > +
> > +   printf(" keys %d, mappings %d\n", sc->sc_nkeys, sc->sc_rawlen);
> > +
> > +   /* Cannot load an empty map. */
> > +   if (sc->sc_maplen > 0)
> > +           ucc_attach_wskbd(sc);
> > +}
> > +
> > +int
> > +ucc_detach(struct device *self, int flags)
> > +{
> > +   struct ucc_softc *sc = (struct ucc_softc *)self;
> > +   int error = 0;
> > +
> > +   if (sc->sc_wskbddev != NULL)
> > +           error = config_detach(sc->sc_wskbddev, flags);
> > +   uhidev_close(&sc->sc_hdev);
> > +   free(sc->sc_map, M_USBDEV, sc->sc_mapsiz);
> > +   free(sc->sc_raw, M_USBDEV, sc->sc_rawsiz);
> > +   return error;
> > +}
> > +
> > +void
> > +ucc_intr(struct uhidev *addr, void *data, u_int len)
> > +{
> > +   struct ucc_softc *sc = (struct ucc_softc *)addr;
> > +   int raw = sc->sc_mode == WSKBD_RAW;
> > +   u_int bit = 0;
> > +
> > +   ucc_dump(__func__, data, len);
> > +
> > +   if (ucc_setbits(data, len, &bit)) {
> > +           /* All zeroes, assume key up event. */
> > +           if (raw) {
> > +                   if (sc->sc_last_raw != 0) {
> > +                           ucc_rawinput(sc, sc->sc_last_raw, 1);
> > +                           sc->sc_last_raw = 0;
> > +                   }
> > +           } else {
> > +                   if (sc->sc_last_translate != -1) {
> > +                           ucc_input(sc, sc->sc_last_translate, 1);
> > +                           sc->sc_last_translate = -1;
> > +                   }
> > +           }
> > +           return;
> > +   }
> > +   if (bit >= sc->sc_nkeys)
> > +           goto unknown;
> > +
> > +   if (raw) {
> > +           u_char c;
> > +
> > +           if (ucc_bit_to_raw(sc, bit, &c))
> > +                   goto unknown;
> > +           if (c != 0) {
> > +                   ucc_rawinput(sc, c, 0);
> > +                   sc->sc_last_raw = c;
> > +                   return;
> > +           }
> > +
> > +           /*
> > +            * The pressed key does not have a corresponding raw scan code
> > +            * which implies that wsbkd must handle the pressed key as if
> > +            * being in translating mode, hence the fall through. This is
> > +            * only the case for volume related keys.
> > +            */
> > +   }
> > +
> > +   ucc_input(sc, bit, 0);
> > +   if (!raw)
> > +           sc->sc_last_translate = bit;
> > +   return;
> > +
> > +unknown:
> > +   DPRINTF("%s: unknown key: bit %d\n", __func__, bit);
> > +}
> > +
> > +void
> > +ucc_attach_wskbd(struct ucc_softc *sc)
> > +{
> > +   static const struct wskbd_accessops accessops = {
> > +           .enable         = ucc_enable,
> > +           .set_leds       = ucc_set_leds,
> > +           .ioctl          = ucc_ioctl,
> > +   };
> > +   struct wskbddev_attach_args a = {
> > +           .console        = 0,
> > +           .keymap         = &sc->sc_keymap,
> > +           .accessops      = &accessops,
> > +           .accesscookie   = sc,
> > +   };
> > +
> > +   sc->sc_keydesc[0].name = KB_US;
> > +   sc->sc_keydesc[0].base = 0;
> > +   sc->sc_keydesc[0].map_size = sc->sc_maplen;
> > +   sc->sc_keydesc[0].map = sc->sc_map;
> > +   sc->sc_keymap.keydesc = sc->sc_keydesc;
> > +   sc->sc_keymap.layout = KB_US | KB_DEFAULT;
> > +   sc->sc_wskbddev = config_found(&sc->sc_hdev.sc_dev, &a, wskbddevprint);
> > +}
> > +
> > +int
> > +ucc_enable(void *v, int on)
> > +{
> > +   struct ucc_softc *sc = (struct ucc_softc *)v;
> > +   int error = 0;
> > +
> > +   if (on)
> > +           error = uhidev_open(&sc->sc_hdev);
> > +   else
> > +           uhidev_close(&sc->sc_hdev);
> > +   return error;
> > +}
> > +
> > +void
> > +ucc_set_leds(void *v, int leds)
> > +{
> > +}
> > +
> > +int
> > +ucc_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
> > +{
> > +   struct ucc_softc *sc = (struct ucc_softc *)v;
> > +
> > +   switch (cmd) {
> > +#ifdef WSDISPLAY_COMPAT_RAWKBD
> > +   case WSKBDIO_SETMODE:
> > +           sc->sc_mode = *((int *)data);
> > +           return 0;
> > +#endif
> > +   }
> > +
> > +   return -1;
> > +}
> > +
> > +/*
> > + * Parse the HID report and construct a mapping between the bits in the 
> > input
> > + * report and the corresponding pressed key.
> > + */
> > +int
> > +ucc_parse_hid(struct ucc_softc *sc, void *desc, int descsiz)
> > +{
> > +   struct hid_item hi;
> > +   struct hid_data *hd;
> > +   int isize;
> > +
> > +   /*
> > +    * The size of the input report is expressed in bytes where each bit in
> > +    * turn represents a pressed key. It's likely that the number of keys is
> > +    * less than this generous estimate.
> > +    */
> > +   isize = sc->sc_hdev.sc_isize * 8;
> > +   if (isize == 0)
> > +           return ENXIO;
> > +
> > +   /*
> > +    * Create mapping between each input bit and the corresponding key used
> > +    * in translating mode. Two entries are needed per bit in order
> > +    * construct a mapping.
> > +    */
> > +   sc->sc_mapsiz = isize * 2 * sizeof(*sc->sc_map);
> > +   sc->sc_map = mallocarray(isize, 2 * sizeof(*sc->sc_map), M_USBDEV,
> > +       M_WAITOK | M_ZERO);
> > +
> > +   /*
> > +    * Create mapping between each input bit and the corresponding scan
> > +    * code used in raw mode.
> > +    */
> > +   sc->sc_rawsiz = isize * sizeof(*sc->sc_raw);
> > +   sc->sc_raw = mallocarray(isize, sizeof(*sc->sc_raw), M_USBDEV,
> > +       M_WAITOK | M_ZERO);
> > +
> > +   hd = hid_start_parse(desc, descsiz, hid_input);
> > +   while (hid_get_item(hd, &hi)) {
> > +           const struct ucc_keysym *us;
> > +           int bit;
> > +
> > +           if (HID_GET_USAGE_PAGE(hi.usage) != HUP_CONSUMER ||
> > +               HID_GET_USAGE(hi.usage) == HUC_CONTROL)
> > +                   continue;
> > +
> > +           bit = sc->sc_nkeys++;
> > +           if (ucc_usage_to_sym(HID_GET_USAGE(hi.usage), &us))
> > +                   continue;
> > +
> > +           if (sc->sc_maplen + 2 >= sc->sc_mapsiz)
> > +                   return ENOMEM;
> > +           sc->sc_map[sc->sc_maplen++] = KS_KEYCODE(bit);
> > +           sc->sc_map[sc->sc_maplen++] = us->us_key;
> > +
> > +           if (sc->sc_rawlen + 1 >= sc->sc_rawsiz)
> > +                   return ENOMEM;
> > +           sc->sc_raw[sc->sc_rawlen].ur_bit = bit;
> > +           sc->sc_raw[sc->sc_rawlen].ur_raw = us->us_raw;
> > +           sc->sc_rawlen++;
> > +
> > +           DPRINTF("%s: bit %d, usage %0x, key %0x\n", __func__,
> > +               bit, HID_GET_USAGE(hi.usage), us->us_key);
> > +   }
> > +   hid_end_parse(hd);
> > +
> > +   return 0;
> > +}
> > +
> > +int
> > +ucc_bit_to_raw(struct ucc_softc *sc, u_int bit, u_char *raw)
> > +{
> > +   u_int i;
> > +
> > +   for (i = 0; i < sc->sc_rawlen; i++) {
> > +           const struct ucc_keyraw *ur = &sc->sc_raw[i];
> > +
> > +           if (ur->ur_bit == bit) {
> > +                   *raw = ur->ur_raw;
> > +                   return 0;
> > +           }
> > +   }
> > +   return 1;
> > +}
> > +
> > +int
> > +ucc_usage_to_sym(int32_t usage, const struct ucc_keysym **us)
> > +{
> > +   int len = nitems(ucc_keysyms);
> > +   int i;
> > +
> > +   for (i = 0; i < len; i++) {
> > +           if (ucc_keysyms[i].us_usage == usage) {
> > +                   *us = &ucc_keysyms[i];
> > +                   return 0;
> > +           }
> > +   }
> > +   return 1;
> > +}
> > +
> > +void
> > +ucc_input(struct ucc_softc *sc, u_int bit, int release)
> > +{
> > +   int s;
> > +
> > +   s = spltty();
> > +   wskbd_input(sc->sc_wskbddev,
> > +       release ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN, bit);
> > +   splx(s);
> > +}
> > +
> > +void
> > +ucc_rawinput(struct ucc_softc *sc, u_char c, int release)
> > +{
> > +   u_char buf[2];
> > +   int len = 0;
> > +   int s;
> > +
> > +   if (c & 0x80)
> > +           buf[len++] = 0xe0;
> > +   buf[len++] = c & 0x7f;
> > +   if (release)
> > +           buf[len - 1] |= 0x80;
> > +
> > +   s = spltty();
> > +   wskbd_rawinput(sc->sc_wskbddev, buf, len);
> > +   splx(s);
> > +}
> > +
> > +int
> > +ucc_setbits(u_char *data, int len, u_int *bit)
> > +{
> > +   int i, j;
> > +
> > +   for (i = 0; i < len; i++) {
> > +           if (data[i] == 0)
> > +                   continue;
> > +
> > +           for (j = 0; j < 8; j++) {
> > +                   if (data[i] & (1 << j)) {
> > +                           *bit = (i * 8) + j;
> > +                           return 0;
> > +                   }
> > +           }
> > +   }
> > +
> > +   return 1;
> > +}
> > +
> > +#ifdef UCC_DEBUG
> > +
> > +void
> > +ucc_dump(const char *prefix, u_char *data, u_int len)
> > +{
> > +   u_int i;
> > +
> > +   if (ucc_debug == 0)
> > +           return;
> > +
> > +   printf("%s:", prefix);
> > +   for (i = 0; i < len; i++)
> > +           printf(" %02x", data[i]);
> > +   printf("\n");
> > +}
> > +
> > +#endif
> > 
> > 
> 

Reply via email to