mirror of
https://github.com/shadps4-emu/ext-libusb.git
synced 2026-01-31 00:55:21 +01:00
Add superspeed endpoint companion descriptor support
Based on earlier work done on this by Maya Erez <merez@codeaurora.org>, Nathan Hjelm <hjelmn@me.com> and Pete Batard <pete@akeo.ie>. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
@@ -808,6 +808,7 @@ static int test_device(uint16_t vid, uint16_t pid)
|
||||
test_mode = USE_SCSI;
|
||||
}
|
||||
for (k=0; k<conf_desc->usb_interface[i].altsetting[j].bNumEndpoints; k++) {
|
||||
struct libusb_ss_endpoint_companion_descriptor *ep_comp = NULL;
|
||||
endpoint = &conf_desc->usb_interface[i].altsetting[j].endpoint[k];
|
||||
printf(" endpoint[%d].address: %02X\n", k, endpoint->bEndpointAddress);
|
||||
// Use the first interrupt or bulk IN/OUT endpoints as default for testing
|
||||
@@ -822,6 +823,12 @@ static int test_device(uint16_t vid, uint16_t pid)
|
||||
}
|
||||
printf(" max packet size: %04X\n", endpoint->wMaxPacketSize);
|
||||
printf(" polling interval: %02X\n", endpoint->bInterval);
|
||||
libusb_get_ss_endpoint_companion_descriptor(NULL, endpoint, &ep_comp);
|
||||
if (ep_comp) {
|
||||
printf(" max burst: %02X (USB 3.0)\n", ep_comp->bMaxBurst);
|
||||
printf(" bytes per interval: %04X (USB 3.0)\n", ep_comp->wBytesPerInterval);
|
||||
libusb_free_ss_endpoint_companion_descriptor(ep_comp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +40,14 @@
|
||||
|
||||
/* set host_endian if the w values are already in host endian format,
|
||||
* as opposed to bus endian. */
|
||||
int usbi_parse_descriptor(unsigned char *source, const char *descriptor,
|
||||
int usbi_parse_descriptor(const unsigned char *source, const char *descriptor,
|
||||
void *dest, int host_endian)
|
||||
{
|
||||
unsigned char *sp = source, *dp = dest;
|
||||
const unsigned char *sp = source;
|
||||
unsigned char *dp = dest;
|
||||
uint16_t w;
|
||||
const char *cp;
|
||||
uint32_t d;
|
||||
|
||||
for (cp = descriptor; *cp; cp++) {
|
||||
switch (*cp) {
|
||||
@@ -64,6 +66,24 @@ int usbi_parse_descriptor(unsigned char *source, const char *descriptor,
|
||||
sp += 2;
|
||||
dp += 2;
|
||||
break;
|
||||
case 'd': /* 32-bit word, convert from little endian to CPU */
|
||||
dp += ((uintptr_t)dp & 1); /* Align to word boundary */
|
||||
|
||||
if (host_endian) {
|
||||
memcpy(dp, sp, 4);
|
||||
} else {
|
||||
d = (sp[3] << 24) | (sp[2] << 16) |
|
||||
(sp[1] << 8) | sp[0];
|
||||
*((uint32_t *)dp) = d;
|
||||
}
|
||||
sp += 4;
|
||||
dp += 4;
|
||||
break;
|
||||
case 'u': /* 16 byte UUID */
|
||||
memcpy(dp, sp, 16);
|
||||
sp += 16;
|
||||
dp += 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -720,6 +740,70 @@ void API_EXPORTED libusb_free_config_descriptor(
|
||||
free(config);
|
||||
}
|
||||
|
||||
/** \ingroup desc
|
||||
* Get an endpoints superspeed endpoint companion descriptor (if any)
|
||||
*
|
||||
* \param ctx the context to operate on, or NULL for the default context
|
||||
* \param endpoint endpoint descriptor from which to get the superspeed
|
||||
* endpoint companion descriptor
|
||||
* \param ep_comp output location for the superspeed endpoint companion
|
||||
* descriptor. Only valid if 0 was returned. Must be freed with
|
||||
* libusb_free_ss_endpoint_companion_descriptor() after use.
|
||||
* \returns 0 on success
|
||||
* \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist
|
||||
* \returns another LIBUSB_ERROR code on error
|
||||
*/
|
||||
int API_EXPORTED libusb_get_ss_endpoint_companion_descriptor(
|
||||
struct libusb_context *ctx,
|
||||
const struct libusb_endpoint_descriptor *endpoint,
|
||||
struct libusb_ss_endpoint_companion_descriptor **ep_comp)
|
||||
{
|
||||
struct usb_descriptor_header header;
|
||||
int size = endpoint->extra_length;
|
||||
const unsigned char *buffer = endpoint->extra;
|
||||
|
||||
*ep_comp = NULL;
|
||||
|
||||
while (size >= DESC_HEADER_LENGTH) {
|
||||
usbi_parse_descriptor(buffer, "bb", &header, 0);
|
||||
if (header.bLength < 2 || header.bLength > size) {
|
||||
usbi_err(ctx, "invalid descriptor length %d",
|
||||
header.bLength);
|
||||
return LIBUSB_ERROR_IO;
|
||||
}
|
||||
if (header.bDescriptorType != LIBUSB_DT_SS_ENDPOINT_COMPANION) {
|
||||
buffer += header.bLength;
|
||||
size -= header.bLength;
|
||||
continue;
|
||||
}
|
||||
if (header.bLength < LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE) {
|
||||
usbi_err(ctx, "invalid ss-ep-comp-desc length %d",
|
||||
header.bLength);
|
||||
return LIBUSB_ERROR_IO;
|
||||
}
|
||||
*ep_comp = malloc(sizeof(**ep_comp));
|
||||
if (*ep_comp == NULL)
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
usbi_parse_descriptor(buffer, "bbbbw", *ep_comp, 0);
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
return LIBUSB_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
/** \ingroup desc
|
||||
* Free a superspeed endpoint companion descriptor obtained from
|
||||
* libusb_get_ss_endpoint_companion_descriptor().
|
||||
* It is safe to call this function with a NULL ep_comp parameter, in which
|
||||
* case the function simply returns.
|
||||
*
|
||||
* \param ep_comp the superspeed endpoint companion descriptor to free
|
||||
*/
|
||||
void API_EXPORTED libusb_free_ss_endpoint_companion_descriptor(
|
||||
struct libusb_ss_endpoint_companion_descriptor *ep_comp)
|
||||
{
|
||||
free(ep_comp);
|
||||
}
|
||||
|
||||
/** \ingroup desc
|
||||
* Retrieve a string descriptor in C style ASCII.
|
||||
*
|
||||
|
||||
@@ -30,6 +30,8 @@ EXPORTS
|
||||
libusb_free_config_descriptor@4 = libusb_free_config_descriptor
|
||||
libusb_free_device_list
|
||||
libusb_free_device_list@8 = libusb_free_device_list
|
||||
libusb_free_ss_endpoint_companion_descriptor
|
||||
libusb_free_ss_endpoint_companion_descriptor@4 = libusb_free_ss_endpoint_companion_descriptor
|
||||
libusb_free_transfer
|
||||
libusb_free_transfer@4 = libusb_free_transfer
|
||||
libusb_get_active_config_descriptor
|
||||
@@ -66,6 +68,8 @@ EXPORTS
|
||||
libusb_get_port_number@4 = libusb_get_port_number
|
||||
libusb_get_port_path
|
||||
libusb_get_port_path@16 = libusb_get_port_path
|
||||
libusb_get_ss_endpoint_companion_descriptor
|
||||
libusb_get_ss_endpoint_companion_descriptor@12 = libusb_get_ss_endpoint_companion_descriptor
|
||||
libusb_get_string_descriptor_ascii
|
||||
libusb_get_string_descriptor_ascii@16 = libusb_get_string_descriptor_ascii
|
||||
libusb_get_version
|
||||
|
||||
@@ -274,16 +274,33 @@ enum libusb_descriptor_type {
|
||||
LIBUSB_DT_HUB = 0x29,
|
||||
|
||||
/** SuperSpeed Hub descriptor */
|
||||
LIBUSB_DT_SUPERSPEED_HUB = 0x2A,
|
||||
LIBUSB_DT_SUPERSPEED_HUB = 0x2a,
|
||||
|
||||
/** SuperSpeed Endpoint Companion descriptor */
|
||||
LIBUSB_DT_SS_ENDPOINT_COMPANION = 0x30
|
||||
};
|
||||
|
||||
/* Descriptor sizes per descriptor type */
|
||||
#define LIBUSB_DT_DEVICE_SIZE 18
|
||||
#define LIBUSB_DT_CONFIG_SIZE 9
|
||||
#define LIBUSB_DT_INTERFACE_SIZE 9
|
||||
#define LIBUSB_DT_ENDPOINT_SIZE 7
|
||||
#define LIBUSB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
|
||||
#define LIBUSB_DT_ENDPOINT_SIZE 7
|
||||
#define LIBUSB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
|
||||
#define LIBUSB_DT_HUB_NONVAR_SIZE 7
|
||||
#define LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE 6
|
||||
#define LIBUSB_DT_BOS_SIZE 5
|
||||
#define LIBUSB_DT_DEVICE_CAPABILITY_SIZE 3
|
||||
|
||||
/* BOS descriptor sizes */
|
||||
#define LIBUSB_BT_USB_2_0_EXTENSION_SIZE 7
|
||||
#define LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE 10
|
||||
#define LIBUSB_BT_CONTAINER_ID_SIZE 20
|
||||
|
||||
/* We unwrap the BOS => define its max size */
|
||||
#define LIBUSB_DT_BOS_MAX_SIZE ((LIBUSB_DT_BOS_SIZE) +\
|
||||
(LIBUSB_BT_USB_2_0_EXTENSION_SIZE) +\
|
||||
(LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE) +\
|
||||
(LIBUSB_BT_CONTAINER_ID_SIZE))
|
||||
|
||||
#define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */
|
||||
#define LIBUSB_ENDPOINT_DIR_MASK 0x80
|
||||
@@ -655,6 +672,38 @@ struct libusb_config_descriptor {
|
||||
int extra_length;
|
||||
};
|
||||
|
||||
/** \ingroup desc
|
||||
* A structure representing the superspeed endpoint companion
|
||||
* descriptor. This descriptor is documented in section 9.6.7 of
|
||||
* the USB 3.0 specification. All multiple-byte fields are represented in
|
||||
* host-endian format.
|
||||
*/
|
||||
struct libusb_ss_endpoint_companion_descriptor {
|
||||
|
||||
/** Size of this descriptor (in bytes) */
|
||||
uint8_t bLength;
|
||||
|
||||
/** Descriptor type. Will have value
|
||||
* \ref libusb_descriptor_type::LIBUSB_DT_SS_ENDPOINT_COMPANION in
|
||||
* this context. */
|
||||
uint8_t bDescriptorType;
|
||||
|
||||
|
||||
/** The maximum number of packets the endpoint can send or
|
||||
* recieve as part of a burst. */
|
||||
uint8_t bMaxBurst;
|
||||
|
||||
/** In bulk EP: bits 4:0 represents the maximum number of
|
||||
* streams the EP supports. In isochronous EP: bits 1:0
|
||||
* represents the Mult - a zero based value that determines
|
||||
* the maximum number of packets within a service interval */
|
||||
uint8_t bmAttributes;
|
||||
|
||||
/** The total number of bytes this EP will transfer every
|
||||
* service interval. valid only for periodic EPs. */
|
||||
uint16_t wBytesPerInterval;
|
||||
};
|
||||
|
||||
/** \ingroup asyncio
|
||||
* Setup packet for control transfers. */
|
||||
struct libusb_control_setup {
|
||||
@@ -1060,6 +1109,12 @@ int LIBUSB_CALL libusb_get_config_descriptor_by_value(libusb_device *dev,
|
||||
uint8_t bConfigurationValue, struct libusb_config_descriptor **config);
|
||||
void LIBUSB_CALL libusb_free_config_descriptor(
|
||||
struct libusb_config_descriptor *config);
|
||||
int LIBUSB_CALL libusb_get_ss_endpoint_companion_descriptor(
|
||||
struct libusb_context *ctx,
|
||||
const struct libusb_endpoint_descriptor *endpoint,
|
||||
struct libusb_ss_endpoint_companion_descriptor **ep_comp);
|
||||
void LIBUSB_CALL libusb_free_ss_endpoint_companion_descriptor(
|
||||
struct libusb_ss_endpoint_companion_descriptor *ep_comp);
|
||||
uint8_t LIBUSB_CALL libusb_get_bus_number(libusb_device *dev);
|
||||
uint8_t LIBUSB_CALL libusb_get_port_number(libusb_device *dev);
|
||||
int LIBUSB_CALL libusb_get_port_numbers(libusb_device *dev, uint8_t* port_numbers, int port_numbers_len);
|
||||
|
||||
@@ -413,7 +413,7 @@ int usbi_handle_transfer_completion(struct usbi_transfer *itransfer,
|
||||
enum libusb_transfer_status status);
|
||||
int usbi_handle_transfer_cancellation(struct usbi_transfer *transfer);
|
||||
|
||||
int usbi_parse_descriptor(unsigned char *source, const char *descriptor,
|
||||
int usbi_parse_descriptor(const unsigned char *source, const char *descriptor,
|
||||
void *dest, int host_endian);
|
||||
int usbi_device_cache_descriptor(libusb_device *dev);
|
||||
int usbi_get_config_index_by_value(struct libusb_device *dev,
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define LIBUSB_NANO 10724
|
||||
#define LIBUSB_NANO 10725
|
||||
|
||||
Reference in New Issue
Block a user