diff -r f3c4a48bd4fa sys/dev/hid/files.hid --- a/sys/dev/hid/files.hid Mon May 18 17:09:16 2026 +0000 +++ b/sys/dev/hid/files.hid Tue Jun 02 22:14:53 2026 +0000 @@ -1,4 +1,4 @@ -# $NetBSD: files.hid,v 1.3.2.2 2025/12/14 11:18:30 martin Exp $ +# $NetBSD: files.hid,v 1.4 2025/12/07 10:05:10 jmcneill Exp $ # Human Interface Devices # Used by USB, bluetooth and i2c @@ -14,3 +14,6 @@ define hidkbd file dev/hid/hidkbd.c hidkbd file dev/hid/hidkbdmap.c ukbd | btkbd | ikbd | linux_keymap + +define hidev +file dev/hid/hidev.c hidev diff -r f3c4a48bd4fa sys/dev/hid/hidev.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/dev/hid/hidev.c Tue Jun 02 22:14:53 2026 +0000 @@ -0,0 +1,86 @@ +/* $NetBSD: hidev.c,v 1.2 2025/12/07 19:59:51 jmcneill Exp $ */ + +/*- + * Copyright (c) 2025 Jared McNeill + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +void +uhidev_get_report_desc(struct uhidev *t, void **desc, int *size) +{ + t->_get_report_desc(t->_cookie, desc, size); +} + +int +uhidev_open(struct uhidev *t, void (*intr)(void *, void *, unsigned), + void *cookie) +{ + return t->_open(t->_cookie, intr, cookie); +} + +void +uhidev_stop(struct uhidev *t) +{ + t->_stop(t->_cookie); +} + +void +uhidev_close(struct uhidev *t) +{ + t->_close(t->_cookie); +} + +usbd_status +uhidev_set_report(struct uhidev *t, int type, void *data, int len) +{ + return t->_set_report(t->_cookie, type, data, len); +} + +usbd_status +uhidev_get_report(struct uhidev *t, int type, void *data, int len) +{ + return t->_get_report(t->_cookie, type, data, len); +} + +usbd_status +uhidev_write(struct uhidev *t, void *data, int len) +{ + return t->_write(t->_cookie, data, len); +} + +usbd_status +uhidev_write_async(struct uhidev *t, void *data, int len, int flags, int timo, + usbd_callback writecallback, void *writecookie) +{ + return t->_write_async(t->_cookie, data, len, flags, timo, + writecallback, writecookie); +} + +int +uhidev_ioctl(struct uhidev *t, u_long cmd, void *addr, int flag, struct lwp *l) +{ + return t->_ioctl(t->_cookie, cmd, addr, flag, l); +} diff -r f3c4a48bd4fa sys/dev/hid/hidev.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/dev/hid/hidev.h Tue Jun 02 22:14:53 2026 +0000 @@ -0,0 +1,55 @@ +/* $NetBSD: hidev.h,v 1.2 2025/12/07 19:59:51 jmcneill Exp $ */ + +/*- + * Copyright (c) 2025 Jared McNeill + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _DEV_HID_HIDEV_H_ +#define _DEV_HID_HIDEV_H_ + +#include + +#include + +struct lwp; + +struct uhidev { + void *_cookie; + + /* HID device methods. */ + void (*_get_report_desc)(void *, void **, int *); + int (*_open)(void *, void (*)(void *, void *, u_int), + void *); + void (*_stop)(void *); + void (*_close)(void *); + usbd_status (*_set_report)(void *, int, void *, int); + usbd_status (*_get_report)(void *, int, void *, int); + usbd_status (*_write)(void *, void *, int); + usbd_status (*_write_async)(void *, void *, int, int, int, + usbd_callback, void *); + int (*_ioctl)(void *, u_long, void *, int, struct lwp *); +}; + +#endif /* _DEV_HID_HIDEV_H_ */ diff -r f3c4a48bd4fa sys/dev/usb/files.usb --- a/sys/dev/usb/files.usb Mon May 18 17:09:16 2026 +0000 +++ b/sys/dev/usb/files.usb Tue Jun 02 22:14:53 2026 +0000 @@ -1,4 +1,4 @@ -# $NetBSD: files.usb,v 1.182.2.2 2025/12/14 11:18:30 martin Exp $ +# $NetBSD: files.usb,v 1.186 2025/12/07 10:05:10 jmcneill Exp $ # # Config file and device description for machine-independent USB code. # Included by ports that need it. Ports that use it must provide @@ -148,7 +148,7 @@ file dev/usb/ugen.c ugen | ugenif nee # HID # HID "bus" -define uhidbus {[ reportid = -1 ]} +define uhidbus {[ reportid = -1 ]}: hidev # HID root device for multiple report IDs device uhidev: hid, uhidbus diff -r f3c4a48bd4fa sys/dev/usb/uhid.c --- a/sys/dev/usb/uhid.c Mon May 18 17:09:16 2026 +0000 +++ b/sys/dev/usb/uhid.c Tue Jun 02 22:14:53 2026 +0000 @@ -1,4 +1,4 @@ -/* $NetBSD: uhid.c,v 1.129.4.2 2025/12/14 11:18:31 martin Exp $ */ +/* $NetBSD: uhid.c,v 1.129 2024/02/04 05:43:06 mrg Exp $ */ /* * Copyright (c) 1998, 2004, 2008, 2012 The NetBSD Foundation, Inc. @@ -35,10 +35,9 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: uhid.c,v 1.129.4.2 2025/12/14 11:18:31 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uhid.c,v 1.129 2024/02/04 05:43:06 mrg Exp $"); #ifdef _KERNEL_OPT -#include "opt_compat_netbsd.h" #include "opt_usb.h" #endif @@ -46,7 +45,6 @@ #include #include -#include #include #include #include @@ -87,7 +85,6 @@ int uhiddebug = 0; struct uhid_softc { device_t sc_dev; struct uhidev *sc_hdev; - struct usbd_device *sc_udev; uint8_t sc_report_id; kmutex_t sc_lock; @@ -180,7 +177,6 @@ uhid_attach(device_t parent, device_t se sc->sc_dev = self; sc->sc_hdev = uha->parent; - sc->sc_udev = uha->uiaa->uiaa_device; sc->sc_report_id = uha->reportid; selinit(&sc->sc_rsel); @@ -654,37 +650,8 @@ uhidioctl(dev_t dev, u_long cmd, void *a *(int *)addr = sc->sc_report_id; break; - case USB_GET_DEVICE_DESC: - *(usb_device_descriptor_t *)addr = - *usbd_get_device_descriptor(sc->sc_udev); - break; - - case USB_GET_DEVICEINFO: - usbd_fill_deviceinfo(sc->sc_udev, - (struct usb_device_info *)addr, 0); - break; - case USB_GET_DEVICEINFO_30: - MODULE_HOOK_CALL(usb_subr_fill_30_hook, - (sc->sc_udev, - (struct usb_device_info30 *)addr, 0, - usbd_devinfo_vp, usbd_printBCD), - enosys(), err); - if (err == 0) - return 0; - break; - case USB_GET_STRING_DESC: - { - struct usb_string_desc *si = (struct usb_string_desc *)addr; - err = usbd_get_string_desc(sc->sc_udev, - si->usd_string_index, - si->usd_language_id, &si->usd_desc, &size); - if (err) - return EINVAL; - break; - } - default: - return EINVAL; + return uhidev_ioctl(sc->sc_hdev, cmd, addr, flag, l); } return 0; } diff -r f3c4a48bd4fa sys/dev/usb/uhidev.c --- a/sys/dev/usb/uhidev.c Mon May 18 17:09:16 2026 +0000 +++ b/sys/dev/usb/uhidev.c Tue Jun 02 22:14:53 2026 +0000 @@ -1,4 +1,4 @@ -/* $NetBSD: uhidev.c,v 1.95.4.2 2025/12/14 11:18:31 martin Exp $ */ +/* $NetBSD: uhidev.c,v 1.97 2025/12/07 19:59:51 jmcneill Exp $ */ /* * Copyright (c) 2001, 2012 The NetBSD Foundation, Inc. @@ -35,9 +35,10 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: uhidev.c,v 1.95.4.2 2025/12/14 11:18:31 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uhidev.c,v 1.97 2025/12/07 19:59:51 jmcneill Exp $"); #ifdef _KERNEL_OPT +#include "opt_compat_netbsd.h" #include "opt_usb.h" #endif @@ -45,6 +46,7 @@ #include #include +#include #include #include #include @@ -66,6 +68,7 @@ #include #include +#include /* Report descriptor for broken Wacom Graphire */ #include @@ -88,7 +91,7 @@ struct uhidev_softc { void *sc_repdesc; u_int sc_nrepid; - struct uhidev { + struct uhidev_usb { struct uhidev_softc *sc_parent; device_t sc_dev; void (*sc_intr)(void *, void *, u_int); @@ -99,6 +102,7 @@ struct uhidev_softc { uint8_t sc_state; #define UHIDEV_OPEN 0x01 /* device is open */ #define UHIDEV_STOPPED 0x02 /* xfers are stopped */ + struct uhidev sc_uhidev; } *sc_subdevs; kmutex_t sc_lock; @@ -146,6 +150,8 @@ static void uhidev_attach(device_t, devi static void uhidev_childdet(device_t, device_t); static int uhidev_detach(device_t, int); +static void uhidev_init_tag(struct uhidev_usb *, struct uhidev *); + CFATTACH_DECL2_NEW(uhidev, sizeof(struct uhidev_softc), uhidev_match, uhidev_attach, uhidev_detach, NULL, NULL, uhidev_childdet); @@ -402,11 +408,12 @@ uhidev_attach(device_t parent, device_t DPRINTF(("uhidev_attach: isize=%d\n", sc->sc_isize)); for (repid = 0; repid < nrepid; repid++) { - struct uhidev *scd = &sc->sc_subdevs[repid]; + struct uhidev_usb *scd = &sc->sc_subdevs[repid]; scd->sc_parent = sc; scd->sc_report_id = repid; scd->sc_in_rep_size = repsizes[repid]; + uhidev_init_tag(scd, &scd->sc_uhidev); DPRINTF(("uhidev_match: try repid=%d\n", repid)); if (hid_report_size(desc, size, hid_input, repid) == 0 && @@ -414,7 +421,7 @@ uhidev_attach(device_t parent, device_t hid_report_size(desc, size, hid_feature, repid) == 0) { ; /* already NULL in sc->sc_subdevs[repid] */ } else { - uha.parent = scd; + uha.parent = &scd->sc_uhidev; uha.reportid = repid; locs[UHIDBUSCF_REPORTID] = repid; @@ -538,7 +545,7 @@ static void uhidev_intr(struct usbd_xfer *xfer, void *addr, usbd_status status) { struct uhidev_softc *sc = addr; - struct uhidev *scd; + struct uhidev_usb *scd; u_char *p; u_int rep; uint32_t cc; @@ -596,9 +603,10 @@ uhidev_intr(struct usbd_xfer *xfer, void scd->sc_intr(scd->sc_cookie, p, cc); } -void -uhidev_get_report_desc(struct uhidev *scd, void **desc, int *size) +static void +uhidev_usb_get_report_desc(void *cookie, void **desc, int *size) { + struct uhidev_usb *scd = cookie; struct uhidev_softc *sc = scd->sc_parent; *desc = sc->sc_repdesc; @@ -851,10 +859,11 @@ uhidev_close_pipes(struct uhidev_softc * device_xname(sc->sc_dev), sc->sc_refcnt); } -int -uhidev_open(struct uhidev *scd, void (*intr)(void *, void *, u_int), - void *cookie) +static int +uhidev_usb_open(void *cookie, void (*intr)(void *, void *, u_int), + void *opencookie) { + struct uhidev_usb *scd = cookie; struct uhidev_softc *sc = scd->sc_parent; int error; @@ -873,7 +882,7 @@ uhidev_open(struct uhidev *scd, void (*i goto out; } scd->sc_intr = intr; - scd->sc_cookie = cookie; + scd->sc_cookie = opencookie; atomic_store_release(&scd->sc_state, scd->sc_state | UHIDEV_OPEN); /* Open the pipes which are shared by all report ids. */ @@ -908,9 +917,10 @@ out: if (error) { * May sleep but only for a short duration to wait for USB * transfer completion callbacks to run. */ -void -uhidev_stop(struct uhidev *scd) +static void +uhidev_usb_stop(void *cookie) { + struct uhidev_usb *scd = cookie; struct uhidev_softc *sc = scd->sc_parent; mutex_enter(&sc->sc_lock); @@ -955,15 +965,16 @@ out: mutex_exit(&sc->sc_lock); } /* - * uhidev_close(scd) + * uhidev_usb_close(scd) * * Close a uhidev previously opened with uhidev_open. If writes * had been stopped with uhidev_stop, allow writes at other report * ids again. */ -void -uhidev_close(struct uhidev *scd) +static void +uhidev_usb_close(void *cookie) { + struct uhidev_usb *scd = cookie; struct uhidev_softc *sc = scd->sc_parent; mutex_enter(&sc->sc_lock); @@ -1033,9 +1044,10 @@ uhidev_close(struct uhidev *scd) mutex_exit(&sc->sc_lock); } -usbd_status -uhidev_set_report(struct uhidev *scd, int type, void *data, int len) +static usbd_status +uhidev_usb_set_report(void *cookie, int type, void *data, int len) { + struct uhidev_usb *scd = cookie; char *buf; usbd_status retstat; @@ -1055,16 +1067,18 @@ uhidev_set_report(struct uhidev *scd, in return retstat; } -usbd_status -uhidev_get_report(struct uhidev *scd, int type, void *data, int len) +static usbd_status +uhidev_usb_get_report(void *cookie, int type, void *data, int len) { + struct uhidev_usb *scd = cookie; return usbd_get_report(scd->sc_parent->sc_iface, type, scd->sc_report_id, data, len); } -usbd_status -uhidev_write(struct uhidev *scd, void *data, int len) +static usbd_status +uhidev_usb_write(void *cookie, void *data, int len) { + struct uhidev_usb *scd = cookie; struct uhidev_softc *sc = scd->sc_parent; usbd_status err; @@ -1148,10 +1162,11 @@ uhidev_write_callback(struct usbd_xfer * (*writecallback)(xfer, writecookie, err); } -usbd_status -uhidev_write_async(struct uhidev *scd, void *data, int len, int flags, +static usbd_status +uhidev_usb_write_async(void *cookie, void *data, int len, int flags, int timo, usbd_callback writecallback, void *writecookie) { + struct uhidev_usb *scd = cookie; struct uhidev_softc *sc = scd->sc_parent; usbd_status err; @@ -1193,3 +1208,63 @@ uhidev_write_async(struct uhidev *scd, v out: mutex_exit(&sc->sc_lock); return err; } + +static int +uhidev_usb_ioctl(void *cookie, u_long cmd, void *addr, int flag, + struct lwp *l) +{ + struct uhidev_usb *scd = cookie; + struct uhidev_softc *sc = scd->sc_parent; + int size; + usbd_status err; + + switch (cmd) { + case USB_GET_DEVICE_DESC: + *(usb_device_descriptor_t *)addr = + *usbd_get_device_descriptor(sc->sc_udev); + break; + + case USB_GET_DEVICEINFO: + usbd_fill_deviceinfo(sc->sc_udev, + (struct usb_device_info *)addr, 0); + break; + case USB_GET_DEVICEINFO_30: + MODULE_HOOK_CALL(usb_subr_fill_30_hook, + (sc->sc_udev, + (struct usb_device_info30 *)addr, 0, + usbd_devinfo_vp, usbd_printBCD), + enosys(), err); + if (err == 0) + return 0; + break; + case USB_GET_STRING_DESC: + { + struct usb_string_desc *si = (struct usb_string_desc *)addr; + err = usbd_get_string_desc(sc->sc_udev, + si->usd_string_index, + si->usd_language_id, &si->usd_desc, &size); + if (err) + return EINVAL; + break; + } + default: + return EINVAL; + } + return 0; +} + +static void +uhidev_init_tag(struct uhidev_usb *scd, struct uhidev *t) +{ + + t->_cookie = scd; + t->_get_report_desc = uhidev_usb_get_report_desc; + t->_open = uhidev_usb_open; + t->_stop = uhidev_usb_stop; + t->_close = uhidev_usb_close; + t->_set_report = uhidev_usb_set_report; + t->_get_report = uhidev_usb_get_report; + t->_write = uhidev_usb_write; + t->_write_async = uhidev_usb_write_async; + t->_ioctl = uhidev_usb_ioctl; +} diff -r f3c4a48bd4fa sys/dev/usb/uhidev.h --- a/sys/dev/usb/uhidev.h Mon May 18 17:09:16 2026 +0000 +++ b/sys/dev/usb/uhidev.h Tue Jun 02 22:14:53 2026 +0000 @@ -1,4 +1,4 @@ -/* $NetBSD: uhidev.h,v 1.27.12.2 2025/12/14 11:18:31 martin Exp $ */ +/* $NetBSD: uhidev.h,v 1.29 2025/12/07 19:59:51 jmcneill Exp $ */ /* * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -33,8 +33,12 @@ #ifndef _DEV_USB_UHIDEV_H_ #define _DEV_USB_UHIDEV_H_ +#include + #include +#include +struct lwp; struct uhidev; struct uhidev_attach_arg { @@ -52,6 +56,7 @@ usbd_status uhidev_get_report(struct uhi usbd_status uhidev_write(struct uhidev *, void *, int); usbd_status uhidev_write_async(struct uhidev *, void *, int, int, int, usbd_callback, void *); +int uhidev_ioctl(struct uhidev *, u_long, void *, int, struct lwp *); #define UHIDEV_OSIZE 64 #define UHIDEV_MAXREPID 255