mirror of
https://github.com/apache/nuttx.git
synced 2026-06-01 16:59:28 +08:00
arch/arm/src/stm32h5/stm32_usbdrdhost.c: Disable host channel when freed
Build Documentation / build-html (push) Has been cancelled
Build Documentation / build-html (push) Has been cancelled
The host interrupt callback was incorrectly using the wrong IRQ for disconnected. In host mode the same IRQ is used for connect/disconnected and it must check a status bit to know which one. When a USB device was unplugged, the host channels were free'd, but if they happen to be mid-transfer, that transfer was never cancelled so the USB hardware might still be trying to perfrom a transfer after was free'd. Fixed by cancelling any transfers on free. Signed-off-by: daniellizewski <daniellizewski@geotab.com>
This commit is contained in:
committed by
Lup Yuen Lee
parent
fe67544d5f
commit
0b0769f8d9
@@ -174,7 +174,7 @@
|
|||||||
#define USB_ISTR_PMAOVRN (1 << 14) /* Bit 14: Packet Memory Area Over / Underrun */
|
#define USB_ISTR_PMAOVRN (1 << 14) /* Bit 14: Packet Memory Area Over / Underrun */
|
||||||
#define USB_ISTR_CTR (1 << 15) /* Bit 15: Correct Transfer */
|
#define USB_ISTR_CTR (1 << 15) /* Bit 15: Correct Transfer */
|
||||||
#define USB_ISTR_THR512 (1 << 16) /* Bit 16: 512byte threshold interrupt */
|
#define USB_ISTR_THR512 (1 << 16) /* Bit 16: 512byte threshold interrupt */
|
||||||
#define USB_ISTR_DDISC (1 << 17) /* Bit 17: Device disconnection */
|
#define USB_ISTR_DDISC (1 << 17) /* Bit 17: Device connection */
|
||||||
#define USB_ISTR_DCON_STAT (1 << 29) /* Bit 29: Device connection status */
|
#define USB_ISTR_DCON_STAT (1 << 29) /* Bit 29: Device connection status */
|
||||||
#define USB_ISTR_LS_DCONN (1 << 30) /* Bit 30: Low-speed device connected */
|
#define USB_ISTR_LS_DCONN (1 << 30) /* Bit 30: Low-speed device connected */
|
||||||
|
|
||||||
|
|||||||
@@ -267,6 +267,10 @@ static int stm32_chan_wait(struct stm32_usbhost_s *priv,
|
|||||||
int timeout_ms);
|
int timeout_ms);
|
||||||
static void stm32_chan_wakeup(struct stm32_usbhost_s *priv,
|
static void stm32_chan_wakeup(struct stm32_usbhost_s *priv,
|
||||||
struct stm32_chan_s *chan);
|
struct stm32_chan_s *chan);
|
||||||
|
static void stm32_set_chep_rx_status(struct stm32_usbhost_s *priv,
|
||||||
|
int chidx, uint32_t status);
|
||||||
|
static void stm32_set_chep_tx_status(struct stm32_usbhost_s *priv,
|
||||||
|
int chidx, uint32_t status);
|
||||||
|
|
||||||
/* Control endpoint helpers */
|
/* Control endpoint helpers */
|
||||||
|
|
||||||
@@ -579,6 +583,7 @@ static int stm32_chan_alloc(struct stm32_usbhost_s *priv)
|
|||||||
priv->chan[chidx].inuse = true;
|
priv->chan[chidx].inuse = true;
|
||||||
priv->chan[chidx].pmabufno = (uint8_t)bufno;
|
priv->chan[chidx].pmabufno = (uint8_t)bufno;
|
||||||
priv->chan[chidx].pmaaddr = STM32H5_PMA_BUFNO2ADDR(bufno);
|
priv->chan[chidx].pmaaddr = STM32H5_PMA_BUFNO2ADDR(bufno);
|
||||||
|
uinfo("Channel allocated: chidx=%d\n", chidx);
|
||||||
return chidx;
|
return chidx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -607,9 +612,12 @@ static inline void stm32_chan_free(struct stm32_usbhost_s *priv,
|
|||||||
|
|
||||||
if (chan->pmabufno != STM32H5_PMA_BUFFER_NONE)
|
if (chan->pmabufno != STM32H5_PMA_BUFFER_NONE)
|
||||||
{
|
{
|
||||||
|
stm32_set_chep_rx_status(priv, chidx, USB_CHEP_RX_STRX_DIS);
|
||||||
|
stm32_set_chep_tx_status(priv, chidx, USB_CHEP_TX_STTX_DIS);
|
||||||
stm32_pma_free_buffer(priv, chan->pmabufno);
|
stm32_pma_free_buffer(priv, chan->pmabufno);
|
||||||
chan->pmabufno = STM32H5_PMA_BUFFER_NONE;
|
chan->pmabufno = STM32H5_PMA_BUFFER_NONE;
|
||||||
chan->pmaaddr = 0;
|
chan->pmaaddr = 0;
|
||||||
|
uinfo("Channel freed: chidx=%d\n", chidx);
|
||||||
}
|
}
|
||||||
|
|
||||||
chan->inuse = false;
|
chan->inuse = false;
|
||||||
@@ -1534,9 +1542,19 @@ static void stm32_hc_in_irq(struct stm32_usbhost_s *priv, int chidx)
|
|||||||
|
|
||||||
if (!transfer_complete && (chan->waiter || chan->callback))
|
if (!transfer_complete && (chan->waiter || chan->callback))
|
||||||
{
|
{
|
||||||
|
/* Clear VTRX by writing 0 to it
|
||||||
|
* (toggle bit, write 1 keeps, write 0 clears)
|
||||||
|
*/
|
||||||
|
|
||||||
|
chepval = stm32_getreg(STM32H5_USB_CHEP(chidx));
|
||||||
|
chepval = (chepval &
|
||||||
|
(0xffff7fff & USB_CHEP_REG_MASK)) | USB_CHEP_VTTX;
|
||||||
|
stm32_putreg(STM32H5_USB_CHEP(chidx), chepval);
|
||||||
|
|
||||||
/* More data expected - reactivate channel for next packet */
|
/* More data expected - reactivate channel for next packet */
|
||||||
|
|
||||||
stm32_transfer_start(priv, chidx);
|
stm32_transfer_start(priv, chidx);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1737,7 +1755,10 @@ static int stm32_usbdrd_interrupt(int irq, void *context, void *arg)
|
|||||||
|
|
||||||
istr = stm32_getreg(STM32_USB_ISTR);
|
istr = stm32_getreg(STM32_USB_ISTR);
|
||||||
|
|
||||||
/* Device connection */
|
/* Device connection/Disconnection. The STM32H5 has both USB_ISTR_DDISC
|
||||||
|
* and USB_ISTR_RESET to detect a connected device. Use USB_ISTR_RESET
|
||||||
|
* since it is signaled after 22 cycles (debounced)
|
||||||
|
*/
|
||||||
|
|
||||||
if ((istr & USB_ISTR_RESET) != 0)
|
if ((istr & USB_ISTR_RESET) != 0)
|
||||||
{
|
{
|
||||||
@@ -1745,15 +1766,20 @@ static int stm32_usbdrd_interrupt(int irq, void *context, void *arg)
|
|||||||
{
|
{
|
||||||
stm32_gint_connected(priv);
|
stm32_gint_connected(priv);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stm32_gint_disconnected(priv);
|
||||||
|
}
|
||||||
|
|
||||||
stm32_putreg(STM32_USB_ISTR, ~USB_ISTR_RESET);
|
stm32_putreg(STM32_USB_ISTR, ~USB_ISTR_RESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Device disconnection */
|
/* Device connection */
|
||||||
|
|
||||||
if ((istr & USB_ISTR_DDISC) != 0)
|
if ((istr & USB_ISTR_DDISC) != 0)
|
||||||
{
|
{
|
||||||
stm32_gint_disconnected(priv);
|
/* Not used. USB_ISTR_RESET used instead */
|
||||||
|
|
||||||
stm32_putreg(STM32_USB_ISTR, ~USB_ISTR_DDISC);
|
stm32_putreg(STM32_USB_ISTR, ~USB_ISTR_DDISC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user