diff --git a/sys/dev/usb/input/usbhid.c b/sys/dev/usb/input/usbhid.c --- a/sys/dev/usb/input/usbhid.c +++ b/sys/dev/usb/input/usbhid.c @@ -308,6 +308,22 @@ }, }; +static inline usb_frlength_t +usbhid_xfer_max_len(struct usb_xfer *xfer) +{ + return (xfer == NULL ? 0 : usbd_xfer_max_len(xfer)); +} + +static inline int +usbhid_xfer_check_len(struct usbhid_softc* sc, int xfer_idx, hid_size_t len) +{ + if (sc->sc_xfer[xfer_idx] == NULL) + return (ENODEV); + if (len > usbd_xfer_max_len(sc->sc_xfer[xfer_idx])) + return (ENOBUFS); + return (0); +} + static void usbhid_intr_setup(device_t dev, hid_intr_t intr, void *context, struct hid_rdesc_info *rdesc) @@ -320,6 +336,7 @@ sc->sc_intr_handler = intr; sc->sc_intr_ctx = context; bcopy(usbhid_config, sc->sc_config, sizeof(usbhid_config)); + bzero(sc->sc_xfer, sizeof(sc->sc_xfer)); /* Set buffer sizes to match HID report sizes */ sc->sc_config[USBHID_INTR_OUT_DT].bufsize = rdesc->osize; @@ -342,17 +359,15 @@ sc->sc_xfer + n, sc->sc_config + n, 1, (void *)(sc->sc_xfer_ctx + n), &sc->sc_mtx); if (error) - break; + DPRINTF("xfer %d setup error=%s\n", n, + usbd_errstr(error)); } - if (error) - DPRINTF("error=%s\n", usbd_errstr(error)); - - rdesc->rdsize = usbd_xfer_max_len(sc->sc_xfer[USBHID_INTR_IN_DT]); - rdesc->grsize = usbd_xfer_max_len(sc->sc_xfer[USBHID_CTRL_DT]); + rdesc->rdsize = usbhid_xfer_max_len(sc->sc_xfer[USBHID_INTR_IN_DT]); + rdesc->grsize = usbhid_xfer_max_len(sc->sc_xfer[USBHID_CTRL_DT]); rdesc->srsize = rdesc->grsize; rdesc->wrsize = nowrite ? rdesc->srsize : - usbd_xfer_max_len(sc->sc_xfer[USBHID_INTR_OUT_DT]); + usbhid_xfer_max_len(sc->sc_xfer[USBHID_INTR_OUT_DT]); sc->sc_intr_buf = malloc(rdesc->rdsize, M_USBDEV, M_ZERO | M_WAITOK); } @@ -371,6 +386,9 @@ { struct usbhid_softc* sc = device_get_softc(dev); + if (sc->sc_xfer[USBHID_INTR_IN_DT] == NULL) + return (ENODEV); + mtx_lock(&sc->sc_mtx); sc->sc_xfer_ctx[USBHID_INTR_IN_DT] = (struct usbhid_xfer_ctx) { .req.intr.maxlen = @@ -493,8 +511,9 @@ union usbhid_device_request req; int error; - if (maxlen > usbd_xfer_max_len(sc->sc_xfer[USBHID_CTRL_DT])) - return (ENOBUFS); + error = usbhid_xfer_check_len(sc, USBHID_CTRL_DT, maxlen); + if (error) + return (error); req.ctrl.bmRequestType = UT_READ_CLASS_INTERFACE; req.ctrl.bRequest = UR_GET_REPORT; @@ -516,9 +535,11 @@ { struct usbhid_softc* sc = device_get_softc(dev); union usbhid_device_request req; + int error; - if (len > usbd_xfer_max_len(sc->sc_xfer[USBHID_CTRL_DT])) - return (ENOBUFS); + error = usbhid_xfer_check_len(sc, USBHID_CTRL_DT, len); + if (error) + return (error); req.ctrl.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.ctrl.bRequest = UR_SET_REPORT; @@ -538,8 +559,9 @@ union usbhid_device_request req; int error; - if (maxlen > usbd_xfer_max_len(sc->sc_xfer[USBHID_INTR_IN_DT])) - return (ENOBUFS); + error = usbhid_xfer_check_len(sc, USBHID_INTR_IN_DT, maxlen); + if (error) + return (error); req.intr.maxlen = maxlen; error = usbhid_sync_xfer(sc, USBHID_INTR_IN_DT, &req, buf); @@ -554,9 +576,11 @@ { struct usbhid_softc* sc = device_get_softc(dev); union usbhid_device_request req; + int error; - if (len > usbd_xfer_max_len(sc->sc_xfer[USBHID_INTR_OUT_DT])) - return (ENOBUFS); + error = usbhid_xfer_check_len(sc, USBHID_INTR_OUT_DT, len); + if (error) + return (error); req.intr.maxlen = len; return (usbhid_sync_xfer(sc, USBHID_INTR_OUT_DT, &req, @@ -568,6 +592,11 @@ { struct usbhid_softc* sc = device_get_softc(dev); union usbhid_device_request req; + int error; + + error = usbhid_xfer_check_len(sc, USBHID_CTRL_DT, 0); + if (error) + return (error); /* Duration is measured in 4 milliseconds per unit. */ req.ctrl.bmRequestType = UT_WRITE_CLASS_INTERFACE; @@ -585,6 +614,11 @@ { struct usbhid_softc* sc = device_get_softc(dev); union usbhid_device_request req; + int error; + + error = usbhid_xfer_check_len(sc, USBHID_CTRL_DT, 0); + if (error) + return (error); req.ctrl.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.ctrl.bRequest = UR_SET_PROTOCOL;