@@ -312,13 +312,32 @@ static bool _device_set_actions(ext_hub_dev_t *ext_hub_dev, uint32_t action_flag
312312
313313static esp_err_t device_enable_int_ep (ext_hub_dev_t * ext_hub_dev )
314314{
315- ESP_LOGD (EXT_HUB_TAG , "[%d] Enable EP IN" , ext_hub_dev -> constant .dev_addr );
316- esp_err_t ret = usbh_ep_enqueue_urb (ext_hub_dev -> constant .ep_in_hdl , ext_hub_dev -> constant .in_urb );
317- if (ret != ESP_OK ) {
318- ESP_LOGE (EXT_HUB_TAG , "[%d] Failed to submit in urb: %s" , ext_hub_dev -> constant .dev_addr , esp_err_to_name (ret ));
319- device_error (ext_hub_dev );
315+ bool call_proc_req_cb = false;
316+ bool is_active = true;
317+ ESP_LOGD (EXT_HUB_TAG , "[%d] Device ports handle complete" , ext_hub_dev -> constant .dev_addr );
318+
319+ // Check if the device should be released
320+ EXT_HUB_ENTER_CRITICAL ();
321+ if (ext_hub_dev -> dynamic .flags .waiting_release ) {
322+ is_active = false;
323+ call_proc_req_cb = _device_set_actions (ext_hub_dev , DEV_ACTION_RELEASE );
320324 }
321- return ret ;
325+ EXT_HUB_EXIT_CRITICAL ();
326+
327+ if (is_active ) {
328+ ESP_LOGD (EXT_HUB_TAG , "[%d] Enable IN EP" , ext_hub_dev -> constant .dev_addr );
329+ esp_err_t ret = usbh_ep_enqueue_urb (ext_hub_dev -> constant .ep_in_hdl , ext_hub_dev -> constant .in_urb );
330+ if (ret != ESP_OK ) {
331+ ESP_LOGE (EXT_HUB_TAG , "[%d] Failed to submit in urb: %s" , ext_hub_dev -> constant .dev_addr , esp_err_to_name (ret ));
332+ device_error (ext_hub_dev );
333+ }
334+ return ret ;
335+ }
336+
337+ if (call_proc_req_cb ) {
338+ p_ext_hub_driver -> constant .proc_req_cb (false, p_ext_hub_driver -> constant .proc_req_cb_arg );
339+ }
340+ return ESP_OK ;
322341}
323342
324343static void device_has_changed (ext_hub_dev_t * ext_hub_dev )
@@ -420,7 +439,6 @@ static esp_err_t device_port_free(ext_hub_dev_t *ext_hub_dev, uint8_t port_idx)
420439 EXT_HUB_CHECK (ext_hub_dev -> constant .ports [port_idx ] != NULL , ESP_ERR_INVALID_STATE );
421440
422441 bool call_proc_req_cb = false;
423- bool all_ports_freed = false;
424442
425443 assert (ext_hub_dev -> single_thread .maxchild != 0 );
426444 assert (p_ext_hub_driver -> constant .port_driver );
@@ -435,25 +453,11 @@ static esp_err_t device_port_free(ext_hub_dev_t *ext_hub_dev, uint8_t port_idx)
435453 ext_hub_dev -> single_thread .maxchild -- ;
436454
437455 EXT_HUB_ENTER_CRITICAL ();
438- if (ext_hub_dev -> dynamic .flags .is_gone ) {
439- all_ports_freed = (ext_hub_dev -> single_thread .maxchild == 0 );
440-
441- if (all_ports_freed ) {
442- ext_hub_dev -> dynamic .flags .waiting_children = 0 ;
443- ext_hub_dev -> dynamic .flags .waiting_free = 1 ;
444- call_proc_req_cb = _device_set_actions (ext_hub_dev , DEV_ACTION_FREE );
445- } else {
446- ext_hub_dev -> dynamic .flags .waiting_children = 1 ;
447- }
456+ if (ext_hub_dev -> dynamic .flags .waiting_free && ext_hub_dev -> single_thread .maxchild == 0 ) {
457+ call_proc_req_cb = _device_set_actions (ext_hub_dev , DEV_ACTION_FREE );
448458 }
449459 EXT_HUB_EXIT_CRITICAL ();
450460
451- // Close the device if all children were freed
452- if (all_ports_freed ) {
453- ESP_LOGD (EXT_HUB_TAG , "[%d] Release USBH device object" , ext_hub_dev -> constant .dev_addr );
454- ESP_ERROR_CHECK (usbh_dev_close (ext_hub_dev -> constant .dev_hdl ));
455- }
456-
457461 if (call_proc_req_cb ) {
458462 p_ext_hub_driver -> constant .proc_req_cb (false, p_ext_hub_driver -> constant .proc_req_cb_arg );
459463 }
@@ -463,71 +467,60 @@ static esp_err_t device_port_free(ext_hub_dev_t *ext_hub_dev, uint8_t port_idx)
463467 return ret ;
464468}
465469
466- static esp_err_t device_release_ports (ext_hub_dev_t * ext_hub_dev )
470+ static esp_err_t device_release_port (ext_hub_dev_t * ext_hub_dev , uint8_t port_idx )
467471{
468- esp_err_t ret = ESP_OK ;
469- // Mark all ports as gone
470- for (uint8_t i = 0 ; i < ext_hub_dev -> constant .hub_desc -> bNbrPorts ; i ++ ) {
471- // Only for ports, that were created
472- if (ext_hub_dev -> constant .ports [i ] != NULL ) {
473- // Mark port as gone
474- ret = p_ext_hub_driver -> constant .port_driver -> gone (ext_hub_dev -> constant .ports [i ]);
475- if (ret == ESP_OK ) {
476- // Port doesn't have a device and can be recycled right now
477- ESP_ERROR_CHECK (device_port_free (ext_hub_dev , i ));
478- } else if (ret == ESP_ERR_NOT_FINISHED ) {
479- // Port has a device and will be recycled after USBH device will be released by all clients and freed
480- ESP_LOGE (EXT_HUB_TAG , "[%d:%d] Port is gone" , ext_hub_dev -> constant .dev_addr , i + 1 );
481- // Not an error case, but it's good to notify this with the error message
482- // TODO: IDF-12173 remove the error, instead set up the flag and verify the flag while recycle
483- ret = ESP_OK ;
484- } else {
485- ESP_LOGE (EXT_HUB_TAG , "[%d:%d] Unable to mark port as gone: %s" ,
486- ext_hub_dev -> constant .dev_addr , i + 1 , esp_err_to_name (ret ));
487- return ret ;
488- }
489- } else {
490- ESP_LOGE (EXT_HUB_TAG , "[%d:%d] Port was not created" , ext_hub_dev -> constant .dev_addr , i + 1 );
491- }
472+ assert (ext_hub_dev -> constant .ports [port_idx ] != NULL );
473+ assert (ext_hub_dev -> single_thread .maxchild != 0 );
474+ assert (p_ext_hub_driver -> constant .port_driver );
475+
476+ // Mark port as gone
477+ esp_err_t ret = p_ext_hub_driver -> constant .port_driver -> gone (ext_hub_dev -> constant .ports [port_idx ]);
478+ if (ret == ESP_OK ) {
479+ // Port doesn't have a device and can be freed right now
480+ ESP_ERROR_CHECK (device_port_free (ext_hub_dev , port_idx ));
481+ } else if (ret == ESP_ERR_NOT_FINISHED ) {
482+ // Port has a device and will be freed on recycle
483+ EXT_HUB_ENTER_CRITICAL ();
484+ ext_hub_dev -> dynamic .flags .waiting_children = 1 ;
485+ EXT_HUB_EXIT_CRITICAL ();
486+ ret = ESP_OK ;
487+ } else {
488+ ESP_LOGE (EXT_HUB_TAG , "[%d:%d] Unable to mark port as gone: %s" ,
489+ ext_hub_dev -> constant .dev_addr , port_idx + 1 , esp_err_to_name (ret ));
490+ return ret ;
492491 }
492+
493493 return ret ;
494494}
495495
496+ static void device_release_ports (ext_hub_dev_t * ext_hub_dev )
497+ {
498+ assert (ext_hub_dev -> constant .hub_desc -> bNbrPorts ); // Sanity check
499+ for (uint8_t i = 0 ; i < ext_hub_dev -> constant .hub_desc -> bNbrPorts ; i ++ ) {
500+ ESP_ERROR_CHECK (device_release_port (ext_hub_dev , i ));
501+ }
502+ }
503+
496504static void device_release (ext_hub_dev_t * ext_hub_dev )
497505{
498506 ESP_LOGD (EXT_HUB_TAG , "[%d] Device release" , ext_hub_dev -> constant .dev_addr );
499507
500508 EXT_HUB_ENTER_CRITICAL ();
501- assert (ext_hub_dev -> dynamic .flags .waiting_release ); // Device should waiting the release
502- ext_hub_dev -> dynamic .flags .is_gone = 1 ;
509+ assert (ext_hub_dev -> dynamic .flags .waiting_release ); // Sanity check
503510 ext_hub_dev -> dynamic .flags .waiting_release = 0 ;
511+ ext_hub_dev -> dynamic .flags .waiting_free = 1 ;
504512 EXT_HUB_EXIT_CRITICAL ();
505513
506- // Release IN EP
507- ESP_ERROR_CHECK (usbh_ep_command (ext_hub_dev -> constant .ep_in_hdl , USBH_EP_CMD_HALT ));
508-
509514 switch (ext_hub_dev -> single_thread .state ) {
510- case EXT_HUB_STATE_ATTACHED :
511- // Device has no configured ports, release the USBH device object
512- ESP_LOGD (EXT_HUB_TAG , "[%d] Release USBH device object" , ext_hub_dev -> constant .dev_addr );
513- ESP_ERROR_CHECK (usbh_dev_close (ext_hub_dev -> constant .dev_hdl ));
514- break ;
515515 case EXT_HUB_STATE_CONFIGURED :
516516 case EXT_HUB_STATE_SUSPENDED :
517517 assert (ext_hub_dev -> constant .hub_desc != NULL ); // Device should have a Hub descriptor
518518 assert (p_ext_hub_driver -> constant .port_driver ); // Port driver should be available
519-
520- // Release ports if device has them
521- if (ext_hub_dev -> constant .hub_desc -> bNbrPorts ) {
522- ESP_ERROR_CHECK (device_release_ports (ext_hub_dev ));
523- }
519+ device_release_ports (ext_hub_dev );
524520 break ;
525521 default :
526- // Should never occur
527- abort ();
528522 break ;
529523 }
530-
531524 ext_hub_dev -> single_thread .state = EXT_HUB_STATE_RELEASED ;
532525}
533526
@@ -771,17 +764,18 @@ static void device_free(ext_hub_dev_t *ext_hub_dev)
771764 TAILQ_REMOVE (& p_ext_hub_driver -> dynamic .ext_hubs_tailq , ext_hub_dev , dynamic .tailq_entry );
772765 EXT_HUB_EXIT_CRITICAL ();
773766
767+ ESP_ERROR_CHECK (usbh_ep_free (ext_hub_dev -> constant .ep_in_hdl ));
768+ ESP_ERROR_CHECK (usbh_dev_close (ext_hub_dev -> constant .dev_hdl ));
769+
774770 if (ext_hub_dev -> constant .hub_desc ) {
775771 heap_caps_free (ext_hub_dev -> constant .hub_desc );
776772 }
777773 if (ext_hub_dev -> constant .ports ) {
778774 heap_caps_free (ext_hub_dev -> constant .ports );
779775 }
780776
781- ESP_ERROR_CHECK (usbh_ep_free (ext_hub_dev -> constant .ep_in_hdl ));
782777 urb_free (ext_hub_dev -> constant .ctrl_urb );
783778 urb_free (ext_hub_dev -> constant .in_urb );
784-
785779 heap_caps_free (ext_hub_dev );
786780}
787781
@@ -1387,6 +1381,7 @@ esp_err_t ext_hub_dev_gone(uint8_t dev_addr)
13871381 ESP_LOGD (EXT_HUB_TAG , "[%d] Device gone" , ext_hub_dev -> constant .dev_addr );
13881382
13891383 EXT_HUB_ENTER_CRITICAL ();
1384+ ext_hub_dev -> dynamic .flags .is_gone = 1 ;
13901385 if (ext_hub_dev -> dynamic .flags .waiting_release ||
13911386 ext_hub_dev -> dynamic .flags .waiting_children ) {
13921387 EXT_HUB_EXIT_CRITICAL ();
@@ -1396,7 +1391,7 @@ esp_err_t ext_hub_dev_gone(uint8_t dev_addr)
13961391 }
13971392
13981393 if ((ext_hub_dev -> single_thread .maxchild == 0 ) && !ext_hub_dev -> dynamic .flags .in_pending_list ) {
1399- // Not in pending list and doesn't have any children
1394+ // Not in pending list and doesn't have any children release and free right away
14001395 ext_hub_dev -> dynamic .flags .waiting_free = 1 ;
14011396 ext_hub_dev -> dynamic .flags .waiting_release = 1 ;
14021397 call_proc_req_cb = _device_set_actions (ext_hub_dev , DEV_ACTION_RELEASE |
@@ -1420,10 +1415,9 @@ esp_err_t ext_hub_dev_gone(uint8_t dev_addr)
14201415 return ret ;
14211416}
14221417
1423- esp_err_t ext_hub_all_free (void )
1418+ void ext_hub_mark_all_free (void )
14241419{
14251420 bool call_proc_req_cb = false;
1426- bool wait_for_free = false;
14271421
14281422 EXT_HUB_ENTER_CRITICAL ();
14291423 for (int i = 0 ; i < 2 ; i ++ ) {
@@ -1438,9 +1432,13 @@ esp_err_t ext_hub_all_free(void)
14381432 while (hub_curr != NULL ) {
14391433 hub_next = TAILQ_NEXT (hub_curr , dynamic .tailq_entry );
14401434 hub_curr -> dynamic .flags .waiting_release = 1 ;
1441- call_proc_req_cb = _device_set_actions (hub_curr , DEV_ACTION_RELEASE );
1442- // At least one hub should be released
1443- wait_for_free = true;
1435+ uint32_t action_flags = DEV_ACTION_EP1_FLUSH | DEV_ACTION_EP1_DEQUEUE ;
1436+ // If device in the IDLE stage, add the release action
1437+ // otherwise, device will be released when the stage changed to IDLE
1438+ if (hub_curr -> single_thread .stage == EXT_HUB_STAGE_IDLE ) {
1439+ action_flags |= DEV_ACTION_RELEASE ;
1440+ }
1441+ call_proc_req_cb = _device_set_actions (hub_curr , action_flags );
14441442 hub_curr = hub_next ;
14451443 }
14461444 }
@@ -1449,8 +1447,6 @@ esp_err_t ext_hub_all_free(void)
14491447 if (call_proc_req_cb ) {
14501448 p_ext_hub_driver -> constant .proc_req_cb (false, p_ext_hub_driver -> constant .proc_req_cb_arg );
14511449 }
1452-
1453- return (wait_for_free ) ? ESP_ERR_NOT_FINISHED : ESP_OK ;
14541450}
14551451
14561452esp_err_t ext_hub_status_handle_complete (ext_hub_handle_t ext_hub_hdl )
@@ -1575,66 +1571,30 @@ esp_err_t ext_hub_port_recycle(ext_hub_handle_t ext_hub_hdl, uint8_t port_num)
15751571 EXT_HUB_CHECK (ext_hub_hdl != NULL , ESP_ERR_INVALID_ARG );
15761572 ext_hub_dev_t * ext_hub_dev = (ext_hub_dev_t * )ext_hub_hdl ;
15771573
1578- esp_err_t ret ;
15791574 uint8_t port_idx = port_num - 1 ;
1580- bool free_port = false;
15811575 bool release_port = false;
1582-
15831576 EXT_HUB_CHECK (port_idx < ext_hub_dev -> constant .hub_desc -> bNbrPorts , ESP_ERR_INVALID_SIZE );
15841577 EXT_HUB_CHECK (p_ext_hub_driver -> constant .port_driver != NULL , ESP_ERR_NOT_SUPPORTED );
15851578 EXT_HUB_CHECK (ext_hub_dev -> single_thread .state == EXT_HUB_STATE_CONFIGURED ||
15861579 ext_hub_dev -> single_thread .state == EXT_HUB_STATE_RELEASED , ESP_ERR_INVALID_STATE );
15871580
15881581 EXT_HUB_ENTER_CRITICAL ();
1589- if (ext_hub_dev -> dynamic .flags .waiting_release ) {
1582+ if (ext_hub_dev -> dynamic .flags .waiting_release ||
1583+ ext_hub_dev -> dynamic .flags .waiting_children ) {
15901584 release_port = true;
1591- } else if (ext_hub_dev -> dynamic .flags .waiting_children ) {
1592- assert (ext_hub_dev -> dynamic .flags .waiting_release == 0 ); // Device should be already released
1593- assert (ext_hub_dev -> dynamic .flags .is_gone == 1 ); // Device should be gone by now
1594- free_port = true;
15951585 }
15961586 EXT_HUB_EXIT_CRITICAL ();
15971587
1598- if (!release_port && !free_port ) {
1588+ esp_err_t ret ;
1589+ if (release_port ) {
1590+ ret = device_release_port (ext_hub_dev , port_idx );
1591+ } else {
15991592 // Parent still present, recycle the port
16001593 ret = p_ext_hub_driver -> constant .port_driver -> recycle (ext_hub_dev -> constant .ports [port_idx ]);
16011594 if (ret != ESP_OK ) {
16021595 ESP_LOGE (EXT_HUB_TAG , "[%d:%d] Unable to recycle the port: %s" , ext_hub_dev -> constant .dev_addr , port_num , esp_err_to_name (ret ));
1603- goto exit ;
1604- }
1605- } else {
1606- if (release_port ) {
1607- // Notify the port that parent is not available anymore and port should be recycled then freed
1608- ret = p_ext_hub_driver -> constant .port_driver -> gone (ext_hub_dev -> constant .ports [port_idx ]);
1609- if (ret == ESP_OK ) {
1610- ESP_LOGD (EXT_HUB_TAG , "[%d:%d] Port doesn't have a device and can be freed right now" ,
1611- ext_hub_dev -> constant .dev_addr ,
1612- port_num );
1613- assert (free_port == false);
1614- free_port = true;
1615- } else if (ret == ESP_ERR_NOT_FINISHED ) {
1616- // Port has a device and will be recycled after USBH device will be released by all clients and freed
1617- ESP_LOGE (EXT_HUB_TAG , "[%d:%d] Port is gone" ,
1618- ext_hub_dev -> constant .dev_addr ,
1619- port_num );
1620- // Logically, recycling logic are finished for the Hub Driver, return ESP_OK to free the node
1621- assert (free_port == false);
1622- } else {
1623- ESP_LOGE (EXT_HUB_TAG , "[%d:%d] Unable to mark port as gone: %s" ,
1624- ext_hub_dev -> constant .dev_addr , port_num , esp_err_to_name (ret ));
1625- }
1626- }
1627-
1628- if (free_port ) {
1629- ret = device_port_free (ext_hub_dev , port_idx );
1630- if (ret != ESP_OK ) {
1631- goto exit ;
1632- }
16331596 }
16341597 }
1635-
1636- ret = ESP_OK ;
1637- exit :
16381598 return ret ;
16391599}
16401600
0 commit comments