Descriptor parser rewrite
This commit is contained in:
parent
768f84b2a4
commit
783eaec80d
|
@ -18,6 +18,8 @@ jobs:
|
|||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'true'
|
||||
- name: Build USB Test Application
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
|
|
|
@ -3,9 +3,8 @@
|
|||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS ../usb_host_cdc_acm
|
||||
../usb_host_msc)
|
||||
../usb_host_uvc
|
||||
$ENV{IDF_PATH}/examples/peripherals/usb/host/msc/components/)
|
||||
../usb_host_msc
|
||||
../usb_host_uvc)
|
||||
|
||||
# Set the components to include the tests for.
|
||||
set(TEST_COMPONENTS "usb_host_cdc_acm" "usb_host_msc" "usb_host_uvc" CACHE STRING "List of components to test")
|
||||
|
|
|
@ -7,7 +7,7 @@ This directory contains USB host UVC driver based on [libuvc](https://github.com
|
|||
Reference [uvc_host_example](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/usb/host/uvc) is similar to one found in `libuvc` repository with few additions:
|
||||
1. Before calling `uvc_init()`, `initialize_usb_host_lib()` has to be called in order to initialize usb host library.
|
||||
2. Since `libuvc` selects highest possible `dwMaxPayloadTransferSize` by default, user has to manually overwrite obatained value to 512 bytes (maximum transfer size supported by ESP32-S2/S3) before passing it to `uvc_print_stream_ctrl()` function.
|
||||
3. Optionally, user can configure `libusb adaprer` by passing appropriate parameters to `libuvc_adapter_set_config()`.
|
||||
3. Optionally, user can configure `libusb adapter` by passing appropriate parameters to `libuvc_adapter_set_config()`.
|
||||
|
||||
## Known limitations
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
version: "0.0.2"
|
||||
version: "1.0.0"
|
||||
description: USB Host UVC driver
|
||||
url: https://github.com/espressif/idf-extra-components/tree/master
|
||||
url: https://github.com/espressif/idf-extra-components/tree/master/usb/usb_host_uvc
|
||||
|
||||
dependencies:
|
||||
idf: ">=4.4"
|
||||
|
|
|
@ -1,30 +1,7 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2007 Daniel Drake <dsd@gentoo.org>
|
||||
* SPDX-FileCopyrightText: 2001 Johannes Erdfelt <johannes@erdfelt.com>
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*
|
||||
* SPDX-FileContributor: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*/
|
||||
|
||||
/*
|
||||
* USB descriptor handling functions for libusb
|
||||
* Copyright © 2007 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
@ -44,6 +21,12 @@ typedef struct {
|
|||
uint8_t bDescriptorSubtype;
|
||||
} desc_header_t;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t *begin;
|
||||
uint8_t **data;
|
||||
size_t *len;
|
||||
} extra_data_t;
|
||||
|
||||
#define DESC_HEADER_LENGTH 2
|
||||
#define USB_MAXENDPOINTS 32
|
||||
#define USB_MAXINTERFACES 32
|
||||
|
@ -53,443 +36,197 @@ typedef struct {
|
|||
|
||||
#define USB_DESC_ATTR __attribute__((packed))
|
||||
|
||||
/** @defgroup libusb_desc USB descriptors
|
||||
* This page details how to examine the various standard USB descriptors
|
||||
* for detected devices
|
||||
*/
|
||||
|
||||
static void parse_descriptor(const void *source, const char *descriptor, void *dest)
|
||||
#define LIBUSB_GOTO_ON_ERROR(exp) do { \
|
||||
int _res_ = exp; \
|
||||
if(_res_ != LIBUSB_SUCCESS) { \
|
||||
ret = _res_; \
|
||||
goto cleanup; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define LIBUSB_GOTO_ON_FALSE(exp) do { \
|
||||
if((exp) == 0) { \
|
||||
goto cleanup; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
static const usb_intf_desc_t *next_interface_desc(const usb_intf_desc_t *desc, size_t len, int *offset)
|
||||
{
|
||||
const uint8_t *sp = source;
|
||||
uint8_t *dp = dest;
|
||||
char field_type;
|
||||
|
||||
while (*descriptor) {
|
||||
field_type = *descriptor++;
|
||||
switch (field_type) {
|
||||
case 'b': /* 8-bit byte */
|
||||
*dp++ = *sp++;
|
||||
break;
|
||||
case 'w': /* 16-bit word, convert from little endian to CPU */
|
||||
dp += ((uintptr_t)dp & 1); /* Align to 16-bit word boundary */
|
||||
|
||||
// *((uint16_t *)dp) = le16toh(*((uint16_t *)sp));
|
||||
*((uint16_t *)dp) = le16toh((uint16_t)sp[0] | sp[1] << 8);
|
||||
sp += 2;
|
||||
dp += 2;
|
||||
break;
|
||||
case 'd': /* 32-bit word, convert from little endian to CPU */
|
||||
dp += 4 - ((uintptr_t)dp & 3); /* Align to 32-bit word boundary */
|
||||
|
||||
*((uint32_t *)dp) = le32toh(((uint32_t)sp[0] | sp[1] << 8 | sp[2] << 16 | sp[3] << 24));
|
||||
sp += 4;
|
||||
dp += 4;
|
||||
break;
|
||||
case 'u': /* 16 byte UUID */
|
||||
memcpy(dp, sp, 16);
|
||||
sp += 16;
|
||||
dp += 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (const usb_intf_desc_t *) usb_parse_next_descriptor_of_type(
|
||||
(const usb_standard_desc_t *)desc, len, USB_B_DESCRIPTOR_TYPE_INTERFACE, offset);
|
||||
}
|
||||
|
||||
static void clear_endpoint(struct libusb_endpoint_descriptor *endpoint)
|
||||
void copy_config_desc(libusb_config_descriptor_t *libusb_desc, const usb_config_desc_t *idf_desc)
|
||||
{
|
||||
free((void *)endpoint->extra);
|
||||
libusb_desc->bLength = idf_desc->bLength;
|
||||
libusb_desc->bDescriptorType = idf_desc->bDescriptorType;
|
||||
libusb_desc->wTotalLength = idf_desc->wTotalLength;
|
||||
libusb_desc->bNumInterfaces = idf_desc->bNumInterfaces;
|
||||
libusb_desc->bConfigurationValue = idf_desc->bConfigurationValue;
|
||||
libusb_desc->iConfiguration = idf_desc->iConfiguration;
|
||||
libusb_desc->bmAttributes = idf_desc->bmAttributes;
|
||||
libusb_desc->bMaxPower = idf_desc->bMaxPower;
|
||||
}
|
||||
|
||||
static int parse_endpoint(struct libusb_endpoint_descriptor *endpoint, const uint8_t *buffer, int size)
|
||||
void copy_interface_desc(libusb_interface_descriptor_t *libusb_desc, const usb_intf_desc_t *idf_desc)
|
||||
{
|
||||
const desc_header_t *header;
|
||||
const uint8_t *begin;
|
||||
void *extra;
|
||||
int parsed = 0;
|
||||
int len;
|
||||
|
||||
if (size < DESC_HEADER_LENGTH) {
|
||||
ESP_LOGE(TAG, "short endpoint descriptor read %d/%d",
|
||||
size, DESC_HEADER_LENGTH);
|
||||
return LIBUSB_ERROR_IO;
|
||||
}
|
||||
|
||||
header = (const desc_header_t *)buffer;
|
||||
if (header->bDescriptorType != LIBUSB_DT_ENDPOINT) {
|
||||
ESP_LOGE(TAG, "unexpected descriptor 0x%x (expected 0x%x)",
|
||||
header->bDescriptorType, LIBUSB_DT_ENDPOINT);
|
||||
return parsed;
|
||||
} else if (header->bLength < LIBUSB_DT_ENDPOINT_SIZE) {
|
||||
ESP_LOGE(TAG, "invalid endpoint bLength (%u)", header->bLength);
|
||||
return LIBUSB_ERROR_IO;
|
||||
} else if (header->bLength > size) {
|
||||
ESP_LOGW(TAG, "short endpoint descriptor read %d/%u",
|
||||
size, header->bLength);
|
||||
return parsed;
|
||||
}
|
||||
|
||||
if (header->bLength >= LIBUSB_DT_ENDPOINT_AUDIO_SIZE) {
|
||||
parse_descriptor(buffer, "bbbbwbbb", endpoint);
|
||||
} else {
|
||||
parse_descriptor(buffer, "bbbbwb", endpoint);
|
||||
}
|
||||
|
||||
buffer += header->bLength;
|
||||
size -= header->bLength;
|
||||
parsed += header->bLength;
|
||||
|
||||
/* Skip over the rest of the Class Specific or Vendor Specific */
|
||||
/* descriptors */
|
||||
begin = buffer;
|
||||
while (size >= DESC_HEADER_LENGTH) {
|
||||
header = (const desc_header_t *)buffer;
|
||||
if (header->bLength < DESC_HEADER_LENGTH) {
|
||||
ESP_LOGE(TAG, "invalid extra ep desc len (%u)",
|
||||
header->bLength);
|
||||
return LIBUSB_ERROR_IO;
|
||||
} else if (header->bLength > size) {
|
||||
ESP_LOGW(TAG, "short extra ep desc read %d/%u",
|
||||
size, header->bLength);
|
||||
return parsed;
|
||||
}
|
||||
|
||||
/* If we find another "proper" descriptor then we're done */
|
||||
if (header->bDescriptorType == LIBUSB_DT_ENDPOINT ||
|
||||
header->bDescriptorType == LIBUSB_DT_INTERFACE ||
|
||||
header->bDescriptorType == LIBUSB_DT_CONFIG ||
|
||||
header->bDescriptorType == LIBUSB_DT_DEVICE) {
|
||||
break;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "skipping descriptor 0x%x", header->bDescriptorType);
|
||||
buffer += header->bLength;
|
||||
size -= header->bLength;
|
||||
parsed += header->bLength;
|
||||
}
|
||||
|
||||
/* Copy any unknown descriptors into a storage area for drivers */
|
||||
/* to later parse */
|
||||
len = (int)(buffer - begin);
|
||||
if (len <= 0) {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
extra = malloc((size_t)len);
|
||||
if (!extra) {
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
memcpy(extra, begin, len);
|
||||
endpoint->extra = extra;
|
||||
endpoint->extra_length = len;
|
||||
|
||||
return parsed;
|
||||
libusb_desc->bLength = idf_desc->bLength;
|
||||
libusb_desc->bDescriptorType = idf_desc->bDescriptorType;
|
||||
libusb_desc->bInterfaceNumber = idf_desc->bInterfaceNumber;
|
||||
libusb_desc->bAlternateSetting = idf_desc->bAlternateSetting;
|
||||
libusb_desc->bNumEndpoints = idf_desc->bNumEndpoints;
|
||||
libusb_desc->bInterfaceClass = idf_desc->bInterfaceClass;
|
||||
libusb_desc->bInterfaceSubClass = idf_desc->bInterfaceSubClass;
|
||||
libusb_desc->bInterfaceProtocol = idf_desc->bInterfaceProtocol;
|
||||
libusb_desc->iInterface = idf_desc->iInterface;
|
||||
}
|
||||
|
||||
static void clear_interface(struct libusb_interface *usb_interface)
|
||||
void copy_endpoint_desc(libusb_endpoint_descriptor_t *libusb_desc, const usb_ep_desc_t *idf_desc)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (usb_interface->altsetting) {
|
||||
for (i = 0; i < usb_interface->num_altsetting; i++) {
|
||||
struct libusb_interface_descriptor *ifp =
|
||||
(struct libusb_interface_descriptor *)
|
||||
usb_interface->altsetting + i;
|
||||
|
||||
free((void *)ifp->extra);
|
||||
if (ifp->endpoint) {
|
||||
uint8_t j;
|
||||
|
||||
for (j = 0; j < ifp->bNumEndpoints; j++)
|
||||
clear_endpoint((struct libusb_endpoint_descriptor *)
|
||||
ifp->endpoint + j);
|
||||
}
|
||||
free((void *)ifp->endpoint);
|
||||
}
|
||||
}
|
||||
free((void *)usb_interface->altsetting);
|
||||
usb_interface->altsetting = NULL;
|
||||
libusb_desc->bLength = idf_desc->bLength;
|
||||
libusb_desc->bDescriptorType = idf_desc->bDescriptorType;
|
||||
libusb_desc->bEndpointAddress = idf_desc->bEndpointAddress;
|
||||
libusb_desc->bmAttributes = idf_desc->bmAttributes;
|
||||
libusb_desc->wMaxPacketSize = idf_desc->wMaxPacketSize;
|
||||
libusb_desc->bInterval = idf_desc->bInterval;
|
||||
}
|
||||
|
||||
static int parse_interface(struct libusb_interface *usb_interface, const uint8_t *buffer, int size)
|
||||
static void set_extra_data(extra_data_t *extra, uint8_t **extra_data, size_t *extra_len, const uint8_t *begin)
|
||||
{
|
||||
int len;
|
||||
int r;
|
||||
int parsed = 0;
|
||||
int interface_number = -1;
|
||||
const desc_header_t *header;
|
||||
const usb_intf_desc_t *if_desc;
|
||||
struct libusb_interface_descriptor *ifp;
|
||||
const uint8_t *begin;
|
||||
extra->data = extra_data;
|
||||
extra->len = extra_len;
|
||||
extra->begin = begin;
|
||||
}
|
||||
|
||||
while (size >= LIBUSB_DT_INTERFACE_SIZE) {
|
||||
struct libusb_interface_descriptor *altsetting;
|
||||
// Copies extra data to previously provided memory.
|
||||
// The function allocates or realllocates memory depending on provided pointer
|
||||
static libusb_status_t add_extra_data(extra_data_t *extra, const void *end)
|
||||
{
|
||||
uint8_t *new_memory = NULL;
|
||||
|
||||
altsetting = realloc((void *)usb_interface->altsetting,
|
||||
sizeof(*altsetting) * (size_t)(usb_interface->num_altsetting + 1));
|
||||
if (!altsetting) {
|
||||
r = LIBUSB_ERROR_NO_MEM;
|
||||
goto err;
|
||||
}
|
||||
usb_interface->altsetting = altsetting;
|
||||
int new_size = (int)((uint8_t *)end - extra->begin);
|
||||
|
||||
ifp = altsetting + usb_interface->num_altsetting;
|
||||
parse_descriptor(buffer, "bbbbbbbbb", ifp);
|
||||
if (ifp->bDescriptorType != LIBUSB_DT_INTERFACE) {
|
||||
ESP_LOGE(TAG, "unexpected descriptor 0x%x (expected 0x%x)",
|
||||
ifp->bDescriptorType, LIBUSB_DT_INTERFACE);
|
||||
return parsed;
|
||||
} else if (ifp->bLength < LIBUSB_DT_INTERFACE_SIZE) {
|
||||
ESP_LOGE(TAG, "invalid interface bLength (%u)",
|
||||
ifp->bLength);
|
||||
r = LIBUSB_ERROR_IO;
|
||||
goto err;
|
||||
} else if (ifp->bLength > size) {
|
||||
ESP_LOGW(TAG, "short intf descriptor read %d/%u",
|
||||
size, ifp->bLength);
|
||||
return parsed;
|
||||
} else if (ifp->bNumEndpoints > USB_MAXENDPOINTS) {
|
||||
ESP_LOGE(TAG, "too many endpoints (%u)", ifp->bNumEndpoints);
|
||||
r = LIBUSB_ERROR_IO;
|
||||
goto err;
|
||||
if (new_size > 0) {
|
||||
if (*extra->data == NULL) {
|
||||
new_memory = malloc(new_size);
|
||||
} else {
|
||||
new_memory = realloc(*extra->data, *extra->len + new_size);
|
||||
}
|
||||
|
||||
usb_interface->num_altsetting++;
|
||||
ifp->extra = NULL;
|
||||
ifp->extra_length = 0;
|
||||
ifp->endpoint = NULL;
|
||||
|
||||
if (interface_number == -1) {
|
||||
interface_number = ifp->bInterfaceNumber;
|
||||
if (!new_memory) {
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
/* Skip over the interface */
|
||||
buffer += ifp->bLength;
|
||||
parsed += ifp->bLength;
|
||||
size -= ifp->bLength;
|
||||
memcpy(new_memory + *extra->len, extra->begin, new_size);
|
||||
*extra->data = new_memory;
|
||||
*extra->len += new_size;
|
||||
}
|
||||
|
||||
begin = buffer;
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
/* Skip over any interface, class or vendor descriptors */
|
||||
while (size >= DESC_HEADER_LENGTH) {
|
||||
header = (const desc_header_t *)buffer;
|
||||
if (header->bLength < DESC_HEADER_LENGTH) {
|
||||
ESP_LOGE(TAG, "invalid extra intf desc len (%u)", header->bLength);
|
||||
r = LIBUSB_ERROR_IO;
|
||||
goto err;
|
||||
} else if (header->bLength > size) {
|
||||
ESP_LOGW(TAG, "short extra intf desc read %d/%u", size, header->bLength);
|
||||
return parsed;
|
||||
}
|
||||
|
||||
/* If we find another "proper" descriptor then we're done */
|
||||
if (header->bDescriptorType == LIBUSB_DT_INTERFACE ||
|
||||
header->bDescriptorType == LIBUSB_DT_ENDPOINT ||
|
||||
header->bDescriptorType == LIBUSB_DT_CONFIG ||
|
||||
header->bDescriptorType == LIBUSB_DT_DEVICE) {
|
||||
break;
|
||||
}
|
||||
|
||||
buffer += header->bLength;
|
||||
parsed += header->bLength;
|
||||
size -= header->bLength;
|
||||
}
|
||||
|
||||
/* Copy any unknown descriptors into a storage area for */
|
||||
/* drivers to later parse */
|
||||
len = (int)(buffer - begin);
|
||||
if (len > 0) {
|
||||
void *extra = malloc((size_t)len);
|
||||
|
||||
if (!extra) {
|
||||
r = LIBUSB_ERROR_NO_MEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy(extra, begin, len);
|
||||
ifp->extra = extra;
|
||||
ifp->extra_length = len;
|
||||
}
|
||||
|
||||
if (ifp->bNumEndpoints > 0) {
|
||||
struct libusb_endpoint_descriptor *endpoint;
|
||||
uint8_t i;
|
||||
|
||||
endpoint = calloc(ifp->bNumEndpoints, sizeof(*endpoint));
|
||||
if (!endpoint) {
|
||||
r = LIBUSB_ERROR_NO_MEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ifp->endpoint = endpoint;
|
||||
for (i = 0; i < ifp->bNumEndpoints; i++) {
|
||||
r = parse_endpoint(endpoint + i, buffer, size);
|
||||
if (r < 0) {
|
||||
goto err;
|
||||
void clear_config_descriptor(libusb_config_descriptor_t *config)
|
||||
{
|
||||
if (config) {
|
||||
if (config->interface) {
|
||||
for (int i = 0; i < config->bNumInterfaces; i++) {
|
||||
libusb_interface_t *interface = &config->interface[i];
|
||||
if (interface->altsetting) {
|
||||
for (int j = 0; j < interface->num_altsetting; j++) {
|
||||
libusb_interface_descriptor_t *alt = &interface->altsetting[j];
|
||||
if (alt->endpoint) {
|
||||
for (int ep = 0; ep < alt->bNumEndpoints; ep++) {
|
||||
free(alt->endpoint[ep].extra);
|
||||
}
|
||||
free(alt->endpoint);
|
||||
}
|
||||
free(alt->extra);
|
||||
}
|
||||
free(interface->altsetting);
|
||||
}
|
||||
if (r == 0) {
|
||||
ifp->bNumEndpoints = i;
|
||||
break;
|
||||
}
|
||||
|
||||
buffer += r;
|
||||
parsed += r;
|
||||
size -= r;
|
||||
}
|
||||
free(config->interface);
|
||||
}
|
||||
|
||||
/* We check to see if it's an alternate to this one */
|
||||
if_desc = (const usb_intf_desc_t *)buffer;
|
||||
if (size < LIBUSB_DT_INTERFACE_SIZE ||
|
||||
if_desc->bDescriptorType != LIBUSB_DT_INTERFACE ||
|
||||
if_desc->bInterfaceNumber != interface_number) {
|
||||
return parsed;
|
||||
}
|
||||
free(config->extra);
|
||||
}
|
||||
|
||||
return parsed;
|
||||
err:
|
||||
clear_interface(usb_interface);
|
||||
return r;
|
||||
}
|
||||
|
||||
void clear_config_descriptor(struct libusb_config_descriptor *config)
|
||||
int parse_configuration(libusb_config_descriptor_t *config, const uint8_t *buffer, int size)
|
||||
{
|
||||
uint8_t i;
|
||||
int offset = 0;
|
||||
extra_data_t extra = { 0 };
|
||||
const usb_ep_desc_t *ep_desc;
|
||||
const usb_config_desc_t *config_start = (const usb_config_desc_t *)buffer;
|
||||
libusb_status_t ret = LIBUSB_ERROR_NO_MEM;
|
||||
|
||||
if (config->interface) {
|
||||
for (i = 0; i < config->bNumInterfaces; i++)
|
||||
clear_interface((struct libusb_interface *)
|
||||
config->interface + i);
|
||||
}
|
||||
free((void *)config->interface);
|
||||
free((void *)config->extra);
|
||||
}
|
||||
copy_config_desc(config, (const usb_config_desc_t *)buffer);
|
||||
config->interface = calloc(config->bNumInterfaces, sizeof(libusb_interface_t));
|
||||
LIBUSB_GOTO_ON_FALSE(config->interface);
|
||||
// set pointers to extra data to be used later for class/vendor specific descriptor
|
||||
set_extra_data(&extra, &config->extra, &config->extra_length, buffer + LIBUSB_DT_CONFIG_SIZE);
|
||||
const usb_intf_desc_t *ifc_desc = (const usb_intf_desc_t *)buffer;
|
||||
|
||||
static int parse_configuration(struct libusb_config_descriptor *config, const uint8_t *buffer, int size)
|
||||
{
|
||||
uint8_t i;
|
||||
int r;
|
||||
const desc_header_t *header;
|
||||
struct libusb_interface *usb_interface;
|
||||
for (int i = 0; i < config->bNumInterfaces; i++) {
|
||||
ifc_desc = next_interface_desc(ifc_desc, config->wTotalLength, &offset);
|
||||
// Copy any unknown descriptors into a storage area for drivers to later parse
|
||||
LIBUSB_GOTO_ON_ERROR( add_extra_data(&extra, ifc_desc) );
|
||||
|
||||
if (size < LIBUSB_DT_CONFIG_SIZE) {
|
||||
ESP_LOGE(TAG, "short config descriptor read %d/%d",
|
||||
size, LIBUSB_DT_CONFIG_SIZE);
|
||||
return LIBUSB_ERROR_IO;
|
||||
}
|
||||
libusb_interface_t *interface = &config->interface[i];
|
||||
// Obtain number of alternate interfaces to given interface number
|
||||
int alt_interfaces = usb_parse_interface_number_of_alternate(config_start, ifc_desc->bInterfaceNumber) + 1;
|
||||
interface->altsetting = calloc(alt_interfaces, sizeof(libusb_interface_descriptor_t));
|
||||
LIBUSB_GOTO_ON_FALSE(interface->altsetting);
|
||||
interface->num_altsetting = alt_interfaces;
|
||||
|
||||
parse_descriptor(buffer, "bbwbbbbb", config);
|
||||
if (config->bDescriptorType != LIBUSB_DT_CONFIG) {
|
||||
ESP_LOGE(TAG, "unexpected descriptor 0x%x (expected 0x%x)",
|
||||
config->bDescriptorType, LIBUSB_DT_CONFIG);
|
||||
return LIBUSB_ERROR_IO;
|
||||
} else if (config->bLength < LIBUSB_DT_CONFIG_SIZE) {
|
||||
ESP_LOGE(TAG, "invalid config bLength (%u)", config->bLength);
|
||||
return LIBUSB_ERROR_IO;
|
||||
} else if (config->bLength > size) {
|
||||
ESP_LOGE(TAG, "short config descriptor read %d/%u",
|
||||
size, config->bLength);
|
||||
return LIBUSB_ERROR_IO;
|
||||
} else if (config->bNumInterfaces > USB_MAXINTERFACES) {
|
||||
ESP_LOGE(TAG, "too many interfaces (%u)", config->bNumInterfaces);
|
||||
return LIBUSB_ERROR_IO;
|
||||
}
|
||||
for (int alt = 0; alt < alt_interfaces; alt++) {
|
||||
libusb_interface_descriptor_t *altsetting = &interface->altsetting[alt];
|
||||
copy_interface_desc(altsetting, ifc_desc);
|
||||
set_extra_data(&extra, &altsetting->extra, &altsetting->extra_length, ((uint8_t *)ifc_desc) + LIBUSB_DT_INTERFACE_SIZE);
|
||||
uint8_t endpoints = ifc_desc->bNumEndpoints;
|
||||
|
||||
usb_interface = calloc(config->bNumInterfaces, sizeof(*usb_interface));
|
||||
if (!usb_interface) {
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
}
|
||||
altsetting->endpoint = calloc(altsetting->bNumEndpoints, sizeof(libusb_endpoint_descriptor_t));
|
||||
LIBUSB_GOTO_ON_FALSE(interface->altsetting);
|
||||
|
||||
config->interface = usb_interface;
|
||||
|
||||
buffer += config->bLength;
|
||||
size -= config->bLength;
|
||||
|
||||
for (i = 0; i < config->bNumInterfaces; i++) {
|
||||
int len;
|
||||
const uint8_t *begin;
|
||||
|
||||
/* Skip over the rest of the Class Specific or Vendor */
|
||||
/* Specific descriptors */
|
||||
begin = buffer;
|
||||
while (size >= DESC_HEADER_LENGTH) {
|
||||
header = (const desc_header_t *)buffer;
|
||||
if (header->bLength < DESC_HEADER_LENGTH) {
|
||||
ESP_LOGE(TAG, "invalid extra config desc len (%u)", header->bLength);
|
||||
r = LIBUSB_ERROR_IO;
|
||||
goto err;
|
||||
} else if (header->bLength > size) {
|
||||
ESP_LOGW(TAG, "short extra config desc read %d/%u", size, header->bLength);
|
||||
config->bNumInterfaces = i;
|
||||
return size;
|
||||
for (int ep = 0; ep < endpoints; ep++) {
|
||||
ep_desc = usb_parse_endpoint_descriptor_by_index(ifc_desc, ep, config->wTotalLength, &offset);
|
||||
ifc_desc = (const usb_intf_desc_t *)ep_desc;
|
||||
libusb_endpoint_descriptor_t *endpoint = &altsetting->endpoint[ep];
|
||||
copy_endpoint_desc(endpoint, ep_desc);
|
||||
LIBUSB_GOTO_ON_ERROR( add_extra_data(&extra, ep_desc) );
|
||||
set_extra_data(&extra, &endpoint->extra, &endpoint->extra_length, ((uint8_t *)ep_desc) + ep_desc->bLength);
|
||||
}
|
||||
|
||||
/* If we find another "proper" descriptor then we're done */
|
||||
if (header->bDescriptorType == LIBUSB_DT_ENDPOINT ||
|
||||
header->bDescriptorType == LIBUSB_DT_INTERFACE ||
|
||||
header->bDescriptorType == LIBUSB_DT_CONFIG ||
|
||||
header->bDescriptorType == LIBUSB_DT_DEVICE) {
|
||||
break;
|
||||
if (alt + 1 < alt_interfaces) {
|
||||
// go over next alternate interface
|
||||
ifc_desc = next_interface_desc(ifc_desc, config->wTotalLength, &offset);
|
||||
LIBUSB_GOTO_ON_ERROR( add_extra_data(&extra, ifc_desc) );
|
||||
extra.begin = ((uint8_t *)ifc_desc) + LIBUSB_DT_INTERFACE_SIZE;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "skipping descriptor 0x%x", header->bDescriptorType);
|
||||
buffer += header->bLength;
|
||||
size -= header->bLength;
|
||||
}
|
||||
|
||||
/* Copy any unknown descriptors into a storage area for */
|
||||
/* drivers to later parse */
|
||||
len = (int)(buffer - begin);
|
||||
if (len > 0) {
|
||||
uint8_t *extra = realloc((void *)config->extra,
|
||||
(size_t)(config->extra_length + len));
|
||||
|
||||
if (!extra) {
|
||||
r = LIBUSB_ERROR_NO_MEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy(extra + config->extra_length, begin, len);
|
||||
config->extra = extra;
|
||||
config->extra_length += len;
|
||||
}
|
||||
|
||||
r = parse_interface(usb_interface + i, buffer, size);
|
||||
if (r < 0) {
|
||||
goto err;
|
||||
}
|
||||
if (r == 0) {
|
||||
config->bNumInterfaces = i;
|
||||
break;
|
||||
}
|
||||
|
||||
buffer += r;
|
||||
size -= r;
|
||||
}
|
||||
// Save any remaining descriptors to extra data
|
||||
LIBUSB_GOTO_ON_ERROR( add_extra_data(&extra, &buffer[config->wTotalLength]) );
|
||||
|
||||
return size;
|
||||
return LIBUSB_SUCCESS;
|
||||
|
||||
err:
|
||||
cleanup:
|
||||
clear_config_descriptor(config);
|
||||
return r;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int raw_desc_to_libusb_config(const uint8_t *buf, int size, struct libusb_config_descriptor **config_desc)
|
||||
{
|
||||
libusb_config_descriptor_t *config = calloc(1, sizeof(*config));
|
||||
int r;
|
||||
|
||||
if (!config) {
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
r = parse_configuration(config, buf, size);
|
||||
int r = parse_configuration(config, buf, size);
|
||||
if (r < 0) {
|
||||
ESP_LOGE(TAG, "parse_configuration failed with error %d", r);
|
||||
free(config);
|
||||
return r;
|
||||
} else if (r > 0) {
|
||||
ESP_LOGW(TAG, "still %d bytes of descriptor data left", r);
|
||||
}
|
||||
|
||||
*config_desc = config;
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
idf_component_register(SRCS
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES usb_host_uvc unity)
|
||||
idf_component_register(SRCS "test_uvc.c" "libusb_parse.c"
|
||||
INCLUDE_DIRS "." "../private_include"
|
||||
REQUIRES usb_host_uvc usb unity)
|
||||
|
|
|
@ -0,0 +1,470 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2007 Daniel Drake <dsd@gentoo.org>
|
||||
* SPDX-FileCopyrightText: 2001 Johannes Erdfelt <johannes@erdfelt.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*
|
||||
* SPDX-FileContributor: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*/
|
||||
|
||||
/*
|
||||
* USB descriptor handling functions for libusb
|
||||
* Copyright © 2007 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <endian.h>
|
||||
#include <sys/param.h>
|
||||
#include "libusb.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "usb/usb_host.h"
|
||||
#include "usb/usb_types_ch9.h"
|
||||
|
||||
#define DESC_HEADER_LENGTH 2
|
||||
#define USB_MAXENDPOINTS 32
|
||||
#define USB_MAXINTERFACES 32
|
||||
#define USB_MAXCONFIG 8
|
||||
|
||||
const char *TAG = "LIBUSB_PARSE";
|
||||
|
||||
typedef struct {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bDescriptorSubtype;
|
||||
} desc_header_t;
|
||||
|
||||
|
||||
static void parse_descriptor(const void *source, const char *descriptor, void *dest)
|
||||
{
|
||||
const uint8_t *sp = source;
|
||||
uint8_t *dp = dest;
|
||||
char field_type;
|
||||
|
||||
while (*descriptor) {
|
||||
field_type = *descriptor++;
|
||||
switch (field_type) {
|
||||
case 'b': /* 8-bit byte */
|
||||
*dp++ = *sp++;
|
||||
break;
|
||||
case 'w': /* 16-bit word, convert from little endian to CPU */
|
||||
dp += ((uintptr_t)dp & 1); /* Align to 16-bit word boundary */
|
||||
|
||||
// *((uint16_t *)dp) = le16toh(*((uint16_t *)sp));
|
||||
*((uint16_t *)dp) = le16toh((uint16_t)sp[0] | sp[1] << 8);
|
||||
sp += 2;
|
||||
dp += 2;
|
||||
break;
|
||||
case 'd': /* 32-bit word, convert from little endian to CPU */
|
||||
dp += 4 - ((uintptr_t)dp & 3); /* Align to 32-bit word boundary */
|
||||
|
||||
*((uint32_t *)dp) = le32toh(((uint32_t)sp[0] | sp[1] << 8 | sp[2] << 16 | sp[3] << 24));
|
||||
sp += 4;
|
||||
dp += 4;
|
||||
break;
|
||||
case 'u': /* 16 byte UUID */
|
||||
memcpy(dp, sp, 16);
|
||||
sp += 16;
|
||||
dp += 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_endpoint(struct libusb_endpoint_descriptor *endpoint)
|
||||
{
|
||||
free((void *)endpoint->extra);
|
||||
}
|
||||
|
||||
static int parse_endpoint(struct libusb_endpoint_descriptor *endpoint, const uint8_t *buffer, int size)
|
||||
{
|
||||
const desc_header_t *header;
|
||||
const uint8_t *begin;
|
||||
void *extra;
|
||||
int parsed = 0;
|
||||
int len;
|
||||
|
||||
if (size < DESC_HEADER_LENGTH) {
|
||||
ESP_LOGE(TAG, "short endpoint descriptor read %d/%d",
|
||||
size, DESC_HEADER_LENGTH);
|
||||
return LIBUSB_ERROR_IO;
|
||||
}
|
||||
|
||||
header = (const desc_header_t *)buffer;
|
||||
if (header->bDescriptorType != LIBUSB_DT_ENDPOINT) {
|
||||
ESP_LOGE(TAG, "unexpected descriptor 0x%x (expected 0x%x)",
|
||||
header->bDescriptorType, LIBUSB_DT_ENDPOINT);
|
||||
return parsed;
|
||||
} else if (header->bLength < LIBUSB_DT_ENDPOINT_SIZE) {
|
||||
ESP_LOGE(TAG, "invalid endpoint bLength (%u)", header->bLength);
|
||||
return LIBUSB_ERROR_IO;
|
||||
} else if (header->bLength > size) {
|
||||
ESP_LOGW(TAG, "short endpoint descriptor read %d/%u",
|
||||
size, header->bLength);
|
||||
return parsed;
|
||||
}
|
||||
|
||||
if (header->bLength >= LIBUSB_DT_ENDPOINT_AUDIO_SIZE) {
|
||||
parse_descriptor(buffer, "bbbbwbbb", endpoint);
|
||||
} else {
|
||||
parse_descriptor(buffer, "bbbbwb", endpoint);
|
||||
}
|
||||
|
||||
buffer += header->bLength;
|
||||
size -= header->bLength;
|
||||
parsed += header->bLength;
|
||||
|
||||
/* Skip over the rest of the Class Specific or Vendor Specific */
|
||||
/* descriptors */
|
||||
begin = buffer;
|
||||
while (size >= DESC_HEADER_LENGTH) {
|
||||
header = (const desc_header_t *)buffer;
|
||||
if (header->bLength < DESC_HEADER_LENGTH) {
|
||||
ESP_LOGE(TAG, "invalid extra ep desc len (%u)",
|
||||
header->bLength);
|
||||
return LIBUSB_ERROR_IO;
|
||||
} else if (header->bLength > size) {
|
||||
ESP_LOGW(TAG, "short extra ep desc read %d/%u",
|
||||
size, header->bLength);
|
||||
return parsed;
|
||||
}
|
||||
|
||||
/* If we find another "proper" descriptor then we're done */
|
||||
if (header->bDescriptorType == LIBUSB_DT_ENDPOINT ||
|
||||
header->bDescriptorType == LIBUSB_DT_INTERFACE ||
|
||||
header->bDescriptorType == LIBUSB_DT_CONFIG ||
|
||||
header->bDescriptorType == LIBUSB_DT_DEVICE) {
|
||||
break;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "skipping descriptor 0x%x", header->bDescriptorType);
|
||||
buffer += header->bLength;
|
||||
size -= header->bLength;
|
||||
parsed += header->bLength;
|
||||
}
|
||||
|
||||
/* Copy any unknown descriptors into a storage area for drivers */
|
||||
/* to later parse */
|
||||
len = (int)(buffer - begin);
|
||||
if (len <= 0) {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
extra = malloc((size_t)len);
|
||||
if (!extra) {
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
memcpy(extra, begin, len);
|
||||
endpoint->extra = extra;
|
||||
endpoint->extra_length = len;
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
static void clear_interface(struct libusb_interface *usb_interface)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (usb_interface->altsetting) {
|
||||
for (i = 0; i < usb_interface->num_altsetting; i++) {
|
||||
struct libusb_interface_descriptor *ifp =
|
||||
(struct libusb_interface_descriptor *)
|
||||
usb_interface->altsetting + i;
|
||||
|
||||
free((void *)ifp->extra);
|
||||
if (ifp->endpoint) {
|
||||
uint8_t j;
|
||||
|
||||
for (j = 0; j < ifp->bNumEndpoints; j++)
|
||||
clear_endpoint((struct libusb_endpoint_descriptor *)
|
||||
ifp->endpoint + j);
|
||||
}
|
||||
free((void *)ifp->endpoint);
|
||||
}
|
||||
}
|
||||
free((void *)usb_interface->altsetting);
|
||||
usb_interface->altsetting = NULL;
|
||||
}
|
||||
|
||||
static int parse_interface(struct libusb_interface *usb_interface, const uint8_t *buffer, int size)
|
||||
{
|
||||
int len;
|
||||
int r;
|
||||
int parsed = 0;
|
||||
int interface_number = -1;
|
||||
const desc_header_t *header;
|
||||
const usb_intf_desc_t *if_desc;
|
||||
struct libusb_interface_descriptor *ifp;
|
||||
const uint8_t *begin;
|
||||
|
||||
while (size >= LIBUSB_DT_INTERFACE_SIZE) {
|
||||
struct libusb_interface_descriptor *altsetting;
|
||||
|
||||
altsetting = realloc((void *)usb_interface->altsetting,
|
||||
sizeof(*altsetting) * (size_t)(usb_interface->num_altsetting + 1));
|
||||
if (!altsetting) {
|
||||
r = LIBUSB_ERROR_NO_MEM;
|
||||
goto err;
|
||||
}
|
||||
usb_interface->altsetting = altsetting;
|
||||
|
||||
ifp = altsetting + usb_interface->num_altsetting;
|
||||
parse_descriptor(buffer, "bbbbbbbbb", ifp);
|
||||
if (ifp->bDescriptorType != LIBUSB_DT_INTERFACE) {
|
||||
ESP_LOGE(TAG, "unexpected descriptor 0x%x (expected 0x%x)",
|
||||
ifp->bDescriptorType, LIBUSB_DT_INTERFACE);
|
||||
return parsed;
|
||||
} else if (ifp->bLength < LIBUSB_DT_INTERFACE_SIZE) {
|
||||
ESP_LOGE(TAG, "invalid interface bLength (%u)",
|
||||
ifp->bLength);
|
||||
r = LIBUSB_ERROR_IO;
|
||||
goto err;
|
||||
} else if (ifp->bLength > size) {
|
||||
ESP_LOGW(TAG, "short intf descriptor read %d/%u",
|
||||
size, ifp->bLength);
|
||||
return parsed;
|
||||
} else if (ifp->bNumEndpoints > USB_MAXENDPOINTS) {
|
||||
ESP_LOGE(TAG, "too many endpoints (%u)", ifp->bNumEndpoints);
|
||||
r = LIBUSB_ERROR_IO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
usb_interface->num_altsetting++;
|
||||
ifp->extra = NULL;
|
||||
ifp->extra_length = 0;
|
||||
ifp->endpoint = NULL;
|
||||
|
||||
if (interface_number == -1) {
|
||||
interface_number = ifp->bInterfaceNumber;
|
||||
}
|
||||
|
||||
/* Skip over the interface */
|
||||
buffer += ifp->bLength;
|
||||
parsed += ifp->bLength;
|
||||
size -= ifp->bLength;
|
||||
|
||||
begin = buffer;
|
||||
|
||||
/* Skip over any interface, class or vendor descriptors */
|
||||
while (size >= DESC_HEADER_LENGTH) {
|
||||
header = (const desc_header_t *)buffer;
|
||||
if (header->bLength < DESC_HEADER_LENGTH) {
|
||||
ESP_LOGE(TAG, "invalid extra intf desc len (%u)", header->bLength);
|
||||
r = LIBUSB_ERROR_IO;
|
||||
goto err;
|
||||
} else if (header->bLength > size) {
|
||||
ESP_LOGW(TAG, "short extra intf desc read %d/%u", size, header->bLength);
|
||||
return parsed;
|
||||
}
|
||||
|
||||
/* If we find another "proper" descriptor then we're done */
|
||||
if (header->bDescriptorType == LIBUSB_DT_INTERFACE ||
|
||||
header->bDescriptorType == LIBUSB_DT_ENDPOINT ||
|
||||
header->bDescriptorType == LIBUSB_DT_CONFIG ||
|
||||
header->bDescriptorType == LIBUSB_DT_DEVICE) {
|
||||
break;
|
||||
}
|
||||
|
||||
buffer += header->bLength;
|
||||
parsed += header->bLength;
|
||||
size -= header->bLength;
|
||||
}
|
||||
|
||||
/* Copy any unknown descriptors into a storage area for */
|
||||
/* drivers to later parse */
|
||||
len = (int)(buffer - begin);
|
||||
if (len > 0) {
|
||||
void *extra = malloc((size_t)len);
|
||||
|
||||
if (!extra) {
|
||||
r = LIBUSB_ERROR_NO_MEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy(extra, begin, len);
|
||||
ifp->extra = extra;
|
||||
ifp->extra_length = len;
|
||||
}
|
||||
|
||||
if (ifp->bNumEndpoints > 0) {
|
||||
struct libusb_endpoint_descriptor *endpoint;
|
||||
uint8_t i;
|
||||
|
||||
endpoint = calloc(ifp->bNumEndpoints, sizeof(*endpoint));
|
||||
if (!endpoint) {
|
||||
r = LIBUSB_ERROR_NO_MEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ifp->endpoint = endpoint;
|
||||
for (i = 0; i < ifp->bNumEndpoints; i++) {
|
||||
r = parse_endpoint(endpoint + i, buffer, size);
|
||||
if (r < 0) {
|
||||
goto err;
|
||||
}
|
||||
if (r == 0) {
|
||||
ifp->bNumEndpoints = i;
|
||||
break;
|
||||
}
|
||||
|
||||
buffer += r;
|
||||
parsed += r;
|
||||
size -= r;
|
||||
}
|
||||
}
|
||||
|
||||
/* We check to see if it's an alternate to this one */
|
||||
if_desc = (const usb_intf_desc_t *)buffer;
|
||||
if (size < LIBUSB_DT_INTERFACE_SIZE ||
|
||||
if_desc->bDescriptorType != LIBUSB_DT_INTERFACE ||
|
||||
if_desc->bInterfaceNumber != interface_number) {
|
||||
return parsed;
|
||||
}
|
||||
}
|
||||
|
||||
return parsed;
|
||||
err:
|
||||
clear_interface(usb_interface);
|
||||
return r;
|
||||
}
|
||||
|
||||
void libusb_clear_config_descriptor(struct libusb_config_descriptor *config)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
if (config->interface) {
|
||||
for (i = 0; i < config->bNumInterfaces; i++) {
|
||||
clear_interface((struct libusb_interface *) config->interface + i);
|
||||
}
|
||||
}
|
||||
free((void *)config->interface);
|
||||
free((void *)config->extra);
|
||||
}
|
||||
|
||||
int libusb_parse_configuration(struct libusb_config_descriptor *config, const uint8_t *buffer, int size)
|
||||
{
|
||||
uint8_t i;
|
||||
int r;
|
||||
const desc_header_t *header;
|
||||
struct libusb_interface *usb_interface;
|
||||
|
||||
if (size < LIBUSB_DT_CONFIG_SIZE) {
|
||||
ESP_LOGE(TAG, "short config descriptor read %d/%d",
|
||||
size, LIBUSB_DT_CONFIG_SIZE);
|
||||
return LIBUSB_ERROR_IO;
|
||||
}
|
||||
|
||||
parse_descriptor(buffer, "bbwbbbbb", config);
|
||||
if (config->bDescriptorType != LIBUSB_DT_CONFIG) {
|
||||
ESP_LOGE(TAG, "unexpected descriptor 0x%x (expected 0x%x)",
|
||||
config->bDescriptorType, LIBUSB_DT_CONFIG);
|
||||
return LIBUSB_ERROR_IO;
|
||||
} else if (config->bLength < LIBUSB_DT_CONFIG_SIZE) {
|
||||
ESP_LOGE(TAG, "invalid config bLength (%u)", config->bLength);
|
||||
return LIBUSB_ERROR_IO;
|
||||
} else if (config->bLength > size) {
|
||||
ESP_LOGE(TAG, "short config descriptor read %d/%u",
|
||||
size, config->bLength);
|
||||
return LIBUSB_ERROR_IO;
|
||||
} else if (config->bNumInterfaces > USB_MAXINTERFACES) {
|
||||
ESP_LOGE(TAG, "too many interfaces (%u)", config->bNumInterfaces);
|
||||
return LIBUSB_ERROR_IO;
|
||||
}
|
||||
|
||||
usb_interface = calloc(config->bNumInterfaces, sizeof(*usb_interface));
|
||||
if (!usb_interface) {
|
||||
return LIBUSB_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
config->interface = usb_interface;
|
||||
|
||||
buffer += config->bLength;
|
||||
size -= config->bLength;
|
||||
|
||||
for (i = 0; i < config->bNumInterfaces; i++) {
|
||||
int len;
|
||||
const uint8_t *begin;
|
||||
|
||||
/* Skip over the rest of the Class Specific or Vendor */
|
||||
/* Specific descriptors */
|
||||
begin = buffer;
|
||||
while (size >= DESC_HEADER_LENGTH) {
|
||||
header = (const desc_header_t *)buffer;
|
||||
if (header->bLength < DESC_HEADER_LENGTH) {
|
||||
ESP_LOGE(TAG, "invalid extra config desc len (%u)", header->bLength);
|
||||
r = LIBUSB_ERROR_IO;
|
||||
goto err;
|
||||
} else if (header->bLength > size) {
|
||||
ESP_LOGW(TAG, "short extra config desc read %d/%u", size, header->bLength);
|
||||
config->bNumInterfaces = i;
|
||||
return size;
|
||||
}
|
||||
|
||||
/* If we find another "proper" descriptor then we're done */
|
||||
if (header->bDescriptorType == LIBUSB_DT_ENDPOINT ||
|
||||
header->bDescriptorType == LIBUSB_DT_INTERFACE ||
|
||||
header->bDescriptorType == LIBUSB_DT_CONFIG ||
|
||||
header->bDescriptorType == LIBUSB_DT_DEVICE) {
|
||||
break;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "skipping descriptor 0x%x", header->bDescriptorType);
|
||||
buffer += header->bLength;
|
||||
size -= header->bLength;
|
||||
}
|
||||
|
||||
/* Copy any unknown descriptors into a storage area for */
|
||||
/* drivers to later parse */
|
||||
len = (int)(buffer - begin);
|
||||
if (len > 0) {
|
||||
uint8_t *extra = realloc((void *)config->extra,
|
||||
(size_t)(config->extra_length + len));
|
||||
|
||||
if (!extra) {
|
||||
r = LIBUSB_ERROR_NO_MEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy(extra + config->extra_length, begin, len);
|
||||
config->extra = extra;
|
||||
config->extra_length += len;
|
||||
}
|
||||
|
||||
r = parse_interface(usb_interface + i, buffer, size);
|
||||
if (r < 0) {
|
||||
goto err;
|
||||
}
|
||||
if (r == 0) {
|
||||
config->bNumInterfaces = i;
|
||||
break;
|
||||
}
|
||||
|
||||
buffer += r;
|
||||
size -= r;
|
||||
}
|
||||
|
||||
return size;
|
||||
|
||||
err:
|
||||
libusb_clear_config_descriptor(config);
|
||||
return r;
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*/
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
#if SOC_USB_OTG_SUPPORTED
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "esp_system.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "esp_private/usb_phy.h"
|
||||
#include "usb/usb_host.h"
|
||||
#include "unity.h"
|
||||
|
||||
#include "libusb.h"
|
||||
#include "descriptor.h"
|
||||
|
||||
#define TAG "UVC_TEST"
|
||||
#define COMPARE_DESCRIPTORS(array) compare_descriptors(array, sizeof(array)/sizeof(array[0]), #array)
|
||||
|
||||
int libusb_parse_configuration(struct libusb_config_descriptor *config, const uint8_t *buffer, int size);
|
||||
void libusb_clear_config_descriptor(struct libusb_config_descriptor *config);
|
||||
|
||||
const uint8_t CANYON_CNE_CWC2[] = {
|
||||
0x09, 0x02, 0x7d, 0x02, 0x04, 0x01, 0x00, 0x80, 0xfa, 0x08, 0x0b, 0x00, 0x02, 0x0e, 0x03, 0x00,
|
||||
0x05, 0x09, 0x04, 0x00, 0x00, 0x01, 0x0e, 0x01, 0x00, 0x05, 0x0d, 0x24, 0x01, 0x00, 0x01, 0x4d,
|
||||
0x00, 0xc0, 0xe1, 0xe4, 0x00, 0x01, 0x01, 0x09, 0x24, 0x03, 0x02, 0x01, 0x01, 0x00, 0x04, 0x00,
|
||||
0x1a, 0x24, 0x06, 0x04, 0x70, 0x33, 0xf0, 0x28, 0x11, 0x63, 0x2e, 0x4a, 0xba, 0x2c, 0x68, 0x90,
|
||||
0xeb, 0x33, 0x40, 0x16, 0x08, 0x01, 0x03, 0x01, 0x0f, 0x00, 0x12, 0x24, 0x02, 0x01, 0x01, 0x02,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0e, 0x20, 0x00, 0x0b, 0x24, 0x05, 0x03,
|
||||
0x01, 0x00, 0x00, 0x02, 0x3f, 0x04, 0x00, 0x07, 0x05, 0x83, 0x03, 0x10, 0x00, 0x06, 0x05, 0x25,
|
||||
0x03, 0x10, 0x00, 0x09, 0x04, 0x01, 0x00, 0x00, 0x0e, 0x02, 0x00, 0x05, 0x0e, 0x24, 0x01, 0x01,
|
||||
0x33, 0x01, 0x81, 0x00, 0x02, 0x02, 0x01, 0x01, 0x01, 0x00, 0x0b, 0x24, 0x06, 0x01, 0x05, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x32, 0x24, 0x07, 0x01, 0x00, 0x80, 0x02, 0xe0, 0x01, 0x00, 0x00,
|
||||
0x77, 0x01, 0x00, 0x00, 0xca, 0x08, 0x00, 0x60, 0x09, 0x00, 0x15, 0x16, 0x05, 0x00, 0x06, 0x15,
|
||||
0x16, 0x05, 0x00, 0x80, 0x1a, 0x06, 0x00, 0x20, 0xa1, 0x07, 0x00, 0x2a, 0x2c, 0x0a, 0x00, 0x40,
|
||||
0x42, 0x0f, 0x00, 0x80, 0x84, 0x1e, 0x00, 0x32, 0x24, 0x07, 0x02, 0x00, 0x60, 0x01, 0x20, 0x01,
|
||||
0x00, 0xc0, 0x7b, 0x00, 0x00, 0x80, 0xe6, 0x02, 0x00, 0x18, 0x03, 0x00, 0x15, 0x16, 0x05, 0x00,
|
||||
0x06, 0x15, 0x16, 0x05, 0x00, 0x80, 0x1a, 0x06, 0x00, 0x20, 0xa1, 0x07, 0x00, 0x2a, 0x2c, 0x0a,
|
||||
0x00, 0x40, 0x42, 0x0f, 0x00, 0x80, 0x84, 0x1e, 0x00, 0x32, 0x24, 0x07, 0x03, 0x00, 0x40, 0x01,
|
||||
0xf0, 0x00, 0x00, 0xc0, 0x5d, 0x00, 0x00, 0x80, 0x32, 0x02, 0x00, 0x58, 0x02, 0x00, 0x15, 0x16,
|
||||
0x05, 0x00, 0x06, 0x15, 0x16, 0x05, 0x00, 0x80, 0x1a, 0x06, 0x00, 0x20, 0xa1, 0x07, 0x00, 0x2a,
|
||||
0x2c, 0x0a, 0x00, 0x40, 0x42, 0x0f, 0x00, 0x80, 0x84, 0x1e, 0x00, 0x32, 0x24, 0x07, 0x04, 0x00,
|
||||
0xb0, 0x00, 0x90, 0x00, 0x00, 0xf0, 0x1e, 0x00, 0x00, 0xa0, 0xb9, 0x00, 0x00, 0xc6, 0x00, 0x00,
|
||||
0x15, 0x16, 0x05, 0x00, 0x06, 0x15, 0x16, 0x05, 0x00, 0x80, 0x1a, 0x06, 0x00, 0x20, 0xa1, 0x07,
|
||||
0x00, 0x2a, 0x2c, 0x0a, 0x00, 0x40, 0x42, 0x0f, 0x00, 0x80, 0x84, 0x1e, 0x00, 0x32, 0x24, 0x07,
|
||||
0x05, 0x00, 0xa0, 0x00, 0x78, 0x00, 0x00, 0x70, 0x17, 0x00, 0x00, 0xa0, 0x8c, 0x00, 0x00, 0x96,
|
||||
0x00, 0x00, 0x15, 0x16, 0x05, 0x00, 0x06, 0x15, 0x16, 0x05, 0x00, 0x80, 0x1a, 0x06, 0x00, 0x20,
|
||||
0xa1, 0x07, 0x00, 0x2a, 0x2c, 0x0a, 0x00, 0x40, 0x42, 0x0f, 0x00, 0x80, 0x84, 0x1e, 0x00, 0x1a,
|
||||
0x24, 0x03, 0x00, 0x05, 0x80, 0x02, 0xe0, 0x01, 0x60, 0x01, 0x20, 0x01, 0x40, 0x01, 0xf0, 0x00,
|
||||
0xb0, 0x00, 0x90, 0x00, 0xa0, 0x00, 0x78, 0x00, 0x00, 0x06, 0x24, 0x0d, 0x01, 0x01, 0x04, 0x09,
|
||||
0x04, 0x01, 0x01, 0x01, 0x0e, 0x02, 0x00, 0x00, 0x07, 0x05, 0x81, 0x05, 0x80, 0x00, 0x01, 0x09,
|
||||
0x04, 0x01, 0x02, 0x01, 0x0e, 0x02, 0x00, 0x00, 0x07, 0x05, 0x81, 0x05, 0x00, 0x01, 0x01, 0x09,
|
||||
0x04, 0x01, 0x03, 0x01, 0x0e, 0x02, 0x00, 0x00, 0x07, 0x05, 0x81, 0x05, 0x00, 0x02, 0x01, 0x09,
|
||||
0x04, 0x01, 0x04, 0x01, 0x0e, 0x02, 0x00, 0x00, 0x07, 0x05, 0x81, 0x05, 0x58, 0x02, 0x01, 0x09,
|
||||
0x04, 0x01, 0x05, 0x01, 0x0e, 0x02, 0x00, 0x00, 0x07, 0x05, 0x81, 0x05, 0x20, 0x03, 0x01, 0x09,
|
||||
0x04, 0x01, 0x06, 0x01, 0x0e, 0x02, 0x00, 0x00, 0x07, 0x05, 0x81, 0x05, 0xbc, 0x03, 0x01, 0x08,
|
||||
0x0b, 0x02, 0x02, 0x01, 0x00, 0x00, 0x04, 0x09, 0x04, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x04,
|
||||
0x09, 0x24, 0x01, 0x00, 0x01, 0x29, 0x00, 0x01, 0x03, 0x0c, 0x24, 0x02, 0x01, 0x01, 0x02, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x24, 0x06, 0x02, 0x01, 0x02, 0x01, 0x00, 0x02, 0x00, 0x00,
|
||||
0x09, 0x24, 0x03, 0x03, 0x01, 0x01, 0x00, 0x02, 0x00, 0x09, 0x04, 0x03, 0x00, 0x00, 0x01, 0x02,
|
||||
0x00, 0x00, 0x09, 0x04, 0x03, 0x01, 0x01, 0x01, 0x02, 0x00, 0x00, 0x07, 0x24, 0x01, 0x03, 0x01,
|
||||
0x01, 0x00, 0x0b, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x01, 0x80, 0x3e, 0x00, 0x09, 0x05, 0x84,
|
||||
0x05, 0x20, 0x00, 0x04, 0x00, 0x00, 0x07, 0x25, 0x01, 0x01, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const uint8_t Logitech_C980[] = {
|
||||
0x09, 0x02, 0x5a, 0x03, 0x05, 0x01, 0x00, 0x80, 0xfa, 0x08, 0x0b, 0x00, 0x02, 0x0e, 0x03, 0x00,
|
||||
0x00, 0x09, 0x04, 0x00, 0x00, 0x01, 0x0e, 0x01, 0x00, 0x00, 0x0d, 0x24, 0x01, 0x00, 0x01, 0xd8,
|
||||
0x00, 0x80, 0xc3, 0xc9, 0x01, 0x01, 0x01, 0x12, 0x24, 0x02, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x2e, 0x2a, 0x02, 0x0b, 0x24, 0x05, 0x03, 0x01, 0x00, 0x40,
|
||||
0x02, 0x5b, 0x17, 0x00, 0x1b, 0x24, 0x06, 0x0e, 0x6a, 0xd1, 0x49, 0x2c, 0xb8, 0x32, 0x85, 0x44,
|
||||
0x3e, 0xa8, 0x64, 0x3a, 0x15, 0x23, 0x62, 0xf2, 0x06, 0x01, 0x03, 0x02, 0x3f, 0x00, 0x00, 0x1b,
|
||||
0x24, 0x06, 0x06, 0xd0, 0x9e, 0xe4, 0x23, 0x78, 0x11, 0x31, 0x4f, 0xae, 0x52, 0xd2, 0xfb, 0x8a,
|
||||
0x8d, 0x3b, 0x48, 0x0e, 0x01, 0x03, 0x02, 0xff, 0x6f, 0x00, 0x1b, 0x24, 0x06, 0x08, 0xe4, 0x8e,
|
||||
0x67, 0x69, 0x0f, 0x41, 0xdb, 0x40, 0xa8, 0x50, 0x74, 0x20, 0xd7, 0xd8, 0x24, 0x0e, 0x08, 0x01,
|
||||
0x03, 0x02, 0x3f, 0x0f, 0x00, 0x1c, 0x24, 0x06, 0x09, 0xa9, 0x4c, 0x5d, 0x1f, 0x11, 0xde, 0x87,
|
||||
0x44, 0x84, 0x0d, 0x50, 0x93, 0x3c, 0x8e, 0xc8, 0xd1, 0x12, 0x01, 0x03, 0x03, 0xff, 0xff, 0x03,
|
||||
0x00, 0x1c, 0x24, 0x06, 0x0a, 0x15, 0x02, 0xe4, 0x49, 0x34, 0xf4, 0xfe, 0x47, 0xb1, 0x58, 0x0e,
|
||||
0x88, 0x50, 0x23, 0xe5, 0x1b, 0x0b, 0x01, 0x03, 0x03, 0xfa, 0xff, 0x01, 0x00, 0x1c, 0x24, 0x06,
|
||||
0x0b, 0x21, 0x2d, 0xe5, 0xff, 0x30, 0x80, 0x2c, 0x4e, 0x82, 0xd9, 0xf5, 0x87, 0xd0, 0x05, 0x40,
|
||||
0xbd, 0x04, 0x01, 0x03, 0x03, 0x00, 0x41, 0x01, 0x00, 0x09, 0x24, 0x03, 0x04, 0x01, 0x01, 0x00,
|
||||
0x03, 0x00, 0x07, 0x05, 0x85, 0x03, 0x40, 0x00, 0x10, 0x05, 0x25, 0x03, 0x40, 0x00, 0x09, 0x04,
|
||||
0x01, 0x00, 0x00, 0x0e, 0x02, 0x00, 0x00, 0x0f, 0x24, 0x01, 0x02, 0x79, 0x01, 0x81, 0x00, 0x04,
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x1b, 0x24, 0x04, 0x01, 0x01, 0x59, 0x55, 0x59, 0x32, 0x00,
|
||||
0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71, 0x10, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x2a, 0x24, 0x05, 0x01, 0x00, 0xb0, 0x00, 0x90, 0x00, 0x00, 0xf0, 0x1e, 0x00, 0x00, 0xd0,
|
||||
0x5c, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x2a, 0x2c, 0x0a, 0x00, 0x04, 0x2a, 0x2c, 0x0a, 0x00, 0x40,
|
||||
0x42, 0x0f, 0x00, 0x55, 0x58, 0x14, 0x00, 0x80, 0x84, 0x1e, 0x00, 0x06, 0x24, 0x0d, 0x01, 0x01,
|
||||
0x04, 0x0b, 0x24, 0x06, 0x02, 0x05, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x36, 0x24, 0x07, 0x01,
|
||||
0x00, 0x80, 0x02, 0xe0, 0x01, 0x00, 0x00, 0x77, 0x01, 0x00, 0x00, 0xca, 0x08, 0x00, 0x60, 0x09,
|
||||
0x00, 0x15, 0x16, 0x05, 0x00, 0x07, 0x15, 0x16, 0x05, 0x00, 0x9a, 0x5b, 0x06, 0x00, 0x20, 0xa1,
|
||||
0x07, 0x00, 0x2a, 0x2c, 0x0a, 0x00, 0x40, 0x42, 0x0f, 0x00, 0x55, 0x58, 0x14, 0x00, 0x80, 0x84,
|
||||
0x1e, 0x00, 0x36, 0x24, 0x07, 0x02, 0x00, 0xb0, 0x00, 0x90, 0x00, 0x00, 0xf0, 0x1e, 0x00, 0x00,
|
||||
0xa0, 0xb9, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x15, 0x16, 0x05, 0x00, 0x07, 0x15, 0x16, 0x05, 0x00,
|
||||
0x9a, 0x5b, 0x06, 0x00, 0x20, 0xa1, 0x07, 0x00, 0x2a, 0x2c, 0x0a, 0x00, 0x40, 0x42, 0x0f, 0x00,
|
||||
0x55, 0x58, 0x14, 0x00, 0x80, 0x84, 0x1e, 0x00, 0x36, 0x24, 0x07, 0x03, 0x00, 0x40, 0x01, 0xf0,
|
||||
0x00, 0x00, 0xc0, 0x5d, 0x00, 0x00, 0x80, 0x32, 0x02, 0x00, 0x58, 0x02, 0x00, 0x15, 0x16, 0x05,
|
||||
0x00, 0x07, 0x15, 0x16, 0x05, 0x00, 0x9a, 0x5b, 0x06, 0x00, 0x20, 0xa1, 0x07, 0x00, 0x2a, 0x2c,
|
||||
0x0a, 0x00, 0x40, 0x42, 0x0f, 0x00, 0x55, 0x58, 0x14, 0x00, 0x80, 0x84, 0x1e, 0x00, 0x36, 0x24,
|
||||
0x07, 0x04, 0x00, 0xa8, 0x01, 0xf0, 0x00, 0x00, 0x38, 0x7c, 0x00, 0x00, 0x50, 0xe9, 0x02, 0x00,
|
||||
0x1b, 0x03, 0x00, 0x15, 0x16, 0x05, 0x00, 0x07, 0x15, 0x16, 0x05, 0x00, 0x9a, 0x5b, 0x06, 0x00,
|
||||
0x20, 0xa1, 0x07, 0x00, 0x2a, 0x2c, 0x0a, 0x00, 0x40, 0x42, 0x0f, 0x00, 0x55, 0x58, 0x14, 0x00,
|
||||
0x80, 0x84, 0x1e, 0x00, 0x36, 0x24, 0x07, 0x05, 0x00, 0x80, 0x02, 0x68, 0x01, 0x00, 0x40, 0x19,
|
||||
0x01, 0x00, 0x80, 0x97, 0x06, 0x00, 0x08, 0x07, 0x00, 0x15, 0x16, 0x05, 0x00, 0x07, 0x15, 0x16,
|
||||
0x05, 0x00, 0x9a, 0x5b, 0x06, 0x00, 0x20, 0xa1, 0x07, 0x00, 0x2a, 0x2c, 0x0a, 0x00, 0x40, 0x42,
|
||||
0x0f, 0x00, 0x55, 0x58, 0x14, 0x00, 0x80, 0x84, 0x1e, 0x00, 0x06, 0x24, 0x0d, 0x01, 0x01, 0x04,
|
||||
0x09, 0x04, 0x01, 0x01, 0x01, 0x0e, 0x02, 0x00, 0x00, 0x07, 0x05, 0x81, 0x05, 0xc0, 0x00, 0x01,
|
||||
0x09, 0x04, 0x01, 0x02, 0x01, 0x0e, 0x02, 0x00, 0x00, 0x07, 0x05, 0x81, 0x05, 0x80, 0x01, 0x01,
|
||||
0x09, 0x04, 0x01, 0x03, 0x01, 0x0e, 0x02, 0x00, 0x00, 0x07, 0x05, 0x81, 0x05, 0x00, 0x02, 0x01,
|
||||
0x09, 0x04, 0x01, 0x04, 0x01, 0x0e, 0x02, 0x00, 0x00, 0x07, 0x05, 0x81, 0x05, 0x80, 0x02, 0x01,
|
||||
0x09, 0x04, 0x01, 0x05, 0x01, 0x0e, 0x02, 0x00, 0x00, 0x07, 0x05, 0x81, 0x05, 0x20, 0x03, 0x01,
|
||||
0x08, 0x0b, 0x02, 0x02, 0x01, 0x02, 0x00, 0x00, 0x09, 0x04, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00,
|
||||
0x00, 0x09, 0x24, 0x01, 0x00, 0x01, 0x26, 0x00, 0x01, 0x03, 0x0c, 0x24, 0x02, 0x01, 0x01, 0x02,
|
||||
0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x09, 0x24, 0x03, 0x03, 0x01, 0x01, 0x00, 0x05, 0x00, 0x08,
|
||||
0x24, 0x06, 0x05, 0x01, 0x01, 0x03, 0x00, 0x09, 0x04, 0x03, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
|
||||
0x09, 0x04, 0x03, 0x01, 0x01, 0x01, 0x02, 0x00, 0x00, 0x07, 0x24, 0x01, 0x03, 0x01, 0x01, 0x00,
|
||||
0x0b, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01, 0x80, 0x3e, 0x00, 0x09, 0x05, 0x84, 0x05, 0x44,
|
||||
0x00, 0x04, 0x00, 0x00, 0x07, 0x25, 0x01, 0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x04, 0x00, 0x01,
|
||||
0x03, 0x00, 0x00, 0x00, 0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x6c, 0x00, 0x07, 0x05, 0x87,
|
||||
0x03, 0x02, 0x00, 0x06, 0x06, 0x30, 0x00, 0x00, 0x02, 0x00
|
||||
};
|
||||
|
||||
const uint8_t unknown_camera[] = {
|
||||
0x09, 0x02, 0x69, 0x01, 0x02, 0x01, 0x00, 0x80, 0xfa, 0x08, 0x0b, 0x00, 0x02, 0x0e, 0x03, 0x00,
|
||||
0x05, 0x09, 0x04, 0x00, 0x00, 0x01, 0x0e, 0x01, 0x00, 0x05, 0x0d, 0x24, 0x01, 0x00, 0x01, 0x4d,
|
||||
0x00, 0xc0, 0xe1, 0xe4, 0x00, 0x01, 0x01, 0x09, 0x24, 0x03, 0x05, 0x01, 0x01, 0x00, 0x03, 0x00,
|
||||
0x1a, 0x24, 0x06, 0x03, 0x70, 0x33, 0xf0, 0x28, 0x11, 0x63, 0x2e, 0x4a, 0xba, 0x2c, 0x68, 0x90,
|
||||
0xeb, 0x33, 0x40, 0x16, 0x08, 0x01, 0x02, 0x01, 0x1f, 0x00, 0x12, 0x24, 0x02, 0x01, 0x01, 0x02,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0e, 0x00, 0x00, 0x0b, 0x24, 0x05, 0x02,
|
||||
0x01, 0x00, 0x00, 0x02, 0x7f, 0x17, 0x00, 0x07, 0x05, 0x83, 0x03, 0x10, 0x00, 0x06, 0x05, 0x25,
|
||||
0x03, 0x10, 0x00, 0x09, 0x04, 0x01, 0x00, 0x00, 0x0e, 0x02, 0x00, 0x05, 0x0f, 0x24, 0x01, 0x02,
|
||||
0x8d, 0x00, 0x81, 0x00, 0x05, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x0b, 0x24, 0x06, 0x01, 0x01,
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x24, 0x07, 0x01, 0x00, 0x40, 0x01, 0xf0, 0x00, 0x08,
|
||||
0x3c, 0x2f, 0x00, 0x30, 0x68, 0x1b, 0x01, 0x4d, 0x2e, 0x01, 0x00, 0x15, 0x16, 0x05, 0x00, 0x05,
|
||||
0x15, 0x16, 0x05, 0x00, 0x20, 0xa1, 0x07, 0x00, 0x2a, 0x2c, 0x0a, 0x00, 0x40, 0x42, 0x0f, 0x00,
|
||||
0x80, 0x84, 0x1e, 0x00, 0x06, 0x24, 0x0d, 0x01, 0x01, 0x04, 0x1b, 0x24, 0x04, 0x02, 0x01, 0x59,
|
||||
0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71, 0x10,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x24, 0x05, 0x01, 0x00, 0x40, 0x01, 0xf0, 0x00, 0x00, 0xc0,
|
||||
0x5d, 0x00, 0x00, 0xc0, 0x5d, 0x00, 0x00, 0x58, 0x02, 0x00, 0x80, 0x84, 0x1e, 0x00, 0x01, 0x80,
|
||||
0x84, 0x1e, 0x00, 0x06, 0x24, 0x0d, 0x01, 0x01, 0x04, 0x09, 0x04, 0x01, 0x01, 0x01, 0x0e, 0x02,
|
||||
0x00, 0x00, 0x07, 0x05, 0x81, 0x05, 0x80, 0x00, 0x01, 0x09, 0x04, 0x01, 0x02, 0x01, 0x0e, 0x02,
|
||||
0x00, 0x00, 0x07, 0x05, 0x81, 0x05, 0x00, 0x01, 0x01, 0x09, 0x04, 0x01, 0x03, 0x01, 0x0e, 0x02,
|
||||
0x00, 0x00, 0x07, 0x05, 0x81, 0x05, 0x00, 0x02, 0x01, 0x09, 0x04, 0x01, 0x04, 0x01, 0x0e, 0x02,
|
||||
0x00, 0x00, 0x07, 0x05, 0x81, 0x05, 0x58, 0x02, 0x01, 0x09, 0x04, 0x01, 0x05, 0x01, 0x0e, 0x02,
|
||||
0x00, 0x00, 0x07, 0x05, 0x81, 0x05, 0x20, 0x03, 0x01, 0x09, 0x04, 0x01, 0x06, 0x01, 0x0e, 0x02,
|
||||
0x00, 0x00, 0x07, 0x05, 0x81, 0x05, 0xbc, 0x03, 0x01
|
||||
};
|
||||
|
||||
static void compare_descriptors(const uint8_t *config_desc, size_t size, const char *camera_name)
|
||||
{
|
||||
ESP_LOGI(TAG, "Comparing descriptrors for %s camera", camera_name);
|
||||
|
||||
struct libusb_config_descriptor *libusb_config = calloc(1, sizeof(struct libusb_config_descriptor));
|
||||
struct libusb_config_descriptor *config = NULL;
|
||||
|
||||
TEST_ASSERT_NOT_NULL( libusb_config );
|
||||
TEST_ASSERT_EQUAL( libusb_parse_configuration(libusb_config, config_desc, size), LIBUSB_SUCCESS );
|
||||
TEST_ASSERT_EQUAL( raw_desc_to_libusb_config(config_desc, size, &config), LIBUSB_SUCCESS );
|
||||
|
||||
TEST_ASSERT_EQUAL( memcmp(libusb_config, config, LIBUSB_DT_CONFIG_SIZE), 0);
|
||||
TEST_ASSERT_NOT_NULL( libusb_config->interface );
|
||||
TEST_ASSERT_NOT_NULL( config->interface );
|
||||
|
||||
TEST_ASSERT_EQUAL( libusb_config->extra_length, config->extra_length );
|
||||
TEST_ASSERT_EQUAL( memcmp(libusb_config->extra, config->extra, config->extra_length), 0);
|
||||
|
||||
TEST_ASSERT_EQUAL( libusb_config->bNumInterfaces, config->bNumInterfaces );
|
||||
|
||||
printf("checking...\n");
|
||||
|
||||
for (int i = 0; i < libusb_config->bNumInterfaces; i++) {
|
||||
printf("interface %u\n", i);
|
||||
libusb_interface_t *ifc = &libusb_config->interface[i];
|
||||
libusb_interface_t *my_ifc = &config->interface[i];
|
||||
TEST_ASSERT_EQUAL( ifc->num_altsetting, my_ifc->num_altsetting );
|
||||
|
||||
for (int j = 0; j < ifc->num_altsetting; j++) {
|
||||
printf(" altsetting %u\n", j);
|
||||
libusb_interface_descriptor_t *libusb_alt = &ifc->altsetting[j];
|
||||
libusb_interface_descriptor_t *alt = &my_ifc->altsetting[j];
|
||||
TEST_ASSERT_EQUAL( memcmp(libusb_alt, alt, LIBUSB_DT_INTERFACE_SIZE), 0);
|
||||
TEST_ASSERT_EQUAL( libusb_alt->extra_length, alt->extra_length );
|
||||
TEST_ASSERT_EQUAL( memcmp(libusb_alt->extra, alt->extra, alt->extra_length), 0);
|
||||
TEST_ASSERT_EQUAL( libusb_alt->bNumEndpoints, alt->bNumEndpoints );
|
||||
|
||||
for (int ep = 0; ep < libusb_alt->bNumEndpoints; ep++) {
|
||||
printf(" endpoint %u\n", ep);
|
||||
libusb_endpoint_descriptor_t *libusb_endpoint = &libusb_alt->endpoint[ep];
|
||||
libusb_endpoint_descriptor_t *endpoint = &alt->endpoint[ep];
|
||||
TEST_ASSERT_EQUAL( memcmp(libusb_endpoint, endpoint, LIBUSB_DT_ENDPOINT_SIZE), 0);
|
||||
TEST_ASSERT_EQUAL( libusb_endpoint->extra_length, endpoint->extra_length );
|
||||
TEST_ASSERT_EQUAL( memcmp(libusb_endpoint->extra, endpoint->extra, endpoint->extra_length), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
libusb_clear_config_descriptor(libusb_config);
|
||||
clear_config_descriptor(config);
|
||||
}
|
||||
|
||||
// Test compares config descriptor created by usb_host_uvc driver and originally used libusb function
|
||||
TEST_CASE("Compare config descriptor parser", "[usb_uvc]")
|
||||
{
|
||||
COMPARE_DESCRIPTORS(CANYON_CNE_CWC2);
|
||||
COMPARE_DESCRIPTORS(Logitech_C980);
|
||||
COMPARE_DESCRIPTORS(unknown_camera);
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue