Descriptor parser rewrite

This commit is contained in:
Martin Valik 2022-08-11 14:48:36 +02:00
parent 768f84b2a4
commit 783eaec80d
8 changed files with 839 additions and 414 deletions

View File

@ -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 }}

View File

@ -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")

View File

@ -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

View File

@ -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"

View File

@ -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;

View File

@ -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)

View File

@ -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;
}

View File

@ -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