diff --git a/lib/libusb/libusb.h b/lib/libusb/libusb.h --- a/lib/libusb/libusb.h +++ b/lib/libusb/libusb.h @@ -234,6 +234,7 @@ LIBUSB_SPEED_HIGH = 3, LIBUSB_SPEED_SUPER = 4, LIBUSB_SPEED_SUPER_PLUS = 5, + LIBUSB_SPEED_SUPER_PLUS_X2 = 6, }; enum libusb_transfer_status { diff --git a/lib/libusb/libusb01.c b/lib/libusb/libusb01.c --- a/lib/libusb/libusb01.c +++ b/lib/libusb/libusb01.c @@ -132,6 +132,8 @@ bufsize = 65536; } else if (speed == LIBUSB20_SPEED_SUPER_PLUS) { bufsize = 131072; + } else if (speed == LIBUSB20_SPEED_SUPER_PLUS) { + bufsize = 262144; } else { bufsize = 16384; } diff --git a/lib/libusb/libusb10.c b/lib/libusb/libusb10.c --- a/lib/libusb/libusb10.c +++ b/lib/libusb/libusb10.c @@ -520,6 +520,8 @@ return (LIBUSB_SPEED_SUPER); case LIBUSB20_SPEED_SUPER_PLUS: return (LIBUSB_SPEED_SUPER_PLUS); + case LIBUSB20_SPEED_SUPER_PLUS_X2: + return (LIBUSB_SPEED_SUPER_PLUS_X2); default: break; } @@ -1159,6 +1161,9 @@ case LIBUSB20_SPEED_SUPER_PLUS: ret = 131072; break; + case LIBUSB20_SPEED_SUPER_PLUS_X2: + ret = 262144; + break; default: ret = 16384; break; diff --git a/lib/libusb/libusb20.h b/lib/libusb/libusb20.h --- a/lib/libusb/libusb20.h +++ b/lib/libusb/libusb20.h @@ -160,6 +160,7 @@ LIBUSB20_SPEED_VARIABLE, LIBUSB20_SPEED_SUPER, LIBUSB20_SPEED_SUPER_PLUS, + LIBUSB20_SPEED_SUPER_PLUS_X2, }; /** \ingroup misc diff --git a/lib/libusb/libusb20_ugen20.c b/lib/libusb/libusb20_ugen20.c --- a/lib/libusb/libusb20_ugen20.c +++ b/lib/libusb/libusb20_ugen20.c @@ -202,6 +202,12 @@ case USB_SPEED_SUPER: pdev->usb_speed = LIBUSB20_SPEED_SUPER; break; + case USB_SPEED_SUPER_PLUS: + pdev->usb_speed = LIBUSB20_SPEED_SUPER_PLUS; + break; + case USB_SPEED_SUPER_PLUS_X2: + pdev->usb_speed = LIBUSB20_SPEED_SUPER_PLUS_X2; + break; default: pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN; break; diff --git a/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c b/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c --- a/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c +++ b/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c @@ -78,7 +78,7 @@ struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); struct r12a_softc *rs = sc->sc_priv; - if (usbd_get_speed(uc->uc_udev) == USB_SPEED_SUPER) { + if (usbd_get_speed(uc->uc_udev) >= USB_SPEED_SUPER) { rs->ac_usb_dma_size = 0x07; rs->ac_usb_dma_time = 0x1a; } else { diff --git a/sys/dev/usb/controller/usb_controller.c b/sys/dev/usb/controller/usb_controller.c --- a/sys/dev/usb/controller/usb_controller.c +++ b/sys/dev/usb/controller/usb_controller.c @@ -736,6 +736,18 @@ device_printf(bus->bdev, "5.0Gbps Super Speed USB v3.0\n"); break; + case USB_REV_3_1: + speed = USB_SPEED_SUPER_PLUS; + device_printf(bus->bdev, + "10-20Gbps Super Speed Plus USB v3.1\n"); + break; + + case USB_REV_3_2: + speed = USB_SPEED_SUPER_PLUS_X2; + device_printf(bus->bdev, + "10-20Gbps Super Speed Plus USB v3.2\n"); + break; + default: device_printf(bus->bdev, "Unsupported USB revision\n"); #if USB_HAVE_ROOT_MOUNT_HOLD diff --git a/sys/dev/usb/controller/xhci.h b/sys/dev/usb/controller/xhci.h --- a/sys/dev/usb/controller/xhci.h +++ b/sys/dev/usb/controller/xhci.h @@ -477,10 +477,29 @@ struct usb_devcap_container_id_descriptor cidd; } __packed; +struct xhci_ssp_bos_31_desc { + struct usb_bos_descriptor bosd; + struct usb_devcap_usb2ext_descriptor usb2extd; + struct usb_devcap_ss_descriptor usbdcd; + struct usb_devcap_container_id_descriptor cidd; + struct usb_devcap_ss_plus_descriptor_header ssplus; + uDWord caps[5]; +} __packed; + +struct xhci_ssp_bos_32_desc { + struct usb_bos_descriptor bosd; + struct usb_devcap_usb2ext_descriptor usb2extd; + struct usb_devcap_ss_descriptor usbdcd; + struct usb_devcap_container_id_descriptor cidd; + struct usb_devcap_ss_plus_descriptor_header ssplus; + uDWord caps[7]; +} __packed; + union xhci_hub_desc { struct usb_status stat; struct usb_port_status ps; struct usb_hub_ss_descriptor hubd; + struct usb_ext_status ext_ps; uint8_t temp[128]; }; 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 @@ -132,6 +132,8 @@ #define XHCI_INTR_ENDPT 1 +static const uint32_t default_psi_vaules[] = { 0x50134, 0xa4135, 0x144137 }; + struct xhci_std_temp { struct xhci_softc *sc; struct usb_page_cache *pc; @@ -506,6 +508,67 @@ return (0); } +static enum usb_revision +xhci_xecp_parse_support_protocol(struct xhci_softc *sc) +{ + uint32_t hccp1; + uint32_t eec; + uint32_t eecp; + uint8_t psic_cnt; + enum usb_revision res = USB_REV_3_0; + + hccp1 = XREAD4(sc, capa, XHCI_HCSPARAMS0); + + if (XHCI_HCS0_XECP(hccp1) == 0) { + device_printf(sc->sc_bus.parent, + "xECP: no capabilities found\n"); + return (USB_REV_3_0); + } + + eec = -1; + for (eecp = XHCI_HCS0_XECP(hccp1) << 2; + eecp != 0 && XHCI_XECP_NEXT(eec) != 0; + eecp += XHCI_XECP_NEXT(eec) << 2) { + eec = XREAD4(sc, capa, eecp); + + uint8_t xecpid = XHCI_XECP_ID(eec); + uint8_t minor = XHCI_XECP_MINOR(eec); + uint32_t val = XREAD4(sc, capa, eecp + 0x08); + int i, j, found; + psic_cnt = XHCI_XECP_PSIC_GET(val); + + if (xecpid == XHCI_ID_PROTOCOLS && + XHCI_XECP_MAJOR(eec) == 0x03) { + for (i = 0, found = 0; i < psic_cnt; ++i) { + val = XREAD4(sc, capa, eecp + 0x10 + i * 4); + for (j = 0; j < nitems(default_psi_vaules); + ++j) { + if (val == default_psi_vaules[j]) { + found = 1; + break; + } + } + if (!found) { + device_printf(sc->sc_bus.parent, + "xECP: not support non-default mapping, rallback to usb 3.0\n"); + break; + } + } + if (i != psic_cnt) + return (USB_REV_3_0); + + if (minor >= 0x20) + res = MAX(res, USB_REV_3_2); + else if (minor >= 0x10) + res = MAX(res, USB_REV_3_1); + else + res = MAX(res, USB_REV_3_0); + } + } + + return (res); +} + usb_error_t xhci_init(struct xhci_softc *sc, device_t self, uint8_t dma32) { @@ -559,6 +622,8 @@ sc->sc_ctx_is_64_byte = 0; } + sc->sc_bus.usbrev = xhci_xecp_parse_support_protocol(sc); + /* get DMA bits */ sc->sc_bus.dma_bits = (XHCI_HCS0_AC64(temp) && xhcidma32 == 0 && dma32 == 0) ? 64 : 32; @@ -2386,6 +2451,8 @@ switch (udev->speed) { case USB_SPEED_SUPER: + case USB_SPEED_SUPER_PLUS: + case USB_SPEED_SUPER_PLUS_X2: if (mult > 3) mult = 3; temp |= XHCI_EPCTX_0_MULT_SET(mult - 1); @@ -2597,8 +2664,7 @@ } is_hub = sc->sc_hw.devs[index].nports != 0 && - (udev->speed == USB_SPEED_SUPER || - udev->speed == USB_SPEED_HIGH); + (udev->speed >= USB_SPEED_HIGH); if (is_hub) temp |= XHCI_SCTX_0_HUB_SET(1); @@ -2627,6 +2693,8 @@ switch (udev->speed) { case USB_SPEED_FULL: case USB_SPEED_LOW: + case USB_SPEED_SUPER: + case USB_SPEED_SUPER_PLUS: if (hubdev != NULL) { temp |= XHCI_SCTX_2_TT_HUB_SID_SET( hubdev->controller_slot_id); @@ -3134,21 +3202,21 @@ }; static const -struct xhci_bos_desc xhci_bosd = { +struct xhci_bos_desc xhci_30_bosd = { .bosd = { - .bLength = sizeof(xhci_bosd.bosd), + .bLength = sizeof(xhci_30_bosd.bosd), .bDescriptorType = UDESC_BOS, - HSETW(.wTotalLength, sizeof(xhci_bosd)), + HSETW(.wTotalLength, sizeof(xhci_30_bosd)), .bNumDeviceCaps = 3, }, .usb2extd = { - .bLength = sizeof(xhci_bosd.usb2extd), - .bDescriptorType = 1, + .bLength = sizeof(xhci_30_bosd.usb2extd), + .bDescriptorType = UDESC_DEVICE_CAPABILITY, .bDevCapabilityType = 2, .bmAttributes[0] = 2, }, .usbdcd = { - .bLength = sizeof(xhci_bosd.usbdcd), + .bLength = sizeof(xhci_30_bosd.usbdcd), .bDescriptorType = UDESC_DEVICE_CAPABILITY, .bDevCapabilityType = 3, .bmAttributes = 0, /* XXX */ @@ -3158,14 +3226,114 @@ .wU2DevExitLat = { 0x00, 0x08 }, }, .cidd = { - .bLength = sizeof(xhci_bosd.cidd), - .bDescriptorType = 1, + .bLength = sizeof(xhci_30_bosd.cidd), + .bDescriptorType = UDESC_DEVICE_CAPABILITY, .bDevCapabilityType = 4, .bReserved = 0, .bContainerID = 0, /* XXX */ }, }; +static const +struct xhci_ssp_bos_31_desc xhci_31_bosd = { + .bosd = { + .bLength = sizeof(xhci_31_bosd.bosd), + .bDescriptorType = UDESC_BOS, + HSETW(.wTotalLength, sizeof(xhci_31_bosd)), + .bNumDeviceCaps = 4, + }, + .usb2extd = { + .bLength = sizeof(xhci_31_bosd.usb2extd), + .bDescriptorType = UDESC_DEVICE_CAPABILITY, + .bDevCapabilityType = 2, + .bmAttributes[0] = 2, + }, + .usbdcd = { + .bLength = sizeof(xhci_31_bosd.usbdcd), + .bDescriptorType = UDESC_DEVICE_CAPABILITY, + .bDevCapabilityType = 3, + .bmAttributes = 0, /* XXX */ + HSETW(.wSpeedsSupported, 0x000C), + .bFunctionalitySupport = 8, + .bU1DevExitLat = 255, /* dummy - not used */ + .wU2DevExitLat = { 0x00, 0x08 }, + }, + .cidd = { + .bLength = sizeof(xhci_31_bosd.cidd), + .bDescriptorType = UDESC_DEVICE_CAPABILITY, + .bDevCapabilityType = 4, + .bReserved = 0, + .bContainerID = 0, /* XXX */ + }, + .ssplus = { + .bLength = sizeof(xhci_31_bosd.ssplus) + sizeof(xhci_31_bosd.caps), + .bDescriptorType = UDESC_DEVICE_CAPABILITY, + .bDevCapabilityType = USB_DEVCAP_SUPERSPEED_PLUS, + .bReserved = 0, + .bmAttributes = {0x54}, /* 5 ID, 5 caps */ + .wFunctionalitySupport = {0x0, 0x11}, /* Rx: 1, Tx: 1 */ + .wReserved = {0}, + }, + .caps = { + [0] = {0x21, 0x00, 0x0c, 0x00}, /* 2: 12 Mbps, Full duplex */ + [1] = {0x12, 0x00, 0xdc, 0x05}, /* 1: 1.5 Mbps, Full duplex */ + [2] = {0x23, 0x00, 0xe0, 0x01}, /* 3: 480 Mbps, Full duplex */ + [3] = {0x34, 0x00, 0x05, 0x00}, /* 4: 5 Gbps, FUll duplex */ + [4] = {0x35, 0x40, 0x0a, 0x00}, /* 5: 10 Gbps, Full duplex */ + }, +}; + +static const +struct xhci_ssp_bos_32_desc xhci_32_bosd = { + .bosd = { + .bLength = sizeof(xhci_32_bosd.bosd), + .bDescriptorType = UDESC_BOS, + HSETW(.wTotalLength, sizeof(xhci_32_bosd)), + .bNumDeviceCaps = 4, + }, + .usb2extd = { + .bLength = sizeof(xhci_32_bosd.usb2extd), + .bDescriptorType = UDESC_DEVICE_CAPABILITY, + .bDevCapabilityType = 2, + .bmAttributes[0] = 2, + }, + .usbdcd = { + .bLength = sizeof(xhci_32_bosd.usbdcd), + .bDescriptorType = UDESC_DEVICE_CAPABILITY, + .bDevCapabilityType = 3, + .bmAttributes = 0, /* XXX */ + HSETW(.wSpeedsSupported, 0x000C), + .bFunctionalitySupport = 8, + .bU1DevExitLat = 255, /* dummy - not used */ + .wU2DevExitLat = { 0x00, 0x08 }, + }, + .cidd = { + .bLength = sizeof(xhci_32_bosd.cidd), + .bDescriptorType = UDESC_DEVICE_CAPABILITY, + .bDevCapabilityType = 4, + .bReserved = 0, + .bContainerID = 0, /* XXX */ + }, + .ssplus = { + .bLength = sizeof(xhci_32_bosd.ssplus) + sizeof(xhci_32_bosd.caps), + .bDescriptorType = UDESC_DEVICE_CAPABILITY, + .bDevCapabilityType = USB_DEVCAP_SUPERSPEED_PLUS, + .bReserved = 0, + .bmAttributes = {0x76}, /* 7 ID, 7 caps */ + .wFunctionalitySupport = {0x0, 0x11}, /* Rx: 1, Tx: 1 */ + .wReserved = {0}, + }, + .caps = { + [0] = {0x21, 0x00, 0x0c, 0x00}, /* 2: 12 Mbps, Full duplex */ + [1] = {0x12, 0x00, 0xdc, 0x05}, /* 1: 1.5 Mbps, Full duplex */ + [2] = {0x23, 0x00, 0xe0, 0x01}, /* 3: 480 Mbps, Full duplex */ + [3] = {0x34, 0x00, 0x05, 0x00}, /* 4: 5 Gbps, FUll duplex */ + [4] = {0x35, 0x40, 0x0a, 0x00}, /* 5: 10 Gbps, Full duplex */ + [5] = {0x36, 0x40, 0x0a, 0x00}, /* 6: 10 Gbps, Full duplex */ + [6] = {0x37, 0x40, 0x14, 0x00}, /* 7: 20 Gbps, Full duplex */ + }, +}; + static const struct xhci_config_desc xhci_confd = { .confd = { @@ -3269,8 +3437,21 @@ err = USB_ERR_IOERROR; goto done; } - len = sizeof(xhci_bosd); - ptr = (const void *)&xhci_bosd; + switch (sc->sc_bus.usbrev) { + case USB_REV_3_2: + len = sizeof(xhci_32_bosd); + ptr = (const void *)&xhci_32_bosd; + break; + case USB_REV_3_1: + len = sizeof(xhci_31_bosd); + ptr = (const void *)&xhci_31_bosd; + break; + default: + len = sizeof(xhci_30_bosd); + ptr = (const void *)&xhci_30_bosd; + break; + } + break; case UDESC_CONFIG: @@ -3465,12 +3646,23 @@ case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): DPRINTFN(9, "UR_GET_STATUS i=%d\n", index); - if ((index < 1) || - (index > sc->sc_noport)) { + if ((index < 1) || (index > sc->sc_noport) || + (value != 0 && value != 2)) { err = USB_ERR_IOERROR; goto done; } + if (value == 2) { + v = XREAD4(sc, oper, XHCI_PORTSC(index)); + v = XHCI_PS_SPEED_GET(v); + USETW(sc->sc_hub_desc.ext_ps.wStatus, + v | (v << 4) | ((v >= 6 ? 1 : 0) << 8) | + ((v >= 6 ? 1 : 0) << 12)); + ptr = (void *)&sc->sc_hub_desc.ext_ps; + len = sizeof(sc->sc_hub_desc.ext_ps.wStatus); + goto done; + } + v = XREAD4(sc, oper, XHCI_PORTSC(index)); DPRINTFN(9, "port status=0x%08x\n", v); @@ -4280,7 +4472,7 @@ DPRINTF("\n"); if (usb_get_device_state(udev) == USB_STATE_CONFIGURED) { - err = uhub_query_info(udev, &sc->sc_hw.devs[index].nports, + err = uhub_query_info(udev, &sc->sc_hw.devs[index].nports, &sc->sc_hw.devs[index].tt); if (err != 0) sc->sc_hw.devs[index].nports = 0; @@ -4376,9 +4568,9 @@ case USB_EP_MODE_DEFAULT: return (0); case USB_EP_MODE_STREAMS: - if (xhcistreams == 0 || + if (xhcistreams == 0 || (ep->edesc->bmAttributes & UE_XFERTYPE) != UE_BULK || - udev->speed != USB_SPEED_SUPER) + udev->speed < USB_SPEED_SUPER) return (USB_ERR_INVAL); return (0); default: diff --git a/sys/dev/usb/controller/xhcireg.h b/sys/dev/usb/controller/xhcireg.h --- a/sys/dev/usb/controller/xhcireg.h +++ b/sys/dev/usb/controller/xhcireg.h @@ -127,6 +127,9 @@ #define XHCI_PS_SPEED_LOW 0x2 /* Low Speed USB */ #define XHCI_PS_SPEED_HIGH 0x3 /* High Speed USB */ #define XHCI_PS_SPEED_SS 0x4 /* Super Speed USB */ +#define XHCI_PS_SPEED_SS_PLUS_GEN2 0x5 /* Super Speed USB */ +#define XHCI_PS_SPEED_SS_PLUS_GEN1_x2 0x6 /* Super Speed USB */ +#define XHCI_PS_SPEED_SS_PLUS_GEN2_x2 0x7 /* Super Speed USB */ #define XHCI_PS_PIC_GET(x) (((x) >> 14) & 0x3) /* RW - port indicator */ #define XHCI_PS_PIC_SET(x) (((x) & 0x3) << 14) /* RW - port indicator */ #define XHCI_PS_LWS 0x00010000 /* RW - port link state write strobe */ @@ -194,9 +197,14 @@ /* XHCI legacy support */ #define XHCI_XECP_ID(x) ((x) & 0xFF) -#define XHCI_XECP_NEXT(x) (((x) >> 8) & 0xFF) -#define XHCI_XECP_BIOS_SEM 0x0002 -#define XHCI_XECP_OS_SEM 0x0003 +#define XHCI_XECP_NEXT(x) (((x) >> 8) & 0xFF) +#define XHCI_XECP_MAJOR(x) (((x) >> 24) & 0xFF) +#define XHCI_XECP_MINOR(x) (((x) >> 16) & 0xFF) +#define XHCI_XECP_BIOS_SEM 0x0002 +#define XHCI_XECP_OS_SEM 0x0003 + +/* Support protocol */ +#define XHCI_XECP_PSIC_GET(x) (((x) >> 28) & 0x0F) /* XHCI capability ID's */ #define XHCI_ID_USB_LEGACY 0x0001 diff --git a/sys/dev/usb/net/if_ure.c b/sys/dev/usb/net/if_ure.c --- a/sys/dev/usb/net/if_ure.c +++ b/sys/dev/usb/net/if_ure.c @@ -1074,6 +1074,8 @@ /* Set RX EARLY timeout and size */ if (sc->sc_flags & URE_FLAG_8153) { switch (usbd_get_speed(sc->sc_ue.ue_udev)) { + case USB_SPEED_SUPER_PLUS_X2: + case USB_SPEED_SUPER_PLUS: case USB_SPEED_SUPER: reg = URE_COALESCE_SUPER / 8; break; @@ -1621,7 +1623,7 @@ URE_CLRBIT_2(sc, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, URE_LED_MODE_MASK); if ((sc->sc_chip & URE_CHIP_VER_5C10) && - usbd_get_speed(sc->sc_ue.ue_udev) != USB_SPEED_SUPER) + usbd_get_speed(sc->sc_ue.ue_udev) < USB_SPEED_SUPER) val = URE_LPM_TIMER_500MS; else val = URE_LPM_TIMER_500US; diff --git a/sys/dev/usb/storage/umass.c b/sys/dev/usb/storage/umass.c --- a/sys/dev/usb/storage/umass.c +++ b/sys/dev/usb/storage/umass.c @@ -2354,6 +2354,8 @@ UMASS_FLOPPY_TRANSFER_SPEED; } else { switch (usbd_get_speed(sc->sc_udev)) { + case USB_SPEED_SUPER_PLUS_X2: + case USB_SPEED_SUPER_PLUS: case USB_SPEED_SUPER: cpi->base_transfer_speed = UMASS_SUPER_TRANSFER_SPEED; diff --git a/sys/dev/usb/template/usb_template.c b/sys/dev/usb/template/usb_template.c --- a/sys/dev/usb/template/usb_template.c +++ b/sys/dev/usb/template/usb_template.c @@ -592,7 +592,15 @@ case USB_SPEED_SUPER: USETW(utd->udd.bcdUSB, 0x0300); utd->udd.bMaxPacketSize = 9; /* 2**9 = 512 bytes */ - break; + break; + case USB_SPEED_SUPER_PLUS: + USETW(utd->udd.bcdUSB, 0x0301); + utd->udd.bMaxPacketSize = 10; /* 2**10 = 512 bytes */ + break; + case USB_SPEED_SUPER_PLUS_X2: + USETW(utd->udd.bcdUSB, 0x0302); + utd->udd.bMaxPacketSize = 11; /* 2**11 = 512 bytes */ + break; default: temp->err = USB_ERR_INVAL; break; 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 @@ -328,6 +328,7 @@ #define USB_DEVCAP_USB2EXT 0x02 #define USB_DEVCAP_SUPER_SPEED 0x03 #define USB_DEVCAP_CONTAINER_ID 0x04 +#define USB_DEVCAP_SUPERSPEED_PLUS 0x0A /* data ... */ } __packed; typedef struct usb_bos_cap_descriptor usb_bos_cap_descriptor_t; @@ -368,6 +369,49 @@ typedef struct usb_devcap_container_id_descriptor usb_devcap_container_id_descriptor_t; +struct usb_devcap_ss_plus_descriptor_header { + uByte bLength; + uByte bDescriptorType; + uByte bDevCapabilityType; + uByte bReserved; + uDWord bmAttributes; + uWord wFunctionalitySupport; + uWord wReserved; +} __packed; + +struct usb_devcap_ss_plus_descriptor { + uByte bLength; + uByte bDescriptorType; + uByte bDevCapabilityType; + uByte bReserved; +#define USB_DEVCAP_SSPLUS_SSAC_GET(x) (x & 0x0F) +#define USB_DEVCAP_SSPLUS_SSAC_SET(v) (v & 0x0F) +#define USB_DEVCAP_SSPLUS_SSIC_GET(x) ((x >> 4) & 0x0F) +#define USB_DEVCAP_SSPLUS_SSIC_SET(v) ((v & 0x0F) << 4) + uDWord bmAttributes; +#define USB_DEVCAP_SSPLUS_MIN_SSID_GET(x) (x & 0x0F) +#define USB_DEVCAP_SSPLUS_MIN_SSID_SET(v) (v & 0x0F) +#define USB_DEVCAP_SSPLUS_MIN_RXLINK_GET(x) ((x >> 8) & 0x0F) +#define USB_DEVCAP_SSPLUS_MIN_RXLINK_SET(v) ((v & 0x0F) << 8) +#define USB_DEVCAP_SSPLUS_MIN_TXLINK_GET(x) ((x >> 12) & 0x0F) +#define USB_DEVCAP_SSPLUS_MIN_TXLINK_SET(v) ((v & 0x0F) << 12) + uWord wFunctionalitySupport; + uWord wReserved; +#define USB_DEVCAP_SSPLUS_SSID_GET(x) (x & 0x0F) +#define USB_DEVCAP_SSPLUS_SSID_SET(v) (v & 0x0F) +#define USB_DEVCAP_SSPLUS_LSE_GET(x) ((x >> 4) & 0x03) +#define USB_DEVCAP_SSPLUS_LSE_SET(v) ((v & 0x03) << 4) +#define USB_DEVCAP_SSPLUS_ST_GET(x) ((x >> 4) & 0x0C) +#define USB_DEVCAP_SSPLUS_ST_SET(v) ((v & 0x0C) << 4) +#define USB_DEVCAP_SSPLUS_LP_GET(x) ((x >> 14) & 0x0C) +#define USB_DEVCAP_SSPLUS_LP_SET(v) ((v & 0x0C) << 14) +#define USB_DEVCAP_SSPLUS_LSM_GET(x) ((x >> 16) & 0xFF) +#define USB_DEVCAP_SSPLUS_LSM_SET(v) ((v & 0xFF) << 16) + uDWord bmSublinkSpeedAttr[]; +} __packed; +typedef struct usb_devcap_superspeed_plus_descriptor + usb_devcap_superspeed_plus_descriptor_t; + /* Device class codes */ #define UDCLASS_IN_INTERFACE 0x00 #define UDCLASS_COMM 0x02 @@ -693,6 +737,15 @@ } __packed; typedef struct usb_status usb_status_t; +struct usb_ext_status { + uDWord wStatus; +#define UDS_RX_SUBLINK_SPEED_ID_BITS(x) (x & 0xF) +#define UDS_TX_SUBLINK_SPEED_ID_BITS(x) ((x >> 4) & 0xF) +#define UDS_RX_SUBLINK_LANE_COUNT_BITS(x) ((x >> 8) & 0xF) +#define UDS_TX_SUBLINK_LANE_COUNT_BITS(x) ((x >> 12) & 0xF) +} __packed; +typedef struct usb_ext_status usb_ext_status_t; + struct usb_hub_status { uWord wHubStatus; #define UHS_LOCAL_POWER 0x0001 @@ -755,8 +808,10 @@ USB_SPEED_FULL, USB_SPEED_HIGH, USB_SPEED_SUPER, + USB_SPEED_SUPER_PLUS, + USB_SPEED_SUPER_PLUS_X2, }; -#define USB_SPEED_MAX (USB_SPEED_SUPER+1) +#define USB_SPEED_MAX (USB_SPEED_SUPER_PLUS_X2+1) /* * The "USB_REV" macros defines all the supported USB revisions. @@ -768,9 +823,11 @@ USB_REV_1_1, USB_REV_2_0, USB_REV_2_5, - USB_REV_3_0 + USB_REV_3_0, + USB_REV_3_1, + USB_REV_3_2, }; -#define USB_REV_MAX (USB_REV_3_0+1) +#define USB_REV_MAX (USB_REV_3_2+1) /* * Supported host controller modes. 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 @@ -524,7 +524,7 @@ return; /* check for SUPER-speed streams mode endpoint */ - if (udev->speed == USB_SPEED_SUPER && ecomp != NULL && + if (udev->speed >= USB_SPEED_SUPER && ecomp != NULL && (edesc->bmAttributes & UE_XFERTYPE) == UE_BULK && (UE_GET_BULK_STREAMS(ecomp->bmAttributes) != 0)) { usbd_set_endpoint_mode(udev, ep, USB_EP_MODE_STREAMS); @@ -1857,7 +1857,7 @@ hub = udev->parent_hub; while (hub) { - if (hub->speed == USB_SPEED_HIGH) { + if (hub->speed >= udev->speed) { udev->hs_hub_addr = hub->address; udev->parent_hs_hub = hub; udev->hs_port_no = adev->port_no; diff --git a/sys/dev/usb/usb_hub.h b/sys/dev/usb/usb_hub.h --- a/sys/dev/usb/usb_hub.h +++ b/sys/dev/usb/usb_hub.h @@ -41,6 +41,25 @@ #endif }; +#define UHUB_SS_SUBLINKS_MAX_IDS 16 + +/* + * The following structure define the usb_sublink_information + */ +struct usb_hub_ss_sublinks { + uint8_t num_ids; + + struct { + uint8_t exp; + uint8_t lp; + uint16_t val; + /* + * Max 4 bit. For each we have 1 rx and 1 tx + * ID starts from 1. + */ + } hub_status[(UHUB_SS_SUBLINKS_MAX_IDS) * 2]; +}; + /* * The following structure defines an USB HUB. */ diff --git a/sys/dev/usb/usb_hub.c b/sys/dev/usb/usb_hub.c --- a/sys/dev/usb/usb_hub.c +++ b/sys/dev/usb/usb_hub.c @@ -588,6 +588,68 @@ return (err); } +static enum usb_dev_speed +usb_hub_sublink_status_to_speed(struct usb_hub_ss_sublinks *links, int id) +{ + if (id > links->num_ids) + return (USB_SPEED_VARIABLE); + + switch (links->hub_status[id].exp) { + case 0: + case 1: + return (USB_SPEED_LOW); + case 2: + return (links->hub_status[id].val >= 480 ? USB_SPEED_HIGH : + USB_SPEED_FULL); + case 3: + if (links->hub_status[id].val <= 5 || + links->hub_status[id].lp == 0) + return (USB_SPEED_SUPER); + if (links->hub_status[id].val <= 10) + return (USB_SPEED_SUPER_PLUS); + return (USB_SPEED_SUPER_PLUS_X2); + } + + return (USB_SPEED_VARIABLE); +} +static usb_error_t +uhub_read_ext_port_status(struct uhub_softc *sc, uint8_t portno) +{ + struct usb_ext_status ps; + usb_error_t err; + uint32_t rx_id, tx_id; + + if (sc->sc_usb_port_errors >= UHUB_USB_PORT_ERRORS_MAX) { + DPRINTFN(4, "port %d, HUB looks dead, too many errors\n", + portno); + sc->sc_st.ext_speed = USB_SPEED_VARIABLE; + return (USB_ERR_TIMEOUT); + } + + err = usbd_req_get_ext_port_status(sc->sc_udev, NULL, &ps, portno); + + if (err == 0) { + rx_id = UDS_RX_SUBLINK_SPEED_ID_BITS(UGETW(ps.wStatus)); + tx_id = UDS_RX_SUBLINK_SPEED_ID_BITS(UGETW(ps.wStatus)); + sc->sc_st.ext_speed = MIN( + usb_hub_sublink_status_to_speed(&sc->sc_slinks, rx_id * 2), + usb_hub_sublink_status_to_speed(&sc->sc_slinks, + (tx_id * 2) + 1)); + + if (UDS_RX_SUBLINK_LANE_COUNT_BITS(UGETW(ps.wStatus)) || + UDS_TX_SUBLINK_LANE_COUNT_BITS(UGETW(ps.wStatus))) + sc->sc_st.ext_speed = USB_SPEED_SUPER_PLUS_X2; + } else { + sc->sc_st.ext_speed = 0; + sc->sc_usb_port_errors++; + } + + /* debugging print */ + + DPRINTFN(4, "port %d, ext_speed=0x%04x\n", portno, sc->sc_st.ext_speed); + return (err); +} + /*------------------------------------------------------------------------* * uhub_reattach_port * @@ -660,6 +722,8 @@ power_mask = UPS_PORT_POWER; break; case USB_SPEED_SUPER: + case USB_SPEED_SUPER_PLUS: + case USB_SPEED_SUPER_PLUS_X2: if (udev->parent_hub == NULL) power_mask = 0; /* XXX undefined */ else @@ -753,9 +817,16 @@ case USB_SPEED_LOW: speed = USB_SPEED_LOW; break; + case USB_SPEED_SUPER_PLUS: + case USB_SPEED_SUPER_PLUS_X2: + err = uhub_read_ext_port_status(sc, portno); + if (!err && sc->sc_st.ext_speed != USB_SPEED_VARIABLE) { + speed = sc->sc_st.ext_speed; + break; + } case USB_SPEED_SUPER: - if (udev->parent_hub == NULL) { - /* Root HUB - special case */ + /* Root HUB - special case */ + if (udev->parent_hub == 0) { switch (sc->sc_st.port_status & UPS_OTHER_SPEED) { case 0: speed = USB_SPEED_FULL; @@ -772,6 +843,7 @@ } } else { speed = USB_SPEED_SUPER; + break; } break; default: @@ -779,7 +851,7 @@ speed = udev->speed; break; } - if (speed == USB_SPEED_SUPER) { + if (speed >= USB_SPEED_SUPER) { err = usbd_req_set_hub_u1_timeout(udev, NULL, portno, 128 - (2 * udev->depth)); if (err) { @@ -972,6 +1044,8 @@ return (1); break; case USB_SPEED_SUPER: + case USB_SPEED_SUPER_PLUS: + case USB_SPEED_SUPER_PLUS_X2: if (udev->depth > USB_SS_HUB_DEPTH_MAX) return (1); break; @@ -1087,7 +1161,7 @@ if (err != USB_ERR_NORMAL_COMPLETION) retval = err; } - if (udev->speed == USB_SPEED_SUPER && + if (udev->speed >= USB_SPEED_SUPER && (sc->sc_st.port_change & UPS_C_BH_PORT_RESET) != 0) { DPRINTF("Warm reset finished on port %u.\n", portno); err = usbd_req_clear_port_feature( @@ -1137,6 +1211,75 @@ return (ENXIO); } +static usb_error_t +uhub_ss_caps_get(struct usb_bos_descriptor *bdesc, + struct usb_devcap_ss_plus_descriptor **desc) +{ + struct usb_bos_cap_descriptor *cap = NULL; + + *desc = NULL; + if (bdesc == NULL) + return (0); + + while ((cap = usbd_bos_foreach(bdesc, cap))) { + if (cap->bDescriptorType == UDESC_DEVICE_CAPABILITY && + cap->bDevCapabilityType == USB_DEVCAP_SUPERSPEED_PLUS) { + *desc = (struct usb_devcap_ss_plus_descriptor *)cap; + return (0); + } + } + return (USB_ERR_INVAL); +} + +static usb_error_t +uhub_ss_caps_to_hub_sslink(struct usb_devcap_ss_plus_descriptor *desc, + struct usb_hub_ss_sublinks *links) +{ + uint32_t attrs = UGETW(desc->bmAttributes); + uint32_t n = USB_DEVCAP_SSPLUS_SSAC_GET(attrs) + 1; + uint32_t link_val; + uint8_t id, st; + uint32_t i; + + links->num_ids = USB_DEVCAP_SSPLUS_SSIC_GET(attrs) + 1; + if (links->num_ids >= UHUB_SS_SUBLINKS_MAX_IDS) { + return (USB_ERR_INVAL); + } + + for (i = 0; i < n; ++i) { + link_val = UGETDW(desc->bmSublinkSpeedAttr[i]); + id = USB_DEVCAP_SSPLUS_SSID_GET(link_val); + st = USB_DEVCAP_SSPLUS_ST_GET(link_val); + + /* + * assymetric link + */ + if (st & 0x01) { + links->hub_status[id * 2 + (st >> 1)].exp = + USB_DEVCAP_SSPLUS_LSE_GET(link_val); + links->hub_status[id * 2 + (st >> 1)].lp = + USB_DEVCAP_SSPLUS_LP_GET(link_val); + links->hub_status[id * 2 + (st >> 1)].val = + USB_DEVCAP_SSPLUS_LSM_GET(link_val); + } else { + links->hub_status[id * 2].exp = + USB_DEVCAP_SSPLUS_LSE_GET(link_val); + links->hub_status[id * 2].lp = USB_DEVCAP_SSPLUS_LP_GET( + link_val); + links->hub_status[id * 2].val = + USB_DEVCAP_SSPLUS_LSM_GET(link_val); + links->hub_status[id * 2 + 1].exp = + USB_DEVCAP_SSPLUS_LSE_GET(link_val); + links->hub_status[id * 2 + 1].lp = + USB_DEVCAP_SSPLUS_LP_GET(link_val); + links->hub_status[id * 2 + 1].val = + USB_DEVCAP_SSPLUS_LSM_GET(link_val); + } + } + + return (USB_ERR_NORMAL_COMPLETION); +} + /* NOTE: The information returned by this function can be wrong. */ usb_error_t uhub_query_info(struct usb_device *udev, uint8_t *pnports, uint8_t *ptt) @@ -1171,7 +1314,8 @@ if (udev->speed == USB_SPEED_HIGH) tt = (UGETW(hubdesc20.wHubCharacteristics) >> 5) & 3; break; - + case USB_SPEED_SUPER_PLUS: + case USB_SPEED_SUPER_PLUS_X2: case USB_SPEED_SUPER: err = usbd_req_get_ss_hub_descriptor(udev, NULL, &hubdesc30, 1); if (err) { @@ -1208,6 +1352,9 @@ struct usb_hub *hub; struct usb_hub_descriptor hubdesc20; struct usb_hub_ss_descriptor hubdesc30; + struct usb_bos_descriptor *bdesc; + struct usb_devcap_ss_plus_descriptor *dev_desc; + uint32_t bdesc_len; #if USB_HAVE_DISABLE_ENUM struct sysctl_ctx_list *sysctl_ctx; struct sysctl_oid *sysctl_tree; @@ -1301,6 +1448,36 @@ } } break; + case USB_SPEED_SUPER_PLUS: + case USB_SPEED_SUPER_PLUS_X2: + err = usbd_req_get_bos_descriptor_full(udev, NULL, &bdesc, + &bdesc_len); + if (err) { + DPRINTFN(0, + "Getting USB BOS descriptor failed," + "error=%s\n", + usbd_errstr(err)); + goto error; + } + err = uhub_ss_caps_get(bdesc, &dev_desc); + if (err) { + DPRINTFN(0, + "Getting USB SS Plus descriptor failed," + "error=%s\n", + usbd_errstr(err)); + free(bdesc, M_USBDEV); + goto error; + } + err = uhub_ss_caps_to_hub_sslink(dev_desc, &sc->sc_slinks); + if (err) { + DPRINTFN(0, "Failed to parse SS Link Descriptor\n"); + free(bdesc, M_USBDEV); + goto error; + } + free(bdesc, M_USBDEV); + /* + * fallthrough + */ case USB_SPEED_SUPER: if (udev->parent_hub != NULL) { err = usbd_req_set_hub_depth(udev, NULL, @@ -1473,6 +1650,8 @@ removable++; break; case USB_SPEED_SUPER: + case USB_SPEED_SUPER_PLUS: + case USB_SPEED_SUPER_PLUS_X2: if (!UHD_NOT_REMOV(&hubdesc30, portno)) removable++; break; diff --git a/sys/dev/usb/usb_hub_private.h b/sys/dev/usb/usb_hub_private.h --- a/sys/dev/usb/usb_hub_private.h +++ b/sys/dev/usb/usb_hub_private.h @@ -46,6 +46,7 @@ struct uhub_current_state { uint16_t port_change; uint16_t port_status; + uint16_t ext_speed; }; struct uhub_softc { @@ -65,6 +66,7 @@ #define UHUB_USB_PORT_ERRORS_MAX 4 uint8_t sc_flags; #define UHUB_FLAG_DID_EXPLORE 0x01 + struct usb_hub_ss_sublinks sc_slinks; }; struct hub_result { struct usb_device *udev; 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 @@ -315,3 +315,24 @@ } return (n); } + +struct usb_bos_cap_descriptor * +usbd_bos_foreach(struct usb_bos_descriptor *bos, + struct usb_bos_cap_descriptor *cap) +{ + /* + * No capabilility + */ + if (bos == NULL || (bos->bLength >= UGETW(bos->wTotalLength))) + return (NULL); + + if (cap == NULL) + return (struct usb_bos_cap_descriptor *)((uint8_t *)bos + + bos->bLength); + + if (UGETW(bos->wTotalLength) <= + (uint8_t *)cap - (uint8_t *)bos + cap->bLength) + return (NULL); + + return (struct usb_bos_cap_descriptor *)((uint8_t *)cap + cap->bLength); +} diff --git a/sys/dev/usb/usb_request.h b/sys/dev/usb/usb_request.h --- a/sys/dev/usb/usb_request.h +++ b/sys/dev/usb/usb_request.h @@ -54,16 +54,24 @@ struct usb_device_descriptor *d); usb_error_t usbd_req_get_device_status(struct usb_device *udev, struct mtx *mtx, struct usb_status *st); +usb_error_t usbd_req_get_device_ext_status(struct usb_device *udev, + struct mtx *mtx, struct usb_ext_status *st); usb_error_t usbd_req_get_hub_descriptor(struct usb_device *udev, struct mtx *mtx, struct usb_hub_descriptor *hd, uint8_t nports); usb_error_t usbd_req_get_ss_hub_descriptor(struct usb_device *udev, struct mtx *mtx, struct usb_hub_ss_descriptor *hd, uint8_t nports); +usb_error_t usbd_req_get_bos_descriptor(struct usb_device *udev, + struct mtx *mtx, struct usb_bos_descriptor *desc, int len); +usb_error_t usbd_req_get_bos_descriptor_full(struct usb_device *udev, + struct mtx *mtx, struct usb_bos_descriptor **pdesc, int *len); usb_error_t usbd_req_get_hub_status(struct usb_device *udev, struct mtx *mtx, struct usb_hub_status *st); usb_error_t usbd_req_get_port_status(struct usb_device *udev, struct mtx *mtx, struct usb_port_status *ps, uint8_t port); +usb_error_t usbd_req_get_ext_port_status(struct usb_device *udev, + struct mtx *mtx, struct usb_ext_status *ps, uint8_t port); usb_error_t usbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port); usb_error_t usbd_req_warm_reset_port(struct usb_device *udev, diff --git a/sys/dev/usb/usb_request.c b/sys/dev/usb/usb_request.c --- a/sys/dev/usb/usb_request.c +++ b/sys/dev/usb/usb_request.c @@ -1491,6 +1491,27 @@ return (usbd_do_request(udev, mtx, &req, st)); } +/*------------------------------------------------------------------------* + * usbd_req_get_device_status + * + * Returns: + * 0: Success + * Else: Failure + *------------------------------------------------------------------------*/ +usb_error_t +usbd_req_get_device_ext_status(struct usb_device *udev, struct mtx *mtx, + struct usb_ext_status *st) +{ + struct usb_device_request req; + + req.bmRequestType = UT_READ_DEVICE; + req.bRequest = UR_GET_STATUS; + USETW(req.wValue, 0); + USETW(req.wIndex, 0); + USETW(req.wLength, sizeof(*st)); + return (usbd_do_request(udev, mtx, &req, st)); +} + /*------------------------------------------------------------------------* * usbd_req_get_hub_descriptor * @@ -1535,6 +1556,67 @@ return (usbd_do_request(udev, mtx, &req, hd)); } +/*------------------------------------------------------------------------* + * usbd_req_get_ss_hub_descriptor + * + * Returns: + * 0: Success + * Else: Failure + *------------------------------------------------------------------------*/ +usb_error_t +usbd_req_get_bos_descriptor(struct usb_device *udev, struct mtx *mtx, + struct usb_bos_descriptor *bd, int len) +{ + struct usb_device_request req; + + req.bmRequestType = UT_READ_DEVICE; + req.bRequest = UR_GET_DESCRIPTOR; + USETW2(req.wValue, UDESC_BOS, 0); + USETW(req.wIndex, 0); + USETW(req.wLength, len); + + return (usbd_do_request_flags(udev, mtx, &req, bd, USB_SHORT_XFER_OK, + NULL, USB_DEFAULT_TIMEOUT)); +} + +/*------------------------------------------------------------------------* + * usbd_req_get_ss_hub_descriptor + * + * Returns: + * 0: Success + * Else: Failure + *------------------------------------------------------------------------*/ +usb_error_t +usbd_req_get_bos_descriptor_full(struct usb_device *udev, struct mtx *mtx, + struct usb_bos_descriptor **bdp, int *len) +{ + struct usb_bos_descriptor *bdesc; + uint32_t desc_len; + int err; + + *bdp = NULL; + *len = 0; + + bdesc = malloc(sizeof(struct usb_bos_descriptor), M_USBDEV, M_WAITOK); + err = usbd_req_get_bos_descriptor(udev, mtx, bdesc, sizeof(*bdesc)); + if (err) { + free(bdesc, M_USBDEV); + return (err); + } + desc_len = UGETW(bdesc->wTotalLength); + free(bdesc, M_USBDEV); + + bdesc = malloc(desc_len, M_USBDEV, M_WAITOK); + err = usbd_req_get_bos_descriptor(udev, mtx, bdesc, desc_len); + if (err) { + free(bdesc, M_USBDEV); + return (err); + } + *bdp = bdesc; + *len = desc_len; + return (0); +} + /*------------------------------------------------------------------------* * usbd_req_get_hub_status * @@ -1624,6 +1706,29 @@ return (usbd_do_request_flags(udev, mtx, &req, ps, 0, NULL, 1000)); } +/*------------------------------------------------------------------------* + * usbd_req_get_ext_port_status + * + * Returns: + * 0: Success + * Else: Failure + *------------------------------------------------------------------------*/ +usb_error_t +usbd_req_get_ext_port_status(struct usb_device *udev, struct mtx *mtx, + struct usb_ext_status *ps, uint8_t port) +{ + struct usb_device_request req; + + req.bmRequestType = UT_READ_CLASS_OTHER; + req.bRequest = UR_GET_STATUS; + USETW(req.wValue, 2); + req.wIndex[0] = port; + req.wIndex[1] = 0; + USETW(req.wLength, sizeof(*ps)); + + return (usbd_do_request_flags(udev, mtx, &req, ps, 0, NULL, 1000)); +} + /*------------------------------------------------------------------------* * usbd_req_clear_hub_feature * @@ -2103,7 +2208,7 @@ } #endif /* Try to warm reset first */ - if (parent_hub->speed == USB_SPEED_SUPER) + if (parent_hub->speed >= USB_SPEED_SUPER) usbd_req_warm_reset_port(parent_hub, mtx, udev->port_no); /* Try to reset the parent HUB port. */ 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 @@ -407,6 +407,8 @@ max_packet_size &= 0x7FF; break; case USB_SPEED_SUPER: + case USB_SPEED_SUPER_PLUS: + case USB_SPEED_SUPER_PLUS_X2: max_packet_count += (max_packet_size >> 11) & 3; if (ecomp != NULL) @@ -517,6 +519,8 @@ xfer->max_packet_size &= 0x7FF; break; case USB_SPEED_SUPER: + case USB_SPEED_SUPER_PLUS: + case USB_SPEED_SUPER_PLUS_X2: xfer->max_packet_count += (xfer->max_packet_size >> 11) & 3; if (ecomp != NULL) 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,8 @@ struct usb_endpoint_ss_comp_descriptor *usb_ed_comp_foreach( struct usb_config_descriptor *cd, struct usb_endpoint_ss_comp_descriptor *ped); +struct usb_bos_cap_descriptor *usbd_bos_foreach(struct usb_bos_descriptor *bos, + struct usb_bos_cap_descriptor *cap); 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/usr.sbin/usbconfig/dump.c b/usr.sbin/usbconfig/dump.c --- a/usr.sbin/usbconfig/dump.c +++ b/usr.sbin/usbconfig/dump.c @@ -101,6 +101,7 @@ case LIBUSB20_SPEED_SUPER: return ("SUPER (5.0Gbps)"); case LIBUSB20_SPEED_SUPER_PLUS: + case LIBUSB20_SPEED_SUPER_PLUS_X2: return ("SUPER+(10-20Gbps)"); default: break; diff --git a/usr.sbin/usbdump/usbdump.c b/usr.sbin/usbdump/usbdump.c --- a/usr.sbin/usbdump/usbdump.c +++ b/usr.sbin/usbdump/usbdump.c @@ -162,6 +162,7 @@ [USB_SPEED_LOW] = "LOW", [USB_SPEED_VARIABLE] = "VARI", [USB_SPEED_SUPER] = "SUPER", + [USB_SPEED_SUPER_PLUS] = "SUPER PLUS", }; static STAILQ_HEAD(,usb_filt) usb_filt_head =