diff --git a/components/hal/include/hal/usbh_hal.h b/components/hal/include/hal/usbh_hal.h index b1782be597..859118adbf 100644 --- a/components/hal/include/hal/usbh_hal.h +++ b/components/hal/include/hal/usbh_hal.h @@ -438,7 +438,7 @@ static inline uint32_t *usbh_hal_port_get_frame_list(usbh_hal_context_t *hal) */ static inline void usbh_hal_port_periodic_enable(usbh_hal_context_t *hal) { - assert(hal->periodic_frame_list != NULL && !hal->flags.periodic_sched_enabled); + assert(hal->periodic_frame_list != NULL); usbh_ll_set_frame_list_base_addr(hal->dev, (uint32_t)hal->periodic_frame_list); usbh_ll_hcfg_set_num_frame_list_entries(hal->dev, hal->frame_list_len); usbh_ll_hcfg_en_perio_sched(hal->dev); diff --git a/components/hal/usbh_hal.c b/components/hal/usbh_hal.c index 1564d27821..6adae33a07 100644 --- a/components/hal/usbh_hal.c +++ b/components/hal/usbh_hal.c @@ -239,6 +239,8 @@ void usbh_hal_chan_free(usbh_hal_context_t *hal, usbh_hal_chan_t *chan_obj) } //Can only free a channel when in the disabled state and descriptor list released assert(!chan_obj->flags.active && !chan_obj->flags.error_pending); + //Disable channel's interrupt + usbh_ll_haintmsk_dis_chan_intr(hal->dev, 1 << chan_obj->flags.chan_idx); //Deallocate channel hal->channels.hdls[chan_obj->flags.chan_idx] = NULL; hal->channels.num_allocd--; diff --git a/components/usb/hcd.c b/components/usb/hcd.c index d4c26d8a92..fefe994d43 100644 --- a/components/usb/hcd.c +++ b/components/usb/hcd.c @@ -821,13 +821,14 @@ static hcd_port_event_t _intr_hdlr_hprt(port_t *port, usbh_hal_port_event_t hal_ port->flags.conn_dev_ena = 0; //Disabled could be due to a disable request or reset request, or due to a port error if (port->state != HCD_PORT_STATE_RESETTING) { //Ignore the disable event if it's due to a reset request - port->state = HCD_PORT_STATE_DISABLED; if (port->flags.disable_requested) { //Disabled by request (i.e. by port command). Generate an internal event + port->state = HCD_PORT_STATE_DISABLED; port->flags.disable_requested = 0; *yield |= _internal_port_event_notify_from_isr(port); } else { //Disabled due to a port error + port->state = HCD_PORT_STATE_RECOVERY; port_event = HCD_PORT_EVENT_ERROR; } } @@ -838,7 +839,7 @@ static hcd_port_event_t _intr_hdlr_hprt(port_t *port, usbh_hal_port_event_t hal_ if (port->state != HCD_PORT_STATE_NOT_POWERED) { //We need to power OFF the port to protect it usbh_hal_port_toggle_power(port->hal, false); - port->state = HCD_PORT_STATE_NOT_POWERED; + port->state = HCD_PORT_STATE_RECOVERY; port_event = HCD_PORT_EVENT_OVERCURRENT; } port->flags.conn_dev_ena = 0; @@ -1347,6 +1348,8 @@ esp_err_t hcd_port_init(int port_number, const hcd_port_config_t *port_config, h port_obj->context = port_config->context; usbh_hal_init(port_obj->hal); port_obj->initialized = true; + //Clear the frame list. We set the frame list register and enable periodic scheduling after a successful reset + memset(port_obj->frame_list, 0, FRAME_LIST_LEN * sizeof(uint32_t)); esp_intr_enable(s_hcd_obj->isr_hdl); *port_hdl = (hcd_port_handle_t)port_obj; HCD_EXIT_CRITICAL(); @@ -1410,8 +1413,7 @@ esp_err_t hcd_port_command(hcd_port_handle_t port_hdl, hcd_port_cmd_t command) //Set FIFO sizes to default usbh_hal_set_fifo_size(port->hal, &fifo_config_default); port->fifo_bias = HCD_PORT_FIFO_BIAS_BALANCED; - //Reset frame list and enable periodic scheduling - memset(port->frame_list, 0, FRAME_LIST_LEN * sizeof(uint32_t)); + //We start periodic scheduling only after a RESET command since SOFs only start after a reset usbh_hal_port_set_frame_list(port->hal, port->frame_list, FRAME_LIST_LEN); usbh_hal_port_periodic_enable(port->hal); ret = ESP_OK; @@ -1501,7 +1503,9 @@ hcd_port_event_t hcd_port_handle_event(hcd_port_handle_t port_hdl) ret = HCD_PORT_EVENT_NONE; } else { //No device connected after debounce delay. This is an actual disconnection - port->state = HCD_PORT_STATE_DISCONNECTED; + if (port->state != HCD_PORT_STATE_NOT_POWERED) { //Don't update state if disconnect was due to power-off + port->state = HCD_PORT_STATE_DISCONNECTED; + } ret = HCD_PORT_EVENT_DISCONNECTION; } break; @@ -1538,6 +1542,10 @@ esp_err_t hcd_port_recover(hcd_port_handle_t port_hdl) port->state = HCD_PORT_STATE_NOT_POWERED; port->last_event = HCD_PORT_EVENT_NONE; port->flags.val = 0; + //Soft reset wipes all registers so we need to reinitialize the HAL + usbh_hal_init(port->hal); + //Clear the frame list. We set the frame list register and enable periodic scheduling after a successful reset + memset(port->frame_list, 0, FRAME_LIST_LEN * sizeof(uint32_t)); esp_intr_enable(s_hcd_obj->isr_hdl); HCD_EXIT_CRITICAL(); return ESP_OK; @@ -1982,7 +1990,7 @@ hcd_pipe_state_t hcd_pipe_get_state(hcd_pipe_handle_t pipe_hdl) esp_err_t hcd_pipe_command(hcd_pipe_handle_t pipe_hdl, hcd_pipe_cmd_t command) { pipe_t *pipe = (pipe_t *)pipe_hdl; - bool ret = ESP_OK; + esp_err_t ret = ESP_OK; HCD_ENTER_CRITICAL(); //Cannot execute pipe commands the pipe is already executing a command, or if the pipe or its port are no longer valid