diff --git a/sys/dev/usb2/core/usb2_hub.c b/sys/dev/usb2/core/usb2_hub.c index cbc1763827a7..6dd6d10ecf80 100644 --- a/sys/dev/usb2/core/usb2_hub.c +++ b/sys/dev/usb2/core/usb2_hub.c @@ -53,6 +53,7 @@ #include #define UHUB_INTR_INTERVAL 250 /* ms */ +#define UHUB_N_TRANSFER 1 #if USB_DEBUG static int uhub_debug = 0; @@ -76,10 +77,9 @@ struct uhub_softc { struct uhub_current_state sc_st;/* current state */ device_t sc_dev; /* base device */ struct usb2_device *sc_udev; /* USB device */ - struct usb2_xfer *sc_xfer[2]; /* interrupt xfer */ + struct usb2_xfer *sc_xfer[UHUB_N_TRANSFER]; /* interrupt xfer */ uint8_t sc_flags; #define UHUB_FLAG_DID_EXPLORE 0x01 -#define UHUB_FLAG_INTR_STALL 0x02 char sc_name[32]; }; @@ -100,12 +100,11 @@ static bus_child_location_str_t uhub_child_location_string; static bus_child_pnpinfo_str_t uhub_child_pnpinfo_string; static usb2_callback_t uhub_intr_callback; -static usb2_callback_t uhub_intr_clear_stall_callback; static void usb2_dev_resume_peer(struct usb2_device *udev); static void usb2_dev_suspend_peer(struct usb2_device *udev); -static const struct usb2_config uhub_config[2] = { +static const struct usb2_config uhub_config[UHUB_N_TRANSFER] = { [0] = { .type = UE_INTERRUPT, @@ -117,17 +116,6 @@ static const struct usb2_config uhub_config[2] = { .mh.callback = &uhub_intr_callback, .mh.interval = UHUB_INTR_INTERVAL, }, - - [1] = { - .type = UE_CONTROL, - .endpoint = 0, - .direction = UE_DIR_ANY, - .mh.timeout = 1000, /* 1 second */ - .mh.interval = 50, /* 50ms */ - .mh.flags = {}, - .mh.bufsize = sizeof(struct usb2_device_request), - .mh.callback = &uhub_intr_clear_stall_callback, - }, }; /* @@ -159,19 +147,6 @@ static driver_t uhub_driver = DRIVER_MODULE(ushub, usbus, uhub_driver, uhub_devclass, 0, 0); DRIVER_MODULE(ushub, ushub, uhub_driver, uhub_devclass, NULL, 0); -static void -uhub_intr_clear_stall_callback(struct usb2_xfer *xfer) -{ - struct uhub_softc *sc = xfer->priv_sc; - struct usb2_xfer *xfer_other = sc->sc_xfer[0]; - - if (usb2_clear_stall_callback(xfer, xfer_other)) { - DPRINTF("stall cleared\n"); - sc->sc_flags &= ~UHUB_FLAG_INTR_STALL; - usb2_transfer_start(xfer_other); - } -} - static void uhub_intr_callback(struct usb2_xfer *xfer) { @@ -189,21 +164,22 @@ uhub_intr_callback(struct usb2_xfer *xfer) usb2_needs_explore(sc->sc_udev->bus, 0); case USB_ST_SETUP: - if (sc->sc_flags & UHUB_FLAG_INTR_STALL) { - usb2_transfer_start(sc->sc_xfer[1]); - } else { - xfer->frlengths[0] = xfer->max_data_length; - usb2_start_hardware(xfer); - } - return; + xfer->frlengths[0] = xfer->max_data_length; + usb2_start_hardware(xfer); + break; default: /* Error */ if (xfer->error != USB_ERR_CANCELLED) { - /* start clear stall */ - sc->sc_flags |= UHUB_FLAG_INTR_STALL; - usb2_transfer_start(sc->sc_xfer[1]); + /* + * Do a clear-stall. The "stall_pipe" flag + * will get cleared before next callback by + * the USB stack. + */ + xfer->flags.stall_pipe = 1; + xfer->frlengths[0] = xfer->max_data_length; + usb2_start_hardware(xfer); } - return; + break; } } @@ -736,7 +712,7 @@ uhub_attach(device_t dev) /* set up interrupt pipe */ iface_index = 0; err = usb2_transfer_setup(udev, &iface_index, sc->sc_xfer, - uhub_config, 2, sc, &Giant); + uhub_config, UHUB_N_TRANSFER, sc, &Giant); if (err) { DPRINTFN(0, "cannot setup interrupt transfer, " "errstr=%s!\n", usb2_errstr(err)); @@ -821,7 +797,7 @@ uhub_attach(device_t dev) return (0); error: - usb2_transfer_unsetup(sc->sc_xfer, 2); + usb2_transfer_unsetup(sc->sc_xfer, UHUB_N_TRANSFER); if (udev->hub) { free(udev->hub, M_USBDEV); @@ -864,7 +840,7 @@ uhub_detach(device_t dev) child = NULL; } - usb2_transfer_unsetup(sc->sc_xfer, 2); + usb2_transfer_unsetup(sc->sc_xfer, UHUB_N_TRANSFER); free(hub, M_USBDEV); sc->sc_udev->hub = NULL; diff --git a/sys/dev/usb2/core/usb2_parse.c b/sys/dev/usb2/core/usb2_parse.c index 223b3c2634da..1f722b557a3d 100644 --- a/sys/dev/usb2/core/usb2_parse.c +++ b/sys/dev/usb2/core/usb2_parse.c @@ -43,25 +43,44 @@ * Else: Next descriptor after "desc" *------------------------------------------------------------------------*/ struct usb2_descriptor * -usb2_desc_foreach(struct usb2_config_descriptor *cd, struct usb2_descriptor *desc) +usb2_desc_foreach(struct usb2_config_descriptor *cd, + struct usb2_descriptor *_desc) { - void *end; + uint8_t *desc_next; + uint8_t *start; + uint8_t *end; + uint8_t *desc; - if (cd == NULL) { + /* be NULL safe */ + if (cd == NULL) return (NULL); - } - end = USB_ADD_BYTES(cd, UGETW(cd->wTotalLength)); - if (desc == NULL) { - desc = USB_ADD_BYTES(cd, 0); - } else { - desc = USB_ADD_BYTES(desc, desc->bLength); - } - return (((((void *)desc) >= ((void *)cd)) && - (((void *)desc) < end) && - (USB_ADD_BYTES(desc, desc->bLength) >= ((void *)cd)) && - (USB_ADD_BYTES(desc, desc->bLength) <= end) && - (desc->bLength >= sizeof(*desc))) ? desc : NULL); + /* We assume that the "wTotalLength" has been checked. */ + start = (uint8_t *)cd; + end = start + UGETW(cd->wTotalLength); + desc = (uint8_t *)_desc; + + /* Get start of next USB descriptor. */ + if (desc == NULL) + desc = start; + else + desc = desc + desc[0]; + + /* Check that the next USB descriptor is within the range. */ + if ((desc < start) || (desc >= end)) + return (NULL); /* out of range, or EOD */ + + /* Check that the second next USB descriptor is within range. */ + desc_next = desc + desc[0]; + if ((desc_next < start) || (desc_next > end)) + return (NULL); /* out of range */ + + /* Check minimum descriptor length. */ + if (desc[0] < 3) + return (NULL); /* too short descriptor */ + + /* Return start of next descriptor. */ + return ((struct usb2_descriptor *)desc); } /*------------------------------------------------------------------------* @@ -140,7 +159,6 @@ usb2_find_edesc(struct usb2_config_descriptor *cd, desc = ((void *)d); while ((desc = usb2_desc_foreach(cd, desc))) { - if (desc->bDescriptorType == UDESC_INTERFACE) { break; } @@ -195,7 +213,6 @@ usb2_get_no_alts(struct usb2_config_descriptor *cd, uint8_t ifaceno) uint16_t n = 0; while ((desc = usb2_desc_foreach(cd, desc))) { - if ((desc->bDescriptorType == UDESC_INTERFACE) && (desc->bLength >= sizeof(*id))) { id = (void *)desc;