mirror of
https://github.com/shadps4-emu/ext-libusb.git
synced 2026-01-31 00:55:21 +01:00
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
This commit is contained in:
committed by
Tormod Volden
parent
f8a6c412f5
commit
f00f06e9eb
@@ -762,6 +762,17 @@ static void read_ms_winsub_feature_descriptors(libusb_device_handle *handle, uin
|
||||
}
|
||||
}
|
||||
|
||||
static void print_sublink_speed_attribute(struct libusb_ssplus_sublink_attribute* ss_attr) {
|
||||
static const char exponent[] = " KMG";
|
||||
printf(" id=%u speed=%u%cbs %s %s SuperSpeed%s",
|
||||
ss_attr->ssid,
|
||||
ss_attr->mantisa,
|
||||
(exponent[ss_attr->exponent]),
|
||||
(ss_attr->type == LIBUSB_SSPLUS_ATTR_TYPE_ASYM)? "Asym" : "Sym",
|
||||
(ss_attr->direction == LIBUSB_SSPLUS_ATTR_DIR_TX)? "TX" : "RX",
|
||||
(ss_attr->protocol == LIBUSB_SSPLUS_ATTR_PROT_SSPLUS)? "+": "" );
|
||||
}
|
||||
|
||||
static void print_device_cap(struct libusb_bos_dev_capability_descriptor *dev_cap)
|
||||
{
|
||||
switch(dev_cap->bDevCapabilityType) {
|
||||
@@ -810,6 +821,25 @@ static void print_device_cap(struct libusb_bos_dev_capability_descriptor *dev_ca
|
||||
break;
|
||||
|
||||
}
|
||||
case LIBUSB_BT_SUPERSPEED_PLUS_CAPABILITY: {
|
||||
struct libusb_ssplus_usb_device_capability_descriptor *ssplus_usb_device_cap = NULL;
|
||||
libusb_get_ssplus_usb_device_capability_descriptor(NULL, dev_cap, &ssplus_usb_device_cap);
|
||||
if (ssplus_usb_device_cap) {
|
||||
printf(" USB 3.1 capabilities:\n");
|
||||
printf(" num speed IDs: %d\n", ssplus_usb_device_cap->numSublinkSpeedIDs);
|
||||
printf(" minLaneSpeed: %d\n", ssplus_usb_device_cap->ssid);
|
||||
printf(" minRXLanes: %d\n", ssplus_usb_device_cap->minRxLaneCount);
|
||||
printf(" minTXLanes: %d\n", ssplus_usb_device_cap->minTxLaneCount);
|
||||
|
||||
printf(" num speed attribute IDs: %d\n", ssplus_usb_device_cap->numSublinkSpeedAttributes);
|
||||
for(uint8_t i=0 ; i < ssplus_usb_device_cap->numSublinkSpeedAttributes ; i++) {
|
||||
print_sublink_speed_attribute(&ssplus_usb_device_cap->sublinkSpeedAttributes[i]);
|
||||
printf("\n");
|
||||
}
|
||||
libusb_free_ssplus_usb_device_capability_descriptor(ssplus_usb_device_cap);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf(" Unknown BOS device capability %02x:\n", dev_cap->bDevCapabilityType);
|
||||
}
|
||||
|
||||
@@ -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().
|
||||
|
||||
@@ -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
|
||||
|
||||
106
libusb/libusb.h
106
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);
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define LIBUSB_NANO 11896
|
||||
#define LIBUSB_NANO 11897
|
||||
|
||||
Reference in New Issue
Block a user