mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
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
This commit is contained in:
parent
e8c901b144
commit
e87bb08216
@ -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
|
||||
|
@ -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 {
|
||||
ESP_LOGE(HUB_DRIVER_TAG, "Stage failed: %s", enum_stage_strings[enum_ctrl->stage]);
|
||||
#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();
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -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 <stdbool.h>
|
||||
#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
|
||||
*/
|
||||
|
@ -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 <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#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 -------------------------------------------------
|
||||
|
@ -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 <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#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) {
|
||||
|
@ -2,3 +2,5 @@ idf_component_register(
|
||||
SRCS "cdc_acm_vcp_example_main.cpp"
|
||||
INCLUDE_DIRS "."
|
||||
)
|
||||
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-missing-field-initializers")
|
||||
|
@ -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));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user