@@ -420,7 +420,6 @@ static esp_err_t device_port_free(ext_hub_dev_t *ext_hub_dev, uint8_t port_idx)
420420 EXT_HUB_CHECK (ext_hub_dev -> constant .ports [port_idx ] != NULL , ESP_ERR_INVALID_STATE );
421421
422422 bool call_proc_req_cb = false;
423- bool all_ports_freed = false;
424423
425424 assert (ext_hub_dev -> single_thread .maxchild != 0 );
426425 assert (p_ext_hub_driver -> constant .port_driver );
@@ -435,25 +434,11 @@ static esp_err_t device_port_free(ext_hub_dev_t *ext_hub_dev, uint8_t port_idx)
435434 ext_hub_dev -> single_thread .maxchild -- ;
436435
437436 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- }
437+ if (ext_hub_dev -> dynamic .flags .waiting_free && ext_hub_dev -> single_thread .maxchild == 0 ) {
438+ call_proc_req_cb = _device_set_actions (ext_hub_dev , DEV_ACTION_FREE );
448439 }
449440 EXT_HUB_EXIT_CRITICAL ();
450441
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-
457442 if (call_proc_req_cb ) {
458443 p_ext_hub_driver -> constant .proc_req_cb (false, p_ext_hub_driver -> constant .proc_req_cb_arg );
459444 }
@@ -463,71 +448,60 @@ static esp_err_t device_port_free(ext_hub_dev_t *ext_hub_dev, uint8_t port_idx)
463448 return ret ;
464449}
465450
466- static esp_err_t device_release_ports (ext_hub_dev_t * ext_hub_dev )
451+ static esp_err_t device_release_port (ext_hub_dev_t * ext_hub_dev , uint8_t port_idx )
467452{
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- }
453+ assert (ext_hub_dev -> constant .ports [port_idx ] != NULL );
454+ assert (ext_hub_dev -> single_thread .maxchild != 0 );
455+ assert (p_ext_hub_driver -> constant .port_driver );
456+
457+ // Mark port as gone
458+ esp_err_t ret = p_ext_hub_driver -> constant .port_driver -> gone (ext_hub_dev -> constant .ports [port_idx ]);
459+ if (ret == ESP_OK ) {
460+ // Port doesn't have a device and can be freed right now
461+ ESP_ERROR_CHECK (device_port_free (ext_hub_dev , port_idx ));
462+ } else if (ret == ESP_ERR_NOT_FINISHED ) {
463+ // Port has a device and will be freed on recycle
464+ EXT_HUB_ENTER_CRITICAL ();
465+ ext_hub_dev -> dynamic .flags .waiting_children = 1 ;
466+ EXT_HUB_EXIT_CRITICAL ();
467+ ret = ESP_OK ;
468+ } else {
469+ ESP_LOGE (EXT_HUB_TAG , "[%d:%d] Unable to mark port as gone: %s" ,
470+ ext_hub_dev -> constant .dev_addr , port_idx + 1 , esp_err_to_name (ret ));
471+ return ret ;
492472 }
473+
493474 return ret ;
494475}
495476
477+ static void device_release_ports (ext_hub_dev_t * ext_hub_dev )
478+ {
479+ assert (ext_hub_dev -> constant .hub_desc -> bNbrPorts ); // Sanity check
480+ for (uint8_t i = 0 ; i < ext_hub_dev -> constant .hub_desc -> bNbrPorts ; i ++ ) {
481+ ESP_ERROR_CHECK (device_release_port (ext_hub_dev , i ));
482+ }
483+ }
484+
496485static void device_release (ext_hub_dev_t * ext_hub_dev )
497486{
498487 ESP_LOGD (EXT_HUB_TAG , "[%d] Device release" , ext_hub_dev -> constant .dev_addr );
499488
500489 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 ;
490+ assert (ext_hub_dev -> dynamic .flags .waiting_release ); // Sanity check
503491 ext_hub_dev -> dynamic .flags .waiting_release = 0 ;
492+ ext_hub_dev -> dynamic .flags .waiting_free = 1 ;
504493 EXT_HUB_EXIT_CRITICAL ();
505494
506- // Release IN EP
507- ESP_ERROR_CHECK (usbh_ep_command (ext_hub_dev -> constant .ep_in_hdl , USBH_EP_CMD_HALT ));
508-
509495 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 ;
515496 case EXT_HUB_STATE_CONFIGURED :
516497 case EXT_HUB_STATE_SUSPENDED :
517498 assert (ext_hub_dev -> constant .hub_desc != NULL ); // Device should have a Hub descriptor
518499 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- }
500+ device_release_ports (ext_hub_dev );
524501 break ;
525502 default :
526- // Should never occur
527- abort ();
528503 break ;
529504 }
530-
531505 ext_hub_dev -> single_thread .state = EXT_HUB_STATE_RELEASED ;
532506}
533507
@@ -771,17 +745,18 @@ static void device_free(ext_hub_dev_t *ext_hub_dev)
771745 TAILQ_REMOVE (& p_ext_hub_driver -> dynamic .ext_hubs_tailq , ext_hub_dev , dynamic .tailq_entry );
772746 EXT_HUB_EXIT_CRITICAL ();
773747
748+ ESP_ERROR_CHECK (usbh_ep_free (ext_hub_dev -> constant .ep_in_hdl ));
749+ ESP_ERROR_CHECK (usbh_dev_close (ext_hub_dev -> constant .dev_hdl ));
750+
774751 if (ext_hub_dev -> constant .hub_desc ) {
775752 heap_caps_free (ext_hub_dev -> constant .hub_desc );
776753 }
777754 if (ext_hub_dev -> constant .ports ) {
778755 heap_caps_free (ext_hub_dev -> constant .ports );
779756 }
780757
781- ESP_ERROR_CHECK (usbh_ep_free (ext_hub_dev -> constant .ep_in_hdl ));
782758 urb_free (ext_hub_dev -> constant .ctrl_urb );
783759 urb_free (ext_hub_dev -> constant .in_urb );
784-
785760 heap_caps_free (ext_hub_dev );
786761}
787762
@@ -1387,6 +1362,7 @@ esp_err_t ext_hub_dev_gone(uint8_t dev_addr)
13871362 ESP_LOGD (EXT_HUB_TAG , "[%d] Device gone" , ext_hub_dev -> constant .dev_addr );
13881363
13891364 EXT_HUB_ENTER_CRITICAL ();
1365+ ext_hub_dev -> dynamic .flags .is_gone = 1 ;
13901366 if (ext_hub_dev -> dynamic .flags .waiting_release ||
13911367 ext_hub_dev -> dynamic .flags .waiting_children ) {
13921368 EXT_HUB_EXIT_CRITICAL ();
@@ -1396,7 +1372,7 @@ esp_err_t ext_hub_dev_gone(uint8_t dev_addr)
13961372 }
13971373
13981374 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
1375+ // Not in pending list and doesn't have any children release and free right away
14001376 ext_hub_dev -> dynamic .flags .waiting_free = 1 ;
14011377 ext_hub_dev -> dynamic .flags .waiting_release = 1 ;
14021378 call_proc_req_cb = _device_set_actions (ext_hub_dev , DEV_ACTION_RELEASE |
@@ -1438,7 +1414,9 @@ esp_err_t ext_hub_all_free(void)
14381414 while (hub_curr != NULL ) {
14391415 hub_next = TAILQ_NEXT (hub_curr , dynamic .tailq_entry );
14401416 hub_curr -> dynamic .flags .waiting_release = 1 ;
1441- call_proc_req_cb = _device_set_actions (hub_curr , DEV_ACTION_RELEASE );
1417+ call_proc_req_cb = _device_set_actions (hub_curr , DEV_ACTION_EP1_FLUSH |
1418+ DEV_ACTION_EP1_DEQUEUE |
1419+ DEV_ACTION_RELEASE );
14421420 // At least one hub should be released
14431421 wait_for_free = true;
14441422 hub_curr = hub_next ;
@@ -1575,66 +1553,30 @@ esp_err_t ext_hub_port_recycle(ext_hub_handle_t ext_hub_hdl, uint8_t port_num)
15751553 EXT_HUB_CHECK (ext_hub_hdl != NULL , ESP_ERR_INVALID_ARG );
15761554 ext_hub_dev_t * ext_hub_dev = (ext_hub_dev_t * )ext_hub_hdl ;
15771555
1578- esp_err_t ret ;
15791556 uint8_t port_idx = port_num - 1 ;
1580- bool free_port = false;
15811557 bool release_port = false;
1582-
15831558 EXT_HUB_CHECK (port_idx < ext_hub_dev -> constant .hub_desc -> bNbrPorts , ESP_ERR_INVALID_SIZE );
15841559 EXT_HUB_CHECK (p_ext_hub_driver -> constant .port_driver != NULL , ESP_ERR_NOT_SUPPORTED );
15851560 EXT_HUB_CHECK (ext_hub_dev -> single_thread .state == EXT_HUB_STATE_CONFIGURED ||
15861561 ext_hub_dev -> single_thread .state == EXT_HUB_STATE_RELEASED , ESP_ERR_INVALID_STATE );
15871562
15881563 EXT_HUB_ENTER_CRITICAL ();
1589- if (ext_hub_dev -> dynamic .flags .waiting_release ) {
1564+ if (ext_hub_dev -> dynamic .flags .waiting_release ||
1565+ ext_hub_dev -> dynamic .flags .waiting_children ) {
15901566 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;
15951567 }
15961568 EXT_HUB_EXIT_CRITICAL ();
15971569
1598- if (!release_port && !free_port ) {
1570+ esp_err_t ret ;
1571+ if (release_port ) {
1572+ ret = device_release_port (ext_hub_dev , port_idx );
1573+ } else {
15991574 // Parent still present, recycle the port
16001575 ret = p_ext_hub_driver -> constant .port_driver -> recycle (ext_hub_dev -> constant .ports [port_idx ]);
16011576 if (ret != ESP_OK ) {
16021577 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- }
16331578 }
16341579 }
1635-
1636- ret = ESP_OK ;
1637- exit :
16381580 return ret ;
16391581}
16401582
0 commit comments