Merge branch 'fix/usb_binterval_parsing' into 'master'

fix(usb/host): Correctly parse wMaxPacketSize and bInterval fields in HighSpeed EP descriptors

See merge request espressif/esp-idf!27395
This commit is contained in:
Tomas Rezucha
2023-12-13 17:28:45 +08:00
6 changed files with 37 additions and 42 deletions

View File

@@ -142,7 +142,7 @@ typedef struct {
uint32_t val; uint32_t val;
}; };
struct { struct {
usb_hal_interval_t interval; /**< The interval of the endpoint */ unsigned int interval; /**< The interval of the endpoint in frames (FS) or microframes (HS) */
uint32_t phase_offset_frames; /**< Phase offset in number of frames */ uint32_t phase_offset_frames; /**< Phase offset in number of frames */
} periodic; /**< Characteristic for periodic (interrupt/isochronous) endpoints only */ } periodic; /**< Characteristic for periodic (interrupt/isochronous) endpoints only */
} usb_dwc_hal_ep_char_t; } usb_dwc_hal_ep_char_t;

View File

@@ -51,19 +51,6 @@ typedef enum {
USB_HAL_FRAME_LIST_LEN_64 = 64, USB_HAL_FRAME_LIST_LEN_64 = 64,
} usb_hal_frame_list_len_t; } usb_hal_frame_list_len_t;
/**
* @brief Support intervals in number of USB frames (i.e., 1ms)
*/
typedef enum {
USB_HAL_INTERVAL_1 = 1,
USB_HAL_INTERVAL_2 = 2,
USB_HAL_INTERVAL_4 = 4,
USB_HAL_INTERVAL_8 = 8,
USB_HAL_INTERVAL_16 = 16,
USB_HAL_INTERVAL_32 = 32,
USB_HAL_INTERVAL_64 = 64,
} usb_hal_interval_t;
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -1536,9 +1536,9 @@ static bool pipe_alloc_hcd_support_verification(usb_dwc_hal_context_t *hal, cons
} }
} }
if (ep_desc->wMaxPacketSize > limit) { if (USB_EP_DESC_GET_MPS(ep_desc) > limit) {
ESP_LOGE(HCD_DWC_TAG, "EP MPS (%d) exceeds supported limit (%d)", ESP_LOGE(HCD_DWC_TAG, "EP MPS (%d) exceeds supported limit (%d)",
ep_desc->wMaxPacketSize, USB_EP_DESC_GET_MPS(ep_desc),
limit); limit);
return false; return false;
} }
@@ -1571,38 +1571,38 @@ static void pipe_set_ep_char(const hcd_pipe_config_t *pipe_config, usb_transfer_
ep_char->mps = (pipe_config->dev_speed == USB_SPEED_LOW) ? CTRL_EP_MAX_MPS_LS : CTRL_EP_MAX_MPS_HSFS; ep_char->mps = (pipe_config->dev_speed == USB_SPEED_LOW) ? CTRL_EP_MAX_MPS_LS : CTRL_EP_MAX_MPS_HSFS;
} else { } else {
ep_char->bEndpointAddress = pipe_config->ep_desc->bEndpointAddress; ep_char->bEndpointAddress = pipe_config->ep_desc->bEndpointAddress;
ep_char->mps = pipe_config->ep_desc->wMaxPacketSize; ep_char->mps = USB_EP_DESC_GET_MPS(pipe_config->ep_desc);
} }
ep_char->dev_addr = pipe_config->dev_addr; ep_char->dev_addr = pipe_config->dev_addr;
ep_char->ls_via_fs_hub = (port_speed == USB_SPEED_FULL && pipe_config->dev_speed == USB_SPEED_LOW); ep_char->ls_via_fs_hub = (port_speed == USB_SPEED_FULL && pipe_config->dev_speed == USB_SPEED_LOW);
// Calculate the pipe's interval in terms of USB frames // Calculate the pipe's interval in terms of USB frames
// @see USB-OTG programming guide chapter 6.5 for more information // @see USB-OTG programming guide chapter 6.5 for more information
if (type == USB_TRANSFER_TYPE_INTR || type == USB_TRANSFER_TYPE_ISOCHRONOUS) { if (type == USB_TRANSFER_TYPE_INTR || type == USB_TRANSFER_TYPE_ISOCHRONOUS) {
unsigned int interval_frames; // Convert bInterval field to real value
unsigned int xfer_list_len; // @see USB 2.0 specs, Table 9-13
if (type == USB_TRANSFER_TYPE_INTR) { unsigned int interval_value;
interval_frames = pipe_config->ep_desc->bInterval; if (type == USB_TRANSFER_TYPE_INTR && pipe_config->dev_speed != USB_SPEED_HIGH) {
xfer_list_len = XFER_LIST_LEN_INTR; interval_value = pipe_config->ep_desc->bInterval;
} else { } else {
interval_frames = (1 << (pipe_config->ep_desc->bInterval - 1)); interval_value = (1 << (pipe_config->ep_desc->bInterval - 1));
xfer_list_len = XFER_LIST_LEN_ISOC;
} }
// Round down interval to nearest power of 2 // Round down interval to nearest power of 2
if (interval_frames >= 32) { if (interval_value >= 32) {
interval_frames = 32; interval_value = 32;
} else if (interval_frames >= 16) { } else if (interval_value >= 16) {
interval_frames = 16; interval_value = 16;
} else if (interval_frames >= 8) { } else if (interval_value >= 8) {
interval_frames = 8; interval_value = 8;
} else if (interval_frames >= 4) { } else if (interval_value >= 4) {
interval_frames = 4; interval_value = 4;
} else if (interval_frames >= 2) { } else if (interval_value >= 2) {
interval_frames = 2; interval_value = 2;
} else if (interval_frames >= 1) { } else if (interval_value >= 1) {
interval_frames = 1; interval_value = 1;
} }
ep_char->periodic.interval = interval_frames; ep_char->periodic.interval = interval_value;
// We are the Nth pipe to be allocated. Use N as a phase offset // We are the Nth pipe to be allocated. Use N as a phase offset
unsigned int xfer_list_len = (type == USB_TRANSFER_TYPE_INTR) ? XFER_LIST_LEN_INTR : XFER_LIST_LEN_ISOC;
ep_char->periodic.phase_offset_frames = pipe_idx & (xfer_list_len - 1); ep_char->periodic.phase_offset_frames = pipe_idx & (xfer_list_len - 1);
} else { } else {
ep_char->periodic.interval = 0; ep_char->periodic.interval = 0;

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -435,6 +435,12 @@ ESP_STATIC_ASSERT(sizeof(usb_ep_desc_t) == USB_EP_DESC_SIZE, "Size of usb_ep_des
#define USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK 0x0f #define USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK 0x0f
#define USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK 0x80 #define USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK 0x80
/**
* @brief Bit masks belonging to the wMaxPacketSize field of endpoint descriptor
*/
#define USB_W_MAX_PACKET_SIZE_MPS_MASK 0x07ff
#define USB_W_MAX_PACKET_SIZE_MULT_MASK 0x1800
/** /**
* @brief Bit masks belonging to the bmAttributes field of an endpoint descriptor * @brief Bit masks belonging to the bmAttributes field of an endpoint descriptor
*/ */
@@ -459,7 +465,8 @@ ESP_STATIC_ASSERT(sizeof(usb_ep_desc_t) == USB_EP_DESC_SIZE, "Size of usb_ep_des
#define USB_EP_DESC_GET_XFERTYPE(desc_ptr) ((usb_transfer_type_t) ((desc_ptr)->bmAttributes & USB_BM_ATTRIBUTES_XFERTYPE_MASK)) #define USB_EP_DESC_GET_XFERTYPE(desc_ptr) ((usb_transfer_type_t) ((desc_ptr)->bmAttributes & USB_BM_ATTRIBUTES_XFERTYPE_MASK))
#define USB_EP_DESC_GET_EP_NUM(desc_ptr) ((desc_ptr)->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) #define USB_EP_DESC_GET_EP_NUM(desc_ptr) ((desc_ptr)->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK)
#define USB_EP_DESC_GET_EP_DIR(desc_ptr) (((desc_ptr)->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK) ? 1 : 0) #define USB_EP_DESC_GET_EP_DIR(desc_ptr) (((desc_ptr)->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK) ? 1 : 0)
#define USB_EP_DESC_GET_MPS(desc_ptr) ((desc_ptr)->wMaxPacketSize & 0x7FF) #define USB_EP_DESC_GET_MPS(desc_ptr) ((desc_ptr)->wMaxPacketSize & USB_W_MAX_PACKET_SIZE_MPS_MASK)
#define USB_EP_DESC_GET_MULT(desc_ptr) (((desc_ptr)->wMaxPacketSize & USB_W_MAX_PACKET_SIZE_MULT_MASK) >> 11)
// ------------------ String Descriptor -------------------- // ------------------ String Descriptor --------------------

View File

@@ -68,10 +68,11 @@ TEST_CASE("Test HCD bulk pipe URBs", "[bulk][full_speed]")
//Create URBs for CBW, Data, and CSW transport. IN Buffer sizes are rounded up to nearest MPS //Create URBs for CBW, Data, and CSW transport. IN Buffer sizes are rounded up to nearest MPS
urb_t *urb_cbw = test_hcd_alloc_urb(0, sizeof(mock_msc_bulk_cbw_t)); urb_t *urb_cbw = test_hcd_alloc_urb(0, sizeof(mock_msc_bulk_cbw_t));
urb_t *urb_data = test_hcd_alloc_urb(0, TEST_NUM_SECTORS_PER_XFER * MOCK_MSC_SCSI_SECTOR_SIZE); urb_t *urb_data = test_hcd_alloc_urb(0, TEST_NUM_SECTORS_PER_XFER * MOCK_MSC_SCSI_SECTOR_SIZE);
urb_t *urb_csw = test_hcd_alloc_urb(0, sizeof(mock_msc_bulk_csw_t) + (mock_msc_scsi_bulk_in_ep_desc.wMaxPacketSize - (sizeof(mock_msc_bulk_csw_t) % mock_msc_scsi_bulk_in_ep_desc.wMaxPacketSize))); const uint16_t mps = USB_EP_DESC_GET_MPS(&mock_msc_scsi_bulk_in_ep_desc) ;
urb_t *urb_csw = test_hcd_alloc_urb(0, sizeof(mock_msc_bulk_csw_t) + (mps - (sizeof(mock_msc_bulk_csw_t) % mps)));
urb_cbw->transfer.num_bytes = sizeof(mock_msc_bulk_cbw_t); urb_cbw->transfer.num_bytes = sizeof(mock_msc_bulk_cbw_t);
urb_data->transfer.num_bytes = TEST_NUM_SECTORS_PER_XFER * MOCK_MSC_SCSI_SECTOR_SIZE; urb_data->transfer.num_bytes = TEST_NUM_SECTORS_PER_XFER * MOCK_MSC_SCSI_SECTOR_SIZE;
urb_csw->transfer.num_bytes = sizeof(mock_msc_bulk_csw_t) + (mock_msc_scsi_bulk_in_ep_desc.wMaxPacketSize - (sizeof(mock_msc_bulk_csw_t) % mock_msc_scsi_bulk_in_ep_desc.wMaxPacketSize)); urb_csw->transfer.num_bytes = sizeof(mock_msc_bulk_csw_t) + (mps - (sizeof(mock_msc_bulk_csw_t) % mps));
for (int block_num = 0; block_num < TEST_NUM_SECTORS_TOTAL; block_num += TEST_NUM_SECTORS_PER_XFER) { for (int block_num = 0; block_num < TEST_NUM_SECTORS_TOTAL; block_num += TEST_NUM_SECTORS_PER_XFER) {
//Initialize CBW URB, then send it on the BULK OUT pipe //Initialize CBW URB, then send it on the BULK OUT pipe

View File

@@ -198,7 +198,7 @@ static void print_ep_desc(const usb_ep_desc_t *ep_desc)
USB_EP_DESC_GET_EP_NUM(ep_desc), USB_EP_DESC_GET_EP_NUM(ep_desc),
USB_EP_DESC_GET_EP_DIR(ep_desc) ? "IN" : "OUT"); USB_EP_DESC_GET_EP_DIR(ep_desc) ? "IN" : "OUT");
printf("\t\tbmAttributes 0x%x\t%s\n", ep_desc->bmAttributes, ep_type_str); printf("\t\tbmAttributes 0x%x\t%s\n", ep_desc->bmAttributes, ep_type_str);
printf("\t\twMaxPacketSize %d\n", ep_desc->wMaxPacketSize); printf("\t\twMaxPacketSize %d\n", USB_EP_DESC_GET_MPS(ep_desc));
printf("\t\tbInterval %d\n", ep_desc->bInterval); printf("\t\tbInterval %d\n", ep_desc->bInterval);
} }