On Tue, Aug 17, 2021 at 08:13:41PM +0200, Anton Lindqvist wrote: > 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? >
hi. the doc parts look good. jmc > 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 >