From 82d912307f8d8a2a4fc9d7bac45ada4221813105 Mon Sep 17 00:00:00 2001 From: Dominik Boehi Date: Tue, 19 Apr 2022 20:43:18 +0200 Subject: descriptor: Add support for BOS platform descriptor parsing Also add BOS platform descriptor dump to xusb example. Closes #1133 [Tormod: Fixed copy-pasto in Doxygen comment] Signed-off-by: Tormod Volden --- examples/xusb.c | 14 ++++++++++++ libusb/descriptor.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ libusb/libusb-1.0.def | 4 ++++ libusb/libusb.h | 39 +++++++++++++++++++++++++++++++- libusb/version_nano.h | 2 +- 5 files changed, 119 insertions(+), 2 deletions(-) diff --git a/examples/xusb.c b/examples/xusb.c index 6266111..0fb5261 100644 --- a/examples/xusb.c +++ b/examples/xusb.c @@ -789,6 +789,20 @@ static void print_device_cap(struct libusb_bos_dev_capability_descriptor *dev_ca } break; } + case LIBUSB_BT_PLATFORM_DESCRIPTOR: { + struct libusb_platform_descriptor *platform_descriptor = NULL; + libusb_get_platform_descriptor(NULL, dev_cap, &platform_descriptor); + if (platform_descriptor) { + printf(" Platform descriptor:\n"); + printf(" bLength : %d\n", platform_descriptor->bLength); + printf(" PlatformCapabilityUUID : %s\n", uuid_to_string(platform_descriptor->PlatformCapabilityUUID)); + display_buffer_hex(&platform_descriptor->CapabilityData[0], platform_descriptor->bLength - 20); + printf("\n"); + libusb_free_platform_descriptor(platform_descriptor); + } + break; + + } default: printf(" Unknown BOS device capability %02x:\n", dev_cap->bDevCapabilityType); } diff --git a/libusb/descriptor.c b/libusb/descriptor.c index 727cf98..97e1d9a 100644 --- a/libusb/descriptor.c +++ b/libusb/descriptor.c @@ -1070,6 +1070,68 @@ void API_EXPORTED libusb_free_container_id_descriptor( free(container_id); } +/** \ingroup libusb_desc + * Get a platform descriptor + * + * \param ctx the context to operate on, or NULL for the default context + * \param dev_cap Device Capability descriptor with a bDevCapabilityType of + * \ref libusb_capability_type::LIBUSB_BT_PLATFORM_DESCRIPTOR + * LIBUSB_BT_PLATFORM_DESCRIPTOR + * \param platform_descriptor output location for the Platform descriptor. + * Only valid if 0 was returned. Must be freed with + * libusb_free_platform_descriptor() after use. + * \returns 0 on success + * \returns a LIBUSB_ERROR code on error + */ +int API_EXPORTED libusb_get_platform_descriptor(libusb_context *ctx, + struct libusb_bos_dev_capability_descriptor *dev_cap, + struct libusb_platform_descriptor **platform_descriptor) +{ + struct libusb_platform_descriptor *_platform_descriptor; + + if (dev_cap->bDevCapabilityType != LIBUSB_BT_PLATFORM_DESCRIPTOR) { + usbi_err(ctx, "unexpected bDevCapabilityType 0x%x (expected 0x%x)", + dev_cap->bDevCapabilityType, + LIBUSB_BT_PLATFORM_DESCRIPTOR); + return LIBUSB_ERROR_INVALID_PARAM; + } else if (dev_cap->bLength < LIBUSB_BT_PLATFORM_DESCRIPTOR_MIN_SIZE) { + usbi_err(ctx, "short dev-cap descriptor read %u/%d", + dev_cap->bLength, LIBUSB_BT_PLATFORM_DESCRIPTOR_MIN_SIZE); + return LIBUSB_ERROR_IO; + } + + _platform_descriptor = malloc(dev_cap->bLength); + if (!_platform_descriptor) + return LIBUSB_ERROR_NO_MEM; + + parse_descriptor(dev_cap, "bbbbu", _platform_descriptor); + + /* Capability data is located after reserved byte and 128-bit UUID */ + uint8_t* capability_data = dev_cap->dev_capability_data + 1 + 16; + + /* Capability data length is total descriptor length minus initial fields */ + size_t capability_data_length = _platform_descriptor->bLength - (16 + 4); + + memcpy(_platform_descriptor->CapabilityData, capability_data, capability_data_length); + + *platform_descriptor = _platform_descriptor; + return LIBUSB_SUCCESS; +} + +/** \ingroup libusb_desc + * Free a platform descriptor obtained from + * libusb_get_platform_descriptor(). + * It is safe to call this function with a NULL platform_descriptor parameter, + * in which case the function simply returns. + * + * \param platform_descriptor the Platform descriptor to free + */ +void API_EXPORTED libusb_free_platform_descriptor( + struct libusb_platform_descriptor *platform_descriptor) +{ + free(platform_descriptor); +} + /** \ingroup libusb_desc * Retrieve a string descriptor in C style ASCII. * diff --git a/libusb/libusb-1.0.def b/libusb/libusb-1.0.def index 01276aa..a12a05d 100644 --- a/libusb/libusb-1.0.def +++ b/libusb/libusb-1.0.def @@ -42,6 +42,8 @@ EXPORTS libusb_free_device_list@8 = libusb_free_device_list libusb_free_interface_association_descriptors libusb_free_interface_association_descriptors@4 = libusb_free_interface_association_descriptors + libusb_free_platform_descriptor + libusb_free_platform_descriptor@4 = libusb_free_platform_descriptor libusb_free_pollfds libusb_free_pollfds@4 = libusb_free_pollfds libusb_free_ss_endpoint_companion_descriptor @@ -90,6 +92,8 @@ EXPORTS libusb_get_next_timeout@8 = libusb_get_next_timeout libusb_get_parent libusb_get_parent@4 = libusb_get_parent + libusb_get_platform_descriptor + libusb_get_platform_descriptor@12 = libusb_get_platform_descriptor libusb_get_pollfds libusb_get_pollfds@4 = libusb_get_pollfds libusb_get_port_number diff --git a/libusb/libusb.h b/libusb/libusb.h index 0946a55..f7b0e19 100644 --- a/libusb/libusb.h +++ b/libusb/libusb.h @@ -313,6 +313,7 @@ enum libusb_descriptor_type { #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 +#define LIBUSB_BT_PLATFORM_DESCRIPTOR_MIN_SIZE 20 /* We unwrap the BOS => define its max size */ #define LIBUSB_DT_BOS_MAX_SIZE \ @@ -531,7 +532,10 @@ enum libusb_bos_type { LIBUSB_BT_SS_USB_DEVICE_CAPABILITY = 0x03, /** Container ID type */ - LIBUSB_BT_CONTAINER_ID = 0x04 + LIBUSB_BT_CONTAINER_ID = 0x04, + + /** Platform descriptor */ + LIBUSB_BT_PLATFORM_DESCRIPTOR = 0x05 }; /** \ingroup libusb_desc @@ -975,6 +979,34 @@ struct libusb_container_id_descriptor { uint8_t ContainerID[16]; }; +/** \ingroup libusb_desc + * A structure representing a Platform descriptor. + * This descriptor is documented in section 9.6.2.4 of the USB 3.2 specification. + */ +struct libusb_platform_descriptor { + /** Size of this descriptor (in bytes) */ + uint8_t bLength; + + /** Descriptor type. Will have value + * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY + * LIBUSB_DT_DEVICE_CAPABILITY in this context. */ + uint8_t bDescriptorType; + + /** Capability type. Will have value + * \ref libusb_capability_type::LIBUSB_BT_PLATFORM_DESCRIPTOR + * LIBUSB_BT_CONTAINER_ID in this context. */ + uint8_t bDevCapabilityType; + + /** Reserved field */ + uint8_t bReserved; + + /** 128 bit UUID */ + uint8_t PlatformCapabilityUUID[16]; + + /** Capability data (bLength - 20) */ + uint8_t CapabilityData[ZERO_SIZED_ARRAY]; +}; + /** \ingroup libusb_asyncio * Setup packet for control transfers. */ #if defined(_MSC_VER) || defined(__WATCOMC__) @@ -1483,6 +1515,11 @@ int LIBUSB_CALL libusb_get_container_id_descriptor(libusb_context *ctx, struct libusb_container_id_descriptor **container_id); void LIBUSB_CALL libusb_free_container_id_descriptor( struct libusb_container_id_descriptor *container_id); +int LIBUSB_CALL libusb_get_platform_descriptor(libusb_context *ctx, + struct libusb_bos_dev_capability_descriptor *dev_cap, + struct libusb_platform_descriptor **platform_descriptor); +void LIBUSB_CALL libusb_free_platform_descriptor( + struct libusb_platform_descriptor *platform_descriptor); 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/version_nano.h b/libusb/version_nano.h index 259aba6..9eac25d 100644 --- a/libusb/version_nano.h +++ b/libusb/version_nano.h @@ -1 +1 @@ -#define LIBUSB_NANO 11766 +#define LIBUSB_NANO 11767 -- cgit v1.2.1