From 8d6167a9ab80e661f9393e9d57ad2d6f330df3f3 Mon Sep 17 00:00:00 2001 From: Roman Leonov Date: Thu, 19 Oct 2023 09:58:52 +0200 Subject: [PATCH 1/4] feat(docs): added USB Host Stack Configuration description --- docs/_static/usb_host/poweron-timings.png | Bin 0 -> 39711 bytes .../en/api-reference/peripherals/usb_host.rst | 41 ++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 docs/_static/usb_host/poweron-timings.png diff --git a/docs/_static/usb_host/poweron-timings.png b/docs/_static/usb_host/poweron-timings.png new file mode 100644 index 0000000000000000000000000000000000000000..867253da18d734fef4d86af9f0628431169986df GIT binary patch literal 39711 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 F0RZNjWkUb} literal 0 HcmV?d00001 diff --git a/docs/en/api-reference/peripherals/usb_host.rst b/docs/en/api-reference/peripherals/usb_host.rst index 2f0756b43f..5007bea0e3 100644 --- a/docs/en/api-reference/peripherals/usb_host.rst +++ b/docs/en/api-reference/peripherals/usb_host.rst @@ -390,6 +390,47 @@ UVC * A host class driver for the USB Video Device Class is distributed as a managed component via the `ESP-IDF Component Registry `__. * The :example:`peripherals/usb/host/uvc` example demonstrates the usage of the UVC host driver to receive a video stream from a USB camera and optionally forward that stream over Wi-Fi. +.. ---------------------------------------------- USB Host Menuconfig -------------------------------------------------- + +Host Stack Configuration +------------------------ + +Non-Compliant Device Support +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To support USB devices that are non-compliant in various scenarios or exhibit specific behaviors it is possible to configure the USB Host stack. + +As a USB device may be hot-plugged, it is essential to have the configurable delays between power switching and device attachment, and when the device's internal power has stabilized. + +Enumeration Configuration +""""""""""""""""""""""""" + +During the process of enumerating connected USB devices, several timeout values ensure the proper functioning of the device. + +.. figure:: ../../../_static/usb_host/poweron-timings.png + :align: center + :alt: USB Root Hub Power-on and Connection Events Timing + :figclass: align-center + + USB Root Hub Power-on and Connection Events Timing + +The figure above shows all the timeouts associated with both turning on port power with a device connected and hot-plugging a device. + +* After a port is reset or resumed, the USB System Software is expected to provide a “recovery” interval of 10 ms before the device attached to the port is expected to respond to data transfers. +* After the reset/resume recovery interval, if a device receives a SetAddress() request, the device must be able to complete processing of the request and be able to successfully complete the Status stage of the request within 50 ms. +* After successful completion of the Status stage, the device is allowed a SetAddress() recovery interval of 2 ms. + +.. note:: + + For more details regarding connection event timings, please refer to the Universal Serial Bus 2.0 specification, chapter 7.1.7.3 "Connect and Disconnect Signaling". + +Configurable parameters of the USB host stack can be configured with multiple options via Menuconfig. + +* For Debounce delay refer to :ref:`CONFIG_USB_HOST_DEBOUNCE_DELAY_MS` +* For Reset hold interval refer to :ref:`CONFIG_USB_HOST_RESET_HOLD_MS` +* For Reset recovery interval refer to :ref:`CONFIG_USB_HOST_RESET_RECOVERY_MS` +* Fer SetAddress() recovery interval refer to: :ref:`CONFIG_USB_HOST_SET_ADDR_RECOVERY_MS` + .. -------------------------------------------------- API Reference ---------------------------------------------------- API Reference From 3e6adac5bfff96e2e4e226e1a6164d6cc5307d37 Mon Sep 17 00:00:00 2001 From: mofeifei Date: Thu, 9 Nov 2023 16:59:38 +0800 Subject: [PATCH 2/4] docs: update cn trans usb_host.rst --- .../en/api-reference/peripherals/usb_host.rst | 18 ++++---- .../api-reference/peripherals/usb_host.rst | 41 +++++++++++++++++++ 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/docs/en/api-reference/peripherals/usb_host.rst b/docs/en/api-reference/peripherals/usb_host.rst index 5007bea0e3..d9f5b555de 100644 --- a/docs/en/api-reference/peripherals/usb_host.rst +++ b/docs/en/api-reference/peripherals/usb_host.rst @@ -398,7 +398,7 @@ Host Stack Configuration Non-Compliant Device Support ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -To support USB devices that are non-compliant in various scenarios or exhibit specific behaviors it is possible to configure the USB Host stack. +To support USB devices that are non-compliant in various scenarios or exhibit specific behaviors, it is possible to configure the USB Host stack. As a USB device may be hot-plugged, it is essential to have the configurable delays between power switching and device attachment, and when the device's internal power has stabilized. @@ -416,20 +416,20 @@ During the process of enumerating connected USB devices, several timeout values The figure above shows all the timeouts associated with both turning on port power with a device connected and hot-plugging a device. -* After a port is reset or resumed, the USB System Software is expected to provide a “recovery” interval of 10 ms before the device attached to the port is expected to respond to data transfers. -* After the reset/resume recovery interval, if a device receives a SetAddress() request, the device must be able to complete processing of the request and be able to successfully complete the Status stage of the request within 50 ms. -* After successful completion of the Status stage, the device is allowed a SetAddress() recovery interval of 2 ms. +* After a port is reset or resumed, the USB system software is expected to provide a "recovery" interval of 10 ms before the device attached to the port is expected to respond to data transfers. +* After the reset/resume recovery interval, if a device receives a ``SetAddress()`` request, the device must be able to complete processing of the request and be able to successfully complete the Status stage of the request within 50 ms. +* After successful completion of the Status stage, the device is allowed a ``SetAddress()`` recovery interval of 2 ms. .. note:: - For more details regarding connection event timings, please refer to the Universal Serial Bus 2.0 specification, chapter 7.1.7.3 "Connect and Disconnect Signaling". + For more details regarding connection event timings, please refer to *Universal Serial Bus 2.0 Specification* > Chapter 7.1.7.3 *Connect and Disconnect Signaling*. Configurable parameters of the USB host stack can be configured with multiple options via Menuconfig. -* For Debounce delay refer to :ref:`CONFIG_USB_HOST_DEBOUNCE_DELAY_MS` -* For Reset hold interval refer to :ref:`CONFIG_USB_HOST_RESET_HOLD_MS` -* For Reset recovery interval refer to :ref:`CONFIG_USB_HOST_RESET_RECOVERY_MS` -* Fer SetAddress() recovery interval refer to: :ref:`CONFIG_USB_HOST_SET_ADDR_RECOVERY_MS` +* For debounce delay, refer to :ref:`CONFIG_USB_HOST_DEBOUNCE_DELAY_MS`. +* For reset hold interval, refer to :ref:`CONFIG_USB_HOST_RESET_HOLD_MS`. +* For reset recovery interval, refer to :ref:`CONFIG_USB_HOST_RESET_RECOVERY_MS`. +* Fer ``SetAddress()`` recovery interval, refer to :ref:`CONFIG_USB_HOST_SET_ADDR_RECOVERY_MS`. .. -------------------------------------------------- API Reference ---------------------------------------------------- diff --git a/docs/zh_CN/api-reference/peripherals/usb_host.rst b/docs/zh_CN/api-reference/peripherals/usb_host.rst index 1f0042a4f5..dc0881d227 100644 --- a/docs/zh_CN/api-reference/peripherals/usb_host.rst +++ b/docs/zh_CN/api-reference/peripherals/usb_host.rst @@ -390,6 +390,47 @@ UVC * USB 视频设备 Class 的主机 Class 驱动程序作为托管组件通过 `ESP-IDF 组件注册器 `__ 分发。 * 示例 :example:`peripherals/usb/host/uvc` 展示了如何使用 UVC 主机驱动程序接收来自 USB 摄像头的视频流,并可选择将该流通过 Wi-Fi 转发。 +.. ---------------------------------------------- USB Host Menuconfig -------------------------------------------------- + +主机栈配置 +---------- + +非兼容设备支持 +^^^^^^^^^^^^^^ + +为了支持在某些情况下非兼容或会表现出特定行为的 USB 设备,可以对 USB 主机栈进行配置。 + +USB 设备可能是热插拔的,因此必须配置电源开关和设备连接之间的延迟,以及设备内部电源稳定后的延迟。 + +枚举配置 +"""""""" + +在枚举已连接 USB 设备的过程中,一些超时值可确保设备正常运行。 + +.. figure:: ../../../_static/usb_host/poweron-timings.png + :align: center + :alt: USB 根集线器上电和连接事件时序 + :figclass: align-center + + USB 根集线器上电和连接事件时序 + +上图展示了与连接设备时开启端口电源和热插拔设备相关的所有超时值。 + +* 端口复位或恢复运行后,USB 系统软件应提供 10 毫秒的恢复时间,此后连接到端口的设备才会响应数据传输。 +* 恢复时间结束后,如果设备收到 ``SetAddress()`` 请求,设备必须能够完成对该请求的处理,并能在 50 毫秒内成功完成请求的状态 (Status) 阶段。 +* 状态阶段结束后,设备允许有 2 毫秒的 ``SetAddress()`` 恢复时间。 + +.. note:: + + 有关连接事件时序的更多信息,请参阅 *通用串行总线 2.0 规范* > 第 7.1.7.3 章 *连接和断开信令*。 + +可通过 Menuconfig 选项设置 USB 主机栈的可配置参数。 + +* :ref:`CONFIG_USB_HOST_DEBOUNCE_DELAY_MS` 用于配置防抖延迟。 +* :ref:`CONFIG_USB_HOST_RESET_HOLD_MS` 用于配置重置保持时间。 +* :ref:`CONFIG_USB_HOST_RESET_RECOVERY_MS` 用于配置重置恢复时间。 +* :ref:`CONFIG_USB_HOST_SET_ADDR_RECOVERY_MS` 用于配置 ``SetAddress()`` 恢复时间。 + .. -------------------------------------------------- API Reference ---------------------------------------------------- API 参考 From d786f187e9cff8a04b6f64420fcd1c21c3a2398c Mon Sep 17 00:00:00 2001 From: Peter Marcisovsky Date: Thu, 23 Nov 2023 16:00:13 +0100 Subject: [PATCH 3/4] feat(us/host): set device cfg during enumeration - user callback funciton to set device configuration as a part of usb_host_install - callback provides device descriptor of a device being enumerated - user can set which cfg descriptor the USB device will be set with - user can filter device enumeration - Kconfig menu to enable callback function - usb_host_lib example demonstration --- components/usb/Kconfig | 11 +++ components/usb/hub.c | 69 +++++++++++++++++-- components/usb/include/usb/usb_host.h | 4 +- components/usb/include/usb/usb_types_stack.h | 26 ++++++- components/usb/private_include/hub.h | 10 ++- components/usb/usb_host.c | 15 +++- .../host/cdc/cdc_acm_vcp/main/CMakeLists.txt | 2 + .../usb_host_lib/main/usb_host_lib_main.c | 38 +++++++++- 8 files changed, 163 insertions(+), 12 deletions(-) diff --git a/components/usb/Kconfig b/components/usb/Kconfig index 5e02abe0d8..e6a426924b 100644 --- a/components/usb/Kconfig +++ b/components/usb/Kconfig @@ -104,4 +104,15 @@ menu "USB-OTG" bool default y + config USB_HOST_ENABLE_ENUM_FILTER_CALLBACK + bool "Enable enumeration filter callback" + default n + help + The enumeration filter callback is called before enumeration of each newly attached device. This callback + allows users to control whether a device should be enumerated, and what configuration number to use when + enumerating a device. + + If enabled, the enumeration filter callback can be set via 'usb_host_config_t' when calling + 'usb_host_install()'. + endmenu #USB-OTG diff --git a/components/usb/hub.c b/components/usb/hub.c index 7f24a60a6d..a19cf063fd 100644 --- a/components/usb/hub.c +++ b/components/usb/hub.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -32,11 +32,15 @@ implement the bare minimum to control the root HCD port. #define HUB_ROOT_HCD_PORT_FIFO_BIAS HCD_PORT_FIFO_BIAS_BALANCED #endif +#ifdef CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK +#define ENABLE_ENUM_FILTER_CALLBACK +#endif // CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK + #define SET_ADDR_RECOVERY_INTERVAL_MS CONFIG_USB_HOST_SET_ADDR_RECOVERY_MS #define ENUM_CTRL_TRANSFER_MAX_DATA_LEN CONFIG_USB_HOST_CONTROL_TRANSFER_MAX_SIZE #define ENUM_DEV_ADDR 1 // Device address used in enumeration -#define ENUM_CONFIG_INDEX 0 // Index used to get the first configuration descriptor of the device +#define ENUM_CONFIG_INDEX_DEFAULT 0 // Index used to get the first configuration descriptor of the device #define ENUM_SHORT_DESC_REQ_LEN 8 // Number of bytes to request when getting a short descriptor (just enough to get bMaxPacketSize0 or wTotalLength) #define ENUM_WORST_CASE_MPS_LS 8 // The worst case MPS of EP0 for a LS device #define ENUM_WORST_CASE_MPS_FS 64 // The worst case MPS of EP0 for a FS device @@ -165,6 +169,11 @@ typedef struct { uint8_t iSerialNumber; /**< Index of the Serial Number string descriptor */ uint8_t str_desc_bLength; /**< Saved bLength from getting a short string descriptor */ uint8_t bConfigurationValue; /**< Device's current configuration number */ + uint8_t enum_config_index; /**< Configuration index used during enumeration */ +#ifdef ENABLE_ENUM_FILTER_CALLBACK + usb_host_enum_filter_cb_t enum_filter_cb; /**< Set device configuration callback */ + bool graceful_exit; /**< Exit enumeration by user's request from the callback function */ +#endif // ENABLE_ENUM_FILTER_CALLBACK } enum_ctrl_t; typedef struct { @@ -280,6 +289,11 @@ static bool enum_stage_start(enum_ctrl_t *enum_ctrl) ESP_ERROR_CHECK(hcd_pipe_update_callback(enum_dflt_pipe_hdl, enum_dflt_pipe_callback, NULL)); enum_ctrl->dev_hdl = enum_dev_hdl; enum_ctrl->pipe = enum_dflt_pipe_hdl; + + // Flag to gracefully exit the enumeration process if requested by the user in the enumeration filter cb +#ifdef ENABLE_ENUM_FILTER_CALLBACK + enum_ctrl->graceful_exit = false; +#endif // ENABLE_ENUM_FILTER_CALLBACK return true; } @@ -323,6 +337,39 @@ static void get_string_desc_index_and_langid(enum_ctrl_t *enum_ctrl, uint8_t *in } } +static bool set_config_index(enum_ctrl_t *enum_ctrl, const usb_device_desc_t *device_desc) +{ +#ifdef ENABLE_ENUM_FILTER_CALLBACK + // Callback enabled in the menuncofig, but the callback function was not defined + if (enum_ctrl->enum_filter_cb == NULL) { + enum_ctrl->enum_config_index = ENUM_CONFIG_INDEX_DEFAULT; + return true; + } + + uint8_t enum_config_index; + const bool enum_continue = enum_ctrl->enum_filter_cb(device_desc, &enum_config_index); + + // User's request NOT to enumerate the USB device + if (!enum_continue) { + ESP_LOGW(HUB_DRIVER_TAG, "USB device (PID = 0x%x, VID = 0x%x) will not be enumerated", device_desc->idProduct, device_desc->idVendor); + enum_ctrl->graceful_exit = true; + return false; + } + + // Set configuration descriptor + if ((enum_config_index == 0) || (enum_config_index > device_desc->bNumConfigurations)) { + ESP_LOGW(HUB_DRIVER_TAG, "bConfigurationValue %d provided by user, device will be configured with configuration descriptor 1", enum_config_index); + enum_ctrl->enum_config_index = ENUM_CONFIG_INDEX_DEFAULT; + } else { + enum_ctrl->enum_config_index = enum_config_index - 1; + } +#else // ENABLE_ENUM_FILTER_CALLBACK + enum_ctrl->enum_config_index = ENUM_CONFIG_INDEX_DEFAULT; +#endif // ENABLE_ENUM_FILTER_CALLBACK + + return true; +} + static bool enum_stage_transfer(enum_ctrl_t *enum_ctrl) { usb_transfer_t *transfer = &enum_ctrl->urb->transfer; @@ -351,7 +398,7 @@ static bool enum_stage_transfer(enum_ctrl_t *enum_ctrl) } case ENUM_STAGE_GET_SHORT_CONFIG_DESC: { // Get a short config descriptor at index 0 - USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)transfer->data_buffer, ENUM_CONFIG_INDEX, ENUM_SHORT_DESC_REQ_LEN); + USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)transfer->data_buffer, enum_ctrl->enum_config_index, ENUM_SHORT_DESC_REQ_LEN); transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(ENUM_SHORT_DESC_REQ_LEN, enum_ctrl->bMaxPacketSize0); // IN data stage should return exactly ENUM_SHORT_DESC_REQ_LEN bytes enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + ENUM_SHORT_DESC_REQ_LEN; @@ -359,7 +406,7 @@ static bool enum_stage_transfer(enum_ctrl_t *enum_ctrl) } case ENUM_STAGE_GET_FULL_CONFIG_DESC: { // Get the full configuration descriptor at index 0, requesting its exact length. - USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)transfer->data_buffer, ENUM_CONFIG_INDEX, enum_ctrl->wTotalLength); + USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)transfer->data_buffer, enum_ctrl->enum_config_index, enum_ctrl->wTotalLength); transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(enum_ctrl->wTotalLength, enum_ctrl->bMaxPacketSize0); // IN data stage should return exactly wTotalLength bytes enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + enum_ctrl->wTotalLength; @@ -497,7 +544,7 @@ static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl) enum_ctrl->iManufacturer = device_desc->iManufacturer; enum_ctrl->iProduct = device_desc->iProduct; enum_ctrl->iSerialNumber = device_desc->iSerialNumber; - ret = true; + ret = set_config_index(enum_ctrl, device_desc); break; } case ENUM_STAGE_CHECK_SHORT_CONFIG_DESC: { @@ -924,7 +971,15 @@ static void enum_handle_events(void) if (stage_pass) { ESP_LOGD(HUB_DRIVER_TAG, "Stage done: %s", enum_stage_strings[enum_ctrl->stage]); } else { +#ifdef ENABLE_ENUM_FILTER_CALLBACK + if (!enum_ctrl->graceful_exit) { + ESP_LOGE(HUB_DRIVER_TAG, "Stage failed: %s", enum_stage_strings[enum_ctrl->stage]); + } else { + ESP_LOGD(HUB_DRIVER_TAG, "Stage done: %s", enum_stage_strings[enum_ctrl->stage]); + } +#else // ENABLE_ENUM_FILTER_CALLBACK ESP_LOGE(HUB_DRIVER_TAG, "Stage failed: %s", enum_stage_strings[enum_ctrl->stage]); +#endif // ENABLE_ENUM_FILTER_CALLBACK } enum_set_next_stage(enum_ctrl, stage_pass); } @@ -959,9 +1014,13 @@ esp_err_t hub_install(hub_config_t *hub_config) hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_INSTALLED; hub_driver_obj->single_thread.enum_ctrl.stage = ENUM_STAGE_NONE; hub_driver_obj->single_thread.enum_ctrl.urb = enum_urb; +#ifdef ENABLE_ENUM_FILTER_CALLBACK + hub_driver_obj->single_thread.enum_ctrl.enum_filter_cb = hub_config->enum_filter_cb; +#endif // ENABLE_ENUM_FILTER_CALLBACK hub_driver_obj->constant.root_port_hdl = port_hdl; hub_driver_obj->constant.proc_req_cb = hub_config->proc_req_cb; hub_driver_obj->constant.proc_req_cb_arg = hub_config->proc_req_cb_arg; + HUB_DRIVER_ENTER_CRITICAL(); if (p_hub_driver_obj != NULL) { HUB_DRIVER_EXIT_CRITICAL(); diff --git a/components/usb/include/usb/usb_host.h b/components/usb/include/usb/usb_host.h index 89cc88cbc9..13a58caee9 100644 --- a/components/usb/include/usb/usb_host.h +++ b/components/usb/include/usb/usb_host.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -106,6 +106,8 @@ typedef struct { set this if they want to use an external USB PHY. Otherwise, the USB Host Library will automatically configure the internal USB PHY */ int intr_flags; /**< Interrupt flags for the underlying ISR used by the USB Host stack */ + usb_host_enum_filter_cb_t enum_filter_cb; /**< Enumeration filter callback. Enable CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK + to use this feature. Set to NULL otherwise. */ } usb_host_config_t; /** diff --git a/components/usb/include/usb/usb_types_stack.h b/components/usb/include/usb/usb_types_stack.h index 00af897182..8b351063f4 100644 --- a/components/usb/include/usb/usb_types_stack.h +++ b/components/usb/include/usb/usb_types_stack.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,6 +10,7 @@ Warning: The USB Host Library API is still a beta version and may be subject to #pragma once +#include #include "usb/usb_types_ch9.h" #ifdef __cplusplus @@ -46,6 +47,29 @@ typedef enum { */ typedef struct usb_device_handle_s *usb_device_handle_t; +/** + * @brief Enumeration filter callback + * + * This callback is called at the beginning of the enumeration process for a newly attached device. + * Through this callback, users are able to: + * + * - filter which devices should be enumerated + * - select the configuration number to use when enumerating the device + * + * The device descriptor is passed to this callback to allow users to filter devices based on + * Vendor ID, Product ID, and class code. + * + * @attention This callback must be non-blocking + * @attention This callback must not submit any USB transfers + * @param[in] dev_desc Device descriptor of the device to enumerate + * @param[out] bConfigurationValue Configuration number to use when enumerating the device (starts with 1) + * + * @return bool + * - true: USB device will be enumerated + * - false: USB device will not be enumerated + */ +typedef bool (*usb_host_enum_filter_cb_t)(const usb_device_desc_t *dev_desc, uint8_t *bConfigurationValue); + /** * @brief Basic information of an enumerated device */ diff --git a/components/usb/private_include/hub.h b/components/usb/private_include/hub.h index 1a8807bf51..dac89b7ea7 100644 --- a/components/usb/private_include/hub.h +++ b/components/usb/private_include/hub.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,6 +8,7 @@ #include #include +#include "sdkconfig.h" #include "esp_err.h" #include "usb_private.h" #include "usbh.h" @@ -22,8 +23,11 @@ extern "C" { * @brief Hub driver configuration */ typedef struct { - usb_proc_req_cb_t proc_req_cb; /**< Processing request callback */ - void *proc_req_cb_arg; /**< Processing request callback argument */ + usb_proc_req_cb_t proc_req_cb; /**< Processing request callback */ + void *proc_req_cb_arg; /**< Processing request callback argument */ +#ifdef CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK + usb_host_enum_filter_cb_t enum_filter_cb; /**< Set device configuration callback */ +#endif // CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK } hub_config_t; // ---------------------------------------------- Hub Driver Functions ------------------------------------------------- diff --git a/components/usb/usb_host.c b/components/usb/usb_host.c index cfea392a43..8328927952 100644 --- a/components/usb/usb_host.c +++ b/components/usb/usb_host.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,6 +10,7 @@ Warning: The USB Host Library API is still a beta version and may be subject to #include #include +#include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" @@ -47,6 +48,10 @@ static portMUX_TYPE host_lock = portMUX_INITIALIZER_UNLOCKED; #define PROCESS_REQUEST_PENDING_FLAG_USBH 0x01 #define PROCESS_REQUEST_PENDING_FLAG_HUB 0x02 +#ifdef CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK +#define ENABLE_ENUM_FILTER_CALLBACK +#endif // CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK + typedef struct ep_wrapper_s ep_wrapper_t; typedef struct interface_s interface_t; typedef struct client_s client_t; @@ -404,10 +409,18 @@ esp_err_t usb_host_install(const usb_host_config_t *config) goto usbh_err; } +#ifdef ENABLE_ENUM_FILTER_CALLBACK + if (config->enum_filter_cb == NULL) { + ESP_LOGW(USB_HOST_TAG, "User callback to set USB device configuration is enabled, but not used"); + } +#endif // ENABLE_ENUM_FILTER_CALLBACK // Install Hub hub_config_t hub_config = { .proc_req_cb = proc_req_callback, .proc_req_cb_arg = NULL, +#ifdef ENABLE_ENUM_FILTER_CALLBACK + .enum_filter_cb = config->enum_filter_cb, +#endif // ENABLE_ENUM_FILTER_CALLBACK }; ret = hub_install(&hub_config); if (ret != ESP_OK) { diff --git a/examples/peripherals/usb/host/cdc/cdc_acm_vcp/main/CMakeLists.txt b/examples/peripherals/usb/host/cdc/cdc_acm_vcp/main/CMakeLists.txt index e52dfe2ba8..477ba42e45 100644 --- a/examples/peripherals/usb/host/cdc/cdc_acm_vcp/main/CMakeLists.txt +++ b/examples/peripherals/usb/host/cdc/cdc_acm_vcp/main/CMakeLists.txt @@ -3,3 +3,5 @@ idf_component_register( INCLUDE_DIRS "." PRIV_REQUIRES usb ) + +target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-missing-field-initializers") diff --git a/examples/peripherals/usb/host/usb_host_lib/main/usb_host_lib_main.c b/examples/peripherals/usb/host/usb_host_lib/main/usb_host_lib_main.c index f73880cabc..c928eb01ec 100644 --- a/examples/peripherals/usb/host/usb_host_lib/main/usb_host_lib_main.c +++ b/examples/peripherals/usb/host/usb_host_lib/main/usb_host_lib_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -14,10 +14,43 @@ #define DAEMON_TASK_PRIORITY 2 #define CLASS_TASK_PRIORITY 3 +#ifdef CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK +#define ENABLE_ENUM_FILTER_CALLBACK +#endif // CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK + extern void class_driver_task(void *arg); static const char *TAG = "DAEMON"; +/** + * @brief Set configuration callback + * + * Set the USB device configuration during the enumeration process, must be enabled in the menuconfig + + * @note bConfigurationValue starts at index 1 + * + * @param[in] dev_desc device descriptor of the USB device currently being enumerated + * @param[out] bConfigurationValue configuration descriptor index, that will be user for enumeration + * + * @return bool + * - true: USB device will be enumerated + * - false: USB device will not be enumerated + */ +#ifdef ENABLE_ENUM_FILTER_CALLBACK +static bool set_config_cb(const usb_device_desc_t *dev_desc, uint8_t *bConfigurationValue) +{ + // If the USB device has more than one configuration, set the second configuration + if (dev_desc->bNumConfigurations > 1) { + *bConfigurationValue = 2; + } else { + *bConfigurationValue = 1; + } + + // Return true to enumerate the USB device + return true; +} +#endif // ENABLE_ENUM_FILTER_CALLBACK + static void host_lib_daemon_task(void *arg) { SemaphoreHandle_t signaling_sem = (SemaphoreHandle_t)arg; @@ -26,6 +59,9 @@ static void host_lib_daemon_task(void *arg) usb_host_config_t host_config = { .skip_phy_setup = false, .intr_flags = ESP_INTR_FLAG_LEVEL1, +#ifdef ENABLE_ENUM_FILTER_CALLBACK + .enum_filter_cb = set_config_cb, +#endif // ENABLE_ENUM_FILTER_CALLBACK }; ESP_ERROR_CHECK(usb_host_install(&host_config)); From fac5596767424523d28c3ffd3c80fd322591f60f Mon Sep 17 00:00:00 2001 From: Peter Marcisovsky Date: Wed, 3 Jan 2024 12:52:51 +0100 Subject: [PATCH 4/4] feat(docs): added usb host enumeration filter description - CN and EN docs --- docs/en/api-reference/peripherals/usb_host.rst | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/en/api-reference/peripherals/usb_host.rst b/docs/en/api-reference/peripherals/usb_host.rst index d9f5b555de..55782c0d46 100644 --- a/docs/en/api-reference/peripherals/usb_host.rst +++ b/docs/en/api-reference/peripherals/usb_host.rst @@ -429,7 +429,22 @@ Configurable parameters of the USB host stack can be configured with multiple op * For debounce delay, refer to :ref:`CONFIG_USB_HOST_DEBOUNCE_DELAY_MS`. * For reset hold interval, refer to :ref:`CONFIG_USB_HOST_RESET_HOLD_MS`. * For reset recovery interval, refer to :ref:`CONFIG_USB_HOST_RESET_RECOVERY_MS`. -* Fer ``SetAddress()`` recovery interval, refer to :ref:`CONFIG_USB_HOST_SET_ADDR_RECOVERY_MS`. +* For ``SetAddress()`` recovery interval, refer to :ref:`CONFIG_USB_HOST_SET_ADDR_RECOVERY_MS`. + +Multiple Configuration Support +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To support USB devices that have more than one configuration, it is possible to specify the desired configuration number during a device's enumeration process. + +Enumeration Filter +"""""""""""""""""" + +The enumeration filter is a callback function of type :cpp:type:`usb_host_enum_filter_cb_t` called at the beginning of the enumeration process once a device descriptor is read from a newly attached USB device. Consequently, the user is provided with the obtained device descriptor. Through this callback, the user can: + +* Select the configuration of the USB device. +* Filter which USB devices should be enumerated. + +To use the enumeration filter, users should enable the :ref:`CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK` option using menuconfig. Users can specify the callback by setting :cpp:member:`usb_host_config_t::enum_filter_cb` which is then passed to the Host Library when calling :cpp:func:`usb_host_install`. .. -------------------------------------------------- API Reference ----------------------------------------------------