mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-01 19:54:32 +02: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:
@@ -494,7 +494,7 @@ static inline void usbh_hal_disable_debounce_lock(usbh_hal_context_t *hal)
|
|||||||
hal->flags.dbnc_lock_enabled = 0;
|
hal->flags.dbnc_lock_enabled = 0;
|
||||||
//Clear Conenction and disconenction interrupt in case it triggered again
|
//Clear Conenction and disconenction interrupt in case it triggered again
|
||||||
usb_ll_intr_clear(hal->dev, USB_LL_INTR_CORE_DISCONNINT);
|
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
|
//Reenable the hprt (connection) and disconnection interrupts
|
||||||
usb_ll_en_intrs(hal->dev, USB_LL_INTR_CORE_PRTINT | USB_LL_INTR_CORE_DISCONNINT);
|
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;
|
} 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 ------------------------
|
// ---------------------- 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);
|
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 ---------------------------------------------------
|
// ------------------------------------------------ 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
|
* 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
|
* @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)->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)->bRequest = USB_B_REQUEST_GET_DESCRIPTOR; \
|
||||||
(setup_pkt_ptr)->wValue = (USB_W_VALUE_DT_STRING << 8) | ((string_index) & 0xFF); \
|
(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); \
|
(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
|
* @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
|
* @brief Structure representing a USB string descriptor
|
||||||
@@ -474,7 +474,7 @@ typedef union {
|
|||||||
struct {
|
struct {
|
||||||
uint8_t bLength; /**< Size of the descriptor in bytes */
|
uint8_t bLength; /**< Size of the descriptor in bytes */
|
||||||
uint8_t bDescriptorType; /**< STRING Descriptor Type */
|
uint8_t bDescriptorType; /**< STRING Descriptor Type */
|
||||||
uint16_t wData[1]; /**< UTF-16LE encoded */
|
uint16_t wData[0]; /**< UTF-16LE encoded */
|
||||||
} USB_DESC_ATTR;
|
} USB_DESC_ATTR;
|
||||||
uint8_t val[USB_STR_DESC_SIZE];
|
uint8_t val[USB_STR_DESC_SIZE];
|
||||||
} usb_str_desc_t;
|
} usb_str_desc_t;
|
||||||
|
@@ -53,6 +53,9 @@ typedef struct {
|
|||||||
uint8_t dev_addr; /**< Device's address */
|
uint8_t dev_addr; /**< Device's address */
|
||||||
uint8_t bMaxPacketSize0; /**< The maximum packet size of the device's default endpoint */
|
uint8_t bMaxPacketSize0; /**< The maximum packet size of the device's default endpoint */
|
||||||
uint8_t bConfigurationValue; /**< Device's current configuration number */
|
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;
|
} usb_device_info_t;
|
||||||
|
|
||||||
// ------------------------------------------------ Transfer Related ---------------------------------------------------
|
// ------------------------------------------------ Transfer Related ---------------------------------------------------
|
||||||
|
@@ -119,6 +119,15 @@ esp_err_t usbh_uninstall(void);
|
|||||||
*/
|
*/
|
||||||
esp_err_t usbh_process(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 Functions ---------------------------------------------------
|
||||||
|
|
||||||
// --------------------- Device Pool -----------------------
|
// --------------------- Device Pool -----------------------
|
||||||
@@ -336,17 +345,6 @@ esp_err_t usbh_hub_dev_port_disabled(usb_device_handle_t dev_hdl);
|
|||||||
|
|
||||||
// ----------------- Enumeration Related -------------------
|
// ----------------- 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
|
* @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);
|
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
|
* @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);
|
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 Hub Driver only
|
||||||
* @note Must call in sequence
|
* @note Must call in sequence
|
||||||
* @param[in] dev_hdl Device handle
|
* @param dev_hdl Device handle
|
||||||
* @param bConfigurationValue
|
* @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
|
* @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
|
* @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
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -14,6 +14,49 @@
|
|||||||
|
|
||||||
const char *MSC_CLIENT_TAG = "MSC Client";
|
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)
|
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
|
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 ------------------------------------------------------
|
// ---------------------------------------------------- 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)
|
void mock_hid_process_report(mock_hid_mouse_report_t *report, int iter)
|
||||||
{
|
{
|
||||||
static int x_pos = 0;
|
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
|
* 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.
|
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 = {
|
//Constant descriptors
|
||||||
.bLength = sizeof(usb_ep_desc_t),
|
extern const uint8_t mock_msc_scsi_dev_desc[];
|
||||||
.bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT,
|
extern const uint8_t mock_msc_scsi_config_desc[];
|
||||||
.bEndpointAddress = 0x01, //EP 1 OUT
|
extern const uint8_t mock_msc_scsi_str_desc_manu[];
|
||||||
.bmAttributes = USB_BM_ATTRIBUTES_XFER_BULK,
|
extern const uint8_t mock_msc_scsi_str_desc_prod[];
|
||||||
.wMaxPacketSize = 64, //MPS of 64 bytes
|
extern const uint8_t mock_msc_scsi_str_desc_ser_num[];
|
||||||
.bInterval = 1,
|
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;
|
||||||
|
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MOCK_MSC_SCSI_DEV_ID_VENDOR 0x125F
|
#define MOCK_MSC_SCSI_DEV_ID_VENDOR 0x125F
|
||||||
#define MOCK_MSC_SCSI_DEV_ID_PRODUCT 0xc08A
|
#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
|
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),
|
extern const usb_ep_desc_t mock_hid_mouse_in_ep_desc;
|
||||||
.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
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MOCK_HID_MOUSE_DEV_ID_VENDOR 0x413C
|
#define MOCK_HID_MOUSE_DEV_ID_VENDOR 0x413C
|
||||||
#define MOCK_HID_MOUSE_DEV_ID_PRODUCT 0x301A
|
#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
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -19,3 +19,5 @@ typedef struct {
|
|||||||
void msc_client_async_seq_task(void *arg);
|
void msc_client_async_seq_task(void *arg);
|
||||||
|
|
||||||
void msc_client_async_dconn_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());
|
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_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;
|
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 ---------------------------------------------------
|
// ------------------------------------------------ Client Functions ---------------------------------------------------
|
||||||
|
|
||||||
// ----------------------- Private -------------------------
|
// ----------------------- Private -------------------------
|
||||||
|
@@ -68,6 +68,9 @@ struct device_s {
|
|||||||
usb_speed_t speed;
|
usb_speed_t speed;
|
||||||
const usb_device_desc_t *desc;
|
const usb_device_desc_t *desc;
|
||||||
const usb_config_desc_t *config_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;
|
} constant;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -171,6 +174,16 @@ static void device_free(device_t *dev_obj)
|
|||||||
if (dev_obj->constant.config_desc) {
|
if (dev_obj->constant.config_desc) {
|
||||||
heap_caps_free((usb_config_desc_t *)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);
|
heap_caps_free((usb_device_desc_t *)dev_obj->constant.desc);
|
||||||
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(dev_obj);
|
heap_caps_free(dev_obj);
|
||||||
@@ -458,6 +471,15 @@ esp_err_t usbh_process(void)
|
|||||||
return ESP_OK;
|
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 Functions ---------------------------------------------------
|
||||||
|
|
||||||
// --------------------- Device Pool -----------------------
|
// --------------------- 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();
|
USBH_EXIT_CRITICAL();
|
||||||
assert(dev_obj->constant.config_desc);
|
assert(dev_obj->constant.config_desc);
|
||||||
dev_info->bConfigurationValue = dev_obj->constant.config_desc->bConfigurationValue;
|
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;
|
ret = ESP_OK;
|
||||||
exit:
|
exit:
|
||||||
return ret;
|
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
|
//Copy the configuration descriptor
|
||||||
memcpy(config_desc, config_desc_full, config_desc_full->wTotalLength);
|
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);
|
assert(dev_obj->constant.config_desc == NULL);
|
||||||
dev_obj->constant.config_desc = config_desc;
|
dev_obj->constant.config_desc = config_desc;
|
||||||
return ESP_OK;
|
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)
|
esp_err_t usbh_hub_enum_done(usb_device_handle_t dev_hdl)
|
||||||
{
|
{
|
||||||
USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG);
|
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
|
* 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_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) );
|
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);
|
usb_standard_desc_t *desc = (usb_standard_desc_t *)(xfer->data_buffer + USB_SETUP_PACKET_SIZE);
|
||||||
|
Reference in New Issue
Block a user