mirror of
https://github.com/apache/nuttx.git
synced 2026-05-24 07:46:16 +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_CTR (1 << 15) /* Bit 15: Correct Transfer */
|
||||
#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_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);
|
||||
static void stm32_chan_wakeup(struct stm32_usbhost_s *priv,
|
||||
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 */
|
||||
|
||||
@@ -579,6 +583,7 @@ static int stm32_chan_alloc(struct stm32_usbhost_s *priv)
|
||||
priv->chan[chidx].inuse = true;
|
||||
priv->chan[chidx].pmabufno = (uint8_t)bufno;
|
||||
priv->chan[chidx].pmaaddr = STM32H5_PMA_BUFNO2ADDR(bufno);
|
||||
uinfo("Channel allocated: chidx=%d\n", 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)
|
||||
{
|
||||
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);
|
||||
chan->pmabufno = STM32H5_PMA_BUFFER_NONE;
|
||||
chan->pmaaddr = 0;
|
||||
uinfo("Channel freed: chidx=%d\n", chidx);
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
/* 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 */
|
||||
|
||||
stm32_transfer_start(priv, chidx);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1737,7 +1755,10 @@ static int stm32_usbdrd_interrupt(int irq, void *context, void *arg)
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -1745,15 +1766,20 @@ static int stm32_usbdrd_interrupt(int irq, void *context, void *arg)
|
||||
{
|
||||
stm32_gint_connected(priv);
|
||||
}
|
||||
else
|
||||
{
|
||||
stm32_gint_disconnected(priv);
|
||||
}
|
||||
|
||||
stm32_putreg(STM32_USB_ISTR, ~USB_ISTR_RESET);
|
||||
}
|
||||
|
||||
/* Device disconnection */
|
||||
/* Device connection */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user