mirror of
https://github.com/espressif/esp-idf
synced 2025-03-10 01:29:21 -04:00
usb: Hub Driver Update and Refactor
Hub Driver is refactored as follows: This commit update and refactors the Hub Driver as follows: - Refactored enumeration state machine and stage functions - Enumeration stage is now incremented - Combined transfer stages of enumeration into common functions - Comments updated - Fixed usbh_hal_disable_debounce_lock() that would cause root_port_handle_events() to fail the HCD_PORT_CMD_RESET call because the previous port connection interrupt was not cleared. The following features were added to the Hub Driver - Enumeration config descriptor is now fetched in two separate stages - Header is fetched first to determine the wTotalLength of the descriptor - Fetching the full descriptor will request exactly wTotalLength bytes - This works around some non-compliant devices that will babble/return zero when requesting a length > wTotalLength - Closes https://github.com/espressif/esp-idf/issues/7799 - Enumeration now stores string descriptors - The Manufacturer, Product, and Serial Number string descriptors are now read and stored during enumeration - String descriptors are now part of usb_device_info_t - Added unit test to test enumeration
This commit is contained in:
parent
854127a57c
commit
1aad12468a
@ -494,7 +494,7 @@ static inline void usbh_hal_disable_debounce_lock(usbh_hal_context_t *hal)
|
||||
hal->flags.dbnc_lock_enabled = 0;
|
||||
//Clear Conenction and disconenction interrupt in case it triggered again
|
||||
usb_ll_intr_clear(hal->dev, USB_LL_INTR_CORE_DISCONNINT);
|
||||
usbh_ll_hprt_intr_clear(hal->dev, USBH_LL_INTR_HPRT_PRTENCHNG);
|
||||
usbh_ll_hprt_intr_clear(hal->dev, USBH_LL_INTR_HPRT_PRTCONNDET);
|
||||
//Reenable the hprt (connection) and disconnection interrupts
|
||||
usb_ll_en_intrs(hal->dev, USB_LL_INTR_CORE_PRTINT | USB_LL_INTR_CORE_DISCONNINT);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -72,6 +72,16 @@ typedef struct {
|
||||
};
|
||||
} usb_host_client_event_msg_t;
|
||||
|
||||
// ------------------------ Info ---------------------------
|
||||
|
||||
/**
|
||||
* @brief Current information about the USB Host Library obtained via usb_host_lib_info()
|
||||
*/
|
||||
typedef struct {
|
||||
int num_devices; /**< Current number of connected (and enumerated) devices */
|
||||
int num_clients; /**< Current number of registered clients */
|
||||
} usb_host_lib_info_t;
|
||||
|
||||
// ---------------------- Callbacks ------------------------
|
||||
|
||||
/**
|
||||
@ -166,6 +176,14 @@ esp_err_t usb_host_lib_handle_events(TickType_t timeout_ticks, uint32_t *event_f
|
||||
*/
|
||||
esp_err_t usb_host_lib_unblock(void);
|
||||
|
||||
/**
|
||||
* @brief Get current information about the USB Host Library
|
||||
*
|
||||
* @param[out] info_ret USB Host Library Information
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t usb_host_lib_info(usb_host_lib_info_t *info_ret);
|
||||
|
||||
// ------------------------------------------------ Client Functions ---------------------------------------------------
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
*/
|
||||
@ -217,11 +217,11 @@ _Static_assert(sizeof(usb_setup_packet_t) == USB_SETUP_PACKET_SIZE, "Size of usb
|
||||
/**
|
||||
* @brief Initializer for a request to get an string descriptor
|
||||
*/
|
||||
#define USB_SETUP_PACKET_INIT_GET_STR_DESC(setup_pkt_ptr, string_index, desc_len) ({ \
|
||||
#define USB_SETUP_PACKET_INIT_GET_STR_DESC(setup_pkt_ptr, string_index, lang_id, desc_len) ({ \
|
||||
(setup_pkt_ptr)->bmRequestType = USB_BM_REQUEST_TYPE_DIR_IN | USB_BM_REQUEST_TYPE_TYPE_STANDARD | USB_BM_REQUEST_TYPE_RECIP_DEVICE; \
|
||||
(setup_pkt_ptr)->bRequest = USB_B_REQUEST_GET_DESCRIPTOR; \
|
||||
(setup_pkt_ptr)->wValue = (USB_W_VALUE_DT_STRING << 8) | ((string_index) & 0xFF); \
|
||||
(setup_pkt_ptr)->wIndex = 0; \
|
||||
(setup_pkt_ptr)->wIndex = (lang_id); \
|
||||
(setup_pkt_ptr)->wLength = (desc_len); \
|
||||
})
|
||||
|
||||
@ -465,7 +465,7 @@ _Static_assert(sizeof(usb_ep_desc_t) == USB_EP_DESC_SIZE, "Size of usb_ep_desc_t
|
||||
/**
|
||||
* @brief Size of a short USB string descriptor in bytes
|
||||
*/
|
||||
#define USB_STR_DESC_SIZE 4
|
||||
#define USB_STR_DESC_SIZE 2
|
||||
|
||||
/**
|
||||
* @brief Structure representing a USB string descriptor
|
||||
@ -474,7 +474,7 @@ typedef union {
|
||||
struct {
|
||||
uint8_t bLength; /**< Size of the descriptor in bytes */
|
||||
uint8_t bDescriptorType; /**< STRING Descriptor Type */
|
||||
uint16_t wData[1]; /**< UTF-16LE encoded */
|
||||
uint16_t wData[0]; /**< UTF-16LE encoded */
|
||||
} USB_DESC_ATTR;
|
||||
uint8_t val[USB_STR_DESC_SIZE];
|
||||
} usb_str_desc_t;
|
||||
|
@ -49,10 +49,13 @@ typedef struct usb_device_handle_s * usb_device_handle_t;
|
||||
* @brief Basic information of an enumerated device
|
||||
*/
|
||||
typedef struct {
|
||||
usb_speed_t speed; /**< Device's speed */
|
||||
uint8_t dev_addr; /**< Device's address */
|
||||
uint8_t bMaxPacketSize0; /**< The maximum packet size of the device's default endpoint */
|
||||
uint8_t bConfigurationValue; /**< Device's current configuration number */
|
||||
usb_speed_t speed; /**< Device's speed */
|
||||
uint8_t dev_addr; /**< Device's address */
|
||||
uint8_t bMaxPacketSize0; /**< The maximum packet size of the device's default endpoint */
|
||||
uint8_t bConfigurationValue; /**< Device's current configuration number */
|
||||
const usb_str_desc_t *str_desc_manufacturer; /**< Pointer to Manufacturer string descriptor (can be NULL) */
|
||||
const usb_str_desc_t *str_desc_product; /**< Pointer to Product string descriptor (can be NULL) */
|
||||
const usb_str_desc_t *str_desc_serial_num; /**< Pointer to Serial Number string descriptor (can be NULL) */
|
||||
} usb_device_info_t;
|
||||
|
||||
// ------------------------------------------------ Transfer Related ---------------------------------------------------
|
||||
|
@ -119,6 +119,15 @@ esp_err_t usbh_uninstall(void);
|
||||
*/
|
||||
esp_err_t usbh_process(void);
|
||||
|
||||
/**
|
||||
* @brief Get the current number of devices
|
||||
*
|
||||
* @note This function can block
|
||||
* @param[out] num_devs_ret Current number of devices
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t usbh_num_devs(int *num_devs_ret);
|
||||
|
||||
// ------------------------------------------------ Device Functions ---------------------------------------------------
|
||||
|
||||
// --------------------- Device Pool -----------------------
|
||||
@ -336,17 +345,6 @@ esp_err_t usbh_hub_dev_port_disabled(usb_device_handle_t dev_hdl);
|
||||
|
||||
// ----------------- Enumeration Related -------------------
|
||||
|
||||
/**
|
||||
* @brief Fill the enumerating device's descriptor
|
||||
*
|
||||
* @note Hub Driver only
|
||||
* @note Must call in sequence
|
||||
* @param[in] dev_hdl Device handle
|
||||
* @param device_desc
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t usbh_hub_enum_fill_dev_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t *device_desc);
|
||||
|
||||
/**
|
||||
* @brief Assign the enumerating device's address
|
||||
*
|
||||
@ -358,6 +356,17 @@ esp_err_t usbh_hub_enum_fill_dev_desc(usb_device_handle_t dev_hdl, const usb_dev
|
||||
*/
|
||||
esp_err_t usbh_hub_enum_fill_dev_addr(usb_device_handle_t dev_hdl, uint8_t dev_addr);
|
||||
|
||||
/**
|
||||
* @brief Fill the enumerating device's descriptor
|
||||
*
|
||||
* @note Hub Driver only
|
||||
* @note Must call in sequence
|
||||
* @param[in] dev_hdl Device handle
|
||||
* @param device_desc
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t usbh_hub_enum_fill_dev_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t *device_desc);
|
||||
|
||||
/**
|
||||
* @brief Fill the enumerating device's active configuration descriptor
|
||||
*
|
||||
@ -371,15 +380,16 @@ esp_err_t usbh_hub_enum_fill_dev_addr(usb_device_handle_t dev_hdl, uint8_t dev_a
|
||||
esp_err_t usbh_hub_enum_fill_config_desc(usb_device_handle_t dev_hdl, const usb_config_desc_t *config_desc_full);
|
||||
|
||||
/**
|
||||
* @brief Assign the enumerating device's active configuration number
|
||||
* @brief Fill one of the string descriptors of the enumerating device
|
||||
*
|
||||
* @note Hub Driver only
|
||||
* @note Must call in sequence
|
||||
* @param[in] dev_hdl Device handle
|
||||
* @param bConfigurationValue
|
||||
* @param dev_hdl Device handle
|
||||
* @param str_desc Pointer to string descriptor
|
||||
* @param select Select which string descriptor. 0/1/2 for Manufacturer/Product/Serial Number string descriptors respecitvely
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t usbh_hub_enum_fill_config_num(usb_device_handle_t dev_hdl, uint8_t bConfigurationValue);
|
||||
esp_err_t usbh_hub_enum_fill_str_desc(usb_device_handle_t dev_hdl, const usb_str_desc_t *str_desc, int select);
|
||||
|
||||
/**
|
||||
* @brief Indicate the device enumeration is completed
|
||||
|
@ -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
|
||||
*/
|
||||
@ -14,6 +14,49 @@
|
||||
|
||||
const char *MSC_CLIENT_TAG = "MSC Client";
|
||||
|
||||
const uint8_t mock_msc_scsi_dev_desc[] = {
|
||||
0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x5F, 0x12, 0x8A, 0xC0, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01,
|
||||
};
|
||||
|
||||
const uint8_t mock_msc_scsi_config_desc[] = {
|
||||
0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0xF0, 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, 0x00, 0x07,
|
||||
0x05, 0x01, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x01,
|
||||
};
|
||||
|
||||
|
||||
const uint8_t mock_msc_scsi_str_desc_manu[] = {
|
||||
0x0c, 0x03, 0x41, 0x00, 0x44, 0x00, 0x41, 0x00, 0x54, 0x00, 0x41, 0x00,
|
||||
};
|
||||
|
||||
const uint8_t mock_msc_scsi_str_desc_prod[] = {
|
||||
0x2c, 0x03, 0x41, 0x00, 0x44, 0x00, 0x41, 0x00, 0x54, 0x00, 0x41, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53, 0x00, 0x42,
|
||||
0x00, 0x20, 0x00, 0x46, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x73, 0x00, 0x68, 0x00, 0x20, 0x00, 0x44, 0x00, 0x72, 0x00,
|
||||
0x69, 0x00, 0x76, 0x00, 0x65, 0x00,
|
||||
};
|
||||
|
||||
const uint8_t mock_msc_scsi_str_desc_ser_num[] = {
|
||||
0x22, 0x03, 0x31, 0x00, 0x33, 0x00, 0x43, 0x00, 0x32, 0x00, 0x38, 0x00, 0x31, 0x00, 0x36, 0x00, 0x35, 0x00, 0x38,
|
||||
0x00, 0x32, 0x00, 0x31, 0x00, 0x38, 0x00, 0x30, 0x00, 0x30, 0x00, 0x38, 0x00, 0x45, 0x00,
|
||||
};
|
||||
|
||||
const usb_ep_desc_t mock_msc_scsi_bulk_out_ep_desc = {
|
||||
.bLength = sizeof(usb_ep_desc_t),
|
||||
.bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT,
|
||||
.bEndpointAddress = 0x01, //EP 1 OUT
|
||||
.bmAttributes = USB_BM_ATTRIBUTES_XFER_BULK,
|
||||
.wMaxPacketSize = 64, //MPS of 64 bytes
|
||||
.bInterval = 1,
|
||||
};
|
||||
|
||||
const usb_ep_desc_t mock_msc_scsi_bulk_in_ep_desc = {
|
||||
.bLength = sizeof(usb_ep_desc_t),
|
||||
.bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT,
|
||||
.bEndpointAddress = 0x82, //EP 2 IN
|
||||
.bmAttributes = USB_BM_ATTRIBUTES_XFER_BULK,
|
||||
.wMaxPacketSize = 64, //MPS of 64 bytes
|
||||
.bInterval = 1,
|
||||
};
|
||||
|
||||
void mock_msc_scsi_init_cbw(mock_msc_bulk_cbw_t *cbw, bool is_read, int offset, int num_sectors, uint32_t tag)
|
||||
{
|
||||
cbw->dCBWSignature = 0x43425355; //Fixed value
|
||||
@ -60,6 +103,15 @@ bool mock_msc_scsi_check_csw(mock_msc_bulk_csw_t *csw, uint32_t tag_expect)
|
||||
|
||||
// ---------------------------------------------------- HID Mouse ------------------------------------------------------
|
||||
|
||||
const usb_ep_desc_t mock_hid_mouse_in_ep_desc = {
|
||||
.bLength = sizeof(usb_ep_desc_t),
|
||||
.bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT,
|
||||
.bEndpointAddress = 0x81, //EP 1 IN
|
||||
.bmAttributes = USB_BM_ATTRIBUTES_XFER_INT,
|
||||
.wMaxPacketSize = 4, //MPS of 4 bytes
|
||||
.bInterval = 10, //Interval of 10ms
|
||||
};
|
||||
|
||||
void mock_hid_process_report(mock_hid_mouse_report_t *report, int iter)
|
||||
{
|
||||
static int x_pos = 0;
|
||||
|
@ -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
|
||||
*/
|
||||
@ -88,23 +88,14 @@ Configuration Descriptor:
|
||||
If you're using a flash driver with different endpoints, modify the endpoint descriptors below.
|
||||
*/
|
||||
|
||||
static const usb_ep_desc_t mock_msc_scsi_bulk_out_ep_desc = {
|
||||
.bLength = sizeof(usb_ep_desc_t),
|
||||
.bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT,
|
||||
.bEndpointAddress = 0x01, //EP 1 OUT
|
||||
.bmAttributes = USB_BM_ATTRIBUTES_XFER_BULK,
|
||||
.wMaxPacketSize = 64, //MPS of 64 bytes
|
||||
.bInterval = 1,
|
||||
};
|
||||
|
||||
static const usb_ep_desc_t mock_msc_scsi_bulk_in_ep_desc = {
|
||||
.bLength = sizeof(usb_ep_desc_t),
|
||||
.bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT,
|
||||
.bEndpointAddress = 0x82, //EP 2 IN
|
||||
.bmAttributes = USB_BM_ATTRIBUTES_XFER_BULK,
|
||||
.wMaxPacketSize = 64, //MPS of 64 bytes
|
||||
.bInterval = 1,
|
||||
};
|
||||
//Constant descriptors
|
||||
extern const uint8_t mock_msc_scsi_dev_desc[];
|
||||
extern const uint8_t mock_msc_scsi_config_desc[];
|
||||
extern const uint8_t mock_msc_scsi_str_desc_manu[];
|
||||
extern const uint8_t mock_msc_scsi_str_desc_prod[];
|
||||
extern const uint8_t mock_msc_scsi_str_desc_ser_num[];
|
||||
extern const usb_ep_desc_t mock_msc_scsi_bulk_out_ep_desc;
|
||||
extern const usb_ep_desc_t mock_msc_scsi_bulk_in_ep_desc;
|
||||
|
||||
#define MOCK_MSC_SCSI_DEV_ID_VENDOR 0x125F
|
||||
#define MOCK_MSC_SCSI_DEV_ID_PRODUCT 0xc08A
|
||||
@ -246,14 +237,8 @@ Device Descriptor:
|
||||
|
||||
If you're using another mice with different endpoints, modify the endpoint descriptor below
|
||||
*/
|
||||
static const usb_ep_desc_t mock_hid_mouse_in_ep_desc = {
|
||||
.bLength = sizeof(usb_ep_desc_t),
|
||||
.bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT,
|
||||
.bEndpointAddress = 0x81, //EP 1 IN
|
||||
.bmAttributes = USB_BM_ATTRIBUTES_XFER_INT,
|
||||
.wMaxPacketSize = 4, //MPS of 4 bytes
|
||||
.bInterval = 10, //Interval of 10ms
|
||||
};
|
||||
|
||||
extern const usb_ep_desc_t mock_hid_mouse_in_ep_desc;
|
||||
|
||||
#define MOCK_HID_MOUSE_DEV_ID_VENDOR 0x413C
|
||||
#define MOCK_HID_MOUSE_DEV_ID_PRODUCT 0x301A
|
||||
|
@ -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
|
||||
*/
|
||||
@ -19,3 +19,5 @@ typedef struct {
|
||||
void msc_client_async_seq_task(void *arg);
|
||||
|
||||
void msc_client_async_dconn_task(void *arg);
|
||||
|
||||
void msc_client_async_enum_task(void *arg);
|
||||
|
169
components/usb/test/usb_host/msc_client_async_enum.c
Normal file
169
components/usb/test/usb_host/msc_client_async_enum.c
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/param.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "test_usb_mock_classes.h"
|
||||
#include "test_usb_common.h"
|
||||
#include "msc_client.h"
|
||||
#include "usb/usb_host.h"
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
/*
|
||||
Implementation of an asynchronous MSC client used for USB Host enumeration test.
|
||||
|
||||
- The MSC client will:
|
||||
- Register itself as a client
|
||||
- Receive USB_HOST_CLIENT_EVENT_NEW_DEV event message, and open the device
|
||||
- Check the device and configuration descriptor of the device
|
||||
- Check the device's information
|
||||
- Close device
|
||||
- Deregister MSC client
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
TEST_STAGE_WAIT_CONN,
|
||||
TEST_STAGE_DEV_OPEN,
|
||||
TEST_STAGE_CHECK_DEV_DESC,
|
||||
TEST_STAGE_CHECK_CONFIG_DESC,
|
||||
TEST_STAGE_CHECK_STR_DESC,
|
||||
TEST_STAGE_DEV_CLOSE,
|
||||
} test_stage_t;
|
||||
|
||||
typedef struct {
|
||||
test_stage_t cur_stage;
|
||||
test_stage_t next_stage;
|
||||
uint8_t dev_addr_to_open;
|
||||
usb_host_client_handle_t client_hdl;
|
||||
usb_device_handle_t dev_hdl;
|
||||
} msc_client_obj_t;
|
||||
|
||||
static void msc_client_event_cb(const usb_host_client_event_msg_t *event_msg, void *arg)
|
||||
{
|
||||
msc_client_obj_t *msc_obj = (msc_client_obj_t *)arg;
|
||||
switch (event_msg->event) {
|
||||
case USB_HOST_CLIENT_EVENT_NEW_DEV:
|
||||
TEST_ASSERT_EQUAL(TEST_STAGE_WAIT_CONN, msc_obj->cur_stage);
|
||||
msc_obj->next_stage = TEST_STAGE_DEV_OPEN;
|
||||
msc_obj->dev_addr_to_open = event_msg->new_dev.address;
|
||||
break;
|
||||
default:
|
||||
abort(); //Should never occur in this test
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void msc_client_async_enum_task(void *arg)
|
||||
{
|
||||
msc_client_obj_t msc_obj;
|
||||
msc_obj.cur_stage = TEST_STAGE_WAIT_CONN;
|
||||
msc_obj.next_stage = TEST_STAGE_WAIT_CONN;
|
||||
msc_obj.client_hdl = NULL;
|
||||
msc_obj.dev_addr_to_open = 0;
|
||||
msc_obj.dev_hdl = NULL;
|
||||
|
||||
//Register client
|
||||
usb_host_client_config_t client_config = {
|
||||
.is_synchronous = false,
|
||||
.max_num_event_msg = MSC_ASYNC_CLIENT_MAX_EVENT_MSGS,
|
||||
.async = {
|
||||
.client_event_callback = msc_client_event_cb,
|
||||
.callback_arg = (void *)&msc_obj,
|
||||
},
|
||||
};
|
||||
TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_register(&client_config, &msc_obj.client_hdl));
|
||||
|
||||
//Wait to be started by main thread
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
ESP_LOGD(MSC_CLIENT_TAG, "Starting");
|
||||
|
||||
bool exit_loop = false;
|
||||
bool skip_event_handling = false;
|
||||
while (!exit_loop) {
|
||||
if (!skip_event_handling) {
|
||||
TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_handle_events(msc_obj.client_hdl, portMAX_DELAY));
|
||||
}
|
||||
skip_event_handling = false;
|
||||
if (msc_obj.cur_stage == msc_obj.next_stage) {
|
||||
continue;
|
||||
}
|
||||
msc_obj.cur_stage = msc_obj.next_stage;
|
||||
|
||||
switch (msc_obj.cur_stage) {
|
||||
case TEST_STAGE_DEV_OPEN: {
|
||||
ESP_LOGD(MSC_CLIENT_TAG, "Open");
|
||||
//Open the device
|
||||
TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_open(msc_obj.client_hdl, msc_obj.dev_addr_to_open, &msc_obj.dev_hdl));
|
||||
msc_obj.next_stage = TEST_STAGE_CHECK_DEV_DESC;
|
||||
skip_event_handling = true; //Need to execute TEST_STAGE_CHECK_DEV_DESC
|
||||
break;
|
||||
}
|
||||
case TEST_STAGE_CHECK_DEV_DESC: {
|
||||
//Check the device descriptor
|
||||
const usb_device_desc_t *device_desc;
|
||||
const usb_device_desc_t *device_desc_ref = (const usb_device_desc_t *)mock_msc_scsi_dev_desc;
|
||||
TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_device_descriptor(msc_obj.dev_hdl, &device_desc));
|
||||
TEST_ASSERT_EQUAL(device_desc_ref->bLength, device_desc->bLength);
|
||||
TEST_ASSERT_EQUAL(0, memcmp(device_desc_ref, device_desc, device_desc_ref->bLength));
|
||||
msc_obj.next_stage = TEST_STAGE_CHECK_CONFIG_DESC;
|
||||
skip_event_handling = true; //Need to execute TEST_STAGE_CHECK_CONFIG_DESC
|
||||
break;
|
||||
}
|
||||
|
||||
case TEST_STAGE_CHECK_CONFIG_DESC: {
|
||||
//Check the configuration descriptor
|
||||
const usb_config_desc_t *config_desc;
|
||||
const usb_config_desc_t *config_desc_ref = (const usb_config_desc_t *)mock_msc_scsi_config_desc;
|
||||
TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_active_config_descriptor(msc_obj.dev_hdl, &config_desc));
|
||||
TEST_ASSERT_EQUAL(config_desc_ref->wTotalLength, config_desc->wTotalLength);
|
||||
TEST_ASSERT_EQUAL(0, memcmp(config_desc_ref, config_desc, config_desc_ref->wTotalLength));
|
||||
msc_obj.next_stage = TEST_STAGE_CHECK_STR_DESC;
|
||||
skip_event_handling = true; //Need to execute TEST_STAGE_CHECK_STR_DESC
|
||||
break;
|
||||
}
|
||||
case TEST_STAGE_CHECK_STR_DESC: {
|
||||
usb_device_info_t dev_info;
|
||||
TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_info(msc_obj.dev_hdl, &dev_info));
|
||||
//Check manufacturer string descriptors
|
||||
const usb_str_desc_t *manu_str_desc_ref = (const usb_str_desc_t *)mock_msc_scsi_str_desc_manu;
|
||||
const usb_str_desc_t *product_str_desc_ref = (const usb_str_desc_t *)mock_msc_scsi_str_desc_prod;
|
||||
const usb_str_desc_t *ser_num_str_desc_ref = (const usb_str_desc_t *)mock_msc_scsi_str_desc_ser_num;
|
||||
TEST_ASSERT_EQUAL(manu_str_desc_ref->bLength, dev_info.str_desc_manufacturer->bLength);
|
||||
TEST_ASSERT_EQUAL(product_str_desc_ref->bLength, dev_info.str_desc_product->bLength);
|
||||
TEST_ASSERT_EQUAL(ser_num_str_desc_ref->bLength, dev_info.str_desc_serial_num->bLength);
|
||||
TEST_ASSERT_EQUAL(0, memcmp(manu_str_desc_ref, dev_info.str_desc_manufacturer , manu_str_desc_ref->bLength));
|
||||
TEST_ASSERT_EQUAL(0, memcmp(product_str_desc_ref, dev_info.str_desc_product , manu_str_desc_ref->bLength));
|
||||
TEST_ASSERT_EQUAL(0, memcmp(ser_num_str_desc_ref, dev_info.str_desc_serial_num , manu_str_desc_ref->bLength));
|
||||
//Get dev info and compare
|
||||
msc_obj.next_stage = TEST_STAGE_DEV_CLOSE;
|
||||
skip_event_handling = true; //Need to execute TEST_STAGE_DEV_CLOSE
|
||||
break;
|
||||
}
|
||||
|
||||
case TEST_STAGE_DEV_CLOSE: {
|
||||
ESP_LOGD(MSC_CLIENT_TAG, "Close");
|
||||
TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_close(msc_obj.client_hdl, msc_obj.dev_hdl));
|
||||
exit_loop = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
//Free transfers and deregister the client
|
||||
TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_deregister(msc_obj.client_hdl));
|
||||
ESP_LOGD(MSC_CLIENT_TAG, "Done");
|
||||
vTaskDelete(NULL);
|
||||
}
|
@ -115,3 +115,40 @@ TEST_CASE("Test USB Host sudden disconnection (single client)", "[usb_host][igno
|
||||
ESP_ERROR_CHECK(usb_host_uninstall());
|
||||
test_usb_deinit_phy(); //Deinitialize the internal USB PHY after testing
|
||||
}
|
||||
|
||||
TEST_CASE("Test USB Host enumeration", "[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");
|
||||
|
||||
//Create task to run client that checks the enumeration of the device
|
||||
TaskHandle_t task_hdl;
|
||||
xTaskCreatePinnedToCore(msc_client_async_enum_task, "async", 4096, NULL, 2, &task_hdl, 0);
|
||||
//Start the task
|
||||
xTaskNotifyGive(task_hdl);
|
||||
|
||||
while (1) {
|
||||
//Start handling system events
|
||||
uint32_t event_flags;
|
||||
usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
|
||||
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
|
||||
printf("No more clients\n");
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FINISHED, usb_host_device_free_all());
|
||||
}
|
||||
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Short delay to allow task to be cleaned up
|
||||
vTaskDelay(10);
|
||||
//Clean up USB Host
|
||||
ESP_ERROR_CHECK(usb_host_uninstall());
|
||||
test_usb_deinit_phy(); //Deinitialize the internal USB PHY after testing
|
||||
}
|
||||
|
@ -542,6 +542,23 @@ esp_err_t usb_host_lib_unblock(void)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t usb_host_lib_info(usb_host_lib_info_t *info_ret)
|
||||
{
|
||||
HOST_CHECK(info_ret != NULL, ESP_ERR_INVALID_ARG);
|
||||
int num_devs_temp;
|
||||
int num_clients_temp;
|
||||
HOST_ENTER_CRITICAL();
|
||||
HOST_CHECK_FROM_CRIT(p_host_lib_obj != NULL, ESP_ERR_INVALID_STATE);
|
||||
num_clients_temp = p_host_lib_obj->dynamic.flags.num_clients;
|
||||
HOST_EXIT_CRITICAL();
|
||||
usbh_num_devs(&num_devs_temp);
|
||||
|
||||
//Write back return values
|
||||
info_ret->num_devices = num_devs_temp;
|
||||
info_ret->num_clients = num_clients_temp;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// ------------------------------------------------ Client Functions ---------------------------------------------------
|
||||
|
||||
// ----------------------- Private -------------------------
|
||||
|
@ -68,6 +68,9 @@ struct device_s {
|
||||
usb_speed_t speed;
|
||||
const usb_device_desc_t *desc;
|
||||
const usb_config_desc_t *config_desc;
|
||||
const usb_str_desc_t *str_desc_manu;
|
||||
const usb_str_desc_t *str_desc_product;
|
||||
const usb_str_desc_t *str_desc_ser_num;
|
||||
} constant;
|
||||
};
|
||||
|
||||
@ -171,6 +174,16 @@ static void device_free(device_t *dev_obj)
|
||||
if (dev_obj->constant.config_desc) {
|
||||
heap_caps_free((usb_config_desc_t *)dev_obj->constant.config_desc);
|
||||
}
|
||||
//String descriptors might not have been allocated (in case of early enumeration failure)
|
||||
if (dev_obj->constant.str_desc_manu) {
|
||||
heap_caps_free((usb_str_desc_t *)dev_obj->constant.str_desc_manu);
|
||||
}
|
||||
if (dev_obj->constant.str_desc_product) {
|
||||
heap_caps_free((usb_str_desc_t *)dev_obj->constant.str_desc_product);
|
||||
}
|
||||
if (dev_obj->constant.str_desc_ser_num) {
|
||||
heap_caps_free((usb_str_desc_t *)dev_obj->constant.str_desc_ser_num);
|
||||
}
|
||||
heap_caps_free((usb_device_desc_t *)dev_obj->constant.desc);
|
||||
ESP_ERROR_CHECK(hcd_pipe_free(dev_obj->constant.default_pipe));
|
||||
heap_caps_free(dev_obj);
|
||||
@ -458,6 +471,15 @@ esp_err_t usbh_process(void)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t usbh_num_devs(int *num_devs_ret)
|
||||
{
|
||||
USBH_CHECK(num_devs_ret != NULL, ESP_ERR_INVALID_ARG);
|
||||
xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
|
||||
*num_devs_ret = p_usbh_obj->mux_protected.num_device;
|
||||
xSemaphoreGive(p_usbh_obj->constant.mux_lock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// ------------------------------------------------ Device Functions ---------------------------------------------------
|
||||
|
||||
// --------------------- Device Pool -----------------------
|
||||
@ -640,6 +662,10 @@ esp_err_t usbh_dev_get_info(usb_device_handle_t dev_hdl, usb_device_info_t *dev_
|
||||
USBH_EXIT_CRITICAL();
|
||||
assert(dev_obj->constant.config_desc);
|
||||
dev_info->bConfigurationValue = dev_obj->constant.config_desc->bConfigurationValue;
|
||||
//String descriptors are allowed to be NULL as not all devices support them
|
||||
dev_info->str_desc_manufacturer = dev_obj->constant.str_desc_manu;
|
||||
dev_info->str_desc_product = dev_obj->constant.str_desc_product;
|
||||
dev_info->str_desc_serial_num = dev_obj->constant.str_desc_ser_num;
|
||||
ret = ESP_OK;
|
||||
exit:
|
||||
return ret;
|
||||
@ -964,12 +990,41 @@ esp_err_t usbh_hub_enum_fill_config_desc(usb_device_handle_t dev_hdl, const usb_
|
||||
}
|
||||
//Copy the configuration descriptor
|
||||
memcpy(config_desc, config_desc_full, config_desc_full->wTotalLength);
|
||||
//Assign the config object to the device object
|
||||
//Assign the config desc to the device object
|
||||
assert(dev_obj->constant.config_desc == NULL);
|
||||
dev_obj->constant.config_desc = config_desc;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t usbh_hub_enum_fill_str_desc(usb_device_handle_t dev_hdl, const usb_str_desc_t *str_desc, int select)
|
||||
{
|
||||
USBH_CHECK(dev_hdl != NULL && str_desc != NULL && (select >= 0 && select < 3), ESP_ERR_INVALID_ARG);
|
||||
device_t *dev_obj = (device_t *)dev_hdl;
|
||||
//Allocate memory to store the manufacturer string descriptor
|
||||
usb_str_desc_t *str_desc_fill = heap_caps_malloc(str_desc->bLength, MALLOC_CAP_DEFAULT);
|
||||
if (str_desc_fill == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
//Copy the string descriptor
|
||||
memcpy(str_desc_fill, str_desc, str_desc->bLength);
|
||||
//Assign filled string descriptor to the device object
|
||||
switch (select) {
|
||||
case 0:
|
||||
assert(dev_obj->constant.str_desc_manu == NULL);
|
||||
dev_obj->constant.str_desc_manu = str_desc_fill;
|
||||
break;
|
||||
case 1:
|
||||
assert(dev_obj->constant.str_desc_product == NULL);
|
||||
dev_obj->constant.str_desc_product = str_desc_fill;
|
||||
break;
|
||||
default: //2
|
||||
assert(dev_obj->constant.str_desc_ser_num == NULL);
|
||||
dev_obj->constant.str_desc_ser_num = str_desc_fill;
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t usbh_hub_enum_done(usb_device_handle_t dev_hdl)
|
||||
{
|
||||
USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG);
|
||||
|
@ -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
|
||||
*/
|
||||
@ -432,7 +432,7 @@ static esp_err_t msc_read_string_desc(msc_device_t *dev, uint8_t index, wchar_t
|
||||
}
|
||||
|
||||
usb_transfer_t *xfer = dev->xfer;
|
||||
USB_SETUP_PACKET_INIT_GET_STR_DESC((usb_setup_packet_t *)xfer->data_buffer, index, 64);
|
||||
USB_SETUP_PACKET_INIT_GET_STR_DESC((usb_setup_packet_t *)xfer->data_buffer, index, 0x409, 64);
|
||||
MSC_RETURN_ON_ERROR( msc_control_transfer(dev, xfer, USB_SETUP_PACKET_SIZE + 64) );
|
||||
|
||||
usb_standard_desc_t *desc = (usb_standard_desc_t *)(xfer->data_buffer + USB_SETUP_PACKET_SIZE);
|
||||
|
Loading…
x
Reference in New Issue
Block a user