mirror of
https://github.com/espressif/esp-idf
synced 2025-03-09 17:19:09 -04:00
feat(ext_port): Added External Port driver
Closes https://github.com/espressif/esp-idf/issues/12554
This commit is contained in:
parent
bcfa928850
commit
70f222e5d2
2
Kconfig
2
Kconfig
@ -678,3 +678,5 @@ mainmenu "Espressif IoT Development Framework Configuration"
|
|||||||
- CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH
|
- CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH
|
||||||
- CONFIG_ESP_WIFI_EAP_TLS1_3
|
- CONFIG_ESP_WIFI_EAP_TLS1_3
|
||||||
- CONFIG_ESP_WIFI_ENABLE_ROAMING_APP
|
- CONFIG_ESP_WIFI_ENABLE_ROAMING_APP
|
||||||
|
- CONFIG_USB_HOST_EXT_PORT_SUPPORT_LS
|
||||||
|
- CONFIG_USB_HOST_EXT_PORT_RESET_ATTEMPTS
|
||||||
|
@ -30,7 +30,8 @@ if(CONFIG_SOC_USB_OTG_SUPPORTED)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CONFIG_USB_HOST_HUBS_SUPPORTED)
|
if(CONFIG_USB_HOST_HUBS_SUPPORTED)
|
||||||
list(APPEND srcs "ext_hub.c")
|
list(APPEND srcs "ext_hub.c"
|
||||||
|
"ext_port.c")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
idf_component_register(SRCS ${srcs}
|
idf_component_register(SRCS ${srcs}
|
||||||
|
@ -112,6 +112,51 @@ menu "USB-OTG"
|
|||||||
help
|
help
|
||||||
Enables support for connecting multiple Hubs simultaneously.
|
Enables support for connecting multiple Hubs simultaneously.
|
||||||
|
|
||||||
|
menu "Downstream Port configuration"
|
||||||
|
depends on USB_HOST_HUBS_SUPPORTED
|
||||||
|
|
||||||
|
config USB_HOST_EXT_PORT_SUPPORT_LS
|
||||||
|
depends on IDF_EXPERIMENTAL_FEATURES
|
||||||
|
bool "Support LS"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Enables support of Low-speed devices, connected through the external Hub.
|
||||||
|
|
||||||
|
config USB_HOST_EXT_PORT_RESET_ATTEMPTS
|
||||||
|
depends on IDF_EXPERIMENTAL_FEATURES
|
||||||
|
# Invisible config option
|
||||||
|
# Todo: IDF-11283
|
||||||
|
int
|
||||||
|
default 1
|
||||||
|
help
|
||||||
|
Amount of attempts to reset the device.
|
||||||
|
|
||||||
|
The default value is 1.
|
||||||
|
|
||||||
|
config USB_HOST_EXT_PORT_CUSTOM_RESET_ENABLE
|
||||||
|
bool "Custom bPwrOn2PwrGood value"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Enables the possibility to configure custom time for the power-on sequence on a port
|
||||||
|
until power is good on that port.
|
||||||
|
|
||||||
|
When enabled, applies the custom PwrOn2PwrGood delay.
|
||||||
|
When disabled, applies the PwrOn2PwrGood value from the Hub Descriptor.
|
||||||
|
|
||||||
|
config USB_HOST_EXT_PORT_CUSTOM_RESET_MS
|
||||||
|
depends on USB_HOST_EXT_PORT_CUSTOM_RESET_ENABLE
|
||||||
|
int "PwrOn2PwrGood delay in ms"
|
||||||
|
default 100
|
||||||
|
range 0 5000
|
||||||
|
help
|
||||||
|
Custom value of delay from the time the power-on sequence begins on a port
|
||||||
|
until power is good on that port.
|
||||||
|
Value 0 is used for a hub with no power switches.
|
||||||
|
|
||||||
|
The default value is 100 ms.
|
||||||
|
|
||||||
|
endmenu #Downstream Port configuration
|
||||||
|
|
||||||
endmenu #Hub Driver Configuration
|
endmenu #Hub Driver Configuration
|
||||||
|
|
||||||
config USB_HOST_ENABLE_ENUM_FILTER_CALLBACK
|
config USB_HOST_ENABLE_ENUM_FILTER_CALLBACK
|
||||||
|
@ -5,18 +5,17 @@
|
|||||||
*/
|
*/
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "sdkconfig.h"
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_heap_caps.h"
|
#include "esp_heap_caps.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "freertos/semphr.h"
|
|
||||||
#include "usb_private.h"
|
#include "usb_private.h"
|
||||||
#include "ext_hub.h"
|
#include "ext_hub.h"
|
||||||
|
#include "ext_port.h"
|
||||||
#include "usb/usb_helpers.h"
|
#include "usb/usb_helpers.h"
|
||||||
|
|
||||||
typedef struct ext_port_s *ext_port_hdl_t; /* This will be implemented during ext_port driver implementation */
|
|
||||||
|
|
||||||
#define EXT_HUB_MAX_STATUS_BYTES_SIZE (sizeof(uint32_t))
|
#define EXT_HUB_MAX_STATUS_BYTES_SIZE (sizeof(uint32_t))
|
||||||
#define EXT_HUB_STATUS_CHANGE_FLAG (1 << 0)
|
#define EXT_HUB_STATUS_CHANGE_FLAG (1 << 0)
|
||||||
#define EXT_HUB_STATUS_PORT1_CHANGE_FLAG (1 << 1)
|
#define EXT_HUB_STATUS_PORT1_CHANGE_FLAG (1 << 1)
|
||||||
@ -396,8 +395,15 @@ static void device_error(ext_hub_dev_t *ext_hub_dev)
|
|||||||
|
|
||||||
static esp_err_t device_port_new(ext_hub_dev_t *ext_hub_dev, uint8_t port_idx)
|
static esp_err_t device_port_new(ext_hub_dev_t *ext_hub_dev, uint8_t port_idx)
|
||||||
{
|
{
|
||||||
|
ext_port_config_t port_config = {
|
||||||
|
.ext_hub_hdl = (ext_hub_handle_t) ext_hub_dev,
|
||||||
|
.parent_dev_hdl = ext_hub_dev->constant.dev_hdl,
|
||||||
|
.parent_port_num = port_idx + 1,
|
||||||
|
.port_power_delay_ms = ext_hub_dev->constant.hub_desc->bPwrOn2PwrGood * 2,
|
||||||
|
};
|
||||||
|
|
||||||
assert(p_ext_hub_driver->constant.port_driver);
|
assert(p_ext_hub_driver->constant.port_driver);
|
||||||
esp_err_t ret = p_ext_hub_driver->constant.port_driver->new (NULL, (void**) &ext_hub_dev->constant.ports[port_idx]);
|
esp_err_t ret = p_ext_hub_driver->constant.port_driver->new (&port_config, (void**) &ext_hub_dev->constant.ports[port_idx]);
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
ESP_LOGE(EXT_HUB_TAG, "[%d:%d] Port allocation error: %s", ext_hub_dev->constant.dev_addr, port_idx + 1, esp_err_to_name(ret));
|
ESP_LOGE(EXT_HUB_TAG, "[%d:%d] Port allocation error: %s", ext_hub_dev->constant.dev_addr, port_idx + 1, esp_err_to_name(ret));
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -418,7 +424,7 @@ static esp_err_t device_port_free(ext_hub_dev_t *ext_hub_dev, uint8_t port_idx)
|
|||||||
|
|
||||||
assert(ext_hub_dev->single_thread.maxchild != 0);
|
assert(ext_hub_dev->single_thread.maxchild != 0);
|
||||||
assert(p_ext_hub_driver->constant.port_driver);
|
assert(p_ext_hub_driver->constant.port_driver);
|
||||||
esp_err_t ret = p_ext_hub_driver->constant.port_driver->free(ext_hub_dev->constant.ports[port_idx]);
|
esp_err_t ret = p_ext_hub_driver->constant.port_driver->del(ext_hub_dev->constant.ports[port_idx]);
|
||||||
|
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
ESP_LOGE(EXT_HUB_TAG, "[%d:%d] Unable to free port: %s", ext_hub_dev->constant.dev_addr, port_idx + 1, esp_err_to_name(ret));
|
ESP_LOGE(EXT_HUB_TAG, "[%d:%d] Unable to free port: %s", ext_hub_dev->constant.dev_addr, port_idx + 1, esp_err_to_name(ret));
|
||||||
@ -1038,6 +1044,7 @@ static void handle_device(ext_hub_dev_t *ext_hub_dev)
|
|||||||
// FSM for external Hub
|
// FSM for external Hub
|
||||||
switch (ext_hub_dev->single_thread.stage) {
|
switch (ext_hub_dev->single_thread.stage) {
|
||||||
case EXT_HUB_STAGE_IDLE:
|
case EXT_HUB_STAGE_IDLE:
|
||||||
|
stage_pass = true;
|
||||||
break;
|
break;
|
||||||
case EXT_HUB_STAGE_GET_DEVICE_STATUS:
|
case EXT_HUB_STAGE_GET_DEVICE_STATUS:
|
||||||
case EXT_HUB_STAGE_GET_HUB_DESCRIPTOR:
|
case EXT_HUB_STAGE_GET_HUB_DESCRIPTOR:
|
||||||
@ -1118,8 +1125,7 @@ esp_err_t ext_hub_install(const ext_hub_config_t *config)
|
|||||||
{
|
{
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
ext_hub_driver_t *ext_hub_drv = heap_caps_calloc(1, sizeof(ext_hub_driver_t), MALLOC_CAP_DEFAULT);
|
ext_hub_driver_t *ext_hub_drv = heap_caps_calloc(1, sizeof(ext_hub_driver_t), MALLOC_CAP_DEFAULT);
|
||||||
SemaphoreHandle_t mux_lock = xSemaphoreCreateMutex();
|
if (ext_hub_drv == NULL) {
|
||||||
if (ext_hub_drv == NULL || mux_lock == NULL) {
|
|
||||||
ret = ESP_ERR_NO_MEM;
|
ret = ESP_ERR_NO_MEM;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@ -1151,9 +1157,6 @@ esp_err_t ext_hub_install(const ext_hub_config_t *config)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
if (mux_lock != NULL) {
|
|
||||||
vSemaphoreDelete(mux_lock);
|
|
||||||
}
|
|
||||||
heap_caps_free(ext_hub_drv);
|
heap_caps_free(ext_hub_drv);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1672,7 +1675,7 @@ esp_err_t ext_hub_port_get_speed(ext_hub_handle_t ext_hub_hdl, uint8_t port_num,
|
|||||||
esp_err_t ext_hub_set_port_feature(ext_hub_handle_t ext_hub_hdl, uint8_t port_num, uint8_t feature)
|
esp_err_t ext_hub_set_port_feature(ext_hub_handle_t ext_hub_hdl, uint8_t port_num, uint8_t feature)
|
||||||
{
|
{
|
||||||
EXT_HUB_ENTER_CRITICAL();
|
EXT_HUB_ENTER_CRITICAL();
|
||||||
EXT_HUB_CHECK_FROM_CRIT(p_ext_hub_driver != NULL, ESP_ERR_INVALID_STATE);
|
EXT_HUB_CHECK_FROM_CRIT(p_ext_hub_driver != NULL, ESP_ERR_NOT_ALLOWED);
|
||||||
EXT_HUB_EXIT_CRITICAL();
|
EXT_HUB_EXIT_CRITICAL();
|
||||||
|
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
@ -1701,7 +1704,7 @@ esp_err_t ext_hub_set_port_feature(ext_hub_handle_t ext_hub_hdl, uint8_t port_nu
|
|||||||
esp_err_t ext_hub_clear_port_feature(ext_hub_handle_t ext_hub_hdl, uint8_t port_num, uint8_t feature)
|
esp_err_t ext_hub_clear_port_feature(ext_hub_handle_t ext_hub_hdl, uint8_t port_num, uint8_t feature)
|
||||||
{
|
{
|
||||||
EXT_HUB_ENTER_CRITICAL();
|
EXT_HUB_ENTER_CRITICAL();
|
||||||
EXT_HUB_CHECK_FROM_CRIT(p_ext_hub_driver != NULL, ESP_ERR_INVALID_STATE);
|
EXT_HUB_CHECK_FROM_CRIT(p_ext_hub_driver != NULL, ESP_ERR_NOT_ALLOWED);
|
||||||
EXT_HUB_EXIT_CRITICAL();
|
EXT_HUB_EXIT_CRITICAL();
|
||||||
|
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
@ -1730,7 +1733,7 @@ esp_err_t ext_hub_clear_port_feature(ext_hub_handle_t ext_hub_hdl, uint8_t port_
|
|||||||
esp_err_t ext_hub_get_port_status(ext_hub_handle_t ext_hub_hdl, uint8_t port_num)
|
esp_err_t ext_hub_get_port_status(ext_hub_handle_t ext_hub_hdl, uint8_t port_num)
|
||||||
{
|
{
|
||||||
EXT_HUB_ENTER_CRITICAL();
|
EXT_HUB_ENTER_CRITICAL();
|
||||||
EXT_HUB_CHECK_FROM_CRIT(p_ext_hub_driver != NULL, ESP_ERR_INVALID_STATE);
|
EXT_HUB_CHECK_FROM_CRIT(p_ext_hub_driver != NULL, ESP_ERR_NOT_ALLOWED);
|
||||||
EXT_HUB_EXIT_CRITICAL();
|
EXT_HUB_EXIT_CRITICAL();
|
||||||
|
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
|
1398
components/usb/ext_port.c
Normal file
1398
components/usb/ext_port.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -20,7 +20,7 @@
|
|||||||
#include "usb/usb_helpers.h"
|
#include "usb/usb_helpers.h"
|
||||||
|
|
||||||
#if ENABLE_USB_HUBS
|
#if ENABLE_USB_HUBS
|
||||||
#include "ext_hub.h"
|
#include "ext_port.h"
|
||||||
#endif // ENABLE_USB_HUBS
|
#endif // ENABLE_USB_HUBS
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -320,6 +320,72 @@ static bool ext_hub_callback(bool in_isr, void *user_arg)
|
|||||||
HUB_DRIVER_EXIT_CRITICAL_SAFE();
|
HUB_DRIVER_EXIT_CRITICAL_SAFE();
|
||||||
return p_hub_driver_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_HUB, in_isr, p_hub_driver_obj->constant.proc_req_cb_arg);
|
return p_hub_driver_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_HUB, in_isr, p_hub_driver_obj->constant.proc_req_cb_arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ext_port_callback(void *user_arg)
|
||||||
|
{
|
||||||
|
HUB_DRIVER_ENTER_CRITICAL();
|
||||||
|
p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_ACTION_EXT_PORT;
|
||||||
|
HUB_DRIVER_EXIT_CRITICAL();
|
||||||
|
p_hub_driver_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_HUB, false, p_hub_driver_obj->constant.proc_req_cb_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ext_port_event_callback(ext_port_event_data_t *event_data, void *arg)
|
||||||
|
{
|
||||||
|
switch (event_data->event) {
|
||||||
|
case EXT_PORT_CONNECTED:
|
||||||
|
// First reset is done by ext_port logic
|
||||||
|
usb_speed_t port_speed;
|
||||||
|
|
||||||
|
if (ext_hub_port_get_speed(event_data->connected.ext_hub_hdl,
|
||||||
|
event_data->connected.parent_port_num,
|
||||||
|
&port_speed) != ESP_OK) {
|
||||||
|
goto new_ds_dev_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: IDF-10023 Move responsibility of parent-child tree building to Hub Driver instead of USBH
|
||||||
|
usb_device_info_t parent_dev_info;
|
||||||
|
ESP_ERROR_CHECK(usbh_dev_get_info(event_data->connected.parent_dev_hdl, &parent_dev_info));
|
||||||
|
if (parent_dev_info.speed == USB_SPEED_HIGH) {
|
||||||
|
if (port_speed != parent_dev_info.speed) {
|
||||||
|
ESP_LOGE(HUB_DRIVER_TAG, "Connected device is %s, transaction translator (TT) is not supported",
|
||||||
|
(char *[]) {
|
||||||
|
"LS", "FS", "HS"
|
||||||
|
}[port_speed]);
|
||||||
|
goto new_ds_dev_err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (!CONFIG_USB_HOST_EXT_PORT_SUPPORT_LS)
|
||||||
|
if (port_speed == USB_SPEED_LOW) {
|
||||||
|
ESP_LOGE(HUB_DRIVER_TAG, "Connected %s-speed device, not supported",
|
||||||
|
(char *[]) {
|
||||||
|
"Low", "Full", "High"
|
||||||
|
}[port_speed]);
|
||||||
|
goto new_ds_dev_err;
|
||||||
|
}
|
||||||
|
#endif // CONFIG_USB_HOST_EXT_PORT_SUPPORT_LS
|
||||||
|
|
||||||
|
if (new_dev_tree_node(event_data->connected.parent_dev_hdl, event_data->connected.parent_port_num, port_speed) != ESP_OK) {
|
||||||
|
ESP_LOGE(HUB_DRIVER_TAG, "Failed to add new downstream device");
|
||||||
|
goto new_ds_dev_err;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
new_ds_dev_err:
|
||||||
|
ext_hub_port_disable(event_data->connected.ext_hub_hdl, event_data->connected.parent_port_num);
|
||||||
|
break;
|
||||||
|
case EXT_PORT_RESET_COMPLETED:
|
||||||
|
ESP_ERROR_CHECK(dev_tree_node_reset_completed(event_data->reset_completed.parent_dev_hdl, event_data->reset_completed.parent_port_num));
|
||||||
|
break;
|
||||||
|
case EXT_PORT_DISCONNECTED:
|
||||||
|
// The node could be freed by now, no need to verify the result here
|
||||||
|
dev_tree_node_dev_gone(event_data->disconnected.parent_dev_hdl, event_data->disconnected.parent_port_num);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Should never occur
|
||||||
|
abort();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif // ENABLE_USB_HUBS
|
#endif // ENABLE_USB_HUBS
|
||||||
|
|
||||||
// ---------------------- Handlers -------------------------
|
// ---------------------- Handlers -------------------------
|
||||||
@ -479,10 +545,20 @@ esp_err_t hub_install(hub_config_t *hub_config, void **client_ret)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_USB_HUBS
|
#if ENABLE_USB_HUBS
|
||||||
|
// Install External Port driver
|
||||||
|
ext_port_driver_config_t ext_port_config = {
|
||||||
|
.proc_req_cb = ext_port_callback,
|
||||||
|
.event_cb = ext_port_event_callback,
|
||||||
|
};
|
||||||
|
ret = ext_port_install(&ext_port_config);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
goto err_ext_port;
|
||||||
|
}
|
||||||
|
|
||||||
// Install External HUB driver
|
// Install External HUB driver
|
||||||
ext_hub_config_t ext_hub_config = {
|
ext_hub_config_t ext_hub_config = {
|
||||||
.proc_req_cb = ext_hub_callback,
|
.proc_req_cb = ext_hub_callback,
|
||||||
.port_driver = NULL,
|
.port_driver = ext_port_get_driver(),
|
||||||
};
|
};
|
||||||
ret = ext_hub_install(&ext_hub_config);
|
ret = ext_hub_install(&ext_hub_config);
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
@ -536,6 +612,8 @@ err:
|
|||||||
#if ENABLE_USB_HUBS
|
#if ENABLE_USB_HUBS
|
||||||
ext_hub_uninstall();
|
ext_hub_uninstall();
|
||||||
err_ext_hub:
|
err_ext_hub:
|
||||||
|
ext_port_uninstall();
|
||||||
|
err_ext_port:
|
||||||
#endif // ENABLE_USB_HUBS
|
#endif // ENABLE_USB_HUBS
|
||||||
heap_caps_free(hub_driver_obj);
|
heap_caps_free(hub_driver_obj);
|
||||||
return ret;
|
return ret;
|
||||||
@ -552,6 +630,7 @@ esp_err_t hub_uninstall(void)
|
|||||||
|
|
||||||
#if ENABLE_USB_HUBS
|
#if ENABLE_USB_HUBS
|
||||||
ESP_ERROR_CHECK(ext_hub_uninstall());
|
ESP_ERROR_CHECK(ext_hub_uninstall());
|
||||||
|
ESP_ERROR_CHECK(ext_port_uninstall());
|
||||||
#endif // ENABLE_USB_HUBS
|
#endif // ENABLE_USB_HUBS
|
||||||
|
|
||||||
ESP_ERROR_CHECK(hcd_port_deinit(hub_driver_obj->constant.root_port_hdl));
|
ESP_ERROR_CHECK(hcd_port_deinit(hub_driver_obj->constant.root_port_hdl));
|
||||||
@ -739,10 +818,7 @@ esp_err_t hub_process(void)
|
|||||||
while (action_flags) {
|
while (action_flags) {
|
||||||
#if ENABLE_USB_HUBS
|
#if ENABLE_USB_HUBS
|
||||||
if (action_flags & HUB_DRIVER_ACTION_EXT_PORT) {
|
if (action_flags & HUB_DRIVER_ACTION_EXT_PORT) {
|
||||||
ESP_LOGW(HUB_DRIVER_TAG, "ext_port_process() has not been implemented yet");
|
|
||||||
/*
|
|
||||||
ESP_ERROR_CHECK(ext_port_process());
|
ESP_ERROR_CHECK(ext_port_process());
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
if (action_flags & HUB_DRIVER_ACTION_EXT_HUB) {
|
if (action_flags & HUB_DRIVER_ACTION_EXT_HUB) {
|
||||||
ESP_ERROR_CHECK(ext_hub_process());
|
ESP_ERROR_CHECK(ext_hub_process());
|
||||||
|
@ -43,6 +43,28 @@ typedef enum {
|
|||||||
USB_B_REQUEST_HUB_STOP_TT = 0x0B, /**< Stop TT. */
|
USB_B_REQUEST_HUB_STOP_TT = 0x0B, /**< Stop TT. */
|
||||||
} usb_hub_class_request_t ;
|
} usb_hub_class_request_t ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief USB Hub Port state
|
||||||
|
*
|
||||||
|
* See USB 2.0 spec, 11.5.1 Downstream Facing Port State Descriptions
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
USB_PORT_STATE_NOT_CONFIGURED = 0x00, /**< The hub is not configured. A port transitions to and remains in this state whenever the value of the hub configuration is zero. */
|
||||||
|
USB_PORT_STATE_POWERED_OFF, /**< Powered_off: Port requires explicit request to transition. */
|
||||||
|
USB_PORT_STATE_DISCONNECTED, /**< In the Disconnected state, the port’s differential transmitter and receiver are disabled and only connection detection is possible.*/
|
||||||
|
USB_PORT_STATE_DISABLED, /**< A port in the Disabled state will not propagate signaling in either the upstream or the downstream direction */
|
||||||
|
USB_PORT_STATE_RESETTING, /**< The duration of the Resetting state is nominally 10 ms to 20 ms (10 ms is preferred). */
|
||||||
|
USB_PORT_STATE_ENABLED, /**< While in this state, the output of the port’s differential receiver is available to the Hub Repeater so that appropriate signaling transitions can establish upstream connectivity*/
|
||||||
|
USB_PORT_STATE_TRANSMIT, /**< This state is entered from the Enabled state on the transition of the Hub Repeater to the WFEOPFU state */
|
||||||
|
USB_PORT_STATE_TRANSMIT_R, /**< When in this state, the port repeats the resume ‘K’ at the upstream facing port to the downstream facing port. */
|
||||||
|
USB_PORT_STATE_SUSPENDED, /**< While a port is in the Suspended state, the port's differential transmitter is disabled. */
|
||||||
|
USB_PORT_STATE_RESUMING, /**< While in this state, the hub drives a 'K' on the port. */
|
||||||
|
USB_PORT_STATE_SEND_EOR, /**< This state is entered from the Resuming state if the 20 ms timer expires. */
|
||||||
|
USB_PORT_STATE_RESTART_S, /**< A port enters the Restart_S state from the Suspended state when an SE0 or ‘K’ is seen at the port and the Receiver is in the Suspended state */
|
||||||
|
USB_PORT_STATE_RESTART_E, /**< A port enters the Restart_E state from the Enabled state when an ‘SE0’ or ‘K’ is seen at the port and the Receiver is in the Suspended state. */
|
||||||
|
USB_PORT_STATE_TESTING, /**< A port transitions to this state from any state when the port sees SetTest. */
|
||||||
|
} usb_hub_port_state_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief USB Hub Port feature selector codes
|
* @brief USB Hub Port feature selector codes
|
||||||
*
|
*
|
||||||
|
@ -46,7 +46,7 @@ typedef struct {
|
|||||||
esp_err_t (*active)(void *port_hdl);
|
esp_err_t (*active)(void *port_hdl);
|
||||||
esp_err_t (*disable)(void *port_hdl);
|
esp_err_t (*disable)(void *port_hdl);
|
||||||
esp_err_t (*gone)(void *port_hdl);
|
esp_err_t (*gone)(void *port_hdl);
|
||||||
esp_err_t (*free)(void *port_hdl);
|
esp_err_t (*del)(void *port_hdl);
|
||||||
esp_err_t (*get_speed)(void *por_hdl, usb_speed_t *speed);
|
esp_err_t (*get_speed)(void *por_hdl, usb_speed_t *speed);
|
||||||
esp_err_t (*get_status)(void *port_hdl);
|
esp_err_t (*get_status)(void *port_hdl);
|
||||||
esp_err_t (*set_status)(void *port_hdl, const usb_port_status_t *status);
|
esp_err_t (*set_status)(void *port_hdl, const usb_port_status_t *status);
|
||||||
@ -278,7 +278,7 @@ esp_err_t ext_hub_port_get_speed(ext_hub_handle_t ext_hub_hdl, uint8_t port_num,
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: Port's feature set successfully
|
* - ESP_OK: Port's feature set successfully
|
||||||
* - ESP_ERR_INVALID_STATE: External Hub driver is not installed;
|
* - ESP_ERR_NOT_ALLOWED: External Hub driver is not installed
|
||||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||||
* - ESP_ERR_INVALID_SIZE: External Hub port number out of the hub's range
|
* - ESP_ERR_INVALID_SIZE: External Hub port number out of the hub's range
|
||||||
*/
|
*/
|
||||||
@ -293,7 +293,7 @@ esp_err_t ext_hub_set_port_feature(ext_hub_handle_t ext_hub_hdl, uint8_t port_nu
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: Port's feature cleared successfully
|
* - ESP_OK: Port's feature cleared successfully
|
||||||
* - ESP_ERR_INVALID_STATE: External Hub driver is not installed;
|
* - ESP_ERR_NOT_ALLOWED: External Hub driver is not installed
|
||||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||||
* - ESP_ERR_INVALID_SIZE: External Hub port number out of the hub's range
|
* - ESP_ERR_INVALID_SIZE: External Hub port number out of the hub's range
|
||||||
*/
|
*/
|
||||||
@ -310,7 +310,7 @@ esp_err_t ext_hub_clear_port_feature(ext_hub_handle_t ext_hub_hdl, uint8_t port_
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: Port's status obtained successfully
|
* - ESP_OK: Port's status obtained successfully
|
||||||
* - ESP_ERR_INVALID_STATE: External Hub driver is not installed;
|
* - ESP_ERR_NOT_ALLOWED: External Hub driver is not installed
|
||||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||||
* - ESP_ERR_INVALID_SIZE: External Hub port number out of the hub's range
|
* - ESP_ERR_INVALID_SIZE: External Hub port number out of the hub's range
|
||||||
*/
|
*/
|
||||||
|
143
components/usb/private_include/ext_port.h
Normal file
143
components/usb/private_include/ext_port.h
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "ext_hub.h"
|
||||||
|
#include "usb/usb_types_stack.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct ext_port_s *ext_port_hdl_t;
|
||||||
|
|
||||||
|
// ------------------------------ Events ---------------------------------------
|
||||||
|
typedef enum {
|
||||||
|
EXT_PORT_CONNECTED = 0x01, /**< Port has a device connection event */
|
||||||
|
EXT_PORT_RESET_COMPLETED, /**< Port has completed the reset routine */
|
||||||
|
EXT_PORT_DISCONNECTED, /**< Port has a device disconnection event */
|
||||||
|
} ext_port_event_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Event data object for External Port driver events
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
ext_port_event_t event;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
ext_hub_handle_t ext_hub_hdl; /**< Ports' parent external Hub handle */
|
||||||
|
usb_device_handle_t parent_dev_hdl; /**< Ports' parent device handle */
|
||||||
|
uint8_t parent_port_num; /**< Ports' parent port number */
|
||||||
|
} connected; /**< EXT_PORT_CONNECTED event specific data */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
usb_device_handle_t parent_dev_hdl; /**< Ports' parent device handle */
|
||||||
|
uint8_t parent_port_num; /**< Ports' parent port number */
|
||||||
|
} reset_completed; /**< EXT_PORT_RESET_COMPLETED event specific data */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
usb_device_handle_t parent_dev_hdl; /**< Ports' parent device handle */
|
||||||
|
uint8_t parent_port_num; /**< Ports' parent port number */
|
||||||
|
} disconnected; /**< EXT_PORT_DISCONNECTED event specific data */
|
||||||
|
};
|
||||||
|
} ext_port_event_data_t;
|
||||||
|
|
||||||
|
// ------------------------------ Callbacks ------------------------------------
|
||||||
|
/**
|
||||||
|
* @brief Callback used to indicate that the External Port Driver requires process callback
|
||||||
|
*
|
||||||
|
* @note For the Hub Driver only
|
||||||
|
*/
|
||||||
|
typedef void (*ext_port_cb_t)(void *user_arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback used to indicate that the External Port driver has an event
|
||||||
|
*
|
||||||
|
* @note For the Hub Driver only
|
||||||
|
*/
|
||||||
|
typedef void (*ext_port_event_cb_t)(ext_port_event_data_t *event_data, void *arg);
|
||||||
|
|
||||||
|
// ----------------- External Port Driver configuration ------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief External Port driver configuration
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
ext_port_cb_t proc_req_cb; /**< External Port process callback */
|
||||||
|
void *proc_req_cb_arg; /**< External Port process callback argument */
|
||||||
|
ext_port_event_cb_t event_cb; /**< External Port event callback */
|
||||||
|
void *event_cb_arg; /**< External Port event callback argument */
|
||||||
|
} ext_port_driver_config_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief External Port configuration
|
||||||
|
*
|
||||||
|
* Structure is used to create new port
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
ext_hub_handle_t ext_hub_hdl; /**< Ports' parent external Hub handle */
|
||||||
|
usb_device_handle_t parent_dev_hdl; /**< Ports' parent device handle */
|
||||||
|
uint8_t parent_port_num; /**< Ports' parent port number */
|
||||||
|
uint16_t port_power_delay_ms; /**< Ports' Power on time to Power Good, ms */
|
||||||
|
} ext_port_config_t;
|
||||||
|
|
||||||
|
// -------------------- External Port Processing Functions ---------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Install the External Port Driver
|
||||||
|
*
|
||||||
|
* @note This function should only be called from the Hub Driver
|
||||||
|
*
|
||||||
|
* @param[in] config External Port Driver configuration
|
||||||
|
* @return
|
||||||
|
* - ESP_ERR_NOT_ALLOWED: The Driver was already installed
|
||||||
|
* - ESP_ERR_NO_MEM: Unable to install the Driver, no memory
|
||||||
|
* - ESP_OK: The Driver has been installed successfully
|
||||||
|
*/
|
||||||
|
esp_err_t ext_port_install(const ext_port_driver_config_t *config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Uninstall the External Port Driver
|
||||||
|
*
|
||||||
|
* @note This function should only be called from the Hub Driver
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_ERR_NOT_ALLOWED: The Driver was not installed
|
||||||
|
* - ESP_ERR_INVALID_STATE: The Driver has ports in the pending list and can't be uninstalled
|
||||||
|
* - ESP_OK: The Driver has been uninstall successfully
|
||||||
|
*/
|
||||||
|
esp_err_t ext_port_uninstall(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief External Port Driver's process function
|
||||||
|
*
|
||||||
|
* @note This function should only be called from the Hub Driver
|
||||||
|
*
|
||||||
|
* External Port Driver process function that must be called repeatedly to process the driver's actions and events.
|
||||||
|
* If blocking, the caller can block on the notification callback of source USB_PROC_REQ_SOURCE_HUB
|
||||||
|
* to run this function.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_ERR_NOT_ALLOWED: The Driver was not installed
|
||||||
|
* - ESP_OK: The Driver processed completed
|
||||||
|
*/
|
||||||
|
esp_err_t ext_port_process(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns External Port Driver's API
|
||||||
|
*
|
||||||
|
* @note This is a specific API for the External Hub Driver to handle the ports.
|
||||||
|
* @return
|
||||||
|
* - NULL: The Driver has not been installed
|
||||||
|
* - not NULL: Pointer to the External Port Driver API
|
||||||
|
*/
|
||||||
|
const ext_hub_port_driver_t *ext_port_get_driver(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -134,8 +134,8 @@ esp_err_t hub_root_stop(void);
|
|||||||
*
|
*
|
||||||
* @note This function should only be called from the Host Library task
|
* @note This function should only be called from the Host Library task
|
||||||
*
|
*
|
||||||
* @param[in] parent_dev_hdl
|
* @param[in] parent_dev_hdl Parent device handle (is used to get the External Hub handle)
|
||||||
* @param[in] parent_port_num
|
* @param[in] parent_port_num Parent number (is used to specify the External Port)
|
||||||
* @param[in] dev_uid Device's unique ID
|
* @param[in] dev_uid Device's unique ID
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
@ -151,9 +151,8 @@ esp_err_t hub_port_recycle(usb_device_handle_t parent_dev_hdl, uint8_t parent_po
|
|||||||
*
|
*
|
||||||
* @note This function should only be called from the Host Library task
|
* @note This function should only be called from the Host Library task
|
||||||
*
|
*
|
||||||
* @param[in] parent_dev_hdl
|
* @param[in] parent_dev_hdl Parent device handle (is used to get the External Hub handle)
|
||||||
* @param[in] parent_port_num
|
* @param[in] parent_port_num Parent number (is used to specify the External Port)
|
||||||
*
|
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: Port reset successful
|
* - ESP_OK: Port reset successful
|
||||||
* - ESP_ERR_INVALID_STATE: Hub driver is not installed
|
* - ESP_ERR_INVALID_STATE: Hub driver is not installed
|
||||||
@ -198,6 +197,8 @@ esp_err_t hub_port_disable(usb_device_handle_t parent_dev_hdl, uint8_t parent_po
|
|||||||
*
|
*
|
||||||
* If device is has a HUB class, then it will be added as External Hub to Hub Driver.
|
* If device is has a HUB class, then it will be added as External Hub to Hub Driver.
|
||||||
*
|
*
|
||||||
|
* @note This function should only be called from the Host Library task
|
||||||
|
*
|
||||||
* @param[in] dev_addr Device bus address
|
* @param[in] dev_addr Device bus address
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
@ -211,6 +212,8 @@ esp_err_t hub_notify_new_dev(uint8_t dev_addr);
|
|||||||
*
|
*
|
||||||
* If the device was an External Hub, then it will be removed from the Hub Driver.
|
* If the device was an External Hub, then it will be removed from the Hub Driver.
|
||||||
*
|
*
|
||||||
|
* @note This function should only be called from the Host Library task
|
||||||
|
*
|
||||||
* @param[in] dev_addr Device bus address
|
* @param[in] dev_addr Device bus address
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
@ -222,6 +225,8 @@ esp_err_t hub_notify_dev_gone(uint8_t dev_addr);
|
|||||||
/**
|
/**
|
||||||
* @brief Notify Hub driver that all devices should be freed
|
* @brief Notify Hub driver that all devices should be freed
|
||||||
*
|
*
|
||||||
|
* @note This function should only be called from the Host Library task
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: All the devices can be freed
|
* - ESP_OK: All the devices can be freed
|
||||||
* - ESP_ERR_INVALID_STATE: Hub driver is not in a correct state
|
* - ESP_ERR_INVALID_STATE: Hub driver is not in a correct state
|
||||||
|
@ -1050,7 +1050,6 @@ esp_err_t usbh_dev_close(usb_device_handle_t dev_hdl)
|
|||||||
if (dev_obj->dynamic.open_count == 0) {
|
if (dev_obj->dynamic.open_count == 0) {
|
||||||
// Sanity check.
|
// Sanity check.
|
||||||
assert(dev_obj->dynamic.num_ctrl_xfers_inflight == 0); // There cannot be any control transfer in-flight
|
assert(dev_obj->dynamic.num_ctrl_xfers_inflight == 0); // There cannot be any control transfer in-flight
|
||||||
assert(!dev_obj->dynamic.flags.waiting_free); // This can only be set when open_count reaches 0
|
|
||||||
if (dev_obj->dynamic.flags.is_gone || dev_obj->dynamic.flags.waiting_free) {
|
if (dev_obj->dynamic.flags.is_gone || dev_obj->dynamic.flags.waiting_free) {
|
||||||
// Device is already gone or is awaiting to be freed. Trigger the USBH process to free the device
|
// Device is already gone or is awaiting to be freed. Trigger the USBH process to free the device
|
||||||
call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE);
|
call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user