@@ -50,9 +50,12 @@ implement the bare minimum to control the root HCD port.
5050
5151// Hub driver action flags. LISTED IN THE ORDER THEY SHOULD BE HANDLED IN within hub_process(). Some actions are mutually exclusive
5252#define HUB_DRIVER_FLAG_ACTION_ROOT_EVENT 0x01
53- #define HUB_DRIVER_FLAG_ACTION_PORT 0x02
53+ #define HUB_DRIVER_FLAG_ACTION_PORT_REQ 0x02
5454#define HUB_DRIVER_FLAG_ACTION_ENUM_EVENT 0x04
5555
56+ #define PORT_REQ_DISABLE 0x01
57+ #define PORT_REQ_RECOVER 0x02
58+
5659/**
5760 * @brief Root port states
5861 *
@@ -185,6 +188,7 @@ typedef struct {
185188 uint32_t val ;
186189 } flags ;
187190 root_port_state_t root_port_state ;
191+ unsigned int port_reqs ;
188192 } dynamic ;
189193 // Single thread members don't require a critical section so long as they are never accessed from multiple threads
190194 struct {
@@ -679,7 +683,8 @@ static void enum_stage_cleanup_failed(enum_ctrl_t *enum_ctrl)
679683 HUB_DRIVER_ENTER_CRITICAL ();
680684 // Enum could have failed due to a port error. If so, we need to trigger a port recovery
681685 if (p_hub_driver_obj -> dynamic .root_port_state == ROOT_PORT_STATE_RECOVERY ) {
682- p_hub_driver_obj -> dynamic .flags .actions |= HUB_DRIVER_FLAG_ACTION_PORT ;
686+ p_hub_driver_obj -> dynamic .port_reqs |= PORT_REQ_RECOVER ;
687+ p_hub_driver_obj -> dynamic .flags .actions |= HUB_DRIVER_FLAG_ACTION_PORT_REQ ;
683688 } else {
684689 // Otherwise, we move to the enum failed state and wait for the device to disconnect
685690 p_hub_driver_obj -> dynamic .root_port_state = ROOT_PORT_STATE_ENUM_FAILED ;
@@ -839,7 +844,8 @@ static void root_port_handle_events(hcd_port_handle_t root_port_hdl)
839844 case ROOT_PORT_STATE_POWERED : // This occurred before enumeration
840845 case ROOT_PORT_STATE_ENUM_FAILED : // This occurred after a failed enumeration.
841846 // Therefore, there's no device and we can go straight to port recovery
842- p_hub_driver_obj -> dynamic .flags .actions |= HUB_DRIVER_FLAG_ACTION_PORT ;
847+ p_hub_driver_obj -> dynamic .port_reqs |= PORT_REQ_RECOVER ;
848+ p_hub_driver_obj -> dynamic .flags .actions |= HUB_DRIVER_FLAG_ACTION_PORT_REQ ;
843849 break ;
844850 case ROOT_PORT_STATE_ENUM :
845851 // This occurred during enumeration. Therefore, we need to cleanup the failed enumeration
@@ -867,6 +873,30 @@ static void root_port_handle_events(hcd_port_handle_t root_port_hdl)
867873 }
868874}
869875
876+ static void root_port_req (hcd_port_handle_t root_port_hdl )
877+ {
878+ unsigned int port_reqs ;
879+
880+ HUB_DRIVER_ENTER_CRITICAL ();
881+ port_reqs = p_hub_driver_obj -> dynamic .port_reqs ;
882+ p_hub_driver_obj -> dynamic .port_reqs = 0 ;
883+ HUB_DRIVER_EXIT_CRITICAL ();
884+
885+ if (port_reqs & PORT_REQ_DISABLE ) {
886+ ESP_LOGD (HUB_DRIVER_TAG , "Disabling root port" );
887+ // We allow this to fail in case a disconnect/port error happens while disabling.
888+ hcd_port_command (p_hub_driver_obj -> constant .root_port_hdl , HCD_PORT_CMD_DISABLE );
889+ }
890+ if (port_reqs & PORT_REQ_RECOVER ) {
891+ ESP_LOGD (HUB_DRIVER_TAG , "Recovering root port" );
892+ ESP_ERROR_CHECK (hcd_port_recover (p_hub_driver_obj -> constant .root_port_hdl ));
893+ ESP_ERROR_CHECK (hcd_port_command (p_hub_driver_obj -> constant .root_port_hdl , HCD_PORT_CMD_POWER_ON ));
894+ HUB_DRIVER_ENTER_CRITICAL ();
895+ p_hub_driver_obj -> dynamic .root_port_state = ROOT_PORT_STATE_POWERED ;
896+ HUB_DRIVER_EXIT_CRITICAL ();
897+ }
898+ }
899+
870900static void enum_handle_events (void )
871901{
872902 bool stage_pass ;
@@ -1055,10 +1085,24 @@ esp_err_t hub_dev_is_free(uint8_t dev_addr)
10551085{
10561086 assert (dev_addr == ENUM_DEV_ADDR );
10571087 assert (p_hub_driver_obj -> single_thread .root_dev_hdl );
1058- p_hub_driver_obj -> single_thread .root_dev_hdl = NULL ;
10591088 // Device is free, we can now request its port be recycled
1089+ hcd_port_state_t port_state = hcd_port_get_state (p_hub_driver_obj -> constant .root_port_hdl );
1090+ p_hub_driver_obj -> single_thread .root_dev_hdl = NULL ;
1091+
10601092 HUB_DRIVER_ENTER_CRITICAL ();
1061- p_hub_driver_obj -> dynamic .flags .actions |= HUB_DRIVER_FLAG_ACTION_PORT ;
1093+ // How the port is recycled will depend on the port's state
1094+ switch (port_state ) {
1095+ case HCD_PORT_STATE_ENABLED :
1096+ p_hub_driver_obj -> dynamic .port_reqs |= PORT_REQ_DISABLE ;
1097+ break ;
1098+ case HCD_PORT_STATE_RECOVERY :
1099+ p_hub_driver_obj -> dynamic .port_reqs |= PORT_REQ_RECOVER ;
1100+ break ;
1101+ default :
1102+ abort (); // Should never occur
1103+ break ;
1104+ }
1105+ p_hub_driver_obj -> dynamic .flags .actions |= HUB_DRIVER_FLAG_ACTION_PORT_REQ ;
10621106 HUB_DRIVER_EXIT_CRITICAL ();
10631107
10641108 p_hub_driver_obj -> constant .proc_req_cb (USB_PROC_REQ_SOURCE_HUB , false, p_hub_driver_obj -> constant .proc_req_cb_arg );
@@ -1076,29 +1120,8 @@ esp_err_t hub_process(void)
10761120 if (action_flags & HUB_DRIVER_FLAG_ACTION_ROOT_EVENT ) {
10771121 root_port_handle_events (p_hub_driver_obj -> constant .root_port_hdl );
10781122 }
1079- if (action_flags & HUB_DRIVER_FLAG_ACTION_PORT ) {
1080- // Check current state of port
1081- hcd_port_state_t port_state = hcd_port_get_state (p_hub_driver_obj -> constant .root_port_hdl );
1082- switch (port_state ) {
1083- case HCD_PORT_STATE_ENABLED :
1084- // Port is still enabled with a connect device. Disable it.
1085- ESP_LOGD (HUB_DRIVER_TAG , "Disabling root port" );
1086- // We allow this to fail in case a disconnect/port error happens while disabling.
1087- hcd_port_command (p_hub_driver_obj -> constant .root_port_hdl , HCD_PORT_CMD_DISABLE );
1088- break ;
1089- case HCD_PORT_STATE_RECOVERY :
1090- // Port is in recovery after a disconnect/error. Recover it.
1091- ESP_LOGD (HUB_DRIVER_TAG , "Recovering root port" );
1092- ESP_ERROR_CHECK (hcd_port_recover (p_hub_driver_obj -> constant .root_port_hdl ));
1093- ESP_ERROR_CHECK (hcd_port_command (p_hub_driver_obj -> constant .root_port_hdl , HCD_PORT_CMD_POWER_ON ));
1094- HUB_DRIVER_ENTER_CRITICAL ();
1095- p_hub_driver_obj -> dynamic .root_port_state = ROOT_PORT_STATE_POWERED ;
1096- HUB_DRIVER_EXIT_CRITICAL ();
1097- break ;
1098- default :
1099- abort (); // Should never occur
1100- break ;
1101- }
1123+ if (action_flags & HUB_DRIVER_FLAG_ACTION_PORT_REQ ) {
1124+ root_port_req (p_hub_driver_obj -> constant .root_port_hdl );
11021125 }
11031126 if (action_flags & HUB_DRIVER_FLAG_ACTION_ENUM_EVENT ) {
11041127 enum_handle_events ();
0 commit comments