diff options
author | Hans de Goede <hdegoede@redhat.com> | 2013-05-27 11:12:28 +0200 |
---|---|---|
committer | Hans de Goede <hdegoede@redhat.com> | 2013-05-30 14:20:44 +0200 |
commit | ef698c633d2ecb597be58deccfa2795cc6c88e25 (patch) | |
tree | 574ffb7ed0d5dc5bd7fba7185b190fdec151c724 | |
parent | cedc7f6e289c427c84a9175045b06614be56ec5a (diff) | |
download | libusb-ef698c633d2ecb597be58deccfa2795cc6c88e25.tar.gz |
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>
-rw-r--r-- | examples/xusb.c | 7 | ||||
-rw-r--r-- | libusb/descriptor.c | 88 | ||||
-rw-r--r-- | libusb/libusb-1.0.def | 4 | ||||
-rw-r--r-- | libusb/libusb.h | 61 | ||||
-rw-r--r-- | libusb/libusbi.h | 2 | ||||
-rw-r--r-- | libusb/version_nano.h | 2 |
6 files changed, 157 insertions, 7 deletions
diff --git a/examples/xusb.c b/examples/xusb.c index 5bb92a6..e1b1931 100644 --- a/examples/xusb.c +++ b/examples/xusb.c @@ -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); + } } } } diff --git a/libusb/descriptor.c b/libusb/descriptor.c index b53df77..14482ca 100644 --- a/libusb/descriptor.c +++ b/libusb/descriptor.c @@ -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; } } @@ -721,6 +741,70 @@ void API_EXPORTED libusb_free_config_descriptor( } /** \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. * * Wrapper around libusb_get_string_descriptor(). Uses the first language diff --git a/libusb/libusb-1.0.def b/libusb/libusb-1.0.def index 0343116..52047ea 100644 --- a/libusb/libusb-1.0.def +++ b/libusb/libusb-1.0.def @@ -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 diff --git a/libusb/libusb.h b/libusb/libusb.h index a67cbcb..593dc09 100644 --- a/libusb/libusb.h +++ b/libusb/libusb.h @@ -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); diff --git a/libusb/libusbi.h b/libusb/libusbi.h index 4dda97e..eabf33d 100644 --- a/libusb/libusbi.h +++ b/libusb/libusbi.h @@ -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, diff --git a/libusb/version_nano.h b/libusb/version_nano.h index a4f4d24..d69b0cc 100644 --- a/libusb/version_nano.h +++ b/libusb/version_nano.h @@ -1 +1 @@ -#define LIBUSB_NANO 10724 +#define LIBUSB_NANO 10725 |