From 1e2c271bd019ff46b4d04ab1ceea370bfe82eb5d Mon Sep 17 00:00:00 2001 From: Tomas Rezucha Date: Wed, 6 Dec 2023 18:05:41 +0100 Subject: [PATCH] fix(usb/host): Correctly parse bInterval field in HighSpeed EP descriptors For LS and FS interrupt endpoint: interval = bInterval For isochronous and HS interrupt endpoint: interval = 2^(bInterval-1) --- components/hal/include/hal/usb_dwc_hal.h | 2 +- components/hal/include/hal/usb_dwc_types.h | 13 ------- components/usb/hcd_dwc.c | 40 +++++++++++----------- 3 files changed, 21 insertions(+), 34 deletions(-) diff --git a/components/hal/include/hal/usb_dwc_hal.h b/components/hal/include/hal/usb_dwc_hal.h index 03ab8736da..7af5bd45fa 100644 --- a/components/hal/include/hal/usb_dwc_hal.h +++ b/components/hal/include/hal/usb_dwc_hal.h @@ -142,7 +142,7 @@ typedef struct { uint32_t val; }; 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 */ } periodic; /**< Characteristic for periodic (interrupt/isochronous) endpoints only */ } usb_dwc_hal_ep_char_t; diff --git a/components/hal/include/hal/usb_dwc_types.h b/components/hal/include/hal/usb_dwc_types.h index 0ffa36aa68..22018953bc 100644 --- a/components/hal/include/hal/usb_dwc_types.h +++ b/components/hal/include/hal/usb_dwc_types.h @@ -51,19 +51,6 @@ typedef enum { USB_HAL_FRAME_LIST_LEN_64 = 64, } 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 } #endif diff --git a/components/usb/hcd_dwc.c b/components/usb/hcd_dwc.c index 5065e6a1bc..6a8689f724 100644 --- a/components/usb/hcd_dwc.c +++ b/components/usb/hcd_dwc.c @@ -1578,31 +1578,31 @@ static void pipe_set_ep_char(const hcd_pipe_config_t *pipe_config, usb_transfer_ // Calculate the pipe's interval in terms of USB frames // @see USB-OTG programming guide chapter 6.5 for more information if (type == USB_TRANSFER_TYPE_INTR || type == USB_TRANSFER_TYPE_ISOCHRONOUS) { - unsigned int interval_frames; - unsigned int xfer_list_len; - if (type == USB_TRANSFER_TYPE_INTR) { - interval_frames = pipe_config->ep_desc->bInterval; - xfer_list_len = XFER_LIST_LEN_INTR; + // Convert bInterval field to real value + // @see USB 2.0 specs, Table 9-13 + unsigned int interval_value; + if (type == USB_TRANSFER_TYPE_INTR && pipe_config->dev_speed != USB_SPEED_HIGH) { + interval_value = pipe_config->ep_desc->bInterval; } else { - interval_frames = (1 << (pipe_config->ep_desc->bInterval - 1)); - xfer_list_len = XFER_LIST_LEN_ISOC; + interval_value = (1 << (pipe_config->ep_desc->bInterval - 1)); } // Round down interval to nearest power of 2 - if (interval_frames >= 32) { - interval_frames = 32; - } else if (interval_frames >= 16) { - interval_frames = 16; - } else if (interval_frames >= 8) { - interval_frames = 8; - } else if (interval_frames >= 4) { - interval_frames = 4; - } else if (interval_frames >= 2) { - interval_frames = 2; - } else if (interval_frames >= 1) { - interval_frames = 1; + if (interval_value >= 32) { + interval_value = 32; + } else if (interval_value >= 16) { + interval_value = 16; + } else if (interval_value >= 8) { + interval_value = 8; + } else if (interval_value >= 4) { + interval_value = 4; + } else if (interval_value >= 2) { + interval_value = 2; + } else if (interval_value >= 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 + 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); } else { ep_char->periodic.interval = 0;