mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-04 05:04:33 +02:00
HCD: Fix multiple bugs
This commit fixes the following bugs with the HCD and USB Host HAL - Make the setting to periodic frame list and scheduling to occur after a reset command - All port errors states should put the port into the HCD_PORT_STATE_RECOVERY state. - Fixed incorrect return type of hcd_port_command() function
This commit is contained in:
@@ -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)
|
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_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_set_num_frame_list_entries(hal->dev, hal->frame_list_len);
|
||||||
usbh_ll_hcfg_en_perio_sched(hal->dev);
|
usbh_ll_hcfg_en_perio_sched(hal->dev);
|
||||||
|
@@ -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
|
//Can only free a channel when in the disabled state and descriptor list released
|
||||||
assert(!chan_obj->flags.active && !chan_obj->flags.error_pending);
|
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
|
//Deallocate channel
|
||||||
hal->channels.hdls[chan_obj->flags.chan_idx] = NULL;
|
hal->channels.hdls[chan_obj->flags.chan_idx] = NULL;
|
||||||
hal->channels.num_allocd--;
|
hal->channels.num_allocd--;
|
||||||
|
@@ -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;
|
port->flags.conn_dev_ena = 0;
|
||||||
//Disabled could be due to a disable request or reset request, or due to a port error
|
//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
|
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) {
|
if (port->flags.disable_requested) {
|
||||||
//Disabled by request (i.e. by port command). Generate an internal event
|
//Disabled by request (i.e. by port command). Generate an internal event
|
||||||
|
port->state = HCD_PORT_STATE_DISABLED;
|
||||||
port->flags.disable_requested = 0;
|
port->flags.disable_requested = 0;
|
||||||
*yield |= _internal_port_event_notify_from_isr(port);
|
*yield |= _internal_port_event_notify_from_isr(port);
|
||||||
} else {
|
} else {
|
||||||
//Disabled due to a port error
|
//Disabled due to a port error
|
||||||
|
port->state = HCD_PORT_STATE_RECOVERY;
|
||||||
port_event = HCD_PORT_EVENT_ERROR;
|
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) {
|
if (port->state != HCD_PORT_STATE_NOT_POWERED) {
|
||||||
//We need to power OFF the port to protect it
|
//We need to power OFF the port to protect it
|
||||||
usbh_hal_port_toggle_power(port->hal, false);
|
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_event = HCD_PORT_EVENT_OVERCURRENT;
|
||||||
}
|
}
|
||||||
port->flags.conn_dev_ena = 0;
|
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;
|
port_obj->context = port_config->context;
|
||||||
usbh_hal_init(port_obj->hal);
|
usbh_hal_init(port_obj->hal);
|
||||||
port_obj->initialized = true;
|
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);
|
esp_intr_enable(s_hcd_obj->isr_hdl);
|
||||||
*port_hdl = (hcd_port_handle_t)port_obj;
|
*port_hdl = (hcd_port_handle_t)port_obj;
|
||||||
HCD_EXIT_CRITICAL();
|
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
|
//Set FIFO sizes to default
|
||||||
usbh_hal_set_fifo_size(port->hal, &fifo_config_default);
|
usbh_hal_set_fifo_size(port->hal, &fifo_config_default);
|
||||||
port->fifo_bias = HCD_PORT_FIFO_BIAS_BALANCED;
|
port->fifo_bias = HCD_PORT_FIFO_BIAS_BALANCED;
|
||||||
//Reset frame list and enable periodic scheduling
|
//We start periodic scheduling only after a RESET command since SOFs only start after a reset
|
||||||
memset(port->frame_list, 0, FRAME_LIST_LEN * sizeof(uint32_t));
|
|
||||||
usbh_hal_port_set_frame_list(port->hal, port->frame_list, FRAME_LIST_LEN);
|
usbh_hal_port_set_frame_list(port->hal, port->frame_list, FRAME_LIST_LEN);
|
||||||
usbh_hal_port_periodic_enable(port->hal);
|
usbh_hal_port_periodic_enable(port->hal);
|
||||||
ret = ESP_OK;
|
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;
|
ret = HCD_PORT_EVENT_NONE;
|
||||||
} else {
|
} else {
|
||||||
//No device connected after debounce delay. This is an actual disconnection
|
//No device connected after debounce delay. This is an actual disconnection
|
||||||
|
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;
|
port->state = HCD_PORT_STATE_DISCONNECTED;
|
||||||
|
}
|
||||||
ret = HCD_PORT_EVENT_DISCONNECTION;
|
ret = HCD_PORT_EVENT_DISCONNECTION;
|
||||||
}
|
}
|
||||||
break;
|
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->state = HCD_PORT_STATE_NOT_POWERED;
|
||||||
port->last_event = HCD_PORT_EVENT_NONE;
|
port->last_event = HCD_PORT_EVENT_NONE;
|
||||||
port->flags.val = 0;
|
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);
|
esp_intr_enable(s_hcd_obj->isr_hdl);
|
||||||
HCD_EXIT_CRITICAL();
|
HCD_EXIT_CRITICAL();
|
||||||
return ESP_OK;
|
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)
|
esp_err_t hcd_pipe_command(hcd_pipe_handle_t pipe_hdl, hcd_pipe_cmd_t command)
|
||||||
{
|
{
|
||||||
pipe_t *pipe = (pipe_t *)pipe_hdl;
|
pipe_t *pipe = (pipe_t *)pipe_hdl;
|
||||||
bool ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
|
|
||||||
HCD_ENTER_CRITICAL();
|
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
|
//Cannot execute pipe commands the pipe is already executing a command, or if the pipe or its port are no longer valid
|
||||||
|
Reference in New Issue
Block a user