diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c --- a/sys/dev/usb/controller/xhci.c +++ b/sys/dev/usb/controller/xhci.c @@ -1981,7 +1981,7 @@ struct xhci_td *td; uint32_t x; uint32_t y; - uint8_t mult; + uint8_t mult = 0; temp.do_isoc_sync = 0; temp.step_td = 0; @@ -2011,11 +2011,30 @@ if (xfer->flags_int.isochronous_xfr) { uint8_t shift; + uint32_t max_burst, max_pkt_sz; + uint64_t value; /* compute multiplier for ISOCHRONOUS transfers */ - mult = xfer->endpoint->ecomp ? - UE_GET_SS_ISO_MULT(xfer->endpoint->ecomp->bmAttributes) - : 0; + if (xfer->endpoint->ecomp) { + if (UE_GET_SSPLUS_ISOC_COMP( + xfer->endpoint->ecomp->bmAttributes) != 0) { + max_burst = xfer->endpoint->ecomp->bMaxBurst; + max_pkt_sz = UGETW( + xfer->endpoint->edesc->wMaxPacketSize); + /* + * The value should be round up the the nearest + * value + */ + value = UGETDW(xfer->endpoint->isoc_comp + ->dwBytesPerInterval); + value = (value + max_burst - 1) / max_burst; + value = (value + max_pkt_sz - 1) / max_pkt_sz; + mult = value > 255 ? 255 : value; + } else + UE_GET_SS_ISO_MULT( + xfer->endpoint->ecomp->bmAttributes); + } + /* check for USB 2.0 multiplier */ if (mult == 0) { mult = (xfer->endpoint->edesc-> @@ -2467,12 +2486,14 @@ { struct xhci_endpoint_ext *pepext; struct usb_endpoint_ss_comp_descriptor *ecomp; + struct usb_endpoint_ssplus_isoc_comp_descriptor *isoc_comp; usb_stream_t x; pepext = xhci_get_endpoint_ext(xfer->xroot->udev, xfer->endpoint->edesc); ecomp = xfer->endpoint->ecomp; + isoc_comp = xfer->endpoint->isoc_comp; for (x = 0; x != XHCI_MAX_STREAMS; x++) { uint64_t temp; @@ -2498,11 +2519,16 @@ usb_pc_cpu_flush(pepext->page_cache); return (xhci_configure_endpoint(xfer->xroot->udev, - xfer->endpoint->edesc, pepext, - xfer->interval, xfer->max_packet_count, - (ecomp != NULL) ? UE_GET_SS_ISO_MULT(ecomp->bmAttributes) + 1 : 1, + xfer->endpoint->edesc, pepext, xfer->interval, + xfer->max_packet_count, + ((ecomp != NULL && !UE_GET_SSPLUS_ISOC_COMP(ecomp->bmAttributes)) ? + UE_GET_SS_ISO_MULT(ecomp->bmAttributes) : + 0) + + 1, usbd_xfer_get_fps_shift(xfer), xfer->max_packet_size, - xfer->max_frame_size, xfer->endpoint->ep_mode)); + isoc_comp != NULL ? UGETDW(isoc_comp->dwBytesPerInterval) : + xfer->max_frame_size, + xfer->endpoint->ep_mode)); } static usb_error_t diff --git a/sys/dev/usb/usb.h b/sys/dev/usb/usb.h --- a/sys/dev/usb/usb.h +++ b/sys/dev/usb/usb.h @@ -215,6 +215,7 @@ #define UDESC_HUB 0x29 #define UDESC_SS_HUB 0x2A /* super speed */ #define UDESC_ENDPOINT_SS_COMP 0x30 /* super speed */ +#define UDESC_ENDPOINT_SSPLUS_ISOC_COMP 0x31 /* super speed plus */ #define UR_SET_DESCRIPTOR 0x07 #define UR_GET_CONFIG 0x08 #define UR_SET_CONFIG 0x09 @@ -569,11 +570,21 @@ uByte bmAttributes; #define UE_GET_BULK_STREAMS(x) ((x) & 0x0F) #define UE_GET_SS_ISO_MULT(x) ((x) & 0x03) +#define UE_GET_SSPLUS_ISOC_COMP(x) ((x) & 0x80) uWord wBytesPerInterval; } __packed; typedef struct usb_endpoint_ss_comp_descriptor usb_endpoint_ss_comp_descriptor_t; +struct usb_endpoint_ssplus_isoc_comp_descriptor { + uByte bLength; + uByte bDescriptorType; + uWord wReserved; + uDWord dwBytesPerInterval; +} __packed; +typedef struct usb_endpoint_ssplus_isoc_comp_descriptor + usb_endpoint_ssplus_isoc_comp_descriptor_t; + struct usb_string_descriptor { uByte bLength; uByte bDescriptorType; diff --git a/sys/dev/usb/usb_core.h b/sys/dev/usb/usb_core.h --- a/sys/dev/usb/usb_core.h +++ b/sys/dev/usb/usb_core.h @@ -163,8 +163,8 @@ * transferred */ usb_stream_t stream_id; /* USB3.0 specific field */ - uint16_t max_packet_size; - uint16_t max_frame_size; + uint32_t max_packet_size; + uint32_t max_frame_size; uint16_t qh_pos; uint16_t isoc_time_complete; /* in ms */ usb_timeout_t interval; /* milliseconds */ diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c --- a/sys/dev/usb/usb_device.c +++ b/sys/dev/usb/usb_device.c @@ -88,9 +88,8 @@ static int sysctl_hw_usb_template(SYSCTL_HANDLER_ARGS); static void usb_init_endpoint(struct usb_device *, uint8_t, - struct usb_endpoint_descriptor *, - struct usb_endpoint_ss_comp_descriptor *, - struct usb_endpoint *); + struct usb_endpoint_descriptor *, struct usb_endpoint_ss_comp_descriptor *, + struct usb_endpoint_ssplus_isoc_comp_descriptor *, struct usb_endpoint *); static void usb_unconfigure(struct usb_device *, uint8_t); static void usb_detach_device_sub(struct usb_device *, device_t *, char **, uint8_t); @@ -499,6 +498,7 @@ usb_init_endpoint(struct usb_device *udev, uint8_t iface_index, struct usb_endpoint_descriptor *edesc, struct usb_endpoint_ss_comp_descriptor *ecomp, + struct usb_endpoint_ssplus_isoc_comp_descriptor *isoc_comp, struct usb_endpoint *ep) { const struct usb_bus_methods *methods; @@ -511,6 +511,7 @@ /* initialise USB endpoint structure */ ep->edesc = edesc; ep->ecomp = ecomp; + ep->isoc_comp = isoc_comp; ep->iface_index = iface_index; /* setup USB stream queues */ @@ -955,13 +956,16 @@ if (do_init) { void *ecomp; + void *isoc_ecomp; ecomp = usb_ed_comp_foreach(udev->cdesc, (void *)ed); if (ecomp != NULL) DPRINTFN(5, "Found endpoint companion descriptor\n"); + isoc_ecomp = usb_ed_ssplus_isoc_comp_foreach( + udev->cdesc, ecomp); - usb_init_endpoint(udev, - ips.iface_index, ed, ecomp, ep); + usb_init_endpoint(udev, ips.iface_index, ed, + ecomp, isoc_ecomp, ep); } temp ++; @@ -1868,10 +1872,8 @@ } /* init the default endpoint */ - usb_init_endpoint(udev, 0, - &udev->ctrl_ep_desc, - &udev->ctrl_ep_comp_desc, - &udev->ctrl_ep); + usb_init_endpoint(udev, 0, &udev->ctrl_ep_desc, + &udev->ctrl_ep_comp_desc, NULL, &udev->ctrl_ep); /* set device index */ udev->device_index = device_index; diff --git a/sys/dev/usb/usb_parse.c b/sys/dev/usb/usb_parse.c --- a/sys/dev/usb/usb_parse.c +++ b/sys/dev/usb/usb_parse.c @@ -253,6 +253,44 @@ return (NULL); } +/*------------------------------------------------------------------------* + * usb_ed_ssplus_isoc_comp_foreacah + * + * This function will iterate all the ssplus isochronous endpoint companion + *descriptors within an endpoint descriptor in an interface descriptor. Starting + * value for the "ped" argument should be a valid endpoint companion + * descriptor. + * + * Return values: + * NULL: End of descriptors + * Else: A valid endpoint companion descriptor + *------------------------------------------------------------------------*/ +struct usb_endpoint_ssplus_isoc_comp_descriptor * +usb_ed_ssplus_isoc_comp_foreach(struct usb_config_descriptor *cd, + struct usb_endpoint_ss_comp_descriptor *ped) +{ + struct usb_descriptor *desc; + + if (ped == NULL) + return (NULL); + + desc = ((struct usb_descriptor *)ped); + + if (UE_GET_SSPLUS_ISOC_COMP(ped->bmAttributes) == 0) + return (NULL); + + /* + * According to the USB 3.1 spec, SSPlus iso companion descriptor should + * follow immediately after the ss comp + */ + desc = usb_desc_foreach(cd, desc); + if (desc == NULL || + desc->bDescriptorType != UDESC_ENDPOINT_SSPLUS_ISOC_COMP) + return (NULL); + + return ((struct usb_endpoint_ssplus_isoc_comp_descriptor *)desc); +} + /*------------------------------------------------------------------------* * usbd_get_no_descriptors * diff --git a/sys/dev/usb/usb_transfer.c b/sys/dev/usb/usb_transfer.c --- a/sys/dev/usb/usb_transfer.c +++ b/sys/dev/usb/usb_transfer.c @@ -25,6 +25,7 @@ * SUCH DAMAGE. */ +#include "dev/usb/usb_endian.h" #ifdef USB_GLOBAL_INCLUDE_FILE #include USB_GLOBAL_INCLUDE_FILE #else @@ -166,8 +167,8 @@ usbd_update_max_frame_size(struct usb_xfer *xfer) { /* compute maximum frame size */ - /* this computation should not overflow 16-bit */ - /* max = 15 * 1024 */ + /* this computation should not overflow 32-bit */ + /* max = 15 * 1024 or dwMaxPacketSize */ xfer->max_frame_size = xfer->max_packet_size * xfer->max_packet_count; } @@ -379,10 +380,12 @@ uint32_t usbd_get_max_frame_length(const struct usb_endpoint_descriptor *edesc, const struct usb_endpoint_ss_comp_descriptor *ecomp, + const struct usb_endpoint_ssplus_isoc_comp_descriptor *isoc_comp, enum usb_dev_speed speed) { uint32_t max_packet_size; uint32_t max_packet_count; + uint32_t max_frame_size; uint8_t type; max_packet_size = UGETW(edesc->wMaxPacketSize); @@ -424,10 +427,24 @@ if (ecomp != NULL) { uint8_t mult; - mult = UE_GET_SS_ISO_MULT( - ecomp->bmAttributes) + 1; - if (mult > 3) - mult = 3; + if (UE_GET_SSPLUS_ISOC_COMP( + ecomp->bmAttributes) != 0) { + max_frame_size = UGETDW( + isoc_comp->dwBytesPerInterval); + mult = (((uint64_t)max_frame_size + + ecomp->bMaxBurst - 1) / + ecomp->bMaxBurst + + UGETW( + edesc->wMaxPacketSize) - + 1) / + UGETW(edesc->wMaxPacketSize); + } else { + mult = UE_GET_SS_ISO_MULT( + ecomp->bmAttributes) + + 1; + if (mult > 3) + mult = 3; + } max_packet_count *= mult; } @@ -462,6 +479,7 @@ struct usb_xfer *xfer = parm->curr_xfer; const struct usb_config *setup = parm->curr_setup; struct usb_endpoint_ss_comp_descriptor *ecomp; + struct usb_endpoint_ssplus_isoc_comp_descriptor *isoc_comp; struct usb_endpoint_descriptor *edesc; struct usb_std_packet_size std_size; usb_frcount_t n_frlengths; @@ -483,6 +501,7 @@ } edesc = xfer->endpoint->edesc; ecomp = xfer->endpoint->ecomp; + isoc_comp = xfer->endpoint->isoc_comp; type = (edesc->bmAttributes & UE_XFERTYPE); @@ -534,10 +553,24 @@ if (ecomp != NULL) { uint8_t mult; - mult = UE_GET_SS_ISO_MULT( - ecomp->bmAttributes) + 1; - if (mult > 3) - mult = 3; + if (UE_GET_SSPLUS_ISOC_COMP( + ecomp->bmAttributes) != 0) { + xfer->max_frame_size = UGETDW( + isoc_comp->dwBytesPerInterval); + mult = + (((uint64_t)xfer->max_frame_size + + ecomp->bMaxBurst - 1) / + ecomp->bMaxBurst + + UGETW(edesc->wMaxPacketSize) - + 1) / + UGETW(edesc->wMaxPacketSize); + } else { + mult = UE_GET_SS_ISO_MULT( + ecomp->bmAttributes) + + 1; + if (mult > 3) + mult = 3; + } xfer->max_packet_count *= mult; } diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h --- a/sys/dev/usb/usbdi.h +++ b/sys/dev/usb/usbdi.h @@ -142,6 +142,7 @@ struct usb_endpoint_descriptor *edesc; struct usb_endpoint_ss_comp_descriptor *ecomp; + struct usb_endpoint_ssplus_isoc_comp_descriptor *isoc_comp; const struct usb_pipe_methods *methods; /* set by HC driver */ uint16_t isoc_next; @@ -611,6 +612,7 @@ uint32_t usbd_get_isoc_fps(struct usb_device *udev); uint32_t usbd_get_max_frame_length(const struct usb_endpoint_descriptor *, const struct usb_endpoint_ss_comp_descriptor *, + const struct usb_endpoint_ssplus_isoc_comp_descriptor *, enum usb_dev_speed); usb_error_t usbd_transfer_setup(struct usb_device *udev, const uint8_t *ifaces, struct usb_xfer **pxfer, diff --git a/sys/dev/usb/usbdi_util.h b/sys/dev/usb/usbdi_util.h --- a/sys/dev/usb/usbdi_util.h +++ b/sys/dev/usb/usbdi_util.h @@ -54,6 +54,9 @@ struct usb_endpoint_ss_comp_descriptor *usb_ed_comp_foreach( struct usb_config_descriptor *cd, struct usb_endpoint_ss_comp_descriptor *ped); +struct usb_endpoint_ssplus_isoc_comp_descriptor *usb_ed_ssplus_isoc_comp_foreach( + struct usb_config_descriptor *cd, + struct usb_endpoint_ss_comp_descriptor *ped); uint8_t usbd_get_no_descriptors(struct usb_config_descriptor *cd, uint8_t type); uint8_t usbd_get_no_alts(struct usb_config_descriptor *cd, diff --git a/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c b/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c --- a/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c +++ b/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c @@ -767,8 +767,8 @@ (i != 0)) { uint32_t temp; - temp = usbd_get_max_frame_length( - ed, NULL, usbd_get_speed(uaa->device)); + temp = usbd_get_max_frame_length(ed, NULL, NULL, + usbd_get_speed(uaa->device)); if (temp > wMaxPacketSize) { wMaxPacketSize = temp; alt_index = j;