The attached patch series partially fixes a bug in the uhidev(9) API
(uhidev_stop didn't do anything at all; now it is merely racy).

But more importantly, the patch series makes struct uhidev_softc
opaque, so the uhidev(9) API can have a more stable ABI.  This will
give us better latitude to fix this race -- and potentially others --
later on and pull them up to netbsd-10 after it branches.

I have tested uhid(4) and ukbd(4).  I haven't tested ucycom(4), which
uses uhidev(9) in a way that nothing else does -- to do async xfers on
the output pipe.  Can anyone review and/or test ucycom(4)?
>From 7aa6050cfb88fbe8b42cf339fd42657b94ff5741 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastr...@netbsd.org>
Date: Wed, 19 Jan 2022 14:43:11 +0000
Subject: [PATCH 1/4] uhidev(9): Partially fix uhidev_write aborting.

In my previous change, I intended to make uhidev_stop abort any
pending write -- but I forgot to initialize sc->sc_writereportid, so
it never did anything.

This changes the API and ABI of uhidev_write so it takes the struct
uhidev pointer, rather than the struct uhidev_softc pointer; this way
uhidev_write knows what the report id of the client is, so it can
arrange to have uhidev_stop abort only this one.

XXX Except it still doesn't actually work because we do this
unlocked, ugh, so the write might complete before we abort anything.
---
 sys/dev/usb/ucycom.c |  2 +-
 sys/dev/usb/uhid.c   |  3 +--
 sys/dev/usb/uhidev.c | 10 ++++++++--
 sys/dev/usb/uhidev.h |  2 +-
 4 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/sys/dev/usb/ucycom.c b/sys/dev/usb/ucycom.c
index bb6046ae1a12..5191d234a52c 100644
--- a/sys/dev/usb/ucycom.c
+++ b/sys/dev/usb/ucycom.c
@@ -1105,7 +1105,7 @@ ucycom_set_status(struct ucycom_softc *sc)
        memset(sc->sc_obuf, 0, sc->sc_olen);
        sc->sc_obuf[0] = sc->sc_mcr;
 
-       err = uhidev_write(sc->sc_hdev.sc_parent, sc->sc_obuf, sc->sc_olen);
+       err = uhidev_write(&sc->sc_hdev, sc->sc_obuf, sc->sc_olen);
        if (err) {
                DPRINTF(("ucycom_set_status: err=%d\n", err));
        }
diff --git a/sys/dev/usb/uhid.c b/sys/dev/usb/uhid.c
index 46769dc0353a..66ab1a74b3c1 100644
--- a/sys/dev/usb/uhid.c
+++ b/sys/dev/usb/uhid.c
@@ -581,8 +581,7 @@ uhid_do_write(struct uhid_softc *sc, struct uio *uio, int 
flag)
 #endif
        if (!error) {
                if (sc->sc_raw)
-                       err = uhidev_write(sc->sc_hdev.sc_parent, sc->sc_obuf,
-                           size);
+                       err = uhidev_write(&sc->sc_hdev, sc->sc_obuf, size);
                else
                        err = uhidev_set_report(&sc->sc_hdev,
                            UHID_OUTPUT_REPORT, sc->sc_obuf, size);
diff --git a/sys/dev/usb/uhidev.c b/sys/dev/usb/uhidev.c
index b0c03092c77a..1a530cd76412 100644
--- a/sys/dev/usb/uhidev.c
+++ b/sys/dev/usb/uhidev.c
@@ -901,7 +901,7 @@ uhidev_stop(struct uhidev *scd)
                abort = true;
        mutex_exit(&sc->sc_lock);
 
-       if (abort && sc->sc_opipe)
+       if (abort && sc->sc_opipe) /* XXX sc_opipe might go away */
                usbd_abort_pipe(sc->sc_opipe);
 }
 
@@ -961,8 +961,9 @@ uhidev_get_report(struct uhidev *scd, int type, void *data, 
int len)
 }
 
 usbd_status
-uhidev_write(struct uhidev_softc *sc, void *data, int len)
+uhidev_write(struct uhidev *scd, void *data, int len)
 {
+       struct uhidev_softc *sc = scd->sc_parent;
        usbd_status err;
 
        DPRINTF(("uhidev_write: data=%p, len=%d\n", data, len));
@@ -985,6 +986,7 @@ uhidev_write(struct uhidev_softc *sc, void *data, int len)
                }
        }
        sc->sc_writelock = curlwp;
+       sc->sc_writereportid = scd->sc_report_id;
        mutex_exit(&sc->sc_lock);
 
 #ifdef UHIDEV_DEBUG
@@ -1006,6 +1008,10 @@ uhidev_write(struct uhidev_softc *sc, void *data, int 
len)
        KASSERT(sc->sc_refcnt);
        KASSERTMSG(sc->sc_writelock == curlwp, "%s: migrated from %p to %p",
            device_xname(sc->sc_dev), curlwp, sc->sc_writelock);
+       KASSERTMSG(sc->sc_writereportid == scd->sc_report_id,
+           "%s: changed write report ids from %d to %d",
+           device_xname(sc->sc_dev), scd->sc_report_id, sc->sc_writereportid);
+       sc->sc_writereportid = -1;
        sc->sc_writelock = NULL;
        cv_broadcast(&sc->sc_cv);
 out:   mutex_exit(&sc->sc_lock);
diff --git a/sys/dev/usb/uhidev.h b/sys/dev/usb/uhidev.h
index 83c0a357744e..447780987af8 100644
--- a/sys/dev/usb/uhidev.h
+++ b/sys/dev/usb/uhidev.h
@@ -97,7 +97,7 @@ void uhidev_stop(struct uhidev *);
 void uhidev_close(struct uhidev *);
 usbd_status uhidev_set_report(struct uhidev *, int, void *, int);
 usbd_status uhidev_get_report(struct uhidev *, int, void *, int);
-usbd_status uhidev_write(struct uhidev_softc *, void *, int);
+usbd_status uhidev_write(struct uhidev *, void *, int);
 
 #define        UHIDEV_OSIZE    64
 

>From 6627dba911522e91e7b7848ff570a5229f0b9176 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastr...@netbsd.org>
Date: Tue, 25 Jan 2022 00:37:14 +0000
Subject: [PATCH 2/4] uhidev(9): New uhidev_write_async.

Like uhidev_write but issues the transfer asynchronously with a
callback.

Use it in ucycom(4).
---
 sys/dev/usb/ucycom.c |  7 ++---
 sys/dev/usb/uhidev.c | 67 ++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/usb/uhidev.h |  4 +++
 3 files changed, 73 insertions(+), 5 deletions(-)

diff --git a/sys/dev/usb/ucycom.c b/sys/dev/usb/ucycom.c
index 5191d234a52c..242ac817fda5 100644
--- a/sys/dev/usb/ucycom.c
+++ b/sys/dev/usb/ucycom.c
@@ -592,11 +592,9 @@ ucycomstart(struct tty *tp)
        }
 #endif
        DPRINTFN(4,("ucycomstart: %d chars\n", len));
-       usbd_setup_xfer(sc->sc_hdev.sc_parent->sc_oxfer, sc, sc->sc_obuf,
-           sc->sc_olen, 0, USBD_NO_TIMEOUT, ucycomwritecb);
-
        /* What can we do on error? */
-       err = usbd_transfer(sc->sc_hdev.sc_parent->sc_oxfer);
+       err = uhidev_write_async(&sc->sc_hdev, sc->sc_obuf, sc->sc_olen, 0,
+           USBD_NO_TIMEOUT, ucycomwritecb, sc);
 
 #ifdef UCYCOM_DEBUG
        if (err != USBD_IN_PROGRESS)
@@ -621,7 +619,6 @@ ucycomwritecb(struct usbd_xfer *xfer, void *p, usbd_status 
status)
 
        if (status) {
                DPRINTF(("ucycomwritecb: status=%d\n", status));
-               usbd_clear_endpoint_stall(sc->sc_hdev.sc_parent->sc_opipe);
                /* XXX we should restart after some delay. */
                goto error;
        }
diff --git a/sys/dev/usb/uhidev.c b/sys/dev/usb/uhidev.c
index 1a530cd76412..d1a2909c5b59 100644
--- a/sys/dev/usb/uhidev.c
+++ b/sys/dev/usb/uhidev.c
@@ -1017,3 +1017,70 @@ uhidev_write(struct uhidev *scd, void *data, int len)
 out:   mutex_exit(&sc->sc_lock);
        return err;
 }
+
+static void
+uhidev_write_callback(struct usbd_xfer *xfer, void *cookie, usbd_status err)
+{
+       struct uhidev_softc *sc = cookie;
+       usbd_callback writecallback;
+       void *writecookie;
+
+       if (err)
+               usbd_clear_endpoint_stall(sc->sc_opipe);
+
+       mutex_enter(&sc->sc_lock);
+       KASSERT(sc->sc_writelock == (void *)1);
+       writecallback = sc->sc_writecallback;
+       writecookie = sc->sc_writecookie;
+       sc->sc_writereportid = -1;
+       sc->sc_writelock = NULL;
+       sc->sc_writecallback = NULL;
+       sc->sc_writecookie = NULL;
+       cv_broadcast(&sc->sc_cv);
+       mutex_exit(&sc->sc_lock);
+
+       (*writecallback)(xfer, writecookie, err);
+}
+
+usbd_status
+uhidev_write_async(struct uhidev *scd, void *data, int len, int flags,
+    int timo, usbd_callback writecallback, void *writecookie)
+{
+       struct uhidev_softc *sc = scd->sc_parent;
+       usbd_status err;
+
+       DPRINTF(("%s: data=%p, len=%d\n", __func__, data, len));
+
+       if (sc->sc_opipe == NULL)
+               return USBD_INVAL;
+
+       mutex_enter(&sc->sc_lock);
+       KASSERT(sc->sc_refcnt);
+       if (sc->sc_dying) {
+               err = USBD_IOERROR;
+               goto out;
+       }
+       if (sc->sc_writelock != NULL) {
+               err = USBD_IN_USE;
+               goto out;
+       }
+       sc->sc_writelock = (void *)1; /* XXX no lwp to attribute async xfer */
+       sc->sc_writereportid = scd->sc_report_id;
+       sc->sc_writecallback = writecallback;
+       sc->sc_writecookie = writecookie;
+       usbd_setup_xfer(sc->sc_oxfer, sc, data, len, flags, timo,
+           uhidev_write_callback);
+       err = usbd_transfer(sc->sc_oxfer);
+       switch (err) {
+       case USBD_IN_PROGRESS:
+               break;
+       case USBD_NORMAL_COMPLETION:
+               panic("unexpected normal completion of async xfer under lock");
+       default:                /* error */
+               sc->sc_writelock = NULL;
+               sc->sc_writereportid = -1;
+               cv_broadcast(&sc->sc_cv);
+       }
+out:   mutex_exit(&sc->sc_lock);
+       return err;
+}
diff --git a/sys/dev/usb/uhidev.h b/sys/dev/usb/uhidev.h
index 447780987af8..0b19e9015fcd 100644
--- a/sys/dev/usb/uhidev.h
+++ b/sys/dev/usb/uhidev.h
@@ -68,6 +68,8 @@ struct uhidev_softc {
        struct usbd_pipe *sc_ipipe;     /* input interrupt pipe */
        struct usbd_pipe *sc_opipe;     /* output interrupt pipe */
        struct usbd_xfer *sc_oxfer;     /* write request */
+       usbd_callback sc_writecallback; /* async write request callback */
+       void *sc_writecookie;
 
        u_int sc_flags;
 #define UHIDEV_F_XB1   0x0001  /* Xbox 1 controller */
@@ -98,6 +100,8 @@ void uhidev_close(struct uhidev *);
 usbd_status uhidev_set_report(struct uhidev *, int, void *, int);
 usbd_status uhidev_get_report(struct uhidev *, int, void *, int);
 usbd_status uhidev_write(struct uhidev *, void *, int);
+usbd_status uhidev_write_async(struct uhidev *, void *, int, int, int,
+    usbd_callback, void *);
 
 #define        UHIDEV_OSIZE    64
 

>From 2f5f3af6a339aace77590048f159cfb93fca70a8 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastr...@netbsd.org>
Date: Wed, 19 Jan 2022 17:18:13 +0000
Subject: [PATCH 3/4] uhidev(9): Get the device and interface through attach
 args.

This way uhidev drivers don't need access to uhidev_softc itself for
it.
---
 sys/arch/macppc/dev/pbms.c |  7 +++++--
 sys/dev/usb/uatp.c         | 14 ++++++++------
 sys/dev/usb/uhid.c         | 11 +++++++----
 sys/dev/usb/ukbd.c         | 15 ++++++++++-----
 sys/dev/usb/ums.c          |  4 +++-
 sys/dev/usb/uthum.c        |  2 +-
 6 files changed, 34 insertions(+), 19 deletions(-)

diff --git a/sys/arch/macppc/dev/pbms.c b/sys/arch/macppc/dev/pbms.c
index a1bfb88516cb..edc2213c619c 100644
--- a/sys/arch/macppc/dev/pbms.c
+++ b/sys/arch/macppc/dev/pbms.c
@@ -307,7 +307,8 @@ pbms_match(device_t parent, cfdata_t match, void *aux)
         * we expect. 
         */
        if (uha->uiaa->uiaa_proto == UIPROTO_MOUSE &&
-           (udd = usbd_get_device_descriptor(uha->parent->sc_udev)) != NULL) {
+           ((udd = usbd_get_device_descriptor(uha->uiaa->uiaa_device))
+               != NULL)) {
                vendor = UGETW(udd->idVendor);
                product = UGETW(udd->idProduct);
                for (i = 0; i < PBMS_NUM_DEVICES; i++) {
@@ -329,6 +330,7 @@ pbms_attach(device_t parent, device_t self, void *aux)
        struct uhidev_attach_arg *uha = aux;
        struct pbms_dev *pd;
        struct pbms_softc *sc = device_private(self);
+       struct usbd_device *udev;
        usb_device_descriptor_t *udd;
        int i;
        uint16_t vendor, product;
@@ -341,7 +343,8 @@ pbms_attach(device_t parent, device_t self, void *aux)
        sc->sc_datalen = PBMS_DATA_LEN;
 
        /* Fill in device-specific parameters. */
-       if ((udd = usbd_get_device_descriptor(uha->parent->sc_udev)) != NULL) {
+       udev = uha->uiaa->uiaa_udevice;
+       if ((udd = usbd_get_device_descriptor(udev)) != NULL) {
                product = UGETW(udd->idProduct);
                vendor = UGETW(udd->idVendor);
                for (i = 0; i < PBMS_NUM_DEVICES; i++) {
diff --git a/sys/dev/usb/uatp.c b/sys/dev/usb/uatp.c
index a94e755f1ed2..d0a564eca616 100644
--- a/sys/dev/usb/uatp.c
+++ b/sys/dev/usb/uatp.c
@@ -486,7 +486,8 @@ static const struct uatp_knobs default_knobs = {
 };
 
 struct uatp_softc {
-       struct uhidev sc_hdev;          /* USB parent.  */
+       struct uhidev sc_hdev;          /* uhidev(9) parent.  */
+       struct usbd_device *sc_udev;    /* USB device.  */
        device_t sc_wsmousedev;         /* Attached wsmouse device.  */
        const struct uatp_parameters *sc_parameters;
        struct uatp_knobs sc_knobs;
@@ -936,6 +937,8 @@ uatp_attach(device_t parent, device_t self, void *aux)
        sc->sc_hdev.sc_parent = uha->parent;
        sc->sc_hdev.sc_report_id = uha->reportid;
 
+       sc->sc_udev = uha->uiaa->uiaa_device;
+
        /* Identify ourselves to dmesg.  */
        uatp_descriptor = find_uatp_descriptor(uha);
        KASSERT(uatp_descriptor != NULL);
@@ -1296,7 +1299,7 @@ uatp_ioctl(void *v, unsigned long cmd, void *data, int 
flag, struct lwp *p)
 static void
 geyser34_enable_raw_mode(struct uatp_softc *sc)
 {
-       struct usbd_device *udev = sc->sc_hdev.sc_parent->sc_udev;
+       struct usbd_device *udev = sc->sc_udev;
        usb_device_request_t req;
        usbd_status status;
        uint8_t report[GEYSER34_MODE_PACKET_SIZE];
@@ -1368,8 +1371,8 @@ geyser34_finalize(struct uatp_softc *sc)
 {
 
        DPRINTF(sc, UATP_DEBUG_MISC, ("finalizing\n"));
-       usb_rem_task_wait(sc->sc_hdev.sc_parent->sc_udev, &sc->sc_reset_task,
-           USB_TASKQ_DRIVER, NULL);
+       usb_rem_task_wait(sc->sc_udev, &sc->sc_reset_task, USB_TASKQ_DRIVER,
+           NULL);
 
        return 0;
 }
@@ -1379,8 +1382,7 @@ geyser34_deferred_reset(struct uatp_softc *sc)
 {
 
        DPRINTF(sc, UATP_DEBUG_RESET, ("deferring reset\n"));
-       usb_add_task(sc->sc_hdev.sc_parent->sc_udev, &sc->sc_reset_task,
-           USB_TASKQ_DRIVER);
+       usb_add_task(sc->sc_udev, &sc->sc_reset_task, USB_TASKQ_DRIVER);
 }
 
 static void
diff --git a/sys/dev/usb/uhid.c b/sys/dev/usb/uhid.c
index 66ab1a74b3c1..3d2841a1867d 100644
--- a/sys/dev/usb/uhid.c
+++ b/sys/dev/usb/uhid.c
@@ -86,6 +86,7 @@ int   uhiddebug = 0;
 
 struct uhid_softc {
        struct uhidev sc_hdev;
+       struct usbd_device *sc_udev;
 
        kmutex_t sc_lock;
        kcondvar_t sc_cv;
@@ -182,6 +183,8 @@ uhid_attach(device_t parent, device_t self, void *aux)
        sc->sc_hdev.sc_parent = uha->parent;
        sc->sc_hdev.sc_report_id = uha->reportid;
 
+       sc->sc_udev = uha->uiaa->uiaa_device;
+
        uhidev_get_report_desc(uha->parent, &desc, &size);
        repid = uha->reportid;
        sc->sc_isize = hid_report_size(desc, size, hid_input,   repid);
@@ -755,16 +758,16 @@ uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, void 
*addr,
 
        case USB_GET_DEVICE_DESC:
                *(usb_device_descriptor_t *)addr =
-                       
*usbd_get_device_descriptor(sc->sc_hdev.sc_parent->sc_udev);
+                       *usbd_get_device_descriptor(sc->sc_udev);
                break;
 
        case USB_GET_DEVICEINFO:
-               usbd_fill_deviceinfo(sc->sc_hdev.sc_parent->sc_udev,
+               usbd_fill_deviceinfo(sc->sc_udev,
                                     (struct usb_device_info *)addr, 0);
                break;
        case USB_GET_DEVICEINFO_OLD:
                MODULE_HOOK_CALL(usb_subr_fill_30_hook,
-                    (sc->sc_hdev.sc_parent->sc_udev,
+                    (sc->sc_udev,
                      (struct usb_device_info_old *)addr, 0,
                       usbd_devinfo_vp, usbd_printBCD),
                     enosys(), err);
@@ -774,7 +777,7 @@ uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, void *addr,
        case USB_GET_STRING_DESC:
            {
                struct usb_string_desc *si = (struct usb_string_desc *)addr;
-               err = usbd_get_string_desc(sc->sc_hdev.sc_parent->sc_udev,
+               err = usbd_get_string_desc(sc->sc_udev,
                        si->usd_string_index,
                        si->usd_language_id, &si->usd_desc, &size);
                if (err)
diff --git a/sys/dev/usb/ukbd.c b/sys/dev/usb/ukbd.c
index 14df4d53730e..4b96e831c8b5 100644
--- a/sys/dev/usb/ukbd.c
+++ b/sys/dev/usb/ukbd.c
@@ -236,6 +236,8 @@ Static const uint8_t ukbd_trtab[256] = {
 
 struct ukbd_softc {
        struct uhidev sc_hdev;
+       struct usbd_device *sc_udev;
+       struct usbd_interface *sc_iface;
 
        struct ukbd_data sc_ndata;
        struct ukbd_data sc_odata;
@@ -410,6 +412,8 @@ ukbd_attach(device_t parent, device_t self, void *aux)
        sc->sc_hdev.sc_intr = ukbd_intr;
        sc->sc_hdev.sc_parent = uha->parent;
        sc->sc_hdev.sc_report_id = uha->reportid;
+       sc->sc_udev = uha->uiaa->uiaa_device;
+       sc->sc_iface = uha->uiaa->uiaa_iface;
        sc->sc_flags = 0;
 
        aprint_naive("\n");
@@ -427,7 +431,7 @@ ukbd_attach(device_t parent, device_t self, void *aux)
        }
 
        /* Quirks */
-       qflags = usbd_get_quirks(uha->parent->sc_udev)->uq_flags;
+       qflags = usbd_get_quirks(sc->sc_udev)->uq_flags;
        if (qflags & UQ_SPUR_BUT_UP)
                sc->sc_flags |= FLAG_DEBOUNCE;
        if (qflags & UQ_APPLE_ISO)
@@ -579,7 +583,7 @@ ukbd_detach(device_t self, int flags)
 
        callout_halt(&sc->sc_delay, NULL);
        callout_halt(&sc->sc_ledreset, NULL);
-       usb_rem_task_wait(sc->sc_hdev.sc_parent->sc_udev, &sc->sc_ledtask,
+       usb_rem_task_wait(sc->sc_udev, &sc->sc_ledtask,
            USB_TASKQ_DRIVER, NULL);
 
        /* The console keyboard does not get a disable call, so check pipe. */
@@ -885,7 +889,7 @@ void
 ukbd_set_leds(void *v, int leds)
 {
        struct ukbd_softc *sc = v;
-       struct usbd_device *udev = sc->sc_hdev.sc_parent->sc_udev;
+       struct usbd_device *udev = sc->sc_udev;
 
        DPRINTF(("%s: sc=%p leds=%d, sc_leds=%d\n", __func__,
                 sc, leds, sc->sc_leds));
@@ -995,7 +999,7 @@ ukbd_cngetc(void *v, u_int *type, int *data)
        DPRINTFN(0,("%s: enter\n", __func__));
        sc->sc_flags |= FLAG_POLLING;
        if (sc->sc_npollchar <= 0)
-               usbd_dopoll(sc->sc_hdev.sc_parent->sc_iface);
+               usbd_dopoll(sc->sc_iface);
        sc->sc_flags &= ~FLAG_POLLING;
        if (sc->sc_npollchar > 0) {
                c = sc->sc_pollchars[0];
@@ -1021,7 +1025,8 @@ ukbd_cnpollc(void *v, int on)
 
        DPRINTFN(2,("%s: sc=%p on=%d\n", __func__, v, on));
 
-       usbd_interface2device_handle(sc->sc_hdev.sc_parent->sc_iface, &dev);
+       /* XXX Can this just use sc->sc_udev, or am I mistaken?  */
+       usbd_interface2device_handle(sc->sc_iface, &dev);
        if (on) {
                sc->sc_spl = splusb();
                pollenter++;
diff --git a/sys/dev/usb/ums.c b/sys/dev/usb/ums.c
index 0f49020b7e9e..a445cc9cfc3c 100644
--- a/sys/dev/usb/ums.c
+++ b/sys/dev/usb/ums.c
@@ -76,6 +76,7 @@ int   umsdebug = 0;
 
 struct ums_softc {
        struct uhidev sc_hdev;
+       struct usbd_device *sc_udev;
        struct hidms sc_ms;
 
        bool    sc_alwayson;
@@ -149,8 +150,9 @@ ums_attach(device_t parent, device_t self, void *aux)
        sc->sc_hdev.sc_intr = ums_intr;
        sc->sc_hdev.sc_parent = uha->parent;
        sc->sc_hdev.sc_report_id = uha->reportid;
+       sc->sc_udev = uha->uiaa->uiaa_device;
 
-       quirks = usbd_get_quirks(uha->parent->sc_udev)->uq_flags;
+       quirks = usbd_get_quirks(sc->sc_udev)->uq_flags;
        if (quirks & UQ_MS_REVZ)
                sc->sc_ms.flags |= HIDMS_REVZ;
        if (quirks & UQ_SPUR_BUT_UP)
diff --git a/sys/dev/usb/uthum.c b/sys/dev/usb/uthum.c
index 924a6586ad21..e2fbd70584e0 100644
--- a/sys/dev/usb/uthum.c
+++ b/sys/dev/usb/uthum.c
@@ -130,7 +130,7 @@ uthum_attach(device_t parent, device_t self, void *aux)
 {
        struct uthum_softc *sc = device_private(self);
        struct uhidev_attach_arg *uha = aux;
-       struct usbd_device *dev = uha->parent->sc_udev;
+       struct usbd_device *dev = uha->uiaa->uiaa_device;
        int size, repid;
        void *desc;
 

>From 7536a756168f47c5afdb8ec41ac73cc291297823 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastr...@netbsd.org>
Date: Tue, 25 Jan 2022 00:43:58 +0000
Subject: [PATCH 4/4] uhidev(9): Move struct uhidev_softc into uhidev.c.

No longer part of any ABI for uhidev modules.
---
 sys/dev/usb/uhidev.c | 40 ++++++++++++++++++++++++++++++++++++++++
 sys/dev/usb/uhidev.h | 40 ----------------------------------------
 2 files changed, 40 insertions(+), 40 deletions(-)

diff --git a/sys/dev/usb/uhidev.c b/sys/dev/usb/uhidev.c
index d1a2909c5b59..cb7130c1dfde 100644
--- a/sys/dev/usb/uhidev.c
+++ b/sys/dev/usb/uhidev.c
@@ -74,6 +74,46 @@ __KERNEL_RCSID(0, "$NetBSD: uhidev.c,v 1.81 2021/08/07 
16:19:17 thorpej Exp $");
 
 #include "locators.h"
 
+struct uhidev_softc {
+       device_t sc_dev;                /* base device */
+       struct usbd_device *sc_udev;
+       struct usbd_interface *sc_iface;        /* interface */
+       int sc_iep_addr;
+       int sc_oep_addr;
+       u_int sc_isize;
+
+       int sc_repdesc_size;
+       void *sc_repdesc;
+
+       u_int sc_nrepid;
+       device_t *sc_subdevs;
+
+       kmutex_t sc_lock;
+       kcondvar_t sc_cv;
+
+       /* Read/written under sc_lock.  */
+       struct lwp *sc_writelock;
+       struct lwp *sc_configlock;
+       int sc_refcnt;
+       int sc_writereportid;
+       u_char sc_dying;
+
+       /*
+        * - Read under sc_lock, provided sc_refcnt > 0.
+        * - Written under sc_configlock only when transitioning to and
+        *   from sc_refcnt = 0.
+        */
+       u_char *sc_ibuf;
+       struct usbd_pipe *sc_ipipe;     /* input interrupt pipe */
+       struct usbd_pipe *sc_opipe;     /* output interrupt pipe */
+       struct usbd_xfer *sc_oxfer;     /* write request */
+       usbd_callback sc_writecallback; /* async write request callback */
+       void *sc_writecookie;
+
+       u_int sc_flags;
+#define UHIDEV_F_XB1   0x0001  /* Xbox 1 controller */
+};
+
 #ifdef UHIDEV_DEBUG
 #define DPRINTF(x)     if (uhidevdebug) printf x
 #define DPRINTFN(n,x)  if (uhidevdebug>(n)) printf x
diff --git a/sys/dev/usb/uhidev.h b/sys/dev/usb/uhidev.h
index 0b19e9015fcd..b75f6f6f74c1 100644
--- a/sys/dev/usb/uhidev.h
+++ b/sys/dev/usb/uhidev.h
@@ -35,46 +35,6 @@
 
 #include <sys/rndsource.h>
 
-struct uhidev_softc {
-       device_t sc_dev;                /* base device */
-       struct usbd_device *sc_udev;
-       struct usbd_interface *sc_iface;        /* interface */
-       int sc_iep_addr;
-       int sc_oep_addr;
-       u_int sc_isize;
-
-       int sc_repdesc_size;
-       void *sc_repdesc;
-
-       u_int sc_nrepid;
-       device_t *sc_subdevs;
-
-       kmutex_t sc_lock;
-       kcondvar_t sc_cv;
-
-       /* Read/written under sc_lock.  */
-       struct lwp *sc_writelock;
-       struct lwp *sc_configlock;
-       int sc_refcnt;
-       int sc_writereportid;
-       u_char sc_dying;
-
-       /*
-        * - Read under sc_lock, provided sc_refcnt > 0.
-        * - Written under sc_configlock only when transitioning to and
-        *   from sc_refcnt = 0.
-        */
-       u_char *sc_ibuf;
-       struct usbd_pipe *sc_ipipe;     /* input interrupt pipe */
-       struct usbd_pipe *sc_opipe;     /* output interrupt pipe */
-       struct usbd_xfer *sc_oxfer;     /* write request */
-       usbd_callback sc_writecallback; /* async write request callback */
-       void *sc_writecookie;
-
-       u_int sc_flags;
-#define UHIDEV_F_XB1   0x0001  /* Xbox 1 controller */
-};
-
 struct uhidev {
        device_t sc_dev;                /* base device */
        struct uhidev_softc *sc_parent;
diff --git a/sys/arch/macppc/dev/pbms.c b/sys/arch/macppc/dev/pbms.c
index a1bfb88516cb..edc2213c619c 100644
--- a/sys/arch/macppc/dev/pbms.c
+++ b/sys/arch/macppc/dev/pbms.c
@@ -307,7 +307,8 @@ pbms_match(device_t parent, cfdata_t match, void *aux)
         * we expect. 
         */
        if (uha->uiaa->uiaa_proto == UIPROTO_MOUSE &&
-           (udd = usbd_get_device_descriptor(uha->parent->sc_udev)) != NULL) {
+           ((udd = usbd_get_device_descriptor(uha->uiaa->uiaa_device))
+               != NULL)) {
                vendor = UGETW(udd->idVendor);
                product = UGETW(udd->idProduct);
                for (i = 0; i < PBMS_NUM_DEVICES; i++) {
@@ -329,6 +330,7 @@ pbms_attach(device_t parent, device_t self, void *aux)
        struct uhidev_attach_arg *uha = aux;
        struct pbms_dev *pd;
        struct pbms_softc *sc = device_private(self);
+       struct usbd_device *udev;
        usb_device_descriptor_t *udd;
        int i;
        uint16_t vendor, product;
@@ -341,7 +343,8 @@ pbms_attach(device_t parent, device_t self, void *aux)
        sc->sc_datalen = PBMS_DATA_LEN;
 
        /* Fill in device-specific parameters. */
-       if ((udd = usbd_get_device_descriptor(uha->parent->sc_udev)) != NULL) {
+       udev = uha->uiaa->uiaa_udevice;
+       if ((udd = usbd_get_device_descriptor(udev)) != NULL) {
                product = UGETW(udd->idProduct);
                vendor = UGETW(udd->idVendor);
                for (i = 0; i < PBMS_NUM_DEVICES; i++) {
diff --git a/sys/dev/usb/uatp.c b/sys/dev/usb/uatp.c
index a94e755f1ed2..d0a564eca616 100644
--- a/sys/dev/usb/uatp.c
+++ b/sys/dev/usb/uatp.c
@@ -486,7 +486,8 @@ static const struct uatp_knobs default_knobs = {
 };
 
 struct uatp_softc {
-       struct uhidev sc_hdev;          /* USB parent.  */
+       struct uhidev sc_hdev;          /* uhidev(9) parent.  */
+       struct usbd_device *sc_udev;    /* USB device.  */
        device_t sc_wsmousedev;         /* Attached wsmouse device.  */
        const struct uatp_parameters *sc_parameters;
        struct uatp_knobs sc_knobs;
@@ -936,6 +937,8 @@ uatp_attach(device_t parent, device_t self, void *aux)
        sc->sc_hdev.sc_parent = uha->parent;
        sc->sc_hdev.sc_report_id = uha->reportid;
 
+       sc->sc_udev = uha->uiaa->uiaa_device;
+
        /* Identify ourselves to dmesg.  */
        uatp_descriptor = find_uatp_descriptor(uha);
        KASSERT(uatp_descriptor != NULL);
@@ -1296,7 +1299,7 @@ uatp_ioctl(void *v, unsigned long cmd, void *data, int 
flag, struct lwp *p)
 static void
 geyser34_enable_raw_mode(struct uatp_softc *sc)
 {
-       struct usbd_device *udev = sc->sc_hdev.sc_parent->sc_udev;
+       struct usbd_device *udev = sc->sc_udev;
        usb_device_request_t req;
        usbd_status status;
        uint8_t report[GEYSER34_MODE_PACKET_SIZE];
@@ -1368,8 +1371,8 @@ geyser34_finalize(struct uatp_softc *sc)
 {
 
        DPRINTF(sc, UATP_DEBUG_MISC, ("finalizing\n"));
-       usb_rem_task_wait(sc->sc_hdev.sc_parent->sc_udev, &sc->sc_reset_task,
-           USB_TASKQ_DRIVER, NULL);
+       usb_rem_task_wait(sc->sc_udev, &sc->sc_reset_task, USB_TASKQ_DRIVER,
+           NULL);
 
        return 0;
 }
@@ -1379,8 +1382,7 @@ geyser34_deferred_reset(struct uatp_softc *sc)
 {
 
        DPRINTF(sc, UATP_DEBUG_RESET, ("deferring reset\n"));
-       usb_add_task(sc->sc_hdev.sc_parent->sc_udev, &sc->sc_reset_task,
-           USB_TASKQ_DRIVER);
+       usb_add_task(sc->sc_udev, &sc->sc_reset_task, USB_TASKQ_DRIVER);
 }
 
 static void
diff --git a/sys/dev/usb/ucycom.c b/sys/dev/usb/ucycom.c
index bb6046ae1a12..242ac817fda5 100644
--- a/sys/dev/usb/ucycom.c
+++ b/sys/dev/usb/ucycom.c
@@ -592,11 +592,9 @@ ucycomstart(struct tty *tp)
        }
 #endif
        DPRINTFN(4,("ucycomstart: %d chars\n", len));
-       usbd_setup_xfer(sc->sc_hdev.sc_parent->sc_oxfer, sc, sc->sc_obuf,
-           sc->sc_olen, 0, USBD_NO_TIMEOUT, ucycomwritecb);
-
        /* What can we do on error? */
-       err = usbd_transfer(sc->sc_hdev.sc_parent->sc_oxfer);
+       err = uhidev_write_async(&sc->sc_hdev, sc->sc_obuf, sc->sc_olen, 0,
+           USBD_NO_TIMEOUT, ucycomwritecb, sc);
 
 #ifdef UCYCOM_DEBUG
        if (err != USBD_IN_PROGRESS)
@@ -621,7 +619,6 @@ ucycomwritecb(struct usbd_xfer *xfer, void *p, usbd_status 
status)
 
        if (status) {
                DPRINTF(("ucycomwritecb: status=%d\n", status));
-               usbd_clear_endpoint_stall(sc->sc_hdev.sc_parent->sc_opipe);
                /* XXX we should restart after some delay. */
                goto error;
        }
@@ -1105,7 +1102,7 @@ ucycom_set_status(struct ucycom_softc *sc)
        memset(sc->sc_obuf, 0, sc->sc_olen);
        sc->sc_obuf[0] = sc->sc_mcr;
 
-       err = uhidev_write(sc->sc_hdev.sc_parent, sc->sc_obuf, sc->sc_olen);
+       err = uhidev_write(&sc->sc_hdev, sc->sc_obuf, sc->sc_olen);
        if (err) {
                DPRINTF(("ucycom_set_status: err=%d\n", err));
        }
diff --git a/sys/dev/usb/uhid.c b/sys/dev/usb/uhid.c
index 46769dc0353a..3d2841a1867d 100644
--- a/sys/dev/usb/uhid.c
+++ b/sys/dev/usb/uhid.c
@@ -86,6 +86,7 @@ int   uhiddebug = 0;
 
 struct uhid_softc {
        struct uhidev sc_hdev;
+       struct usbd_device *sc_udev;
 
        kmutex_t sc_lock;
        kcondvar_t sc_cv;
@@ -182,6 +183,8 @@ uhid_attach(device_t parent, device_t self, void *aux)
        sc->sc_hdev.sc_parent = uha->parent;
        sc->sc_hdev.sc_report_id = uha->reportid;
 
+       sc->sc_udev = uha->uiaa->uiaa_device;
+
        uhidev_get_report_desc(uha->parent, &desc, &size);
        repid = uha->reportid;
        sc->sc_isize = hid_report_size(desc, size, hid_input,   repid);
@@ -581,8 +584,7 @@ uhid_do_write(struct uhid_softc *sc, struct uio *uio, int 
flag)
 #endif
        if (!error) {
                if (sc->sc_raw)
-                       err = uhidev_write(sc->sc_hdev.sc_parent, sc->sc_obuf,
-                           size);
+                       err = uhidev_write(&sc->sc_hdev, sc->sc_obuf, size);
                else
                        err = uhidev_set_report(&sc->sc_hdev,
                            UHID_OUTPUT_REPORT, sc->sc_obuf, size);
@@ -756,16 +758,16 @@ uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, void 
*addr,
 
        case USB_GET_DEVICE_DESC:
                *(usb_device_descriptor_t *)addr =
-                       
*usbd_get_device_descriptor(sc->sc_hdev.sc_parent->sc_udev);
+                       *usbd_get_device_descriptor(sc->sc_udev);
                break;
 
        case USB_GET_DEVICEINFO:
-               usbd_fill_deviceinfo(sc->sc_hdev.sc_parent->sc_udev,
+               usbd_fill_deviceinfo(sc->sc_udev,
                                     (struct usb_device_info *)addr, 0);
                break;
        case USB_GET_DEVICEINFO_OLD:
                MODULE_HOOK_CALL(usb_subr_fill_30_hook,
-                    (sc->sc_hdev.sc_parent->sc_udev,
+                    (sc->sc_udev,
                      (struct usb_device_info_old *)addr, 0,
                       usbd_devinfo_vp, usbd_printBCD),
                     enosys(), err);
@@ -775,7 +777,7 @@ uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, void *addr,
        case USB_GET_STRING_DESC:
            {
                struct usb_string_desc *si = (struct usb_string_desc *)addr;
-               err = usbd_get_string_desc(sc->sc_hdev.sc_parent->sc_udev,
+               err = usbd_get_string_desc(sc->sc_udev,
                        si->usd_string_index,
                        si->usd_language_id, &si->usd_desc, &size);
                if (err)
diff --git a/sys/dev/usb/uhidev.c b/sys/dev/usb/uhidev.c
index b0c03092c77a..cb7130c1dfde 100644
--- a/sys/dev/usb/uhidev.c
+++ b/sys/dev/usb/uhidev.c
@@ -74,6 +74,46 @@ __KERNEL_RCSID(0, "$NetBSD: uhidev.c,v 1.81 2021/08/07 
16:19:17 thorpej Exp $");
 
 #include "locators.h"
 
+struct uhidev_softc {
+       device_t sc_dev;                /* base device */
+       struct usbd_device *sc_udev;
+       struct usbd_interface *sc_iface;        /* interface */
+       int sc_iep_addr;
+       int sc_oep_addr;
+       u_int sc_isize;
+
+       int sc_repdesc_size;
+       void *sc_repdesc;
+
+       u_int sc_nrepid;
+       device_t *sc_subdevs;
+
+       kmutex_t sc_lock;
+       kcondvar_t sc_cv;
+
+       /* Read/written under sc_lock.  */
+       struct lwp *sc_writelock;
+       struct lwp *sc_configlock;
+       int sc_refcnt;
+       int sc_writereportid;
+       u_char sc_dying;
+
+       /*
+        * - Read under sc_lock, provided sc_refcnt > 0.
+        * - Written under sc_configlock only when transitioning to and
+        *   from sc_refcnt = 0.
+        */
+       u_char *sc_ibuf;
+       struct usbd_pipe *sc_ipipe;     /* input interrupt pipe */
+       struct usbd_pipe *sc_opipe;     /* output interrupt pipe */
+       struct usbd_xfer *sc_oxfer;     /* write request */
+       usbd_callback sc_writecallback; /* async write request callback */
+       void *sc_writecookie;
+
+       u_int sc_flags;
+#define UHIDEV_F_XB1   0x0001  /* Xbox 1 controller */
+};
+
 #ifdef UHIDEV_DEBUG
 #define DPRINTF(x)     if (uhidevdebug) printf x
 #define DPRINTFN(n,x)  if (uhidevdebug>(n)) printf x
@@ -901,7 +941,7 @@ uhidev_stop(struct uhidev *scd)
                abort = true;
        mutex_exit(&sc->sc_lock);
 
-       if (abort && sc->sc_opipe)
+       if (abort && sc->sc_opipe) /* XXX sc_opipe might go away */
                usbd_abort_pipe(sc->sc_opipe);
 }
 
@@ -961,8 +1001,9 @@ uhidev_get_report(struct uhidev *scd, int type, void 
*data, int len)
 }
 
 usbd_status
-uhidev_write(struct uhidev_softc *sc, void *data, int len)
+uhidev_write(struct uhidev *scd, void *data, int len)
 {
+       struct uhidev_softc *sc = scd->sc_parent;
        usbd_status err;
 
        DPRINTF(("uhidev_write: data=%p, len=%d\n", data, len));
@@ -985,6 +1026,7 @@ uhidev_write(struct uhidev_softc *sc, void *data, int len)
                }
        }
        sc->sc_writelock = curlwp;
+       sc->sc_writereportid = scd->sc_report_id;
        mutex_exit(&sc->sc_lock);
 
 #ifdef UHIDEV_DEBUG
@@ -1006,8 +1048,79 @@ uhidev_write(struct uhidev_softc *sc, void *data, int 
len)
        KASSERT(sc->sc_refcnt);
        KASSERTMSG(sc->sc_writelock == curlwp, "%s: migrated from %p to %p",
            device_xname(sc->sc_dev), curlwp, sc->sc_writelock);
+       KASSERTMSG(sc->sc_writereportid == scd->sc_report_id,
+           "%s: changed write report ids from %d to %d",
+           device_xname(sc->sc_dev), scd->sc_report_id, sc->sc_writereportid);
+       sc->sc_writereportid = -1;
        sc->sc_writelock = NULL;
        cv_broadcast(&sc->sc_cv);
 out:   mutex_exit(&sc->sc_lock);
        return err;
 }
+
+static void
+uhidev_write_callback(struct usbd_xfer *xfer, void *cookie, usbd_status err)
+{
+       struct uhidev_softc *sc = cookie;
+       usbd_callback writecallback;
+       void *writecookie;
+
+       if (err)
+               usbd_clear_endpoint_stall(sc->sc_opipe);
+
+       mutex_enter(&sc->sc_lock);
+       KASSERT(sc->sc_writelock == (void *)1);
+       writecallback = sc->sc_writecallback;
+       writecookie = sc->sc_writecookie;
+       sc->sc_writereportid = -1;
+       sc->sc_writelock = NULL;
+       sc->sc_writecallback = NULL;
+       sc->sc_writecookie = NULL;
+       cv_broadcast(&sc->sc_cv);
+       mutex_exit(&sc->sc_lock);
+
+       (*writecallback)(xfer, writecookie, err);
+}
+
+usbd_status
+uhidev_write_async(struct uhidev *scd, void *data, int len, int flags,
+    int timo, usbd_callback writecallback, void *writecookie)
+{
+       struct uhidev_softc *sc = scd->sc_parent;
+       usbd_status err;
+
+       DPRINTF(("%s: data=%p, len=%d\n", __func__, data, len));
+
+       if (sc->sc_opipe == NULL)
+               return USBD_INVAL;
+
+       mutex_enter(&sc->sc_lock);
+       KASSERT(sc->sc_refcnt);
+       if (sc->sc_dying) {
+               err = USBD_IOERROR;
+               goto out;
+       }
+       if (sc->sc_writelock != NULL) {
+               err = USBD_IN_USE;
+               goto out;
+       }
+       sc->sc_writelock = (void *)1; /* XXX no lwp to attribute async xfer */
+       sc->sc_writereportid = scd->sc_report_id;
+       sc->sc_writecallback = writecallback;
+       sc->sc_writecookie = writecookie;
+       usbd_setup_xfer(sc->sc_oxfer, sc, data, len, flags, timo,
+           uhidev_write_callback);
+       err = usbd_transfer(sc->sc_oxfer);
+       switch (err) {
+       case USBD_IN_PROGRESS:
+               break;
+       case USBD_NORMAL_COMPLETION:
+               panic("unexpected normal completion of async xfer under lock");
+       default:                /* error */
+               sc->sc_writelock = NULL;
+               sc->sc_writereportid = -1;
+               cv_broadcast(&sc->sc_cv);
+       }
+out:   mutex_exit(&sc->sc_lock);
+       return err;
+}
diff --git a/sys/dev/usb/uhidev.h b/sys/dev/usb/uhidev.h
index 83c0a357744e..b75f6f6f74c1 100644
--- a/sys/dev/usb/uhidev.h
+++ b/sys/dev/usb/uhidev.h
@@ -35,44 +35,6 @@
 
 #include <sys/rndsource.h>
 
-struct uhidev_softc {
-       device_t sc_dev;                /* base device */
-       struct usbd_device *sc_udev;
-       struct usbd_interface *sc_iface;        /* interface */
-       int sc_iep_addr;
-       int sc_oep_addr;
-       u_int sc_isize;
-
-       int sc_repdesc_size;
-       void *sc_repdesc;
-
-       u_int sc_nrepid;
-       device_t *sc_subdevs;
-
-       kmutex_t sc_lock;
-       kcondvar_t sc_cv;
-
-       /* Read/written under sc_lock.  */
-       struct lwp *sc_writelock;
-       struct lwp *sc_configlock;
-       int sc_refcnt;
-       int sc_writereportid;
-       u_char sc_dying;
-
-       /*
-        * - Read under sc_lock, provided sc_refcnt > 0.
-        * - Written under sc_configlock only when transitioning to and
-        *   from sc_refcnt = 0.
-        */
-       u_char *sc_ibuf;
-       struct usbd_pipe *sc_ipipe;     /* input interrupt pipe */
-       struct usbd_pipe *sc_opipe;     /* output interrupt pipe */
-       struct usbd_xfer *sc_oxfer;     /* write request */
-
-       u_int sc_flags;
-#define UHIDEV_F_XB1   0x0001  /* Xbox 1 controller */
-};
-
 struct uhidev {
        device_t sc_dev;                /* base device */
        struct uhidev_softc *sc_parent;
@@ -97,7 +59,9 @@ void uhidev_stop(struct uhidev *);
 void uhidev_close(struct uhidev *);
 usbd_status uhidev_set_report(struct uhidev *, int, void *, int);
 usbd_status uhidev_get_report(struct uhidev *, int, void *, int);
-usbd_status uhidev_write(struct uhidev_softc *, void *, int);
+usbd_status uhidev_write(struct uhidev *, void *, int);
+usbd_status uhidev_write_async(struct uhidev *, void *, int, int, int,
+    usbd_callback, void *);
 
 #define        UHIDEV_OSIZE    64
 
diff --git a/sys/dev/usb/ukbd.c b/sys/dev/usb/ukbd.c
index 14df4d53730e..4b96e831c8b5 100644
--- a/sys/dev/usb/ukbd.c
+++ b/sys/dev/usb/ukbd.c
@@ -236,6 +236,8 @@ Static const uint8_t ukbd_trtab[256] = {
 
 struct ukbd_softc {
        struct uhidev sc_hdev;
+       struct usbd_device *sc_udev;
+       struct usbd_interface *sc_iface;
 
        struct ukbd_data sc_ndata;
        struct ukbd_data sc_odata;
@@ -410,6 +412,8 @@ ukbd_attach(device_t parent, device_t self, void *aux)
        sc->sc_hdev.sc_intr = ukbd_intr;
        sc->sc_hdev.sc_parent = uha->parent;
        sc->sc_hdev.sc_report_id = uha->reportid;
+       sc->sc_udev = uha->uiaa->uiaa_device;
+       sc->sc_iface = uha->uiaa->uiaa_iface;
        sc->sc_flags = 0;
 
        aprint_naive("\n");
@@ -427,7 +431,7 @@ ukbd_attach(device_t parent, device_t self, void *aux)
        }
 
        /* Quirks */
-       qflags = usbd_get_quirks(uha->parent->sc_udev)->uq_flags;
+       qflags = usbd_get_quirks(sc->sc_udev)->uq_flags;
        if (qflags & UQ_SPUR_BUT_UP)
                sc->sc_flags |= FLAG_DEBOUNCE;
        if (qflags & UQ_APPLE_ISO)
@@ -579,7 +583,7 @@ ukbd_detach(device_t self, int flags)
 
        callout_halt(&sc->sc_delay, NULL);
        callout_halt(&sc->sc_ledreset, NULL);
-       usb_rem_task_wait(sc->sc_hdev.sc_parent->sc_udev, &sc->sc_ledtask,
+       usb_rem_task_wait(sc->sc_udev, &sc->sc_ledtask,
            USB_TASKQ_DRIVER, NULL);
 
        /* The console keyboard does not get a disable call, so check pipe. */
@@ -885,7 +889,7 @@ void
 ukbd_set_leds(void *v, int leds)
 {
        struct ukbd_softc *sc = v;
-       struct usbd_device *udev = sc->sc_hdev.sc_parent->sc_udev;
+       struct usbd_device *udev = sc->sc_udev;
 
        DPRINTF(("%s: sc=%p leds=%d, sc_leds=%d\n", __func__,
                 sc, leds, sc->sc_leds));
@@ -995,7 +999,7 @@ ukbd_cngetc(void *v, u_int *type, int *data)
        DPRINTFN(0,("%s: enter\n", __func__));
        sc->sc_flags |= FLAG_POLLING;
        if (sc->sc_npollchar <= 0)
-               usbd_dopoll(sc->sc_hdev.sc_parent->sc_iface);
+               usbd_dopoll(sc->sc_iface);
        sc->sc_flags &= ~FLAG_POLLING;
        if (sc->sc_npollchar > 0) {
                c = sc->sc_pollchars[0];
@@ -1021,7 +1025,8 @@ ukbd_cnpollc(void *v, int on)
 
        DPRINTFN(2,("%s: sc=%p on=%d\n", __func__, v, on));
 
-       usbd_interface2device_handle(sc->sc_hdev.sc_parent->sc_iface, &dev);
+       /* XXX Can this just use sc->sc_udev, or am I mistaken?  */
+       usbd_interface2device_handle(sc->sc_iface, &dev);
        if (on) {
                sc->sc_spl = splusb();
                pollenter++;
diff --git a/sys/dev/usb/ums.c b/sys/dev/usb/ums.c
index 0f49020b7e9e..a445cc9cfc3c 100644
--- a/sys/dev/usb/ums.c
+++ b/sys/dev/usb/ums.c
@@ -76,6 +76,7 @@ int   umsdebug = 0;
 
 struct ums_softc {
        struct uhidev sc_hdev;
+       struct usbd_device *sc_udev;
        struct hidms sc_ms;
 
        bool    sc_alwayson;
@@ -149,8 +150,9 @@ ums_attach(device_t parent, device_t self, void *aux)
        sc->sc_hdev.sc_intr = ums_intr;
        sc->sc_hdev.sc_parent = uha->parent;
        sc->sc_hdev.sc_report_id = uha->reportid;
+       sc->sc_udev = uha->uiaa->uiaa_device;
 
-       quirks = usbd_get_quirks(uha->parent->sc_udev)->uq_flags;
+       quirks = usbd_get_quirks(sc->sc_udev)->uq_flags;
        if (quirks & UQ_MS_REVZ)
                sc->sc_ms.flags |= HIDMS_REVZ;
        if (quirks & UQ_SPUR_BUT_UP)
diff --git a/sys/dev/usb/uthum.c b/sys/dev/usb/uthum.c
index 924a6586ad21..e2fbd70584e0 100644
--- a/sys/dev/usb/uthum.c
+++ b/sys/dev/usb/uthum.c
@@ -130,7 +130,7 @@ uthum_attach(device_t parent, device_t self, void *aux)
 {
        struct uthum_softc *sc = device_private(self);
        struct uhidev_attach_arg *uha = aux;
-       struct usbd_device *dev = uha->parent->sc_udev;
+       struct usbd_device *dev = uha->uiaa->uiaa_device;
        int size, repid;
        void *desc;
 

Reply via email to