diff options
| author | sakumisu <[email protected]> | 2022-02-13 14:31:59 +0800 |
|---|---|---|
| committer | sakumisu <[email protected]> | 2022-02-13 14:31:59 +0800 |
| commit | bc525ff9f55c4141bfc7d70b53467eb6f91a9566 (patch) | |
| tree | de3a3e9b08e5d64ecccfe84916d378103735181f | |
| parent | f7cd434ec7fa060488cfa1f5932399ef3286646b (diff) | |
update synopsys driver
| -rw-r--r-- | port/synopsys/usb_hc_synopsys.c | 276 |
1 files changed, 202 insertions, 74 deletions
diff --git a/port/synopsys/usb_hc_synopsys.c b/port/synopsys/usb_hc_synopsys.c index beb8204b..c0a9e248 100644 --- a/port/synopsys/usb_hc_synopsys.c +++ b/port/synopsys/usb_hc_synopsys.c @@ -13,13 +13,19 @@ HCD_HandleTypeDef hhcd_USB_OTG_FS; #endif #endif -#define USBH_PID_SETUP 0U -#define USBH_PID_DATA 1U - #ifndef CONFIG_USBHOST_CHANNELS #define CONFIG_USBHOST_CHANNELS 12 /* Number of host channels */ #endif +#define CONFIG_CONTROL_RETRY_COUNT 10 + +#define USBH_PID_SETUP 0U +#define USBH_PID_DATA 1U + +enum usb_synopsys_transfer_state { + TRANSFER_IDLE = 0, + TRANSFER_BUSY, +}; /* This structure retains the state of one host channel. NOTE: Since there * is only one channel operation active at a time, some of the fields in * in the structure could be moved in struct stm32_ubhost_s to achieve @@ -30,6 +36,8 @@ struct usb_synopsys_chan { usb_osal_sem_t waitsem; /* Channel wait semaphore */ volatile int result; /* The result of the transfer */ bool inuse; /* True: This channel is "in use" */ + uint8_t interval; /* Interrupt/isochronous EP polling interval */ + uint8_t transfer_state; /* Interrupt/isochronous EP transfer state */ bool in; /* True: IN endpoint */ volatile bool waiter; /* True: Thread is waiting for a channel event */ volatile uint16_t xfrd; /* Bytes transferred (at end of transfer) */ @@ -51,6 +59,7 @@ struct usb_synopsys_ctrlinfo { struct usb_synopsys_priv { HCD_HandleTypeDef *handle; + volatile uint64_t sof_timer; volatile bool connected; /* Connected to device */ volatile bool pscwait; /* True: Thread is waiting for a port event */ usb_osal_sem_t exclsem; /* Support mutually exclusive access */ @@ -154,6 +163,8 @@ static int usb_synopsys_chan_waitsetup(struct usb_synopsys_priv *priv, */ chan->waiter = true; + chan->result = -EBUSY; + chan->xfrd = 0; #ifdef CONFIG_USBHOST_ASYNCH chan->callback = NULL; chan->arg = NULL; @@ -197,6 +208,8 @@ static int usb_synopsys_chan_asynchsetup(struct usb_synopsys_priv *priv, */ chan->waiter = false; + chan->result = -EBUSY; + chan->xfrd = 0; chan->callback = callback; chan->arg = arg; ret = 0; @@ -228,8 +241,11 @@ static int usb_synopsys_chan_wait(struct usb_synopsys_priv *priv, struct usb_syn * when the transfer is completed. */ - while (chan->waiter) { - usb_osal_sem_take(chan->waitsem); + if (chan->waiter) { + ret = usb_osal_sem_take(chan->waitsem); + if (ret < 0) { + return ret; + } } /* The transfer is complete re-enable interrupts and return the result */ @@ -371,9 +387,9 @@ int usbh_ep0_reconfigure(usbh_epinfo_t ep, uint8_t dev_addr, uint8_t ep_mps, uin } if (speed == USB_SPEED_FULL) { - speed = HCD_SPEED_FULL; + speed = 1; } else if (speed == USB_SPEED_LOW) { - speed = HCD_SPEED_LOW; + speed = 2; } ret = HAL_HCD_HC_Init(g_usbhost.handle, ep0info->outndx, 0x00, dev_addr, speed, USB_ENDPOINT_TYPE_CONTROL, ep_mps); @@ -384,6 +400,8 @@ int usbh_ep0_reconfigure(usbh_epinfo_t ep, uint8_t dev_addr, uint8_t ep_mps, uin int usbh_ep_alloc(usbh_epinfo_t *ep, const struct usbh_endpoint_cfg *ep_cfg) { + struct usb_synopsys_chan *chan; + struct usb_synopsys_priv *priv = &g_usbhost; struct usb_synopsys_ctrlinfo *ep0; struct usbh_hubport *hport; int chidx; @@ -398,9 +416,9 @@ int usbh_ep_alloc(usbh_epinfo_t *ep, const struct usbh_endpoint_cfg *ep_cfg) hport = ep_cfg->hport; if (hport->speed == USB_SPEED_FULL) { - speed = HCD_SPEED_FULL; + speed = 1; } else if (hport->speed == USB_SPEED_LOW) { - speed = HCD_SPEED_LOW; + speed = 2; } if (ep_cfg->ep_type == USB_ENDPOINT_TYPE_CONTROL) { @@ -409,6 +427,11 @@ int usbh_ep_alloc(usbh_epinfo_t *ep, const struct usbh_endpoint_cfg *ep_cfg) ep0->outndx = usb_synopsys_chan_alloc(&g_usbhost); ep0->inndx = usb_synopsys_chan_alloc(&g_usbhost); + chan = &priv->chan[ep0->outndx]; + chan->interval = 0; + chan = &priv->chan[ep0->inndx]; + chan->interval = 0; + HAL_HCD_HC_Init(g_usbhost.handle, ep0->outndx, 0x00, hport->dev_addr, speed, USB_ENDPOINT_TYPE_CONTROL, ep_cfg->ep_mps); HAL_HCD_HC_Init(g_usbhost.handle, ep0->inndx, 0x80, hport->dev_addr, speed, USB_ENDPOINT_TYPE_CONTROL, ep_cfg->ep_mps); @@ -416,6 +439,10 @@ int usbh_ep_alloc(usbh_epinfo_t *ep, const struct usbh_endpoint_cfg *ep_cfg) } else { chidx = usb_synopsys_chan_alloc(&g_usbhost); + + chan = &priv->chan[chidx]; + chan->interval = ep_cfg->ep_interval; + HAL_HCD_HC_Init(g_usbhost.handle, chidx, ep_cfg->ep_addr, hport->dev_addr, speed, ep_cfg->ep_type, ep_cfg->ep_mps); g_usbhost.handle->hc[chidx].toggle_in = 0; @@ -450,7 +477,7 @@ int usbh_ep_free(usbh_epinfo_t ep) int usbh_control_transfer(usbh_epinfo_t ep, struct usb_setup_packet *setup, uint8_t *buffer) { int ret; - uint32_t flags; + uint32_t retries; struct usb_synopsys_chan *chan; struct usb_synopsys_priv *priv = &g_usbhost; struct usb_synopsys_ctrlinfo *ep0info = (struct usb_synopsys_ctrlinfo *)ep; @@ -460,9 +487,9 @@ int usbh_control_transfer(usbh_epinfo_t ep, struct usb_setup_packet *setup, uint return ret; } - flags = usb_osal_enter_critical_section(); chan = &priv->chan[ep0info->outndx]; usb_synopsys_chan_waitsetup(priv, chan); + ret = HAL_HCD_HC_SubmitRequest(g_usbhost.handle, ep0info->outndx, /* Pipe index */ 0, /* Direction : OUT */ @@ -471,17 +498,17 @@ int usbh_control_transfer(usbh_epinfo_t ep, struct usb_setup_packet *setup, uint (uint8_t *)setup, /* data buffer */ 8, /* data length */ 0); /* do ping (HS Only)*/ - usb_osal_leave_critical_section(flags); ret = usb_synopsys_chan_wait(priv, chan); if (ret < 0) { goto errout_with_mutex; } + if (setup->wLength && buffer) { if (setup->bmRequestType & 0x80) { - flags = usb_osal_enter_critical_section(); chan = &priv->chan[ep0info->inndx]; usb_synopsys_chan_waitsetup(priv, chan); + ret = HAL_HCD_HC_SubmitRequest(g_usbhost.handle, ep0info->inndx, /* Pipe index */ 1, /* Direction : IN */ @@ -490,49 +517,74 @@ int usbh_control_transfer(usbh_epinfo_t ep, struct usb_setup_packet *setup, uint buffer, /* data buffer */ setup->wLength, /* data length */ 0); /* do ping (HS Only)*/ - usb_osal_leave_critical_section(flags); + ret = usb_synopsys_chan_wait(priv, chan); if (ret < 0) { goto errout_with_mutex; } - flags = usb_osal_enter_critical_section(); chan = &priv->chan[ep0info->outndx]; - usb_synopsys_chan_waitsetup(priv, chan); - ret = HAL_HCD_HC_SubmitRequest(g_usbhost.handle, - ep0info->outndx, /* Pipe index */ - 0, /* Direction : OUT */ - 0, /* EP type */ - USBH_PID_DATA, /* Type Data */ - NULL, /* data buffer */ - 0, /* data length */ - 0); /* do ping (HS Only)*/ - usb_osal_leave_critical_section(flags); - ret = usb_synopsys_chan_wait(priv, chan); - if (ret < 0) { + + /* For ep0 out,we must retry more */ + for (retries = 0; retries < 10; retries++) { + usb_synopsys_chan_waitsetup(priv, chan); + + ret = HAL_HCD_HC_SubmitRequest(g_usbhost.handle, + ep0info->outndx, /* Pipe index */ + 0, /* Direction : OUT */ + 0, /* EP type */ + USBH_PID_DATA, /* Type Data */ + NULL, /* data buffer */ + 0, /* data length */ + 0); /* do ping (HS Only)*/ + + ret = usb_synopsys_chan_wait(priv, chan); + if (ret == -EAGAIN) { + continue; + } else if (ret < 0) { + goto errout_with_mutex; + } else if (ret == 0) { + break; + } + } + if (retries >= CONFIG_CONTROL_RETRY_COUNT) { + ret = -ETIMEDOUT; goto errout_with_mutex; } + } else { - flags = usb_osal_enter_critical_section(); chan = &priv->chan[ep0info->outndx]; - usb_synopsys_chan_waitsetup(priv, chan); - ret = HAL_HCD_HC_SubmitRequest(g_usbhost.handle, - ep0info->outndx, /* Pipe index */ - 0, /* Direction : OUT */ - 0, /* EP type */ - USBH_PID_DATA, /* Type Data */ - buffer, /* data buffer */ - setup->wLength, /* data length */ - 0); /* do ping (HS Only)*/ - usb_osal_leave_critical_section(flags); - ret = usb_synopsys_chan_wait(priv, chan); - if (ret < 0) { + + /* For ep0 out,we must retry more */ + for (retries = 0; retries < CONFIG_CONTROL_RETRY_COUNT; retries++) { + usb_synopsys_chan_waitsetup(priv, chan); + + ret = HAL_HCD_HC_SubmitRequest(g_usbhost.handle, + ep0info->outndx, /* Pipe index */ + 0, /* Direction : OUT */ + 0, /* EP type */ + USBH_PID_DATA, /* Type Data */ + buffer, /* data buffer */ + setup->wLength, /* data length */ + 0); /* do ping (HS Only)*/ + + ret = usb_synopsys_chan_wait(priv, chan); + if (ret == -EAGAIN) { + continue; + } else if (ret < 0) { + goto errout_with_mutex; + } else if (ret == 0) { + break; + } + } + if (retries >= CONFIG_CONTROL_RETRY_COUNT) { + ret = -ETIMEDOUT; goto errout_with_mutex; } - flags = usb_osal_enter_critical_section(); chan = &priv->chan[ep0info->inndx]; usb_synopsys_chan_waitsetup(priv, chan); + ret = HAL_HCD_HC_SubmitRequest(g_usbhost.handle, ep0info->inndx, /* Pipe index */ 1, /* Direction : IN */ @@ -541,16 +593,16 @@ int usbh_control_transfer(usbh_epinfo_t ep, struct usb_setup_packet *setup, uint NULL, /* data buffer */ 0, /* data length */ 0); /* do ping (HS Only)*/ - usb_osal_leave_critical_section(flags); + ret = usb_synopsys_chan_wait(priv, chan); if (ret < 0) { goto errout_with_mutex; } } } else { - flags = usb_osal_enter_critical_section(); chan = &priv->chan[ep0info->inndx]; usb_synopsys_chan_waitsetup(priv, chan); + ret = HAL_HCD_HC_SubmitRequest(g_usbhost.handle, ep0info->inndx, /* Pipe index */ 1, /* Direction : IN */ @@ -559,7 +611,7 @@ int usbh_control_transfer(usbh_epinfo_t ep, struct usb_setup_packet *setup, uint NULL, /* data buffer */ 0, /* data length */ 0); /* do ping (HS Only)*/ - usb_osal_leave_critical_section(flags); + ret = usb_synopsys_chan_wait(priv, chan); if (ret < 0) { goto errout_with_mutex; @@ -575,7 +627,6 @@ errout_with_mutex: int usbh_ep_bulk_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen) { int ret; - uint32_t flags; struct usb_synopsys_chan *chan; struct usb_synopsys_priv *priv = &g_usbhost; uint8_t chidx = (uint8_t)ep; @@ -585,9 +636,9 @@ int usbh_ep_bulk_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen) return ret; } - flags = usb_osal_enter_critical_section(); chan = &priv->chan[chidx]; usb_synopsys_chan_waitsetup(priv, chan); + ret = HAL_HCD_HC_SubmitRequest(g_usbhost.handle, chidx, /* Pipe index */ g_usbhost.handle->hc[chidx].ep_is_in ? 1 : 0, /* Direction : IN */ @@ -596,7 +647,7 @@ int usbh_ep_bulk_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen) buffer, /* data buffer */ buflen, /* data length */ 0); /* do ping (HS Only)*/ - usb_osal_leave_critical_section(flags); + ret = usb_synopsys_chan_wait(priv, chan); if (ret < 0) { goto errout_with_mutex; @@ -612,6 +663,7 @@ errout_with_mutex: int usbh_ep_intr_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen) { uint32_t flags; + uint32_t retries; int ret; struct usb_synopsys_chan *chan; struct usb_synopsys_priv *priv = &g_usbhost; @@ -621,9 +673,13 @@ int usbh_ep_intr_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen) if (ret < 0) { return ret; } - flags = usb_osal_enter_critical_section(); + chan = &priv->chan[chidx]; + usb_synopsys_chan_waitsetup(priv, chan); + flags = usb_osal_enter_critical_section(); + chan->transfer_state = TRANSFER_BUSY; + ret = HAL_HCD_HC_SubmitRequest(g_usbhost.handle, chidx, /* Pipe index */ g_usbhost.handle->hc[chidx].ep_is_in ? 1 : 0, /* Direction : IN */ @@ -632,6 +688,7 @@ int usbh_ep_intr_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen) buffer, /* data buffer */ buflen, /* data length */ 0); /* do ping (HS Only)*/ + usb_osal_leave_critical_section(flags); ret = usb_synopsys_chan_wait(priv, chan); if (ret < 0) { @@ -648,7 +705,6 @@ errout_with_mutex: int usbh_ep_bulk_async_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen, usbh_asynch_callback_t callback, void *arg) { int ret; - uint32_t flags; struct usb_synopsys_chan *chan; struct usb_synopsys_priv *priv = &g_usbhost; uint8_t chidx = (uint8_t)ep; @@ -658,9 +714,9 @@ int usbh_ep_bulk_async_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t bufl return ret; } - flags = usb_osal_enter_critical_section(); chan = &priv->chan[chidx]; usb_synopsys_chan_asynchsetup(priv, chan, callback, arg); + ret = HAL_HCD_HC_SubmitRequest(g_usbhost.handle, chidx, /* Pipe index */ g_usbhost.handle->hc[chidx].ep_is_in ? 1 : 0, /* Direction : IN */ @@ -669,7 +725,6 @@ int usbh_ep_bulk_async_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t bufl buffer, /* data buffer */ buflen, /* data length */ 0); /* do ping (HS Only)*/ - usb_osal_leave_critical_section(flags); usb_osal_mutex_give(g_usbhost.exclsem); @@ -689,9 +744,11 @@ int usbh_ep_intr_async_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t bufl return ret; } - flags = usb_osal_enter_critical_section(); chan = &priv->chan[chidx]; usb_synopsys_chan_asynchsetup(priv, chan, callback, arg); + flags = usb_osal_enter_critical_section(); + chan->transfer_state = TRANSFER_BUSY; + ret = HAL_HCD_HC_SubmitRequest(g_usbhost.handle, chidx, /* Pipe index */ g_usbhost.handle->hc[chidx].ep_is_in ? 1 : 0, /* Direction : IN */ @@ -700,8 +757,8 @@ int usbh_ep_intr_async_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t bufl buffer, /* data buffer */ buflen, /* data length */ 0); /* do ping (HS Only)*/ - usb_osal_leave_critical_section(flags); + usb_osal_leave_critical_section(flags); usb_osal_mutex_give(g_usbhost.exclsem); return ret; @@ -709,6 +766,49 @@ int usbh_ep_intr_async_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t bufl int usb_ep_cancel(usbh_epinfo_t ep) { + int ret; + uint32_t flags; + struct usb_synopsys_chan *chan; + struct usb_synopsys_priv *priv = &g_usbhost; + + uint8_t chidx = (uint8_t)ep; + + chan = &priv->chan[chidx]; + + flags = usb_osal_enter_critical_section(); + + chan->result = -ESHUTDOWN; + /* Is there a thread waiting for this transfer to complete? */ + + if (chan->waiter) { + /* Wake'em up! */ + chan->waiter = false; + usb_osal_sem_give(chan->waitsem); + } +#ifdef CONFIG_USBHOST_ASYNCH + /* No.. is an asynchronous callback expected when the transfer + * completes? + */ + + else if (chan->callback) { + usbh_asynch_callback_t callback; + void *arg; + + /* Extract the callback information */ + + callback = chan->callback; + arg = chan->arg; + + chan->callback = NULL; + chan->arg = NULL; + chan->xfrd = 0; + + /* Then perform the callback */ + + callback(arg, -ESHUTDOWN); + } +#endif + usb_osal_leave_critical_section(flags); return 0; } @@ -731,6 +831,17 @@ void HAL_HCD_Disconnect_Callback(HCD_HandleTypeDef *hhcd) if (g_usbhost.connected) { g_usbhost.connected = false; usb_synopsys_chan_freeall(&g_usbhost); + + if (g_usbhost.chan[0].waiter) { + /* Wake'em up! */ + g_usbhost.chan[0].waiter = false; + usb_osal_sem_give(g_usbhost.chan[0].waitsem); + } + if (g_usbhost.chan[1].waiter) { + /* Wake'em up! */ + g_usbhost.chan[1].waiter = false; + usb_osal_sem_give(g_usbhost.chan[1].waitsem); + } extern void usbh_event_notify_handler(uint8_t event, uint8_t rhport); usbh_event_notify_handler(USBH_EVENT_REMOVED, 1); } @@ -742,28 +853,45 @@ void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *hhcd, uint8_t chnum, struct usb_synopsys_priv *priv = &g_usbhost; chan = &priv->chan[chnum]; - if (urb_state == URB_DONE || urb_state == URB_STALL || urb_state == URB_ERROR || urb_state == URB_NOTREADY) { - if (urb_state != URB_NOTREADY) { - if (urb_state == URB_ERROR) { - chan->result = -EIO; - } else if (urb_state == URB_STALL) { - chan->result = -EPERM; - } else if (urb_state == URB_DONE) { - chan->result = 0; - } - chan->in = g_usbhost.handle->hc[chnum].ep_is_in; - chan->xfrd = g_usbhost.handle->hc[chnum].ep_is_in ? HAL_HCD_HC_GetXferCount(g_usbhost.handle, chnum) : g_usbhost.handle->hc[chnum].xfer_len; - usb_synopsys_chan_wakeup(priv, chan); - } else { - if (g_usbhost.handle->hc[chnum].ep_is_in == 0 && (g_usbhost.handle->hc[chnum].ep_type == USB_ENDPOINT_TYPE_CONTROL || g_usbhost.handle->hc[chnum].ep_type == USB_ENDPOINT_TYPE_BULK)) { + + if (urb_state == URB_NOTREADY) { + chan->result = -EAGAIN; + } else if (urb_state == URB_STALL) { + chan->result = -EPERM; + } else if (urb_state == URB_ERROR) { + chan->result = -EIO; + } else if (urb_state == URB_DONE) { + chan->transfer_state = TRANSFER_IDLE; + chan->result = 0; + } + chan->in = g_usbhost.handle->hc[chnum].ep_is_in; + chan->xfrd = g_usbhost.handle->hc[chnum].ep_is_in ? HAL_HCD_HC_GetXferCount(g_usbhost.handle, chnum) : g_usbhost.handle->hc[chnum].xfer_len; + + if (g_usbhost.handle->hc[chnum].ep_type == 0x00 && (urb_state == URB_NOTREADY) && g_usbhost.handle->hc[chnum].ep_is_in) { + return; + } + if ((g_usbhost.handle->hc[chnum].ep_type == 0x02) && (urb_state == URB_NOTREADY)) { + return; + } + + usb_synopsys_chan_wakeup(priv, chan); +} + +void HAL_HCD_SOF_Callback(HCD_HandleTypeDef *hhcd) +{ + g_usbhost.sof_timer++; + for (uint8_t chnum = 2; chnum < CONFIG_USBHOST_CHANNELS; chnum++) { + if (g_usbhost.handle->hc[chnum].ep_type == 0x01 || g_usbhost.handle->hc[chnum].ep_type == 0x03) { + if ((g_usbhost.chan[chnum].transfer_state == TRANSFER_BUSY) && + ((g_usbhost.sof_timer % g_usbhost.chan[chnum].interval) == 0)) { HAL_HCD_HC_SubmitRequest(g_usbhost.handle, - chnum, /* Pipe index */ - 0, /* Direction : OUT */ - g_usbhost.handle->hc[chnum].ep_type, /* EP type */ - USBH_PID_DATA, /* Type Data */ - g_usbhost.handle->hc[chnum].xfer_buff, /* data buffer */ - g_usbhost.handle->hc[chnum].xfer_len, /* data length */ - 0); /* do ping (HS Only)*/ + chnum, /* Pipe index */ + g_usbhost.handle->hc[chnum].ep_is_in ? 1 : 0, /* Direction : IN */ + g_usbhost.handle->hc[chnum].ep_type, /* EP type */ + USBH_PID_DATA, /* Type Data */ + g_usbhost.handle->hc[chnum].xfer_buff, /* data buffer */ + g_usbhost.handle->hc[chnum].xfer_len, /* data length */ + 0); /* do ping (HS Only)*/ } } } |
