usbh use the new tusb_time_delay_ms_api()
fix duplicated device attach for some devices which cause "USBH Defer Attach until current enumeration complete" include dev0 for tuh_edpt_abort_xfer()
This commit is contained in:
		| @@ -136,6 +136,6 @@ int board_getchar(void) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| uint32_t tusb_time_millis(void) { | uint32_t tusb_time_millis_api(void) { | ||||||
|   return board_millis(); |   return board_millis(); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -173,7 +173,7 @@ void board_init(void) { | |||||||
| #endif // vbus sense | #endif // vbus sense | ||||||
|  |  | ||||||
|   //------------- rhport1: OTG_HS -------------// |   //------------- rhport1: OTG_HS -------------// | ||||||
|   #ifdef USB_HS_PHYC | #ifdef USB_HS_PHYC | ||||||
|   // MCU with built-in HS PHY such as F723, F733, F730 |   // MCU with built-in HS PHY such as F723, F733, F730 | ||||||
|  |  | ||||||
|   /* Configure DM DP Pins */ |   /* Configure DM DP Pins */ | ||||||
| @@ -197,7 +197,7 @@ void board_init(void) { | |||||||
|   /* Enable PHYC Clocks */ |   /* Enable PHYC Clocks */ | ||||||
|   __HAL_RCC_OTGPHYC_CLK_ENABLE(); |   __HAL_RCC_OTGPHYC_CLK_ENABLE(); | ||||||
|  |  | ||||||
|   #else | #else | ||||||
|   // MCU with external ULPI PHY |   // MCU with external ULPI PHY | ||||||
|  |  | ||||||
|   /* ULPI CLK */ |   /* ULPI CLK */ | ||||||
| @@ -243,7 +243,7 @@ void board_init(void) { | |||||||
|   GPIO_InitStruct.Pull = GPIO_NOPULL; |   GPIO_InitStruct.Pull = GPIO_NOPULL; | ||||||
|   GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; |   GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; | ||||||
|   HAL_GPIO_Init(GPIOI, &GPIO_InitStruct); |   HAL_GPIO_Init(GPIOI, &GPIO_InitStruct); | ||||||
|   #endif // USB_HS_PHYC | #endif // USB_HS_PHYC | ||||||
|  |  | ||||||
|   // Enable USB HS & ULPI Clocks |   // Enable USB HS & ULPI Clocks | ||||||
|   __HAL_RCC_USB_OTG_HS_ULPI_CLK_ENABLE(); |   __HAL_RCC_USB_OTG_HS_ULPI_CLK_ENABLE(); | ||||||
|   | |||||||
							
								
								
									
										104
									
								
								src/host/usbh.c
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								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_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); | 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_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)); |   TU_ASSERT(osal_queue_send(_usbh_q, event, in_isr)); | ||||||
|   tuh_event_hook_cb(event->rhport, event->event_id, 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. |         // 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 |         // TODO better to have an separated queue for newly attached devices | ||||||
|         if (_dev0.enumerating) { |         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); |             bool is_empty = osal_queue_empty(_usbh_q); | ||||||
|           queue_event(&event, in_isr); |             queue_event(&event, in_isr); | ||||||
|  |  | ||||||
|           if (is_empty) { |             if (is_empty) { | ||||||
|             // Exit if this is the only event in the queue, otherwise we may loop forever |               // Exit if this is the only event in the queue, otherwise we may loop forever | ||||||
|             return; |               return; | ||||||
|  |             } | ||||||
|           } |           } | ||||||
|         } else { |         } 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; |           _dev0.enumerating = 1; | ||||||
|           enum_new_device(&event); |           enum_new_device(&event); | ||||||
|         } |         } | ||||||
| @@ -603,12 +604,12 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) { | |||||||
|   TU_VERIFY(xfer->ep_addr == 0 && xfer->setup); |   TU_VERIFY(xfer->ep_addr == 0 && xfer->setup); | ||||||
|  |  | ||||||
|   // Check if device is still connected (enumerating for dev0) |   // Check if device is still connected (enumerating for dev0) | ||||||
|   uint8_t const daddr = xfer->daddr; |   const uint8_t daddr = xfer->daddr; | ||||||
|   if ( daddr == 0 ) { |   if (daddr == 0) { | ||||||
|     if (!_dev0.enumerating) return false; |     TU_VERIFY(_dev0.enumerating); | ||||||
|   } else { |   } else { | ||||||
|     usbh_device_t const* dev = get_device(daddr); |     const usbh_device_t* dev = get_device(daddr); | ||||||
|     if (dev && dev->connected == 0) return false; |     TU_VERIFY(dev && dev->connected); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // pre-check to help reducing mutex lock |   // 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) { | 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); |   TU_LOG_USBH("[%u] Aborted transfer on EP %02X\r\n", daddr, ep_addr); | ||||||
|  |  | ||||||
|   uint8_t const epnum = tu_edpt_number(ep_addr); |   const uint8_t epnum = tu_edpt_number(ep_addr); | ||||||
|   uint8_t const dir   = tu_edpt_dir(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 |     // 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(daddr == _ctrl_xfer.daddr && _ctrl_xfer.stage != CONTROL_STAGE_IDLE); | ||||||
|     TU_VERIFY(hcd_edpt_abort_xfer(dev->rhport, daddr, ep_addr)); |     hcd_edpt_abort_xfer(rhport, daddr, ep_addr); | ||||||
|     // reset control transfer state to idle |     _set_control_xfer_stage(CONTROL_STAGE_IDLE); // reset control transfer state to idle | ||||||
|     _set_control_xfer_stage(CONTROL_STAGE_IDLE); |  | ||||||
|   } else { |   } else { | ||||||
|     // non-control skip if not busy |     usbh_device_t* dev = get_device(daddr); | ||||||
|     TU_VERIFY(dev->ep_status[epnum][dir].busy); |     TU_VERIFY(dev); | ||||||
|     TU_VERIFY(hcd_edpt_abort_xfer(dev->rhport, daddr, ep_addr)); |  | ||||||
|  |     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 |     // mark as ready and release endpoint if transfer is aborted | ||||||
|     dev->ep_status[epnum][dir].busy = false; |     dev->ep_status[epnum][dir].busy = false; | ||||||
|     tu_edpt_release(&dev->ep_status[epnum][dir], _usbh_mutex); |     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 { | ||||||
|   ENUM_RESET_DELAY = 50, // USB specs: 10 to 50ms |   ENUM_RESET_DELAY_MS = 50,       // USB specs: 10 to 50ms | ||||||
|   ENUM_CONTACT_DEBOUNCING_DELAY = 450, // when plug/unplug a device, physical connection can be bouncing and may |   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 |                                   // generate a series of attach/detach event. This delay wait for stable connection | ||||||
| }; | }; | ||||||
|  |  | ||||||
| enum { | enum { | ||||||
| @@ -1322,7 +1325,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { | |||||||
|     bool retry = _dev0.enumerating && (failed_count < ATTEMPT_COUNT_MAX); |     bool retry = _dev0.enumerating && (failed_count < ATTEMPT_COUNT_MAX); | ||||||
|     if ( retry ) { |     if ( retry ) { | ||||||
|       failed_count++; |       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); |       TU_LOG1("Enumeration attempt %u\r\n", failed_count); | ||||||
|       retry = tuh_control_xfer(xfer); |       retry = tuh_control_xfer(xfer); | ||||||
|     } |     } | ||||||
| @@ -1364,7 +1367,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     case ENUM_HUB_GET_STATUS_2: |     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, |       TU_ASSERT(hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, | ||||||
|                                     process_enumeration, ENUM_HUB_CLEAR_RESET_2),); |                                     process_enumeration, ENUM_HUB_CLEAR_RESET_2),); | ||||||
|       break; |       break; | ||||||
| @@ -1402,7 +1405,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { | |||||||
|         if (_dev0.hub_addr == 0) { |         if (_dev0.hub_addr == 0) { | ||||||
|           // connected directly to roothub |           // connected directly to roothub | ||||||
|           hcd_port_reset( _dev0.rhport ); |           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 |                                         // sof of controller may not running while resetting | ||||||
|           hcd_port_reset_end(_dev0.rhport); |           hcd_port_reset_end(_dev0.rhport); | ||||||
|           // TODO: fall through to SET ADDRESS, refactor later |           // 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: { |     case ENUM_GET_DEVICE_DESC: { | ||||||
|       // Allow 2ms for address recovery time, Ref USB Spec 9.2.6.3 |       // 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); |       usbh_device_t* new_dev = get_device(new_addr); | ||||||
|       TU_ASSERT(new_dev,); |       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) { | static bool enum_new_device(hcd_event_t* event) { | ||||||
|   _dev0.rhport = event->rhport; |   _dev0.rhport = event->rhport; | ||||||
|   _dev0.hub_addr = event->connection.hub_addr; |   _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) { |   if (_dev0.hub_addr == 0) { | ||||||
|     // connected directly to roothub |     // connected directly to roothub | ||||||
|     hcd_port_reset(_dev0.rhport); |     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 |     // Since we are in middle of rhport reset, frame number is not available yet. | ||||||
|     // need to depend on tusb_time_millis() instead |     // need to depend on tusb_time_millis_api() | ||||||
|     const uint32_t start_reset = tusb_time_millis(); |     tusb_time_delay_ms_api(ENUM_RESET_DELAY_MS); | ||||||
|     while ((tusb_time_millis() - start_reset) < ENUM_RESET_DELAY) {} |  | ||||||
| #else |  | ||||||
|     osal_task_delay(ENUM_RESET_DELAY); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     hcd_port_reset_end(_dev0.rhport); |     hcd_port_reset_end(_dev0.rhport); | ||||||
|  |  | ||||||
|     // wait until device connection is stable TODO non blocking |     // 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 |     // device unplugged while delaying | ||||||
|     if (!hcd_port_connect_status(_dev0.rhport)) { |     if (!hcd_port_connect_status(_dev0.rhport)) { | ||||||
| @@ -1557,10 +1558,9 @@ static bool enum_new_device(hcd_event_t* event) { | |||||||
|   else { |   else { | ||||||
|     // connected via external hub |     // connected via external hub | ||||||
|     // wait until device connection is stable TODO non blocking |     // 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 |     // 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, |     TU_ASSERT(hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, | ||||||
|                                   process_enumeration, ENUM_HUB_CLEAR_RESET_1)); |                                   process_enumeration, ENUM_HUB_CLEAR_RESET_1)); | ||||||
|   } |   } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 hathach
					hathach