# --- T2-COPYRIGHT-NOTE-BEGIN --- # T2 SDE: package/*/libusb/hotfix-sspeedx2.patch # Copyright (C) 2024 The T2 SDE Project # # This Copyright note is generated by scripts/Create-CopyPatch, # more information can be found in the files COPYING and README. # # This patch file is dual-licensed. It is available under the license the # patched project is licensed under, as long as it is an OpenSource license # as defined at http://www.opensource.org/ (e.g. BSD, X11) or under the terms # of the GNU General Public License version 2 as used by the T2 SDE. # --- T2-COPYRIGHT-NOTE-END --- From f00f06e9ebfcb5673c636e75d1f3d06375eccf03 Mon Sep 17 00:00:00 2001 From: Fabien Sanglard Date: Sat, 6 Jan 2024 00:45:37 -0800 Subject: [PATCH] Add support for SuperSpeed+ Capability Descriptors See specs in USB 3.1 specs in section: 9.6.2.5 SuperSpeedPlus USB Device Capability Closes #1428 Fixes #1429 --- examples/xusb.c | 30 ++++++++++++ libusb/descriptor.c | 90 ++++++++++++++++++++++++++++++++++- libusb/libusb-1.0.def | 4 ++ libusb/libusb.h | 106 +++++++++++++++++++++++++++++++++++++++++- libusb/version_nano.h | 2 +- 5 files changed, 229 insertions(+), 3 deletions(-) diff --git a/libusb/descriptor.c b/libusb/descriptor.c index 84055fe38..b72f558c9 100644 --- a/libusb/descriptor.c +++ b/libusb/descriptor.c @@ -59,9 +59,14 @@ static void parse_descriptor(const void *source, const char *descriptor, void *d sp += 2; dp += 2; break; - case 'd': /* 32-bit word, convert from little endian to CPU */ + case 'd': /* 32-bit word, convert from little endian to CPU (4-byte align dst before write). */ dp += 4 - ((uintptr_t)dp & 3); /* Align to 32-bit word boundary */ + *((uint32_t *)dp) = READ_LE32(sp); + sp += 4; + dp += 4; + break; + case 'i': /* 32-bit word, convert from little endian to CPU (no dst alignment before write) */ *((uint32_t *)dp) = READ_LE32(sp); sp += 4; dp += 4; @@ -1001,6 +1006,89 @@ int API_EXPORTED libusb_get_ss_usb_device_capability_descriptor( return LIBUSB_SUCCESS; } +// We use this private struct ony to parse a superspeed+ device capability +// descriptor according to section 9.6.2.5 of the USB 3.1 specification. +// We don't expose it. +struct internal_ssplus_capability_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t bReserved; + uint32_t bmAttributes; + uint16_t wFunctionalitySupport; + uint16_t wReserved; +}; + +int API_EXPORTED libusb_get_ssplus_usb_device_capability_descriptor( + libusb_context *ctx, + struct libusb_bos_dev_capability_descriptor *dev_cap, + struct libusb_ssplus_usb_device_capability_descriptor **ssplus_usb_device_cap) +{ + struct libusb_ssplus_usb_device_capability_descriptor *_ssplus_cap; + + // Use a private struct to re-use our descriptor parsing system. + struct internal_ssplus_capability_descriptor parsedDescriptor; + + // Some size/type checks to make sure everything is in order + if (dev_cap->bDevCapabilityType != LIBUSB_BT_SUPERSPEED_PLUS_CAPABILITY) { + usbi_err(ctx, "unexpected bDevCapabilityType 0x%x (expected 0x%x)", + dev_cap->bDevCapabilityType, + LIBUSB_BT_SUPERSPEED_PLUS_CAPABILITY); + return LIBUSB_ERROR_INVALID_PARAM; + } else if (dev_cap->bLength < LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE) { + usbi_err(ctx, "short dev-cap descriptor read %u/%d", + dev_cap->bLength, LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE); + return LIBUSB_ERROR_IO; + } + + // We can only parse the non-variable size part of the SuperSpeedPlus descriptor. The attributes + // have to be read "manually". + parse_descriptor(dev_cap, "bbbbiww", &parsedDescriptor); + + uint8_t numSublikSpeedAttributes = (parsedDescriptor.bmAttributes & 0xF) + 1; + _ssplus_cap = malloc(sizeof(struct libusb_ssplus_usb_device_capability_descriptor) + numSublikSpeedAttributes * sizeof(struct libusb_ssplus_sublink_attribute)); + if (!_ssplus_cap) + return LIBUSB_ERROR_NO_MEM; + + // Parse bmAttributes + _ssplus_cap->numSublinkSpeedAttributes = numSublikSpeedAttributes; + _ssplus_cap->numSublinkSpeedIDs = ((parsedDescriptor.bmAttributes & 0xF0) >> 4) + 1; + + // Parse wFunctionalitySupport + _ssplus_cap->ssid = parsedDescriptor.wFunctionalitySupport & 0xF; + _ssplus_cap->minRxLaneCount = (parsedDescriptor.wFunctionalitySupport & 0x0F00) >> 8; + _ssplus_cap->minTxLaneCount = (parsedDescriptor.wFunctionalitySupport & 0xF000) >> 12; + + // Check that we have enough to read all the sublink attributes + if (dev_cap->bLength < LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE + _ssplus_cap->numSublinkSpeedAttributes * sizeof(uint32_t)) { + usbi_err(ctx, "short ssplus capability descriptor, unable to read sublinks: Not enough data"); + return LIBUSB_ERROR_IO; + } + + // Read the attributes + uint8_t* base = ((uint8_t*)dev_cap) + LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE; + for(uint8_t i = 0 ; i < _ssplus_cap->numSublinkSpeedAttributes ; i++) { + uint32_t attr = READ_LE32(base + i * sizeof(uint32_t)); + _ssplus_cap->sublinkSpeedAttributes[i].ssid = attr & 0x0f; + _ssplus_cap->sublinkSpeedAttributes[i].mantisa = attr >> 16; + _ssplus_cap->sublinkSpeedAttributes[i].exponent = (attr >> 4) & 0x3 ; + _ssplus_cap->sublinkSpeedAttributes[i].type = attr & 0x40 ? LIBUSB_SSPLUS_ATTR_TYPE_ASYM : LIBUSB_SSPLUS_ATTR_TYPE_SYM; + _ssplus_cap->sublinkSpeedAttributes[i].direction = attr & 0x80 ? LIBUSB_SSPLUS_ATTR_DIR_TX : LIBUSB_SSPLUS_ATTR_DIR_RX; + _ssplus_cap->sublinkSpeedAttributes[i].protocol = attr & 0x4000 ? LIBUSB_SSPLUS_ATTR_PROT_SSPLUS: LIBUSB_SSPLUS_ATTR_PROT_SS; + } + + *ssplus_usb_device_cap = _ssplus_cap; + return LIBUSB_SUCCESS; +} + +void API_EXPORTED libusb_free_ssplus_usb_device_capability_descriptor( + struct libusb_ssplus_usb_device_capability_descriptor *ssplus_usb_device_cap) +{ + free(ssplus_usb_device_cap); +} + + + /** \ingroup libusb_desc * Free a SuperSpeed USB Device Capability descriptor obtained from * libusb_get_ss_usb_device_capability_descriptor(). diff --git a/libusb/libusb-1.0.def b/libusb/libusb-1.0.def index 6d7caa7f7..921f3dd91 100644 --- a/libusb/libusb-1.0.def +++ b/libusb/libusb-1.0.def @@ -50,6 +50,8 @@ EXPORTS libusb_free_ss_endpoint_companion_descriptor@4 = libusb_free_ss_endpoint_companion_descriptor libusb_free_ss_usb_device_capability_descriptor libusb_free_ss_usb_device_capability_descriptor@4 = libusb_free_ss_usb_device_capability_descriptor + libusb_free_ssplus_usb_device_capability_descriptor + libusb_free_ssplus_usb_device_capability_descriptor@4 = libusb_free_ssplus_usb_device_capability_descriptor libusb_free_streams libusb_free_streams@12 = libusb_free_streams libusb_free_transfer @@ -108,6 +110,8 @@ EXPORTS libusb_get_ss_endpoint_companion_descriptor@12 = libusb_get_ss_endpoint_companion_descriptor libusb_get_ss_usb_device_capability_descriptor libusb_get_ss_usb_device_capability_descriptor@12 = libusb_get_ss_usb_device_capability_descriptor + libusb_get_ssplus_usb_device_capability_descriptor + libusb_get_ssplus_usb_device_capability_descriptor@12 = libusb_get_ssplus_usb_device_capability_descriptor libusb_get_string_descriptor_ascii libusb_get_string_descriptor_ascii@16 = libusb_get_string_descriptor_ascii libusb_get_usb_2_0_extension_descriptor diff --git a/libusb/libusb.h b/libusb/libusb.h index f4e9203c6..32dd65f1d 100644 --- a/libusb/libusb.h +++ b/libusb/libusb.h @@ -339,6 +339,7 @@ enum libusb_descriptor_type { /* BOS descriptor sizes */ #define LIBUSB_BT_USB_2_0_EXTENSION_SIZE 7 #define LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE 10 +#define LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE 12 #define LIBUSB_BT_CONTAINER_ID_SIZE 20 #define LIBUSB_BT_PLATFORM_DESCRIPTOR_MIN_SIZE 20 @@ -562,7 +563,10 @@ enum libusb_bos_type { LIBUSB_BT_CONTAINER_ID = 0x04, /** Platform descriptor */ - LIBUSB_BT_PLATFORM_DESCRIPTOR = 0x05 + LIBUSB_BT_PLATFORM_DESCRIPTOR = 0x05, + + /* SuperSpeed+ device capability */ + LIBUSB_BT_SUPERSPEED_PLUS_CAPABILITY = 0x0A, }; /** \ingroup libusb_desc @@ -980,6 +984,100 @@ struct libusb_ss_usb_device_capability_descriptor { uint16_t bU2DevExitLat; }; +/** \ingroup libusb_desc + * enum used in \ref libusb_ssplus_sublink_attribute + */ +enum libusb_superspeedplus_sublink_attribute_sublink_type { + LIBUSB_SSPLUS_ATTR_TYPE_SYM = 0, + LIBUSB_SSPLUS_ATTR_TYPE_ASYM = 1, +}; + +/** \ingroup libusb_desc + * enum used in \ref libusb_ssplus_sublink_attribute + */ +enum libusb_superspeedplus_sublink_attribute_sublink_direction { + LIBUSB_SSPLUS_ATTR_DIR_RX = 0, + LIBUSB_SSPLUS_ATTR_DIR_TX = 1, +}; + +/** \ingroup libusb_desc + * enum used in \ref libusb_ssplus_sublink_attribute + * Bit = Bits per second + * Kb = Kbps + * Mb = Mbps + * Gb = Gbps + */ +enum libusb_superspeedplus_sublink_attribute_exponent { + LIBUSB_SSPLUS_ATTR_EXP_BPS = 0, + LIBUSB_SSPLUS_ATTR_EXP_KBS = 1, + LIBUSB_SSPLUS_ATTR_EXP_MBS = 2, + LIBUSB_SSPLUS_ATTR_EXP_GBS = 3, +}; + +/** \ingroup libusb_desc + * enum used in \ref libusb_ssplus_sublink_attribute + */ +enum libusb_superspeedplus_sublink_attribute_link_protocol { + LIBUSB_SSPLUS_ATTR_PROT_SS = 0, + LIBUSB_SSPLUS_ATTR_PROT_SSPLUS = 1, +}; + +/** \ingroup libusb_desc + * Expose \ref libusb_ssplus_usb_device_capability_descriptor.sublinkSpeedAttributes + */ +struct libusb_ssplus_sublink_attribute { + /** Sublink Speed Attribute ID (SSID). + This field is an ID that uniquely identifies the speed of this sublink */ + uint8_t ssid; + + /** This field defines the + base 10 exponent times 3, that shall be applied to the + mantissa. */ + enum libusb_superspeedplus_sublink_attribute_exponent exponent; + + /** This field identifies whether the + Sublink Speed Attribute defines a symmetric or + asymmetric bit rate.*/ + enum libusb_superspeedplus_sublink_attribute_sublink_type type; + + /** This field indicates if this + Sublink Speed Attribute defines the receive or + transmit bit rate. */ + enum libusb_superspeedplus_sublink_attribute_sublink_direction direction; + + /** This field identifies the protocol + supported by the link. */ + enum libusb_superspeedplus_sublink_attribute_link_protocol protocol; + + /** This field defines the mantissa that shall be applied to the exponent when + calculating the maximum bit rate. */ + uint16_t mantisa; +}; + +/** \ingroup libusb_desc + * A structure representing the SuperSpeedPlus descriptor + * This descriptor is documented in section 9.6.2.5 of the USB 3.1 specification. + */ +struct libusb_ssplus_usb_device_capability_descriptor { + /** Sublink Speed Attribute Count */ + uint8_t numSublinkSpeedAttributes; + + /** Sublink Speed ID Count */ + uint8_t numSublinkSpeedIDs; + + /** Unique ID to indicates the minimum lane speed */ + uint8_t ssid; + + /** This field indicates the minimum receive lane count.*/ + uint8_t minRxLaneCount; + + /** This field indicates the minimum transmit lane count*/ + uint8_t minTxLaneCount; + + /** num attrtibutes= \ref libusb_ssplus_usb_device_capability_descriptor.numSublinkSpeedAttributes= */ + struct libusb_ssplus_sublink_attribute sublinkSpeedAttributes[]; +}; + /** \ingroup libusb_desc * A structure representing the Container ID descriptor. * This descriptor is documented in section 9.6.2.3 of the USB 3.0 specification. @@ -1625,6 +1723,12 @@ int LIBUSB_CALL libusb_get_ss_usb_device_capability_descriptor( struct libusb_ss_usb_device_capability_descriptor **ss_usb_device_cap); void LIBUSB_CALL libusb_free_ss_usb_device_capability_descriptor( struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_cap); +int LIBUSB_CALL libusb_get_ssplus_usb_device_capability_descriptor( + libusb_context *ctx, + struct libusb_bos_dev_capability_descriptor *dev_cap, + struct libusb_ssplus_usb_device_capability_descriptor **ssplus_usb_device_cap); +void LIBUSB_CALL libusb_free_ssplus_usb_device_capability_descriptor( + struct libusb_ssplus_usb_device_capability_descriptor *ssplus_usb_device_cap); int LIBUSB_CALL libusb_get_container_id_descriptor(libusb_context *ctx, struct libusb_bos_dev_capability_descriptor *dev_cap, struct libusb_container_id_descriptor **container_id); From 5b17c383f8dd27e6938ffcc125c2a839db72c1ff Mon Sep 17 00:00:00 2001 From: Harry Mallon Date: Wed, 27 Mar 2024 16:52:18 +0000 Subject: [PATCH] Add API support for LIBUSB_SPEED_SUPER_PLUS_X2 20Gbps USB 3.2 gen 2x2 Implement detection on darwin and linux_usbfs, and report it in xusb. Closes #1477 --- android/examples/unrooted_android.c | 1 + examples/testlibusb.c | 1 + examples/xusb.c | 12 +++++++++--- libusb/libusb.h | 5 ++++- libusb/os/darwin_usb.c | 3 +++ libusb/os/linux_usbfs.c | 1 + libusb/version_nano.h | 2 +- 7 files changed, 20 insertions(+), 5 deletions(-) diff --git a/libusb/libusb.h b/libusb/libusb.h index 32dd65f1d..2353f4c72 100644 --- a/libusb/libusb.h +++ b/libusb/libusb.h @@ -1265,7 +1265,10 @@ enum libusb_speed { LIBUSB_SPEED_SUPER = 4, /** The device is operating at super speed plus (10000MBit/s). */ - LIBUSB_SPEED_SUPER_PLUS = 5 + LIBUSB_SPEED_SUPER_PLUS = 5, + + /** The device is operating at super speed plus x2 (20000MBit/s). */ + LIBUSB_SPEED_SUPER_PLUS_X2 = 6, }; /** \ingroup libusb_misc diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c index 238fbb184..ae09db7b2 100644 --- a/libusb/os/darwin_usb.c +++ b/libusb/os/darwin_usb.c @@ -1437,6 +1437,9 @@ static enum libusb_error process_new_device (struct libusb_context *ctx, struct #endif #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 case kUSBDeviceSpeedSuperPlus: dev->speed = LIBUSB_SPEED_SUPER_PLUS; break; +#endif +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101500 + case kUSBDeviceSpeedSuperPlusBy2: dev->speed = LIBUSB_SPEED_SUPER_PLUS_X2; break; #endif default: usbi_warn (ctx, "Got unknown device speed %d", devSpeed); diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c index ed8597ba9..25ee02ea0 100644 --- a/libusb/os/linux_usbfs.c +++ b/libusb/os/linux_usbfs.c @@ -933,6 +933,7 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, case 480: dev->speed = LIBUSB_SPEED_HIGH; break; case 5000: dev->speed = LIBUSB_SPEED_SUPER; break; case 10000: dev->speed = LIBUSB_SPEED_SUPER_PLUS; break; + case 20000: dev->speed = LIBUSB_SPEED_SUPER_PLUS_X2; break; default: usbi_warn(ctx, "unknown device speed: %d Mbps", speed); } From b00332d34eaf54a9a77ec309e5d1782c10e34038 Mon Sep 17 00:00:00 2001 From: Fabien Sanglard Date: Tue, 21 May 2024 17:04:26 -0700 Subject: [PATCH] SuperSpeedPlus: Fix typo mantisa -> mantissa in struct field Fixup of commit f00f06e9 Closes #1499 --- examples/xusb.c | 2 +- libusb/descriptor.c | 2 +- libusb/libusb.h | 2 +- libusb/version_nano.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libusb/descriptor.c b/libusb/descriptor.c index b72f558c9..3814682f8 100644 --- a/libusb/descriptor.c +++ b/libusb/descriptor.c @@ -1070,7 +1070,7 @@ int API_EXPORTED libusb_get_ssplus_usb_device_capability_descriptor( for(uint8_t i = 0 ; i < _ssplus_cap->numSublinkSpeedAttributes ; i++) { uint32_t attr = READ_LE32(base + i * sizeof(uint32_t)); _ssplus_cap->sublinkSpeedAttributes[i].ssid = attr & 0x0f; - _ssplus_cap->sublinkSpeedAttributes[i].mantisa = attr >> 16; + _ssplus_cap->sublinkSpeedAttributes[i].mantissa = attr >> 16; _ssplus_cap->sublinkSpeedAttributes[i].exponent = (attr >> 4) & 0x3 ; _ssplus_cap->sublinkSpeedAttributes[i].type = attr & 0x40 ? LIBUSB_SSPLUS_ATTR_TYPE_ASYM : LIBUSB_SSPLUS_ATTR_TYPE_SYM; _ssplus_cap->sublinkSpeedAttributes[i].direction = attr & 0x80 ? LIBUSB_SSPLUS_ATTR_DIR_TX : LIBUSB_SSPLUS_ATTR_DIR_RX; diff --git a/libusb/libusb.h b/libusb/libusb.h index 2353f4c72..a3be4cc01 100644 --- a/libusb/libusb.h +++ b/libusb/libusb.h @@ -1051,7 +1051,7 @@ struct libusb_ssplus_sublink_attribute { /** This field defines the mantissa that shall be applied to the exponent when calculating the maximum bit rate. */ - uint16_t mantisa; + uint16_t mantissa; }; /** \ingroup libusb_desc