mirror of
https://github.com/shadps4-emu/ext-libusb.git
synced 2026-01-31 00:55:21 +01:00
descriptor: Introduce interface association descriptors (IAD)
Types: struct libusb_interface_association_descriptor struct libusb_interface_association_descriptor_array Accessor / cleanup functions: libusb_get_interface_association_descriptors libusb_get_active_interface_association_descriptors libusb_free_interface_association_descriptors Signed-off-by: Ryan Metcalfe <ryan.metcalfe@novanta.com> [Tormod: Fixed Doxygen comment] Signed-off-by: Tormod Volden <debian.tormod@gmail.com>
This commit is contained in:
committed by
Tormod Volden
parent
e263e32f20
commit
809a6df614
@@ -1137,3 +1137,188 @@ int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev_ha
|
||||
data[di] = 0;
|
||||
return di;
|
||||
}
|
||||
|
||||
static int parse_iad_array(struct libusb_context *ctx,
|
||||
struct libusb_interface_association_descriptor_array *iad_array,
|
||||
const uint8_t *buffer, int size)
|
||||
{
|
||||
uint8_t i;
|
||||
struct usbi_descriptor_header header;
|
||||
int consumed = 0;
|
||||
const uint8_t *buf = buffer;
|
||||
struct libusb_interface_association_descriptor *iad;
|
||||
|
||||
if (size < LIBUSB_DT_CONFIG_SIZE) {
|
||||
usbi_err(ctx, "short config descriptor read %d/%d",
|
||||
size, LIBUSB_DT_CONFIG_SIZE);
|
||||
return LIBUSB_ERROR_IO;
|
||||
}
|
||||
|
||||
// First pass: Iterate through desc list, count number of IADs
|
||||
iad_array->length = 0;
|
||||
while (consumed < size) {
|
||||
parse_descriptor(buf, "bb", &header);
|
||||
if (header.bDescriptorType == LIBUSB_DT_INTERFACE_ASSOCIATION)
|
||||
iad_array->length++;
|
||||
buf += header.bLength;
|
||||
consumed += header.bLength;
|
||||
}
|
||||
|
||||
iad_array->iad = NULL;
|
||||
if (iad_array->length > 0) {
|
||||
iad = calloc(iad_array->length, sizeof(*iad));
|
||||
if (!iad)
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
|
||||
iad_array->iad = iad;
|
||||
|
||||
// Second pass: Iterate through desc list, fill IAD structures
|
||||
consumed = 0;
|
||||
i = 0;
|
||||
while (consumed < size) {
|
||||
parse_descriptor(buffer, "bb", &header);
|
||||
if (header.bDescriptorType == LIBUSB_DT_INTERFACE_ASSOCIATION)
|
||||
parse_descriptor(buffer, "bbbbbbbb", &iad[i++]);
|
||||
buffer += header.bLength;
|
||||
consumed += header.bLength;
|
||||
}
|
||||
}
|
||||
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
static int raw_desc_to_iad_array(struct libusb_context *ctx, const uint8_t *buf,
|
||||
int size, struct libusb_interface_association_descriptor_array **iad_array)
|
||||
{
|
||||
struct libusb_interface_association_descriptor_array *_iad_array
|
||||
= calloc(1, sizeof(*_iad_array));
|
||||
int r;
|
||||
|
||||
if (!_iad_array)
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
|
||||
r = parse_iad_array(ctx, _iad_array, buf, size);
|
||||
if (r < 0) {
|
||||
usbi_err(ctx, "parse_iad_array failed with error %d", r);
|
||||
free(_iad_array);
|
||||
return r;
|
||||
}
|
||||
|
||||
*iad_array = _iad_array;
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
/** \ingroup libusb_desc
|
||||
* Get an array of interface association descriptors (IAD) for a given
|
||||
* configuration.
|
||||
* This is a non-blocking function which does not involve any requests being
|
||||
* sent to the device.
|
||||
*
|
||||
* \param dev a device
|
||||
* \param config_index the index of the configuration you wish to retrieve the
|
||||
* IADs for.
|
||||
* \param iad_array output location for the array of IADs. Only valid if 0 was
|
||||
* returned. Must be freed with libusb_free_interface_association_descriptors()
|
||||
* after use. It's possible that a given configuration contains no IADs. In this
|
||||
* case the iad_array is still output, but will have 'length' field set to 0, and
|
||||
* iad field set to NULL.
|
||||
* \returns 0 on success
|
||||
* \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist
|
||||
* \returns another LIBUSB_ERROR code on error
|
||||
* \see libusb_get_active_interface_association_descriptors()
|
||||
*/
|
||||
int API_EXPORTED libusb_get_interface_association_descriptors(libusb_device *dev,
|
||||
uint8_t config_index, struct libusb_interface_association_descriptor_array **iad_array)
|
||||
{
|
||||
union usbi_config_desc_buf _config;
|
||||
uint16_t config_len;
|
||||
uint8_t *buf;
|
||||
int r;
|
||||
|
||||
if (!iad_array)
|
||||
return LIBUSB_ERROR_INVALID_PARAM;
|
||||
|
||||
usbi_dbg(DEVICE_CTX(dev), "IADs for config index %u", config_index);
|
||||
if (config_index >= dev->device_descriptor.bNumConfigurations)
|
||||
return LIBUSB_ERROR_NOT_FOUND;
|
||||
|
||||
r = get_config_descriptor(dev, config_index, _config.buf, sizeof(_config.buf));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
config_len = libusb_le16_to_cpu(_config.desc.wTotalLength);
|
||||
buf = malloc(config_len);
|
||||
if (!buf)
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
|
||||
r = get_config_descriptor(dev, config_index, buf, config_len);
|
||||
if (r >= 0)
|
||||
r = raw_desc_to_iad_array(DEVICE_CTX(dev), buf, r, iad_array);
|
||||
|
||||
free(buf);
|
||||
return r;
|
||||
}
|
||||
|
||||
/** \ingroup libusb_desc
|
||||
* Get an array of interface association descriptors (IAD) for the currently
|
||||
* active configuration.
|
||||
* This is a non-blocking function which does not involve any requests being
|
||||
* sent to the device.
|
||||
*
|
||||
* \param dev a device
|
||||
* \param iad_array output location for the array of IADs. Only valid if 0 was
|
||||
* returned. Must be freed with libusb_free_interface_association_descriptors()
|
||||
* after use. It's possible that a given configuration contains no IADs. In this
|
||||
* case the iad_array is still output, but will have 'length' field set to 0, and
|
||||
* iad field set to NULL.
|
||||
* \returns 0 on success
|
||||
* \returns LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state
|
||||
* \returns another LIBUSB_ERROR code on error
|
||||
* \see libusb_get_interface_association_descriptors
|
||||
*/
|
||||
int API_EXPORTED libusb_get_active_interface_association_descriptors(libusb_device *dev,
|
||||
struct libusb_interface_association_descriptor_array **iad_array)
|
||||
{
|
||||
union usbi_config_desc_buf _config;
|
||||
uint16_t config_len;
|
||||
uint8_t *buf;
|
||||
int r;
|
||||
|
||||
if (!iad_array)
|
||||
return LIBUSB_ERROR_INVALID_PARAM;
|
||||
|
||||
r = get_active_config_descriptor(dev, _config.buf, sizeof(_config.buf));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
config_len = libusb_le16_to_cpu(_config.desc.wTotalLength);
|
||||
buf = malloc(config_len);
|
||||
if (!buf)
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
|
||||
r = get_active_config_descriptor(dev, buf, config_len);
|
||||
if (r >= 0)
|
||||
r = raw_desc_to_iad_array(DEVICE_CTX(dev), buf, r, iad_array);
|
||||
free(buf);
|
||||
return r;
|
||||
}
|
||||
|
||||
/** \ingroup libusb_desc
|
||||
* Free an array of interface association descriptors (IADs) obtained from
|
||||
* libusb_get_interface_association_descriptors() or
|
||||
* libusb_get_active_interface_association_descriptors().
|
||||
* It is safe to call this function with a NULL iad_array parameter, in which
|
||||
* case the function simply returns.
|
||||
*
|
||||
* \param iad_array the IAD array to free
|
||||
*/
|
||||
void API_EXPORTED libusb_free_interface_association_descriptors(
|
||||
struct libusb_interface_association_descriptor_array *iad_array)
|
||||
{
|
||||
if (!iad_array)
|
||||
return;
|
||||
|
||||
if (iad_array->iad)
|
||||
free((void*)iad_array->iad);
|
||||
free(iad_array);
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ EXPORTS
|
||||
libusb_free_container_id_descriptor@4 = libusb_free_container_id_descriptor
|
||||
libusb_free_device_list
|
||||
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_pollfds
|
||||
libusb_free_pollfds@4 = libusb_free_pollfds
|
||||
libusb_free_ss_endpoint_companion_descriptor
|
||||
@@ -54,6 +56,8 @@ EXPORTS
|
||||
libusb_free_usb_2_0_extension_descriptor@4 = libusb_free_usb_2_0_extension_descriptor
|
||||
libusb_get_active_config_descriptor
|
||||
libusb_get_active_config_descriptor@8 = libusb_get_active_config_descriptor
|
||||
libusb_get_active_interface_association_descriptors
|
||||
libusb_get_active_interface_association_descriptors@8 = libusb_get_active_interface_association_descriptors
|
||||
libusb_get_bos_descriptor
|
||||
libusb_get_bos_descriptor@8 = libusb_get_bos_descriptor
|
||||
libusb_get_bus_number
|
||||
@@ -76,6 +80,8 @@ EXPORTS
|
||||
libusb_get_device_list@8 = libusb_get_device_list
|
||||
libusb_get_device_speed
|
||||
libusb_get_device_speed@4 = libusb_get_device_speed
|
||||
libusb_get_interface_association_descriptors
|
||||
libusb_get_interface_association_descriptors@12 = libusb_get_interface_association_descriptors
|
||||
libusb_get_max_iso_packet_size
|
||||
libusb_get_max_iso_packet_size@8 = libusb_get_max_iso_packet_size
|
||||
libusb_get_max_packet_size
|
||||
|
||||
@@ -269,6 +269,10 @@ enum libusb_descriptor_type {
|
||||
/** Endpoint descriptor. See libusb_endpoint_descriptor. */
|
||||
LIBUSB_DT_ENDPOINT = 0x05,
|
||||
|
||||
/** Interface Association Descriptor.
|
||||
* See libusb_interface_association_descriptor */
|
||||
LIBUSB_DT_INTERFACE_ASSOCIATION = 0x0b,
|
||||
|
||||
/** BOS descriptor */
|
||||
LIBUSB_DT_BOS = 0x0f,
|
||||
|
||||
@@ -632,6 +636,65 @@ struct libusb_endpoint_descriptor {
|
||||
int extra_length;
|
||||
};
|
||||
|
||||
/** \ingroup libusb_desc
|
||||
* A structure representing the standard USB interface association descriptor.
|
||||
* This descriptor is documented in section 9.6.4 of the USB 3.0 specification.
|
||||
* All multiple-byte fields are represented in host-endian format.
|
||||
*/
|
||||
struct libusb_interface_association_descriptor {
|
||||
/** Size of this descriptor (in bytes) */
|
||||
uint8_t bLength;
|
||||
|
||||
/** Descriptor type. Will have value
|
||||
* \ref libusb_descriptor_type::LIBUSB_DT_INTERFACE_ASSOCIATION
|
||||
* LIBUSB_DT_INTERFACE_ASSOCIATION in this context. */
|
||||
uint8_t bDescriptorType;
|
||||
|
||||
/** Interface number of the first interface that is associated
|
||||
* with this function */
|
||||
uint8_t bFirstInterface;
|
||||
|
||||
/** Number of contiguous interfaces that are associated with
|
||||
* this function */
|
||||
uint8_t bInterfaceCount;
|
||||
|
||||
/** USB-IF class code for this function.
|
||||
* A value of zero is not allowed in this descriptor.
|
||||
* If this field is 0xff, the function class is vendor-specific.
|
||||
* All other values are reserved for assignment by the USB-IF.
|
||||
*/
|
||||
uint8_t bFunctionClass;
|
||||
|
||||
/** USB-IF subclass code for this function.
|
||||
* If this field is not set to 0xff, all values are reserved
|
||||
* for assignment by the USB-IF
|
||||
*/
|
||||
uint8_t bFunctionSubClass;
|
||||
|
||||
/** USB-IF protocol code for this function.
|
||||
* These codes are qualified by the values of the bFunctionClass
|
||||
* and bFunctionSubClass fields.
|
||||
*/
|
||||
uint8_t bFunctionProtocol;
|
||||
|
||||
/** Index of string descriptor describing this function */
|
||||
uint8_t iFunction;
|
||||
};
|
||||
|
||||
/** \ingroup libusb_desc
|
||||
* Structure containing an array of 0 or more interface association
|
||||
* descriptors
|
||||
*/
|
||||
struct libusb_interface_association_descriptor_array {
|
||||
/** Array of interface association descriptors. The size of this array
|
||||
* is determined by the length field.
|
||||
*/
|
||||
const struct libusb_interface_association_descriptor *iad;
|
||||
|
||||
/** Number of interface association descriptors contained. Read-only. */
|
||||
int length;
|
||||
};
|
||||
|
||||
/** \ingroup libusb_desc
|
||||
* A structure representing the standard USB interface descriptor. This
|
||||
* descriptor is documented in section 9.6.5 of the USB 3.0 specification.
|
||||
@@ -1433,6 +1496,13 @@ int LIBUSB_CALL libusb_get_max_packet_size(libusb_device *dev,
|
||||
int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev,
|
||||
unsigned char endpoint);
|
||||
|
||||
int LIBUSB_CALL libusb_get_interface_association_descriptors(libusb_device *dev,
|
||||
uint8_t config_index, struct libusb_interface_association_descriptor_array **iad_array);
|
||||
int LIBUSB_CALL libusb_get_active_interface_association_descriptors(libusb_device *dev,
|
||||
struct libusb_interface_association_descriptor_array **iad_array);
|
||||
void LIBUSB_CALL libusb_free_interface_association_descriptors(
|
||||
struct libusb_interface_association_descriptor_array *iad_array);
|
||||
|
||||
int LIBUSB_CALL libusb_wrap_sys_device(libusb_context *ctx, intptr_t sys_dev, libusb_device_handle **dev_handle);
|
||||
int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **dev_handle);
|
||||
void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle);
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define LIBUSB_NANO 11763
|
||||
#define LIBUSB_NANO 11764
|
||||
|
||||
Reference in New Issue
Block a user