diff --git a/hw/bsp/board.c b/hw/bsp/board.c index d4fdb7586..6d9488431 100644 --- a/hw/bsp/board.c +++ b/hw/bsp/board.c @@ -136,6 +136,6 @@ int board_getchar(void) { } -uint32_t tusb_time_millis(void) { +uint32_t tusb_time_millis_api(void) { return board_millis(); } diff --git a/hw/bsp/stm32f7/family.c b/hw/bsp/stm32f7/family.c index f1671b362..630837d8c 100644 --- a/hw/bsp/stm32f7/family.c +++ b/hw/bsp/stm32f7/family.c @@ -173,7 +173,7 @@ void board_init(void) { #endif // vbus sense //------------- rhport1: OTG_HS -------------// - #ifdef USB_HS_PHYC +#ifdef USB_HS_PHYC // MCU with built-in HS PHY such as F723, F733, F730 /* Configure DM DP Pins */ @@ -197,7 +197,7 @@ void board_init(void) { /* Enable PHYC Clocks */ __HAL_RCC_OTGPHYC_CLK_ENABLE(); - #else +#else // MCU with external ULPI PHY /* ULPI CLK */ @@ -243,7 +243,7 @@ void board_init(void) { GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; HAL_GPIO_Init(GPIOI, &GPIO_InitStruct); - #endif // USB_HS_PHYC +#endif // USB_HS_PHYC // Enable USB HS & ULPI Clocks __HAL_RCC_USB_OTG_HS_ULPI_CLK_ENABLE(); diff --git a/src/host/usbh.c b/src/host/usbh.c index 8bf40a607..b0a2b2160 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -278,15 +278,6 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size); static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); -#if CFG_TUSB_OS == OPT_OS_NONE -// TODO rework time-related function later -// weak and overridable -TU_ATTR_WEAK void osal_task_delay(uint32_t msec) { - const uint32_t start = hcd_frame_number(_usbh_controller); - while ( ( hcd_frame_number(_usbh_controller) - start ) < msec ) {} -} -#endif - TU_ATTR_ALWAYS_INLINE static inline bool queue_event(hcd_event_t const * event, bool in_isr) { TU_ASSERT(osal_queue_send(_usbh_q, event, in_isr)); tuh_event_hook_cb(event->rhport, event->event_id, in_isr); @@ -487,17 +478,27 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { // due to the shared _usbh_ctrl_buf, we must complete enumerating one device before enumerating another one. // TODO better to have an separated queue for newly attached devices if (_dev0.enumerating) { - TU_LOG_USBH("[%u:] USBH Defer Attach until current enumeration complete\r\n", event.rhport); + // Some device can cause multiple duplicated attach events + // drop current enumerating and start over for a proper port reset + if (event.rhport == _dev0.rhport && event.connection.hub_addr == _dev0.hub_addr && + event.connection.hub_port == _dev0.hub_port) { + // abort/cancel current enumeration and start new one + TU_LOG1("[%u:] USBH Device Attach (duplicated)\r\n", event.rhport); + tuh_edpt_abort_xfer(0, 0); + enum_new_device(&event); + } else { + TU_LOG_USBH("[%u:] USBH Defer Attach until current enumeration complete\r\n", event.rhport); - bool is_empty = osal_queue_empty(_usbh_q); - queue_event(&event, in_isr); + bool is_empty = osal_queue_empty(_usbh_q); + queue_event(&event, in_isr); - if (is_empty) { - // Exit if this is the only event in the queue, otherwise we may loop forever - return; + if (is_empty) { + // Exit if this is the only event in the queue, otherwise we may loop forever + return; + } } } else { - TU_LOG_USBH("[%u:] USBH DEVICE ATTACH\r\n", event.rhport); + TU_LOG1("[%u:] USBH Device Attach\r\n", event.rhport); _dev0.enumerating = 1; enum_new_device(&event); } @@ -603,12 +604,12 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) { TU_VERIFY(xfer->ep_addr == 0 && xfer->setup); // Check if device is still connected (enumerating for dev0) - uint8_t const daddr = xfer->daddr; - if ( daddr == 0 ) { - if (!_dev0.enumerating) return false; + const uint8_t daddr = xfer->daddr; + if (daddr == 0) { + TU_VERIFY(_dev0.enumerating); } else { - usbh_device_t const* dev = get_device(daddr); - if (dev && dev->connected == 0) return false; + const usbh_device_t* dev = get_device(daddr); + TU_VERIFY(dev && dev->connected); } // pre-check to help reducing mutex lock @@ -778,24 +779,26 @@ bool tuh_edpt_xfer(tuh_xfer_t* xfer) { } bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr) { - usbh_device_t* dev = get_device(daddr); - TU_VERIFY(dev); - TU_LOG_USBH("[%u] Aborted transfer on EP %02X\r\n", daddr, ep_addr); - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + const uint8_t epnum = tu_edpt_number(ep_addr); + const uint8_t dir = tu_edpt_dir(ep_addr); + + if (epnum == 0) { + // Also include dev0 for aborting enumerating + const uint8_t rhport = usbh_get_rhport(daddr); - if ( epnum == 0 ) { // control transfer: only 1 control at a time, check if we are aborting the current one TU_VERIFY(daddr == _ctrl_xfer.daddr && _ctrl_xfer.stage != CONTROL_STAGE_IDLE); - TU_VERIFY(hcd_edpt_abort_xfer(dev->rhport, daddr, ep_addr)); - // reset control transfer state to idle - _set_control_xfer_stage(CONTROL_STAGE_IDLE); + hcd_edpt_abort_xfer(rhport, daddr, ep_addr); + _set_control_xfer_stage(CONTROL_STAGE_IDLE); // reset control transfer state to idle } else { - // non-control skip if not busy - TU_VERIFY(dev->ep_status[epnum][dir].busy); - TU_VERIFY(hcd_edpt_abort_xfer(dev->rhport, daddr, ep_addr)); + usbh_device_t* dev = get_device(daddr); + TU_VERIFY(dev); + + TU_VERIFY(dev->ep_status[epnum][dir].busy); // non-control skip if not busy + hcd_edpt_abort_xfer(dev->rhport, daddr, ep_addr); + // mark as ready and release endpoint if transfer is aborted dev->ep_status[epnum][dir].busy = false; tu_edpt_release(&dev->ep_status[epnum][dir], _usbh_mutex); @@ -1281,9 +1284,9 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu //--------------------------------------------------------------------+ enum { - ENUM_RESET_DELAY = 50, // USB specs: 10 to 50ms - ENUM_CONTACT_DEBOUNCING_DELAY = 450, // when plug/unplug a device, physical connection can be bouncing and may - // generate a series of attach/detach event. This delay wait for stable connection + ENUM_RESET_DELAY_MS = 50, // USB specs: 10 to 50ms + ENUM_DEBOUNCING_DELAY_MS = 450, // when plug/unplug a device, physical connection can be bouncing and may + // generate a series of attach/detach event. This delay wait for stable connection }; enum { @@ -1322,7 +1325,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { bool retry = _dev0.enumerating && (failed_count < ATTEMPT_COUNT_MAX); if ( retry ) { failed_count++; - osal_task_delay(ATTEMPT_DELAY_MS); // delay a bit + tusb_time_delay_ms_api(ATTEMPT_DELAY_MS); // delay a bit TU_LOG1("Enumeration attempt %u\r\n", failed_count); retry = tuh_control_xfer(xfer); } @@ -1364,7 +1367,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { } case ENUM_HUB_GET_STATUS_2: - osal_task_delay(ENUM_RESET_DELAY); + tusb_time_delay_ms_api(ENUM_RESET_DELAY_MS); TU_ASSERT(hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, process_enumeration, ENUM_HUB_CLEAR_RESET_2),); break; @@ -1402,7 +1405,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { if (_dev0.hub_addr == 0) { // connected directly to roothub hcd_port_reset( _dev0.rhport ); - osal_task_delay(RESET_DELAY); // TODO may not work for no-OS on MCU that require reset_end() since + tusb_time_delay_ms_api(RESET_DELAY); // TODO may not work for no-OS on MCU that require reset_end() since // sof of controller may not running while resetting hcd_port_reset_end(_dev0.rhport); // TODO: fall through to SET ADDRESS, refactor later @@ -1424,9 +1427,9 @@ static void process_enumeration(tuh_xfer_t* xfer) { case ENUM_GET_DEVICE_DESC: { // Allow 2ms for address recovery time, Ref USB Spec 9.2.6.3 - osal_task_delay(2); + tusb_time_delay_ms_api(2); - uint8_t const new_addr = (uint8_t) tu_le16toh(xfer->setup->wValue); + const uint8_t new_addr = (uint8_t) tu_le16toh(xfer->setup->wValue); usbh_device_t* new_dev = get_device(new_addr); TU_ASSERT(new_dev,); @@ -1514,6 +1517,8 @@ static void process_enumeration(tuh_xfer_t* xfer) { } } + + static bool enum_new_device(hcd_event_t* event) { _dev0.rhport = event->rhport; _dev0.hub_addr = event->connection.hub_addr; @@ -1522,19 +1527,15 @@ static bool enum_new_device(hcd_event_t* event) { if (_dev0.hub_addr == 0) { // connected directly to roothub hcd_port_reset(_dev0.rhport); -#if CFG_TUSB_OS == OPT_OS_NONE - // Since we are in middle of rhport reset, frame number is not available for time delay - // need to depend on tusb_time_millis() instead - const uint32_t start_reset = tusb_time_millis(); - while ((tusb_time_millis() - start_reset) < ENUM_RESET_DELAY) {} -#else - osal_task_delay(ENUM_RESET_DELAY); -#endif + + // Since we are in middle of rhport reset, frame number is not available yet. + // need to depend on tusb_time_millis_api() + tusb_time_delay_ms_api(ENUM_RESET_DELAY_MS); hcd_port_reset_end(_dev0.rhport); // wait until device connection is stable TODO non blocking - osal_task_delay(ENUM_CONTACT_DEBOUNCING_DELAY); + tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); // device unplugged while delaying if (!hcd_port_connect_status(_dev0.rhport)) { @@ -1557,10 +1558,9 @@ static bool enum_new_device(hcd_event_t* event) { else { // connected via external hub // wait until device connection is stable TODO non blocking - osal_task_delay(ENUM_CONTACT_DEBOUNCING_DELAY); + tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); // ENUM_HUB_GET_STATUS - //TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, enum_hub_get_status0_complete, 0) ); TU_ASSERT(hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, process_enumeration, ENUM_HUB_CLEAR_RESET_1)); }