usb: Update USB Host Library

This commit updates the USB Host Library as follows:

- usb_helpers.h
    - Removed dependency on USB Host Library API
    - Added function to print string descriptors
- usbh
    - Fixed bug where an interface/endpoint could be claimed/allocated multiple times
    - Removed redundant device ref_count change
- Added unit test for USB Host Library API usage
This commit is contained in:
Darian Leung 2021-12-23 18:22:55 +08:00
parent 22c152c388
commit b6dfadb168
7 changed files with 240 additions and 64 deletions

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -111,6 +111,44 @@ const usb_ep_desc_t *usb_parse_endpoint_descriptor_by_index(const usb_intf_desc_
*/ */
const usb_ep_desc_t *usb_parse_endpoint_descriptor_by_address(const usb_config_desc_t *config_desc, uint8_t bInterfaceNumber, uint8_t bAlternateSetting, uint8_t bEndpointAddress, int *offset); const usb_ep_desc_t *usb_parse_endpoint_descriptor_by_address(const usb_config_desc_t *config_desc, uint8_t bInterfaceNumber, uint8_t bAlternateSetting, uint8_t bEndpointAddress, int *offset);
// ----------------------------------------------- Descriptor Printing -------------------------------------------------
/**
* @brief Print class specific descriptor callback
*
* Optional callback to be provided to usb_print_config_descriptor() function.
* The callback is called when when a non-standard descriptor is encountered.
* The callback should decode the descriptor as print it.
*/
typedef void (*print_class_descriptor_cb)(const usb_standard_desc_t *);
/**
* @brief Print device descriptor
*
* @param devc_desc Device descriptor
*/
void usb_print_device_descriptor(const usb_device_desc_t *devc_desc);
/**
* @brief Print configuration descriptor
*
* - This function prints the full contents of a configuration descriptor (including interface and endpoint descriptors)
* - When a non-standard descriptor is encountered, this function will call the class_specific_cb if it is provided
*
* @param cfg_desc Configuration descriptor
* @param class_specific_cb Class specific descriptor callback. Can be NULL
*/
void usb_print_config_descriptor(const usb_config_desc_t *cfg_desc, print_class_descriptor_cb class_specific_cb);
/**
* @brief Print a string descriptor
*
* This funciton will only print ASCII characters of the UTF-16 encoded string
*
* @param str_desc String descriptor
*/
void usb_print_string_descriptor(const usb_str_desc_t *str_desc);
// ------------------------------------------------------ Misc --------------------------------------------------------- // ------------------------------------------------------ Misc ---------------------------------------------------------
/** /**
@ -118,6 +156,8 @@ const usb_ep_desc_t *usb_parse_endpoint_descriptor_by_address(const usb_config_d
* *
* This is a convenience function to round up a size/length to an endpoint's MPS (Maximum packet size). This is useful * This is a convenience function to round up a size/length to an endpoint's MPS (Maximum packet size). This is useful
* when calculating transfer or buffer lengths of IN endpoints. * when calculating transfer or buffer lengths of IN endpoints.
* - If MPS <= 0, this function will return 0
* - If num_bytes <= 0, this function will return 0
* *
* @param[in] num_bytes Number of bytes * @param[in] num_bytes Number of bytes
* @param[in] mps MPS * @param[in] mps MPS
@ -125,31 +165,12 @@ const usb_ep_desc_t *usb_parse_endpoint_descriptor_by_address(const usb_config_d
*/ */
static inline int usb_round_up_to_mps(int num_bytes, int mps) static inline int usb_round_up_to_mps(int num_bytes, int mps)
{ {
if (num_bytes < 0 || mps < 0) { if (num_bytes <= 0 || mps <= 0) { //MPS can never be zero
return 0; return 0;
} }
return ((num_bytes + mps - 1) / mps) * mps; return ((num_bytes + mps - 1) / mps) * mps;
} }
/**
* @brief Print class specific descriptor callback
*
* Optional callback to be provided to usb_print_descriptors() function.
* The callback is called when when a non-standard descriptor is encountered.
* The callback should decode the descriptor as print it.
*/
typedef void (*print_class_descriptor_cb)(const usb_standard_desc_t *);
/**
* @brief Prints usb descriptors
*
* @param[in] device Handle to device
* @param[in] class_specific_cb Optional callback to print class specific descriptors
* @return esp_err_t
*/
esp_err_t usb_print_descriptors(usb_device_handle_t device, print_class_descriptor_cb class_specific_cb);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -148,7 +148,7 @@ esp_err_t usb_host_install(const usb_host_config_t *config);
* - All devices must have been freed by calling usb_host_device_free_all() and receiving the * - All devices must have been freed by calling usb_host_device_free_all() and receiving the
* USB_HOST_LIB_EVENT_FLAGS_ALL_FREE event flag * USB_HOST_LIB_EVENT_FLAGS_ALL_FREE event flag
* *
* @note If skip_phy_setup was set when the Host Library was installed, the user is responsible for diasbling the * @note If skip_phy_setup was set when the Host Library was installed, the user is responsible for disabling the
* underlying Host Controller and USB PHY (internal or external). * underlying Host Controller and USB PHY (internal or external).
* @return esp_err_t * @return esp_err_t
*/ */
@ -159,10 +159,11 @@ esp_err_t usb_host_uninstall(void);
* *
* - This function handles all of the USB Host Library's processing and should be called repeatedly in a loop * - This function handles all of the USB Host Library's processing and should be called repeatedly in a loop
* - Check event_flags_ret to see if an flags are set indicating particular USB Host Library events * - Check event_flags_ret to see if an flags are set indicating particular USB Host Library events
* - This function should never be called by multiple threads simultaneously
* *
* @note This function can block * @note This function can block
* @param[in] timeout_ticks Timeout in ticks to wait for an event to occur * @param[in] timeout_ticks Timeout in ticks to wait for an event to occur
* @param[out] event_flags_ret Event flags that indicate what USB Host Library event occurred * @param[out] event_flags_ret Event flags that indicate what USB Host Library event occurred.
* @return esp_err_t * @return esp_err_t
*/ */
esp_err_t usb_host_lib_handle_events(TickType_t timeout_ticks, uint32_t *event_flags_ret); esp_err_t usb_host_lib_handle_events(TickType_t timeout_ticks, uint32_t *event_flags_ret);
@ -213,6 +214,7 @@ esp_err_t usb_host_client_deregister(usb_host_client_handle_t client_hdl);
* @brief USB Host Library client processing function * @brief USB Host Library client processing function
* *
* - This function handles all of a client's processing and should be called repeatedly in a loop * - This function handles all of a client's processing and should be called repeatedly in a loop
* - For a particular client, this function should never be called by multiple threads simultaneously
* *
* @note This function can block * @note This function can block
* @param[in] client_hdl Client handle * @param[in] client_hdl Client handle
@ -283,8 +285,7 @@ esp_err_t usb_host_device_free_all(void);
* *
* - This function fills an empty list with the address of connected devices * - This function fills an empty list with the address of connected devices
* - The Device addresses can then used in usb_host_device_open() * - The Device addresses can then used in usb_host_device_open()
* - If there are more devices than the list_len, this function will only fill * - If there are more devices than the list_len, this function will only fill up to list_len number of devices.
* up to list_len number of devices.
* *
* @param[in] list_len Length of the empty list * @param[in] list_len Length of the empty list
* @param[inout] dev_addr_list Empty list to be filled * @param[inout] dev_addr_list Empty list to be filled

View File

@ -45,7 +45,7 @@ Procedure:
- Uninstall USB Host Library - Uninstall USB Host Library
*/ */
TEST_CASE("Test USB Host async (single client)", "[usb_host][ignore]") TEST_CASE("Test USB Host async client (single client)", "[usb_host][ignore]")
{ {
test_usb_init_phy(); //Initialize the internal USB PHY and USB Controller for testing test_usb_init_phy(); //Initialize the internal USB PHY and USB Controller for testing
//Install USB Host //Install USB Host
@ -109,7 +109,7 @@ Procedure:
- Free all devices - Free all devices
- Uninstall USB Host Library - Uninstall USB Host Library
*/ */
TEST_CASE("Test USB Host async (multi client)", "[usb_host][ignore]") TEST_CASE("Test USB Host async client (multi client)", "[usb_host][ignore]")
{ {
test_usb_init_phy(); //Initialize the internal USB PHY and USB Controller for testing test_usb_init_phy(); //Initialize the internal USB PHY and USB Controller for testing
//Install USB Host //Install USB Host
@ -163,3 +163,145 @@ TEST_CASE("Test USB Host async (multi client)", "[usb_host][ignore]")
ESP_ERROR_CHECK(usb_host_uninstall()); ESP_ERROR_CHECK(usb_host_uninstall());
test_usb_deinit_phy(); //Deinitialize the internal USB PHY after testing test_usb_deinit_phy(); //Deinitialize the internal USB PHY after testing
} }
/*
Test USB Host Asynchronous API Usage
Requires: This test requires an MSC SCSI device to be attached (see the MSC mock class)
Purpose:
- Test that incorrect usage of USB Host Asynchronous API will returns errors
Procedure:
- Install USB Host Library
- Register two clients and all event handler functions from the same loop
- Wait for each client to detect device connection
- Check that both clients can open the same device
- Check that a client cannot open a non-existent device
- Check that only one client can claim a particular interface
- Check that a client cannot release an already released interface
- Wait for device disconnection
- Cleanup
*/
static uint8_t dev_addr = 0;
typedef enum {
CLIENT_TEST_STAGE_NONE,
CLIENT_TEST_STAGE_CONN,
CLIENT_TEST_STAGE_DCONN,
} client_test_stage_t;
static void test_async_client_cb(const usb_host_client_event_msg_t *event_msg, void *arg)
{
client_test_stage_t *stage = (client_test_stage_t *)arg;
switch (event_msg->event) {
case USB_HOST_CLIENT_EVENT_NEW_DEV:
if (dev_addr == 0) {
dev_addr = event_msg->new_dev.address;
} else {
TEST_ASSERT_EQUAL(dev_addr, event_msg->new_dev.address);
}
*stage = CLIENT_TEST_STAGE_CONN;
break;
case USB_HOST_CLIENT_EVENT_DEV_GONE:
*stage = CLIENT_TEST_STAGE_DCONN;
break;
default:
abort();
break;
}
}
TEST_CASE("Test USB Host async API", "[usb_host][ignore]")
{
test_usb_init_phy(); //Initialize the internal USB PHY and USB Controller for testing
//Install USB Host
usb_host_config_t host_config = {
.skip_phy_setup = true, //test_usb_init_phy() will already have setup the internal USB PHY for us
.intr_flags = ESP_INTR_FLAG_LEVEL1,
};
ESP_ERROR_CHECK(usb_host_install(&host_config));
printf("Installed\n");
//Register two clients
client_test_stage_t client0_stage = CLIENT_TEST_STAGE_NONE;
client_test_stage_t client1_stage = CLIENT_TEST_STAGE_NONE;
usb_host_client_config_t client_config = {
.is_synchronous = false,
.max_num_event_msg = 5,
.async = {
.client_event_callback = test_async_client_cb,
.callback_arg = (void *)&client0_stage,
},
};
usb_host_client_handle_t client0_hdl;
usb_host_client_handle_t client1_hdl;
TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_register(&client_config, &client0_hdl));
client_config.async.callback_arg = (void *)&client1_stage;
TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_register(&client_config, &client1_hdl));
//Wait until the device connects and the clients receive the event
while (!(client0_stage == CLIENT_TEST_STAGE_CONN && client1_stage == CLIENT_TEST_STAGE_CONN)) {
usb_host_lib_handle_events(0, NULL);
usb_host_client_handle_events(client0_hdl, 0);
usb_host_client_handle_events(client1_hdl, 0);
vTaskDelay(10);
}
//Check that both clients can open the device
TEST_ASSERT_NOT_EQUAL(0, dev_addr);
usb_device_handle_t client0_dev_hdl;
usb_device_handle_t client1_dev_hdl;
TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_open(client0_hdl, dev_addr, &client0_dev_hdl));
TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_open(client1_hdl, dev_addr, &client1_dev_hdl));
TEST_ASSERT_EQUAL(client0_dev_hdl, client1_dev_hdl); //Check that its the same device
//Check that a client cannot open a non-existent device
TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_device_open(client0_hdl, 0, &client0_dev_hdl));
//Check that the device cannot be opened again by the same client
usb_device_handle_t dummy_dev_hdl;
TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_device_open(client0_hdl, dev_addr, &dummy_dev_hdl));
TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_device_open(client1_hdl, dev_addr, &dummy_dev_hdl));
//Check that both clients cannot claim the same interface
TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_claim(client0_hdl, client0_dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER, MOCK_MSC_SCSI_INTF_ALT_SETTING));
TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_interface_claim(client1_hdl, client1_dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER, MOCK_MSC_SCSI_INTF_ALT_SETTING));
//Check that client0 cannot claim the same interface multiple times
TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_interface_claim(client0_hdl, client0_dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER, MOCK_MSC_SCSI_INTF_ALT_SETTING));
//Check that client0 can release the interface
TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_release(client0_hdl, client0_dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER));
//Check that client0 cannot release interface it has not claimed
TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_interface_release(client0_hdl, client0_dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER));
//Wait until the device disconnects and the clients receive the event
test_usb_set_phy_state(false, 0);
while (!(client0_stage == CLIENT_TEST_STAGE_DCONN && client1_stage == CLIENT_TEST_STAGE_DCONN)) {
usb_host_lib_handle_events(0, NULL);
usb_host_client_handle_events(client0_hdl, 0);
usb_host_client_handle_events(client1_hdl, 0);
vTaskDelay(10);
}
TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_close(client0_hdl, client0_dev_hdl));
TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_close(client1_hdl, client1_dev_hdl));
//Deregister the clients
TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_deregister(client0_hdl));
TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_deregister(client1_hdl));
while (1) {
uint32_t event_flags;
usb_host_lib_handle_events(0, &event_flags);
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
break;
}
vTaskDelay(10);
}
//Cleanup
TEST_ASSERT_EQUAL(ESP_OK, usb_host_uninstall());
test_usb_deinit_phy();
}

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -15,8 +15,6 @@
#include "esp_check.h" #include "esp_check.h"
#include "usb/usb_host.h" #include "usb/usb_host.h"
static const char *TAG = "usb_helper";
// ---------------------------------------- Configuration Descriptor Parsing ------------------------------------------- // ---------------------------------------- Configuration Descriptor Parsing -------------------------------------------
const usb_standard_desc_t *usb_parse_next_descriptor(const usb_standard_desc_t *cur_desc, uint16_t wTotalLength, int *offset) const usb_standard_desc_t *usb_parse_next_descriptor(const usb_standard_desc_t *cur_desc, uint16_t wTotalLength, int *offset)
@ -171,7 +169,7 @@ const usb_ep_desc_t *usb_parse_endpoint_descriptor_by_address(const usb_config_d
return ep_desc; return ep_desc;
} }
// ------------------------------------------ Descriptor printing --------------------------------------------- // ----------------------------------------------- Descriptor Printing -------------------------------------------------
static void print_ep_desc(const usb_ep_desc_t *ep_desc) static void print_ep_desc(const usb_ep_desc_t *ep_desc)
{ {
@ -232,8 +230,12 @@ static void usbh_print_cfg_desc(const usb_config_desc_t *cfg_desc)
printf("bMaxPower %dmA\n", cfg_desc->bMaxPower * 2); printf("bMaxPower %dmA\n", cfg_desc->bMaxPower * 2);
} }
static void print_device_descriptor(const usb_device_desc_t *devc_desc) void usb_print_device_descriptor(const usb_device_desc_t *devc_desc)
{ {
if (devc_desc == NULL) {
return;
}
printf("*** Device descriptor ***\n"); printf("*** Device descriptor ***\n");
printf("bLength %d\n", devc_desc->bLength); printf("bLength %d\n", devc_desc->bLength);
printf("bDescriptorType %d\n", devc_desc->bDescriptorType); printf("bDescriptorType %d\n", devc_desc->bDescriptorType);
@ -251,8 +253,12 @@ static void print_device_descriptor(const usb_device_desc_t *devc_desc)
printf("bNumConfigurations %d\n", devc_desc->bNumConfigurations); printf("bNumConfigurations %d\n", devc_desc->bNumConfigurations);
} }
static void print_config_descriptor(const usb_config_desc_t *cfg_desc, print_class_descriptor_cb class_specific_cb) void usb_print_config_descriptor(const usb_config_desc_t *cfg_desc, print_class_descriptor_cb class_specific_cb)
{ {
if (cfg_desc == NULL) {
return;
}
int offset = 0; int offset = 0;
uint16_t wTotalLength = cfg_desc->wTotalLength; uint16_t wTotalLength = cfg_desc->wTotalLength;
const usb_standard_desc_t *next_desc = (const usb_standard_desc_t *)cfg_desc; const usb_standard_desc_t *next_desc = (const usb_standard_desc_t *)cfg_desc;
@ -280,22 +286,21 @@ static void print_config_descriptor(const usb_config_desc_t *cfg_desc, print_cla
} while (next_desc != NULL); } while (next_desc != NULL);
} }
esp_err_t usb_print_descriptors(usb_device_handle_t device, print_class_descriptor_cb class_specific_cb) void usb_print_string_descriptor(const usb_str_desc_t *str_desc)
{ {
if (device == NULL) { if (str_desc == NULL) {
return ESP_ERR_INVALID_ARG; return;
} }
const usb_config_desc_t *config_desc; for (int i = 0; i < str_desc->bLength/2; i++) {
const usb_device_desc_t *device_desc; /*
USB String descriptors of UTF-16.
ESP_RETURN_ON_ERROR( usb_host_get_device_descriptor(device, &device_desc), TAG, "Failed to get devices descriptor" ); Right now We just skip any character larger than 0xFF to stay in BMP Basic Latin and Latin-1 Supplement range.
ESP_RETURN_ON_ERROR( usb_host_get_active_config_descriptor(device, &config_desc), TAG, "Failed to get config descriptor" ); */
if (str_desc->wData[i] > 0xFF) {
print_device_descriptor(device_desc); continue;
print_config_descriptor(config_desc, class_specific_cb); }
printf("%c", (char)str_desc->wData[i]);
return ESP_OK; }
printf("\n");
} }
// ------------------------------------------------------ Misc ---------------------------------------------------------

View File

@ -1012,14 +1012,14 @@ static esp_err_t interface_claim(client_t *client_obj, usb_device_handle_t dev_h
if (ret != ESP_OK) { if (ret != ESP_OK) {
goto ep_alloc_err; goto ep_alloc_err;
} }
//Store endpoint object into interface object //Fill the interface object with the allocated endpoints
intf_obj->constant.endpoints[i] = ep_obj; intf_obj->constant.endpoints[i] = ep_obj;
} }
//Add interface object to client (safe because we have already taken the mutex) //Add interface object to client (safe because we have already taken the mutex)
TAILQ_INSERT_TAIL(&client_obj->mux_protected.interface_tailq, intf_obj, mux_protected.tailq_entry); TAILQ_INSERT_TAIL(&client_obj->mux_protected.interface_tailq, intf_obj, mux_protected.tailq_entry);
//Add each endpoint to the client's endpoint list //Add each endpoint to the client's endpoint list
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) { for (int i = 0; i < intf_desc->bNumEndpoints; i++) {
TAILQ_INSERT_TAIL(&client_obj->dynamic.idle_ep_tailq, intf_obj->constant.endpoints[i], dynamic.tailq_entry); TAILQ_INSERT_TAIL(&client_obj->dynamic.idle_ep_tailq, intf_obj->constant.endpoints[i], dynamic.tailq_entry);
} }
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
@ -1029,7 +1029,7 @@ static esp_err_t interface_claim(client_t *client_obj, usb_device_handle_t dev_h
return ret; return ret;
ep_alloc_err: ep_alloc_err:
for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) { for (int i = 0; i < intf_desc->bNumEndpoints; i++) {
endpoint_free(dev_hdl, intf_obj->constant.endpoints[i]); endpoint_free(dev_hdl, intf_obj->constant.endpoints[i]);
intf_obj->constant.endpoints[i] = NULL; intf_obj->constant.endpoints[i] = NULL;
} }

View File

@ -748,13 +748,8 @@ esp_err_t usbh_ep_alloc(usb_device_handle_t dev_hdl, usbh_ep_config_t *ep_config
{ {
USBH_CHECK(dev_hdl != NULL && ep_config != NULL && pipe_hdl_ret != NULL, ESP_ERR_INVALID_ARG); USBH_CHECK(dev_hdl != NULL && ep_config != NULL && pipe_hdl_ret != NULL, ESP_ERR_INVALID_ARG);
device_t *dev_obj = (device_t *)dev_hdl; device_t *dev_obj = (device_t *)dev_hdl;
USBH_ENTER_CRITICAL();
USBH_CHECK_FROM_CRIT(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED, ESP_ERR_INVALID_STATE);
dev_obj->dynamic.ref_count++; //Increase the ref_count to keep the device alive while allocating the endpoint
USBH_EXIT_CRITICAL();
esp_err_t ret; esp_err_t ret;
//Allocate HCD pipe //Allocate HCD pipe
hcd_pipe_config_t pipe_config = { hcd_pipe_config_t pipe_config = {
.callback = ep_config->pipe_cb, .callback = ep_config->pipe_cb,
@ -776,17 +771,22 @@ esp_err_t usbh_ep_alloc(usb_device_handle_t dev_hdl, usbh_ep_config_t *ep_config
//We need to take the mux_lock to access mux_protected members //We need to take the mux_lock to access mux_protected members
xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); 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 USBH_ENTER_CRITICAL();
//Check the device's state before we assign the pipes to the endpoint
if (dev_obj->dynamic.state != USB_DEVICE_STATE_CONFIGURED) {
USBH_EXIT_CRITICAL();
ret = ESP_ERR_INVALID_STATE;
goto assign_err;
}
USBH_EXIT_CRITICAL();
//Assign the allocated pipe to the correct endpoint
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; dev_obj->mux_protected.ep_in[addr - 1] = pipe_hdl;
assigned = true; assigned = true;
} else { } else if (dev_obj->mux_protected.ep_out[addr - 1] == NULL) { //Is an OUT EP
dev_obj->mux_protected.ep_out[addr - 1] = pipe_hdl; dev_obj->mux_protected.ep_out[addr - 1] = pipe_hdl;
assigned = true; assigned = true;
} }
//Restore ref_count
USBH_ENTER_CRITICAL();
dev_obj->dynamic.ref_count--;
USBH_EXIT_CRITICAL();
xSemaphoreGive(p_usbh_obj->constant.mux_lock); xSemaphoreGive(p_usbh_obj->constant.mux_lock);
if (!assigned) { if (!assigned) {

View File

@ -469,7 +469,14 @@ esp_err_t msc_host_get_device_info(msc_host_device_handle_t device, msc_host_dev
esp_err_t msc_host_print_descriptors(msc_host_device_handle_t device) esp_err_t msc_host_print_descriptors(msc_host_device_handle_t device)
{ {
return usb_print_descriptors(((msc_device_t *)device)->handle, NULL); msc_device_t *dev = (msc_device_t *)device;
const usb_device_desc_t *device_desc;
const usb_config_desc_t *config_desc;
MSC_RETURN_ON_ERROR( usb_host_get_device_descriptor(dev->handle, &device_desc) );
MSC_RETURN_ON_ERROR( usb_host_get_active_config_descriptor(dev->handle, &config_desc) );
usb_print_device_descriptor(device_desc);
usb_print_config_descriptor(config_desc, NULL);
return ESP_OK;
} }
static void transfer_callback(usb_transfer_t *transfer) static void transfer_callback(usb_transfer_t *transfer)