mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
usb: Fix USBH handling of disconnections
This commit fixes how the USBH handling of a sudden device disconnection, more specifically handling of device gone. - Previously the USBH would only halt, flush, and dequeue the device's default EP, then send a device gone event to the Host Library layer. - Now the USBH will also halt and flush all non-default EPs, allowing all of the URBs to be dequeud. - Some internal object members are now protected by a mutex instead of a spinlock. Closes https://github.com/espressif/esp-idf/issues/7505
This commit is contained in:
parent
de6bf09f40
commit
0a948594cb
@ -110,6 +110,7 @@ esp_err_t usbh_uninstall(void);
|
|||||||
* - If blocking, the caller can block until a USB_NOTIF_SOURCE_USBH notification is received before running this
|
* - If blocking, the caller can block until a USB_NOTIF_SOURCE_USBH notification is received before running this
|
||||||
* function
|
* function
|
||||||
*
|
*
|
||||||
|
* @note This function can block
|
||||||
* @return esp_err_t
|
* @return esp_err_t
|
||||||
*/
|
*/
|
||||||
esp_err_t usbh_process(void);
|
esp_err_t usbh_process(void);
|
||||||
@ -164,6 +165,7 @@ esp_err_t usbh_dev_get_addr(usb_device_handle_t dev_hdl, uint8_t *dev_addr);
|
|||||||
/**
|
/**
|
||||||
* @brief Get a device's information
|
* @brief Get a device's information
|
||||||
*
|
*
|
||||||
|
* @note This function can block
|
||||||
* @param[in] dev_hdl Device handle
|
* @param[in] dev_hdl Device handle
|
||||||
* @param[out] dev_info Device information
|
* @param[out] dev_info Device information
|
||||||
* @return esp_err_t
|
* @return esp_err_t
|
||||||
@ -186,6 +188,7 @@ esp_err_t usbh_dev_get_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t
|
|||||||
*
|
*
|
||||||
* Simply returns a reference to the internally cached configuration descriptor
|
* Simply returns a reference to the internally cached configuration descriptor
|
||||||
*
|
*
|
||||||
|
* @note This function can block
|
||||||
* @param[in] dev_hdl Device handle
|
* @param[in] dev_hdl Device handle
|
||||||
* @param config_desc_ret
|
* @param config_desc_ret
|
||||||
* @return esp_err_t
|
* @return esp_err_t
|
||||||
@ -209,6 +212,7 @@ esp_err_t usbh_dev_submit_ctrl_urb(usb_device_handle_t dev_hdl, urb_t *urb);
|
|||||||
* Clients that have opened a device must call this function to allocate all endpoints in an interface that is claimed.
|
* Clients that have opened a device must call this function to allocate all endpoints in an interface that is claimed.
|
||||||
* The pipe handle of the endpoint is returned so that clients can use and control the pipe directly.
|
* The pipe handle of the endpoint is returned so that clients can use and control the pipe directly.
|
||||||
*
|
*
|
||||||
|
* @note This function can block
|
||||||
* @note Default pipes are owned by the USBH. For control transfers, use usbh_dev_submit_ctrl_urb() instead
|
* @note Default pipes are owned by the USBH. For control transfers, use usbh_dev_submit_ctrl_urb() instead
|
||||||
* @note Device must be opened by the client first
|
* @note Device must be opened by the client first
|
||||||
*
|
*
|
||||||
@ -224,6 +228,7 @@ esp_err_t usbh_ep_alloc(usb_device_handle_t dev_hdl, usbh_ep_config_t *ep_config
|
|||||||
*
|
*
|
||||||
* Free an endpoint previously opened by usbh_ep_alloc()
|
* Free an endpoint previously opened by usbh_ep_alloc()
|
||||||
*
|
*
|
||||||
|
* @note This function can block
|
||||||
* @param[in] dev_hdl Device handle
|
* @param[in] dev_hdl Device handle
|
||||||
* @param[in] bEndpointAddress Endpoint's address
|
* @param[in] bEndpointAddress Endpoint's address
|
||||||
* @return esp_err_t
|
* @return esp_err_t
|
||||||
@ -235,6 +240,7 @@ esp_err_t usbh_ep_free(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress);
|
|||||||
*
|
*
|
||||||
* Get the context variable assigned to and endpoint on allocation.
|
* Get the context variable assigned to and endpoint on allocation.
|
||||||
*
|
*
|
||||||
|
* @note This function can block
|
||||||
* @param[in] dev_hdl Device handle
|
* @param[in] dev_hdl Device handle
|
||||||
* @param[in] bEndpointAddress Endpoint's address
|
* @param[in] bEndpointAddress Endpoint's address
|
||||||
* @param[out] context_ret Context variable
|
* @param[out] context_ret Context variable
|
||||||
@ -336,6 +342,7 @@ esp_err_t usbh_hub_enum_fill_dev_addr(usb_device_handle_t dev_hdl, uint8_t dev_a
|
|||||||
*
|
*
|
||||||
* @note Hub Driver only
|
* @note Hub Driver only
|
||||||
* @note Must call in sequence
|
* @note Must call in sequence
|
||||||
|
* @note This function can block
|
||||||
* @param[in] dev_hdl Device handle
|
* @param[in] dev_hdl Device handle
|
||||||
* @param config_desc_full
|
* @param config_desc_full
|
||||||
* @return esp_err_t
|
* @return esp_err_t
|
||||||
@ -360,6 +367,7 @@ esp_err_t usbh_hub_enum_fill_config_num(usb_device_handle_t dev_hdl, uint8_t bCo
|
|||||||
*
|
*
|
||||||
* @note Hub Driver only
|
* @note Hub Driver only
|
||||||
* @note Must call in sequence
|
* @note Must call in sequence
|
||||||
|
* @note This function can block
|
||||||
* @param[in] dev_hdl Device handle
|
* @param[in] dev_hdl Device handle
|
||||||
* @return esp_err_t
|
* @return esp_err_t
|
||||||
*/
|
*/
|
||||||
@ -373,6 +381,7 @@ esp_err_t usbh_hub_enum_done(usb_device_handle_t dev_hdl);
|
|||||||
*
|
*
|
||||||
* @note Hub Driver only
|
* @note Hub Driver only
|
||||||
* @note Must call in sequence
|
* @note Must call in sequence
|
||||||
|
* @note This function can block
|
||||||
* @param[in] dev_hdl Device handle
|
* @param[in] dev_hdl Device handle
|
||||||
* @return esp_err_t
|
* @return esp_err_t
|
||||||
*/
|
*/
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/portmacro.h"
|
#include "freertos/portmacro.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/semphr.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"
|
||||||
@ -20,14 +21,15 @@
|
|||||||
#include "usb/usb_helpers.h"
|
#include "usb/usb_helpers.h"
|
||||||
#include "usb/usb_types_ch9.h"
|
#include "usb/usb_types_ch9.h"
|
||||||
|
|
||||||
//Device action flags. Listed in the order they should handled in. Some actions are mutually exclusive
|
//Device action flags. LISTED IN THE ORDER THEY SHOULD BE HANDLED IN within usbh_process(). Some actions are mutually exclusive
|
||||||
#define DEV_FLAG_ACTION_SEND_GONE_EVENT 0x01 //Send a USB_HOST_CLIENT_EVENT_DEV_GONE event
|
#define DEV_FLAG_ACTION_PIPE_HALT_AND_FLUSH 0x01 //Halt all non-default pipes then flush them (called after a device gone is gone)
|
||||||
#define DEV_FLAG_ACTION_DEFAULT_PIPE_FLUSH 0x02 //Retire all URBS in the default pipe
|
#define DEV_FLAG_ACTION_DEFAULT_PIPE_FLUSH 0x02 //Retire all URBS in the default pipe
|
||||||
#define DEV_FLAG_ACTION_DEFAULT_PIPE_DEQUEUE 0x04 //Dequeue all URBs from default pipe
|
#define DEV_FLAG_ACTION_DEFAULT_PIPE_DEQUEUE 0x04 //Dequeue all URBs from default pipe
|
||||||
#define DEV_FLAG_ACTION_DEFAULT_PIPE_CLEAR 0x08 //Move the default pipe to the active state
|
#define DEV_FLAG_ACTION_DEFAULT_PIPE_CLEAR 0x08 //Move the default pipe to the active state
|
||||||
#define DEV_FLAG_ACTION_FREE 0x10 //Free the device object
|
#define DEV_FLAG_ACTION_SEND_GONE_EVENT 0x10 //Send a USB_HOST_CLIENT_EVENT_DEV_GONE event
|
||||||
#define DEV_FLAG_ACTION_PORT_DISABLE 0x20
|
#define DEV_FLAG_ACTION_FREE 0x20 //Free the device object
|
||||||
#define DEV_FLAG_ACTION_SEND_NEW 0x40 //Send a new device event
|
#define DEV_FLAG_ACTION_PORT_DISABLE 0x40 //Request the hub driver to disable the port of the device
|
||||||
|
#define DEV_FLAG_ACTION_SEND_NEW 0x80 //Send a new device event
|
||||||
|
|
||||||
#define DEV_ENUM_TODO_FLAG_DEV_ADDR 0x01
|
#define DEV_ENUM_TODO_FLAG_DEV_ADDR 0x01
|
||||||
#define DEV_ENUM_TODO_FLAG_DEV_DESC 0x02
|
#define DEV_ENUM_TODO_FLAG_DEV_DESC 0x02
|
||||||
@ -56,10 +58,13 @@ struct device_s {
|
|||||||
int num_ctrl_xfers_inflight;
|
int num_ctrl_xfers_inflight;
|
||||||
usb_device_state_t state;
|
usb_device_state_t state;
|
||||||
uint32_t ref_count;
|
uint32_t ref_count;
|
||||||
|
} dynamic;
|
||||||
|
//Mux protected members must be protected by the USBH mux_lock when accessed
|
||||||
|
struct {
|
||||||
usb_config_desc_t *config_desc;
|
usb_config_desc_t *config_desc;
|
||||||
hcd_pipe_handle_t ep_in[EP_NUM_MAX - 1]; //IN EP owner contexts. -1 to exclude the default endpoint
|
hcd_pipe_handle_t ep_in[EP_NUM_MAX - 1]; //IN EP owner contexts. -1 to exclude the default endpoint
|
||||||
hcd_pipe_handle_t ep_out[EP_NUM_MAX - 1]; //OUT EP owner contexts. -1 to exclude the default endpoint
|
hcd_pipe_handle_t ep_out[EP_NUM_MAX - 1]; //OUT EP owner contexts. -1 to exclude the default endpoint
|
||||||
} dynamic;
|
} mux_protected;
|
||||||
//Constant members do no change after device allocation and enumeration thus do not require a critical section
|
//Constant members do no change after device allocation and enumeration thus do not require a critical section
|
||||||
struct {
|
struct {
|
||||||
hcd_pipe_handle_t default_pipe;
|
hcd_pipe_handle_t default_pipe;
|
||||||
@ -76,8 +81,11 @@ typedef struct {
|
|||||||
struct {
|
struct {
|
||||||
TAILQ_HEAD(tailhead_devs, device_s) devs_idle_tailq; //Tailq of all enum and configured devices
|
TAILQ_HEAD(tailhead_devs, device_s) devs_idle_tailq; //Tailq of all enum and configured devices
|
||||||
TAILQ_HEAD(tailhead_devs_cb, device_s) devs_pending_tailq; //Tailq of devices that need to have their cb called
|
TAILQ_HEAD(tailhead_devs_cb, device_s) devs_pending_tailq; //Tailq of devices that need to have their cb called
|
||||||
uint8_t num_device; //Number of enumerated devices
|
|
||||||
} dynamic;
|
} dynamic;
|
||||||
|
//Mux protected members must be protected by the USBH mux_lock when accessed
|
||||||
|
struct {
|
||||||
|
uint8_t num_device; //Number of enumerated devices
|
||||||
|
} mux_protected;
|
||||||
//Constant members do no change after installation thus do not require a critical section
|
//Constant members do no change after installation thus do not require a critical section
|
||||||
struct {
|
struct {
|
||||||
usb_notif_cb_t notif_cb;
|
usb_notif_cb_t notif_cb;
|
||||||
@ -88,6 +96,7 @@ typedef struct {
|
|||||||
void *event_cb_arg;
|
void *event_cb_arg;
|
||||||
usbh_ctrl_xfer_cb_t ctrl_xfer_cb;
|
usbh_ctrl_xfer_cb_t ctrl_xfer_cb;
|
||||||
void *ctrl_xfer_cb_arg;
|
void *ctrl_xfer_cb_arg;
|
||||||
|
SemaphoreHandle_t mux_lock;
|
||||||
} constant;
|
} constant;
|
||||||
} usbh_t;
|
} usbh_t;
|
||||||
|
|
||||||
@ -165,7 +174,7 @@ static void device_free(device_t *dev_obj)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//Configuration must be freed
|
//Configuration must be freed
|
||||||
assert(dev_obj->dynamic.config_desc == NULL);
|
assert(dev_obj->mux_protected.config_desc == NULL); //Sanity check. No need for mux
|
||||||
ESP_ERROR_CHECK(hcd_pipe_free(dev_obj->constant.default_pipe));
|
ESP_ERROR_CHECK(hcd_pipe_free(dev_obj->constant.default_pipe));
|
||||||
heap_caps_free((usb_device_desc_t *)dev_obj->constant.desc);
|
heap_caps_free((usb_device_desc_t *)dev_obj->constant.desc);
|
||||||
heap_caps_free(dev_obj);
|
heap_caps_free(dev_obj);
|
||||||
@ -240,8 +249,28 @@ static bool default_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t p
|
|||||||
return yield;
|
return yield;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_pipe_halt_and_flush(device_t *dev_obj)
|
||||||
|
{
|
||||||
|
//We need to take the mux_lock to access mux_protected members
|
||||||
|
xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
|
||||||
|
//Halt then flush all non-default IN pipes
|
||||||
|
for (int i = 0; i < (EP_NUM_MAX - 1); i++) {
|
||||||
|
if (dev_obj->mux_protected.ep_in[i] != NULL) {
|
||||||
|
ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->mux_protected.ep_in[i], HCD_PIPE_CMD_HALT));
|
||||||
|
ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->mux_protected.ep_in[i], HCD_PIPE_CMD_FLUSH));
|
||||||
|
}
|
||||||
|
if (dev_obj->mux_protected.ep_out[i] != NULL) {
|
||||||
|
ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->mux_protected.ep_out[i], HCD_PIPE_CMD_HALT));
|
||||||
|
ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->mux_protected.ep_out[i], HCD_PIPE_CMD_FLUSH));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xSemaphoreGive(p_usbh_obj->constant.mux_lock);
|
||||||
|
}
|
||||||
|
|
||||||
static bool handle_dev_free(device_t *dev_obj)
|
static bool handle_dev_free(device_t *dev_obj)
|
||||||
{
|
{
|
||||||
|
//We need to take the mux_lock to access mux_protected members
|
||||||
|
xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
|
||||||
USBH_ENTER_CRITICAL();
|
USBH_ENTER_CRITICAL();
|
||||||
//Remove the device object for it's containing list
|
//Remove the device object for it's containing list
|
||||||
if (dev_obj->dynamic.flags.in_pending_list) {
|
if (dev_obj->dynamic.flags.in_pending_list) {
|
||||||
@ -250,13 +279,13 @@ static bool handle_dev_free(device_t *dev_obj)
|
|||||||
} else {
|
} else {
|
||||||
TAILQ_REMOVE(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry);
|
TAILQ_REMOVE(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry);
|
||||||
}
|
}
|
||||||
p_usbh_obj->dynamic.num_device--;
|
|
||||||
bool all_free = (p_usbh_obj->dynamic.num_device == 0);
|
|
||||||
USBH_EXIT_CRITICAL();
|
USBH_EXIT_CRITICAL();
|
||||||
|
p_usbh_obj->mux_protected.num_device--;
|
||||||
heap_caps_free(dev_obj->dynamic.config_desc);
|
bool all_free = (p_usbh_obj->mux_protected.num_device == 0);
|
||||||
dev_obj->dynamic.config_desc = NULL;
|
heap_caps_free(dev_obj->mux_protected.config_desc);
|
||||||
|
dev_obj->mux_protected.config_desc = NULL;
|
||||||
device_free(dev_obj);
|
device_free(dev_obj);
|
||||||
|
xSemaphoreGive(p_usbh_obj->constant.mux_lock);
|
||||||
return all_free;
|
return all_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,11 +298,13 @@ esp_err_t usbh_install(const usbh_config_t *usbh_config)
|
|||||||
USBH_CHECK_FROM_CRIT(p_usbh_obj == NULL, ESP_ERR_INVALID_STATE);
|
USBH_CHECK_FROM_CRIT(p_usbh_obj == NULL, ESP_ERR_INVALID_STATE);
|
||||||
USBH_EXIT_CRITICAL();
|
USBH_EXIT_CRITICAL();
|
||||||
|
|
||||||
usbh_t *usbh_obj = heap_caps_calloc(1, sizeof(usbh_t), MALLOC_CAP_DEFAULT);
|
|
||||||
if (usbh_obj == NULL) {
|
|
||||||
return ESP_ERR_NO_MEM;
|
|
||||||
}
|
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
|
usbh_t *usbh_obj = heap_caps_calloc(1, sizeof(usbh_t), MALLOC_CAP_DEFAULT);
|
||||||
|
SemaphoreHandle_t mux_lock = xSemaphoreCreateMutex();
|
||||||
|
if (usbh_obj == NULL || mux_lock == NULL) {
|
||||||
|
ret = ESP_ERR_NO_MEM;
|
||||||
|
goto alloc_err;
|
||||||
|
}
|
||||||
//Install HCD
|
//Install HCD
|
||||||
ret = hcd_install(&usbh_config->hcd_config);
|
ret = hcd_install(&usbh_config->hcd_config);
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
@ -288,6 +319,7 @@ esp_err_t usbh_install(const usbh_config_t *usbh_config)
|
|||||||
usbh_obj->constant.event_cb_arg = usbh_config->event_cb_arg;
|
usbh_obj->constant.event_cb_arg = usbh_config->event_cb_arg;
|
||||||
usbh_obj->constant.ctrl_xfer_cb = usbh_config->ctrl_xfer_cb;
|
usbh_obj->constant.ctrl_xfer_cb = usbh_config->ctrl_xfer_cb;
|
||||||
usbh_obj->constant.ctrl_xfer_cb_arg = usbh_config->ctrl_xfer_cb_arg;
|
usbh_obj->constant.ctrl_xfer_cb_arg = usbh_config->ctrl_xfer_cb_arg;
|
||||||
|
usbh_obj->constant.mux_lock = mux_lock;
|
||||||
|
|
||||||
//Assign usbh object pointer
|
//Assign usbh object pointer
|
||||||
USBH_ENTER_CRITICAL();
|
USBH_ENTER_CRITICAL();
|
||||||
@ -305,24 +337,47 @@ esp_err_t usbh_install(const usbh_config_t *usbh_config)
|
|||||||
assign_err:
|
assign_err:
|
||||||
ESP_ERROR_CHECK(hcd_uninstall());
|
ESP_ERROR_CHECK(hcd_uninstall());
|
||||||
hcd_install_err:
|
hcd_install_err:
|
||||||
|
alloc_err:
|
||||||
|
if (mux_lock != NULL) {
|
||||||
|
vSemaphoreDelete(mux_lock);
|
||||||
|
}
|
||||||
heap_caps_free(usbh_obj);
|
heap_caps_free(usbh_obj);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t usbh_uninstall(void)
|
esp_err_t usbh_uninstall(void)
|
||||||
{
|
{
|
||||||
|
//Check that USBH is in a state to be uninstalled
|
||||||
USBH_ENTER_CRITICAL();
|
USBH_ENTER_CRITICAL();
|
||||||
USBH_CHECK_FROM_CRIT(p_usbh_obj != NULL, ESP_ERR_INVALID_STATE);
|
USBH_CHECK_FROM_CRIT(p_usbh_obj != NULL, ESP_ERR_INVALID_STATE);
|
||||||
//Check that USBH is in a state to be uninstalled
|
|
||||||
USBH_CHECK_FROM_CRIT(p_usbh_obj->dynamic.num_device == 0, ESP_ERR_INVALID_STATE);
|
|
||||||
usbh_t *usbh_obj = p_usbh_obj;
|
usbh_t *usbh_obj = p_usbh_obj;
|
||||||
p_usbh_obj = NULL;
|
|
||||||
USBH_EXIT_CRITICAL();
|
USBH_EXIT_CRITICAL();
|
||||||
|
|
||||||
//Uninstall HCD
|
esp_err_t ret;
|
||||||
|
//We need to take the mux_lock to access mux_protected members
|
||||||
|
xSemaphoreTake(usbh_obj->constant.mux_lock, portMAX_DELAY);
|
||||||
|
if (p_usbh_obj->mux_protected.num_device > 0) {
|
||||||
|
//There are still devices allocated. Can't uninstall right now.
|
||||||
|
ret = ESP_ERR_INVALID_STATE;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
//Check again if we can uninstall
|
||||||
|
USBH_ENTER_CRITICAL();
|
||||||
|
assert(p_usbh_obj == usbh_obj);
|
||||||
|
p_usbh_obj = NULL;
|
||||||
|
USBH_EXIT_CRITICAL();
|
||||||
|
xSemaphoreGive(usbh_obj->constant.mux_lock);
|
||||||
|
|
||||||
|
//Uninstall HCD, free resources
|
||||||
ESP_ERROR_CHECK(hcd_uninstall());
|
ESP_ERROR_CHECK(hcd_uninstall());
|
||||||
|
vSemaphoreDelete(usbh_obj->constant.mux_lock);
|
||||||
heap_caps_free(usbh_obj);
|
heap_caps_free(usbh_obj);
|
||||||
return ESP_OK;
|
ret = ESP_OK;
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
xSemaphoreGive(p_usbh_obj->constant.mux_lock);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t usbh_process(void)
|
esp_err_t usbh_process(void)
|
||||||
@ -340,14 +395,16 @@ esp_err_t usbh_process(void)
|
|||||||
dev_obj->dynamic.flags.actions = 0;
|
dev_obj->dynamic.flags.actions = 0;
|
||||||
dev_obj->dynamic.flags.in_pending_list = 0;
|
dev_obj->dynamic.flags.in_pending_list = 0;
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------
|
||||||
|
Exit critical section to handle device action flags in their listed order
|
||||||
|
--------------------------------------------------------------------- */
|
||||||
USBH_EXIT_CRITICAL();
|
USBH_EXIT_CRITICAL();
|
||||||
ESP_LOGD(USBH_TAG, "Processing actions 0x%x", action_flags);
|
ESP_LOGD(USBH_TAG, "Processing actions 0x%x", action_flags);
|
||||||
//Sanity check. If the device is being freed, there must not be any other action flags set
|
//Sanity check. If the device is being freed, there must not be any other action flags set
|
||||||
assert(!(action_flags & DEV_FLAG_ACTION_FREE) || action_flags == DEV_FLAG_ACTION_FREE);
|
assert(!(action_flags & DEV_FLAG_ACTION_FREE) || action_flags == DEV_FLAG_ACTION_FREE);
|
||||||
if (action_flags & DEV_FLAG_ACTION_SEND_GONE_EVENT) {
|
|
||||||
//Flush the default pipe. Then do an event gone
|
if (action_flags & DEV_FLAG_ACTION_PIPE_HALT_AND_FLUSH) {
|
||||||
ESP_LOGE(USBH_TAG, "Device %d gone", dev_obj->constant.address);
|
handle_pipe_halt_and_flush(dev_obj);
|
||||||
p_usbh_obj->constant.event_cb((usb_device_handle_t)dev_obj, USBH_EVENT_DEV_GONE, p_usbh_obj->constant.event_cb_arg);
|
|
||||||
}
|
}
|
||||||
if (action_flags & DEV_FLAG_ACTION_DEFAULT_PIPE_FLUSH) {
|
if (action_flags & DEV_FLAG_ACTION_DEFAULT_PIPE_FLUSH) {
|
||||||
ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->constant.default_pipe, HCD_PIPE_CMD_HALT));
|
ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->constant.default_pipe, HCD_PIPE_CMD_HALT));
|
||||||
@ -371,6 +428,11 @@ esp_err_t usbh_process(void)
|
|||||||
//We allow the pipe command to fail just in case the pipe becomes invalid mid command
|
//We allow the pipe command to fail just in case the pipe becomes invalid mid command
|
||||||
hcd_pipe_command(dev_obj->constant.default_pipe, HCD_PIPE_CMD_CLEAR);
|
hcd_pipe_command(dev_obj->constant.default_pipe, HCD_PIPE_CMD_CLEAR);
|
||||||
}
|
}
|
||||||
|
if (action_flags & DEV_FLAG_ACTION_SEND_GONE_EVENT) {
|
||||||
|
//Flush the default pipe. Then do an event gone
|
||||||
|
ESP_LOGE(USBH_TAG, "Device %d gone", dev_obj->constant.address);
|
||||||
|
p_usbh_obj->constant.event_cb((usb_device_handle_t)dev_obj, USBH_EVENT_DEV_GONE, p_usbh_obj->constant.event_cb_arg);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
Note: We make these action flags mutually exclusive in case they happen in rapid succession. They are handled
|
Note: We make these action flags mutually exclusive in case they happen in rapid succession. They are handled
|
||||||
in the order of precedence
|
in the order of precedence
|
||||||
@ -393,6 +455,9 @@ esp_err_t usbh_process(void)
|
|||||||
p_usbh_obj->constant.event_cb((usb_device_handle_t)dev_obj, USBH_EVENT_DEV_NEW, p_usbh_obj->constant.event_cb_arg);
|
p_usbh_obj->constant.event_cb((usb_device_handle_t)dev_obj, USBH_EVENT_DEV_NEW, p_usbh_obj->constant.event_cb_arg);
|
||||||
}
|
}
|
||||||
USBH_ENTER_CRITICAL();
|
USBH_ENTER_CRITICAL();
|
||||||
|
/* ---------------------------------------------------------------------
|
||||||
|
Re-enter critical sections. All device action flags should have been handled.
|
||||||
|
--------------------------------------------------------------------- */
|
||||||
|
|
||||||
}
|
}
|
||||||
USBH_EXIT_CRITICAL();
|
USBH_EXIT_CRITICAL();
|
||||||
@ -534,19 +599,30 @@ esp_err_t usbh_dev_get_info(usb_device_handle_t dev_hdl, usb_device_info_t *dev_
|
|||||||
USBH_CHECK(dev_hdl != NULL && dev_info != NULL, ESP_ERR_INVALID_ARG);
|
USBH_CHECK(dev_hdl != NULL && dev_info != NULL, ESP_ERR_INVALID_ARG);
|
||||||
device_t *dev_obj = (device_t *)dev_hdl;
|
device_t *dev_obj = (device_t *)dev_hdl;
|
||||||
|
|
||||||
|
esp_err_t ret;
|
||||||
|
//We need to take the mux_lock to access mux_protected members
|
||||||
|
xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
|
||||||
|
//Device must be configured, or not attached (if it suddenly disconnected)
|
||||||
USBH_ENTER_CRITICAL();
|
USBH_ENTER_CRITICAL();
|
||||||
USBH_CHECK_FROM_CRIT(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED || dev_obj->dynamic.state == USB_DEVICE_STATE_NOT_ATTACHED, ESP_ERR_INVALID_STATE);
|
if (!(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED || dev_obj->dynamic.state == USB_DEVICE_STATE_NOT_ATTACHED)) {
|
||||||
|
USBH_EXIT_CRITICAL();
|
||||||
|
ret = ESP_ERR_INVALID_STATE;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
//Critical section for the dynamic members
|
||||||
dev_info->speed = dev_obj->constant.speed;
|
dev_info->speed = dev_obj->constant.speed;
|
||||||
dev_info->dev_addr = dev_obj->constant.address;
|
dev_info->dev_addr = dev_obj->constant.address;
|
||||||
dev_info->bMaxPacketSize0 = dev_obj->constant.desc->bMaxPacketSize0;
|
dev_info->bMaxPacketSize0 = dev_obj->constant.desc->bMaxPacketSize0;
|
||||||
if (dev_obj->dynamic.config_desc == NULL) {
|
USBH_EXIT_CRITICAL();
|
||||||
|
if (dev_obj->mux_protected.config_desc == NULL) {
|
||||||
dev_info->bConfigurationValue = 0;
|
dev_info->bConfigurationValue = 0;
|
||||||
} else {
|
} else {
|
||||||
dev_info->bConfigurationValue = dev_obj->dynamic.config_desc->bConfigurationValue;
|
dev_info->bConfigurationValue = dev_obj->mux_protected.config_desc->bConfigurationValue;
|
||||||
}
|
}
|
||||||
USBH_EXIT_CRITICAL();
|
ret = ESP_OK;
|
||||||
|
exit:
|
||||||
return ESP_OK;
|
xSemaphoreGive(p_usbh_obj->constant.mux_lock);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t usbh_dev_get_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t **dev_desc_ret)
|
esp_err_t usbh_dev_get_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t **dev_desc_ret)
|
||||||
@ -567,12 +643,22 @@ esp_err_t usbh_dev_get_config_desc(usb_device_handle_t dev_hdl, const usb_config
|
|||||||
USBH_CHECK(dev_hdl != NULL && config_desc_ret != NULL, ESP_ERR_INVALID_ARG);
|
USBH_CHECK(dev_hdl != NULL && config_desc_ret != NULL, ESP_ERR_INVALID_ARG);
|
||||||
device_t *dev_obj = (device_t *)dev_hdl;
|
device_t *dev_obj = (device_t *)dev_hdl;
|
||||||
|
|
||||||
|
esp_err_t ret;
|
||||||
|
//We need to take the mux_lock to access mux_protected members
|
||||||
|
xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
|
||||||
|
//Device must be in the configured state
|
||||||
USBH_ENTER_CRITICAL();
|
USBH_ENTER_CRITICAL();
|
||||||
USBH_CHECK_FROM_CRIT(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED, ESP_ERR_INVALID_STATE);
|
if (dev_obj->dynamic.state != USB_DEVICE_STATE_CONFIGURED) {
|
||||||
*config_desc_ret = dev_obj->dynamic.config_desc;
|
USBH_EXIT_CRITICAL();
|
||||||
|
ret = ESP_ERR_INVALID_STATE;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
USBH_EXIT_CRITICAL();
|
USBH_EXIT_CRITICAL();
|
||||||
|
*config_desc_ret = dev_obj->mux_protected.config_desc;
|
||||||
return ESP_OK;
|
ret = ESP_OK;
|
||||||
|
exit:
|
||||||
|
xSemaphoreGive(p_usbh_obj->constant.mux_lock);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t usbh_dev_submit_ctrl_urb(usb_device_handle_t dev_hdl, urb_t *urb)
|
esp_err_t usbh_dev_submit_ctrl_urb(usb_device_handle_t dev_hdl, urb_t *urb)
|
||||||
@ -633,21 +719,24 @@ esp_err_t usbh_ep_alloc(usb_device_handle_t dev_hdl, usbh_ep_config_t *ep_config
|
|||||||
goto pipe_alloc_err;
|
goto pipe_alloc_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
USBH_ENTER_CRITICAL();
|
|
||||||
//Check that endpoint has not be allocated yet
|
|
||||||
bool is_in = ep_config->ep_desc->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK;
|
bool is_in = ep_config->ep_desc->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK;
|
||||||
uint8_t addr = ep_config->ep_desc->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK;
|
uint8_t addr = ep_config->ep_desc->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK;
|
||||||
//Assign the pipe handle
|
|
||||||
bool assigned = false;
|
bool assigned = false;
|
||||||
if (is_in && dev_obj->dynamic.ep_in[addr - 1] == NULL) { //Is an IN EP
|
|
||||||
dev_obj->dynamic.ep_in[addr - 1] = pipe_hdl;
|
//We need to take the mux_lock to access mux_protected members
|
||||||
|
xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
|
||||||
|
if (is_in && dev_obj->mux_protected.ep_in[addr - 1] == NULL) { //Is an IN EP
|
||||||
|
dev_obj->mux_protected.ep_in[addr - 1] = pipe_hdl;
|
||||||
assigned = true;
|
assigned = true;
|
||||||
} else {
|
} else {
|
||||||
dev_obj->dynamic.ep_out[addr - 1] = pipe_hdl;
|
dev_obj->mux_protected.ep_out[addr - 1] = pipe_hdl;
|
||||||
assigned = true;
|
assigned = true;
|
||||||
}
|
}
|
||||||
dev_obj->dynamic.ref_count--; //Restore ref_count
|
//Restore ref_count
|
||||||
|
USBH_ENTER_CRITICAL();
|
||||||
|
dev_obj->dynamic.ref_count--;
|
||||||
USBH_EXIT_CRITICAL();
|
USBH_EXIT_CRITICAL();
|
||||||
|
xSemaphoreGive(p_usbh_obj->constant.mux_lock);
|
||||||
|
|
||||||
if (!assigned) {
|
if (!assigned) {
|
||||||
ret = ESP_ERR_INVALID_STATE;
|
ret = ESP_ERR_INVALID_STATE;
|
||||||
@ -669,24 +758,38 @@ esp_err_t usbh_ep_free(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress)
|
|||||||
USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG);
|
USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG);
|
||||||
device_t *dev_obj = (device_t *)dev_hdl;
|
device_t *dev_obj = (device_t *)dev_hdl;
|
||||||
|
|
||||||
USBH_ENTER_CRITICAL();
|
esp_err_t ret;
|
||||||
//Un-assign the pipe handle from the endpoint
|
|
||||||
bool is_in = bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK;
|
bool is_in = bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK;
|
||||||
uint8_t addr = bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK;
|
uint8_t addr = bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK;
|
||||||
hcd_pipe_handle_t pipe_hdl;
|
hcd_pipe_handle_t pipe_hdl;
|
||||||
if (is_in) {
|
|
||||||
USBH_CHECK_FROM_CRIT(dev_obj->dynamic.ep_in[addr - 1] != NULL, ESP_ERR_INVALID_STATE);
|
|
||||||
pipe_hdl = dev_obj->dynamic.ep_in[addr - 1];
|
|
||||||
dev_obj->dynamic.ep_in[addr - 1] = NULL;
|
|
||||||
} else {
|
|
||||||
USBH_CHECK_FROM_CRIT(dev_obj->dynamic.ep_out[addr - 1] != NULL, ESP_ERR_INVALID_STATE);
|
|
||||||
pipe_hdl = dev_obj->dynamic.ep_out[addr - 1];
|
|
||||||
dev_obj->dynamic.ep_out[addr - 1] = NULL;
|
|
||||||
}
|
|
||||||
USBH_EXIT_CRITICAL();
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK(hcd_pipe_free(pipe_hdl));
|
//We need to take the mux_lock to access mux_protected members
|
||||||
return ESP_OK;
|
xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
|
||||||
|
//Check if the EP was previously allocated. If so, set it to NULL
|
||||||
|
if (is_in) {
|
||||||
|
if (dev_obj->mux_protected.ep_in[addr - 1] != NULL) {
|
||||||
|
pipe_hdl = dev_obj->mux_protected.ep_in[addr - 1];
|
||||||
|
dev_obj->mux_protected.ep_in[addr - 1] = NULL;
|
||||||
|
ret = ESP_OK;
|
||||||
|
} else {
|
||||||
|
ret = ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//EP must have been previously allocated
|
||||||
|
if (dev_obj->mux_protected.ep_out[addr - 1] != NULL) {
|
||||||
|
pipe_hdl = dev_obj->mux_protected.ep_out[addr - 1];
|
||||||
|
dev_obj->mux_protected.ep_out[addr - 1] = NULL;
|
||||||
|
ret = ESP_OK;
|
||||||
|
} else {
|
||||||
|
ret = ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xSemaphoreGive(p_usbh_obj->constant.mux_lock);
|
||||||
|
|
||||||
|
if (ret == ESP_OK) {
|
||||||
|
ESP_ERROR_CHECK(hcd_pipe_free(pipe_hdl));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t usbh_ep_get_context(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress, void **context_ret)
|
esp_err_t usbh_ep_get_context(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress, void **context_ret)
|
||||||
@ -698,29 +801,30 @@ esp_err_t usbh_ep_get_context(usb_device_handle_t dev_hdl, uint8_t bEndpointAddr
|
|||||||
addr <= EP_NUM_MAX &&
|
addr <= EP_NUM_MAX &&
|
||||||
context_ret != NULL,
|
context_ret != NULL,
|
||||||
ESP_ERR_INVALID_ARG);
|
ESP_ERR_INVALID_ARG);
|
||||||
device_t *dev_obj = (device_t *)dev_hdl;
|
|
||||||
|
|
||||||
USBH_ENTER_CRITICAL();
|
|
||||||
//Get the endpoint's corresponding pipe
|
|
||||||
hcd_pipe_handle_t pipe_hdl;
|
|
||||||
if (is_in) {
|
|
||||||
pipe_hdl = dev_obj->dynamic.ep_in[addr - 1];
|
|
||||||
} else {
|
|
||||||
pipe_hdl = dev_obj->dynamic.ep_out[addr - 1];
|
|
||||||
}
|
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
|
device_t *dev_obj = (device_t *)dev_hdl;
|
||||||
|
hcd_pipe_handle_t pipe_hdl;
|
||||||
|
|
||||||
|
//We need to take the mux_lock to access mux_protected members
|
||||||
|
xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
|
||||||
|
//Get the endpoint's corresponding pipe
|
||||||
|
if (is_in) {
|
||||||
|
pipe_hdl = dev_obj->mux_protected.ep_in[addr - 1];
|
||||||
|
} else {
|
||||||
|
pipe_hdl = dev_obj->mux_protected.ep_out[addr - 1];
|
||||||
|
}
|
||||||
|
//Check if the EP was allocated to begin with
|
||||||
if (pipe_hdl == NULL) {
|
if (pipe_hdl == NULL) {
|
||||||
USBH_EXIT_CRITICAL();
|
|
||||||
ret = ESP_ERR_NOT_FOUND;
|
ret = ESP_ERR_NOT_FOUND;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
//Return the context of the pipe
|
//Return the context of the pipe
|
||||||
void *context = hcd_pipe_get_context(pipe_hdl);
|
void *context = hcd_pipe_get_context(pipe_hdl);
|
||||||
*context_ret = context;
|
*context_ret = context;
|
||||||
USBH_EXIT_CRITICAL();
|
|
||||||
|
|
||||||
ret = ESP_OK;
|
ret = ESP_OK;
|
||||||
exit:
|
exit:
|
||||||
|
xSemaphoreGive(p_usbh_obj->constant.mux_lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -772,11 +876,13 @@ esp_err_t usbh_hub_mark_dev_gone(usb_device_handle_t dev_hdl)
|
|||||||
//Check if the device can be freed now
|
//Check if the device can be freed now
|
||||||
if (dev_obj->dynamic.ref_count == 0) {
|
if (dev_obj->dynamic.ref_count == 0) {
|
||||||
dev_obj->dynamic.flags.waiting_free = 1;
|
dev_obj->dynamic.flags.waiting_free = 1;
|
||||||
|
//Device is already waiting free so none of it's pipes will be in use. Can free immediately.
|
||||||
call_notif_cb = _dev_set_actions(dev_obj, DEV_FLAG_ACTION_FREE);
|
call_notif_cb = _dev_set_actions(dev_obj, DEV_FLAG_ACTION_FREE);
|
||||||
} else {
|
} else {
|
||||||
call_notif_cb = _dev_set_actions(dev_obj, DEV_FLAG_ACTION_SEND_GONE_EVENT |
|
call_notif_cb = _dev_set_actions(dev_obj, DEV_FLAG_ACTION_PIPE_HALT_AND_FLUSH |
|
||||||
DEV_FLAG_ACTION_DEFAULT_PIPE_FLUSH |
|
DEV_FLAG_ACTION_DEFAULT_PIPE_FLUSH |
|
||||||
DEV_FLAG_ACTION_DEFAULT_PIPE_DEQUEUE);
|
DEV_FLAG_ACTION_DEFAULT_PIPE_DEQUEUE |
|
||||||
|
DEV_FLAG_ACTION_SEND_GONE_EVENT);
|
||||||
}
|
}
|
||||||
USBH_EXIT_CRITICAL();
|
USBH_EXIT_CRITICAL();
|
||||||
|
|
||||||
@ -852,10 +958,11 @@ esp_err_t usbh_hub_enum_fill_config_desc(usb_device_handle_t dev_hdl, const usb_
|
|||||||
goto assign_err;
|
goto assign_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
USBH_ENTER_CRITICAL();
|
//We need to take the mux_lock to access mux_protected members
|
||||||
assert(dev_obj->dynamic.config_desc == NULL);
|
xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
|
||||||
dev_obj->dynamic.config_desc = config_desc;
|
assert(dev_obj->mux_protected.config_desc == NULL);
|
||||||
USBH_EXIT_CRITICAL();
|
dev_obj->mux_protected.config_desc = config_desc;
|
||||||
|
xSemaphoreGive(p_usbh_obj->constant.mux_lock);
|
||||||
|
|
||||||
//We can modify the info members outside the critical section
|
//We can modify the info members outside the critical section
|
||||||
dev_obj->constant.enum_todo_flags &= ~DEV_ENUM_TODO_FLAG_CONFIG_DESC;
|
dev_obj->constant.enum_todo_flags &= ~DEV_ENUM_TODO_FLAG_CONFIG_DESC;
|
||||||
@ -874,13 +981,16 @@ esp_err_t usbh_hub_enum_done(usb_device_handle_t dev_hdl)
|
|||||||
device_t *dev_obj = (device_t *)dev_hdl;
|
device_t *dev_obj = (device_t *)dev_hdl;
|
||||||
USBH_CHECK(dev_obj->constant.enum_todo_flags == 0, ESP_ERR_INVALID_STATE); //All enumeration stages to be done
|
USBH_CHECK(dev_obj->constant.enum_todo_flags == 0, ESP_ERR_INVALID_STATE); //All enumeration stages to be done
|
||||||
|
|
||||||
|
//We need to take the mux_lock to access mux_protected members
|
||||||
|
xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
|
||||||
USBH_ENTER_CRITICAL();
|
USBH_ENTER_CRITICAL();
|
||||||
dev_obj->dynamic.state = USB_DEVICE_STATE_CONFIGURED;
|
dev_obj->dynamic.state = USB_DEVICE_STATE_CONFIGURED;
|
||||||
//Add the device to list of devices, then trigger a device event
|
//Add the device to list of devices, then trigger a device event
|
||||||
TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry); //Add it to the idle device list first
|
TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry); //Add it to the idle device list first
|
||||||
p_usbh_obj->dynamic.num_device++;
|
|
||||||
bool call_notif_cb = _dev_set_actions(dev_obj, DEV_FLAG_ACTION_SEND_NEW);
|
bool call_notif_cb = _dev_set_actions(dev_obj, DEV_FLAG_ACTION_SEND_NEW);
|
||||||
USBH_EXIT_CRITICAL();
|
USBH_EXIT_CRITICAL();
|
||||||
|
p_usbh_obj->mux_protected.num_device++;
|
||||||
|
xSemaphoreGive(p_usbh_obj->constant.mux_lock);
|
||||||
|
|
||||||
//Update the default pipe callback
|
//Update the default pipe callback
|
||||||
ESP_ERROR_CHECK(hcd_pipe_update_callback(dev_obj->constant.default_pipe, default_pipe_callback, (void *)dev_obj));
|
ESP_ERROR_CHECK(hcd_pipe_update_callback(dev_obj->constant.default_pipe, default_pipe_callback, (void *)dev_obj));
|
||||||
@ -896,10 +1006,11 @@ esp_err_t usbh_hub_enum_failed(usb_device_handle_t dev_hdl)
|
|||||||
USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG);
|
USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG);
|
||||||
device_t *dev_obj = (device_t *)dev_hdl;
|
device_t *dev_obj = (device_t *)dev_hdl;
|
||||||
|
|
||||||
USBH_ENTER_CRITICAL();
|
//We need to take the mux_lock to access mux_protected members
|
||||||
usb_config_desc_t *config_desc = dev_obj->dynamic.config_desc;
|
xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
|
||||||
dev_obj->dynamic.config_desc = NULL;
|
usb_config_desc_t *config_desc = dev_obj->mux_protected.config_desc;
|
||||||
USBH_EXIT_CRITICAL();
|
dev_obj->mux_protected.config_desc = NULL;
|
||||||
|
xSemaphoreGive(p_usbh_obj->constant.mux_lock);
|
||||||
|
|
||||||
if (config_desc) {
|
if (config_desc) {
|
||||||
heap_caps_free(config_desc);
|
heap_caps_free(config_desc);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user