summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-08-21 18:13:35 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-08-21 18:13:35 +0000
commit9cfd924bbadfbf8501fde3a08545526d5d19a0b3 (patch)
treeca3cd8de818eece64ebd3e454b95494b22640c68
parentdc83e974e93bd5e130c43a6ab9247182e1d02513 (diff)
downloadnuttx-9cfd924bbadfbf8501fde3a08545526d5d19a0b3.tar.gz
nuttx-9cfd924bbadfbf8501fde3a08545526d5d19a0b3.tar.bz2
nuttx-9cfd924bbadfbf8501fde3a08545526d5d19a0b3.zip
Several bug fixes for STM32 OTG FS host driver
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5043 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r--nuttx/arch/arm/src/stm32/chip/stm32_otgfs.h26
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_otgfshost.c442
2 files changed, 226 insertions, 242 deletions
diff --git a/nuttx/arch/arm/src/stm32/chip/stm32_otgfs.h b/nuttx/arch/arm/src/stm32/chip/stm32_otgfs.h
index f6966a598..ee34172cf 100644
--- a/nuttx/arch/arm/src/stm32/chip/stm32_otgfs.h
+++ b/nuttx/arch/arm/src/stm32/chip/stm32_otgfs.h
@@ -205,6 +205,10 @@
#define STM32_OTGFS_DOEPTSIZ2_OFFSET 0x00b50 /* Device OUT endpoint-2 transfer size register */
#define STM32_OTGFS_DOEPTSIZ3_OFFSET 0x00b70 /* Device OUT endpoint-3 transfer size register */
+/* Power and clock gating registers */
+
+#define STM32_OTGFS_PCGCCTL_OFFSET 0x0e00 /* Power and clock gating control register */
+
/* Data FIFO (DFIFO) access registers */
#define STM32_OTGFS_DFIFO_DEP_OFFSET(n) (0x1000 + ((n) << 12))
@@ -216,15 +220,11 @@
#define STM32_OTGFS_DFIFO_DEP1_OFFSET 0x2000 /* 0x2000-0x2ffc Device IN/OUT Endpoint 1 DFIFO Write/Read Access */
#define STM32_OTGFS_DFIFO_HCH1_OFFSET 0x2000 /* 0x2000-0x2ffc Host OUT/IN Channel 1 DFIFO Read/Write Access */
-#define STM32_OTGFS_DFIFO_DEP2_OFFSET 0x3000 /* 0x3000-0x3ffc Device IN/OUT Endpoint 1 DFIFO Write/Read Access */
-#define STM32_OTGFS_DFIFO_HCH2_OFFSET 0x3000 /* 0x3000-0x3ffc Host OUT/IN Channel 1 DFIFO Read/Write Access */
+#define STM32_OTGFS_DFIFO_DEP2_OFFSET 0x3000 /* 0x3000-0x3ffc Device IN/OUT Endpoint 2 DFIFO Write/Read Access */
+#define STM32_OTGFS_DFIFO_HCH2_OFFSET 0x3000 /* 0x3000-0x3ffc Host OUT/IN Channel 2 DFIFO Read/Write Access */
-#define STM32_OTGFS_DFIFO_DEP3_OFFSET 0x4000 /* 0x4000-0x4ffc Device IN/OUT Endpoint 1 DFIFO Write/Read Access */
-#define STM32_OTGFS_DFIFO_HCH3_OFFSET 0x4000 /* 0x4000-0x4ffc Host OUT/IN Channel 1 DFIFO Read/Write Access */
-
-/* Power and clock gating registers */
-
-#define STM32_OTGFS_PCGCCTL_OFFSET 0x0e00 /* Power and clock gating control register */
+#define STM32_OTGFS_DFIFO_DEP3_OFFSET 0x4000 /* 0x4000-0x4ffc Device IN/OUT Endpoint 3 DFIFO Write/Read Access */
+#define STM32_OTGFS_DFIFO_HCH3_OFFSET 0x4000 /* 0x4000-0x4ffc Host OUT/IN Channel 3 DFIFO Read/Write Access */
/* Register Addresses *******************************************************************************/
@@ -361,6 +361,10 @@
#define STM32_OTGFS_DOEPTSIZ2 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPTSIZ2_OFFSET)
#define STM32_OTGFS_DOEPTSIZ3 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPTSIZ3_OFFSET)
+/* Power and clock gating registers */
+
+#define STM32_OTGFS_PCGCCTL (STM32_OTGFS_BASE+STM32_OTGFS_PCGCCTL_OFFSET)
+
/* Data FIFO (DFIFO) access registers */
#define STM32_OTGFS_DFIFO_DEP(n) (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_DEP_OFFSET(n))
@@ -378,10 +382,6 @@
#define STM32_OTGFS_DFIFO_DEP3 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_DEP3_OFFSET)
#define STM32_OTGFS_DFIFO_HCH3 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_HCH3_OFFSET)
-/* Power and clock gating registers */
-
-#define STM32_OTGFS_PCGCCTL (STM32_OTGFS_BASE+STM32_OTGFS_PCGCCTL_OFFSET)
-
/* Register Bitfield Definitions ********************************************************************/
/* Core global control and status registers */
@@ -1006,8 +1006,6 @@
# define OTGFS_DOEPTSIZ_RXDPID_DATA1 (2 << OTGFS_DOEPTSIZ_RXDPID_SHIFT)
# define OTGFS_DOEPTSIZ_RXDPID_MDATA (3 << OTGFS_DOEPTSIZ_RXDPID_SHIFT)
/* Bit 31: Reserved, must be kept at reset value */
-/* Power and clock gating registers */
-
/* Power and clock gating control register */
#define OTGFS_PCGCCTL_STPPCLK (1 << 0) /* Bit 0: Stop PHY clock */
diff --git a/nuttx/arch/arm/src/stm32/stm32_otgfshost.c b/nuttx/arch/arm/src/stm32/stm32_otgfshost.c
index 398f2dff6..e6ea2de06 100644
--- a/nuttx/arch/arm/src/stm32/stm32_otgfshost.c
+++ b/nuttx/arch/arm/src/stm32/stm32_otgfshost.c
@@ -268,6 +268,7 @@ static int stm32_chan_alloc(FAR struct stm32_usbhost_s *priv);
static inline void stm32_chan_free(FAR struct stm32_usbhost_s *priv, int chidx);
static inline void stm32_chan_freeall(FAR struct stm32_usbhost_s *priv);
static void stm32_chan_configure(FAR struct stm32_usbhost_s *priv, int chidx);
+static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx);
static int stm32_chan_waitsetup(FAR struct stm32_usbhost_s *priv,
FAR struct stm32_chan_s *chan);
static int stm32_chan_wait(FAR struct stm32_usbhost_s *priv,
@@ -291,7 +292,6 @@ static int stm32_ctrl_recvdata(FAR struct stm32_usbhost_s *priv,
static void stm32_gint_wrpacket(FAR struct stm32_usbhost_s *priv,
FAR uint8_t *buffer, int chidx, int buflen);
-static void stm32_gint_halttxchan(FAR struct stm32_usbhost_s *priv, int chidx);
static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv,
int chidx);
static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv,
@@ -610,6 +610,13 @@ static int stm32_chan_alloc(FAR struct stm32_usbhost_s *priv)
static void stm32_chan_free(FAR struct stm32_usbhost_s *priv, int chidx)
{
DEBUGASSERT((unsigned)chidx < STM32_NHOST_CHANNELS);
+
+ /* Halt the channel */
+
+ stm32_chan_halt(priv, chidx);
+
+ /* Mark the channel available */
+
priv->chan[chidx].inuse = false;
}
@@ -625,11 +632,11 @@ static inline void stm32_chan_freeall(FAR struct stm32_usbhost_s *priv)
{
uint8_t chidx;
- /* Clear address an "in-use" flag for all host channels */
+ /* Free all host channels */
for (chidx = 2; chidx < STM32_NHOST_CHANNELS ; chidx ++)
{
- priv->chan[chidx].inuse = false;
+ stm32_chan_free(priv, chidx);
}
}
@@ -754,6 +761,82 @@ static void stm32_chan_configure(FAR struct stm32_usbhost_s *priv, int chidx)
}
/*******************************************************************************
+ * Name: stm32_chan_halt
+ *
+ * Description:
+ * Halt the channel associated with 'chidx' by setting the CHannel DISable
+ * (CHDIS) bit in in the HCCHAR register.
+ *
+ *******************************************************************************/
+
+static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx)
+{
+ uint32_t hcchar;
+ uint32_t intmsk;
+ uint32_t eptype;
+ unsigned int avail;
+
+ /* "The application can disable any channel by programming the OTG_FS_HCCHARx
+ * register with the CHDIS and CHENA bits set to 1. This enables the OTG_FS
+ * host to flush the posted requests (if any) and generates a channel halted
+ * interrupt. The application must wait for the CHH interrupt in OTG_FS_HCINTx
+ * before reallocating the channel for other transactions. The OTG_FS host
+ * does not interrupt the transaction that has already been started on the
+ * USB."
+ */
+
+ hcchar = stm32_getreg(STM32_OTGFS_HCCHAR(chidx));
+ hcchar |= (OTGFS_HCCHAR_CHDIS | OTGFS_HCCHAR_CHENA);
+
+ /* Get the endpoint type from the HCCHAR register */
+
+ eptype = (hcchar & OTGFS_HCCHAR_EPTYP_MASK);
+
+ /* Check for space in the Tx FIFO to issue the halt.
+ *
+ * "Before disabling a channel, the application must ensure that there is at
+ * least one free space available in the non-periodic request queue (when
+ * disabling a non-periodic channel) or the periodic request queue (when
+ * disabling a periodic channel). The application can simply flush the
+ * posted requests when the Request queue is full (before disabling the
+ * channel), by programming the OTG_FS_HCCHARx register with the CHDIS bit
+ * set to 1, and the CHENA bit cleared to 0.
+ */
+
+ if (eptype == OTGFS_HCCHAR_EPTYP_CTRL || eptype == OTGFS_HCCHAR_EPTYP_BULK)
+ {
+ /* Get the number of words available in the non-periodic Tx FIFO. */
+
+ avail = stm32_getreg(STM32_OTGFS_HNPTXSTS) & OTGFS_HNPTXSTS_NPTXFSAV_MASK;
+ }
+ else /* if (eptype == OTGFS_HCCHAR_EPTYP_ISOC || eptype == OTGFS_HCCHAR_EPTYP_INTR) */
+ {
+ /* Get the number of words available in the non-periodic Tx FIFO. */
+
+ avail = stm32_getreg(STM32_OTGFS_HPTXSTS) & OTGFS_HPTXSTS_PTXFSAVL_MASK;
+ }
+
+ /* Check if there is any space available in the Tx FIFO. */
+
+ if (avail == 0)
+ {
+ /* The Tx FIFO is full... disable the channel to flush the requests */
+
+ hcchar &= ~OTGFS_HCCHAR_CHENA;
+ }
+
+ /* Unmask the CHannel Halted (CHH) interrupt */
+
+ intmsk = stm32_getreg(STM32_OTGFS_HCINTMSK(chidx));
+ intmsk |= OTGFS_HCINT_CHH;
+ stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), intmsk);
+
+ /* Halt the channel by setting CHDIS (and maybe CHENA) in the HCCHAR */
+
+ stm32_putreg(STM32_OTGFS_HCCHAR(chidx), hcchar);
+}
+
+/*******************************************************************************
* Name: stm32_chan_waitsetup
*
* Description:
@@ -891,49 +974,51 @@ static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, int chidx)
priv->chan[chidx].xfrlen = 0;
/* Compute the expected number of packets associated to the transfer.
- * If it is a IN endpoint, then we need to round down to the number
- * of full, maximally sized packets that can fit in the read buffer.
+ * If the transfer length is zero (or less than the size of one maximum
+ * size packet), then one packet is expected.
*/
- maxpacket = priv->chan[chidx].maxpacket;
- if (priv->chan[chidx].in)
- {
- npackets = priv->chan[chidx].buflen / maxpacket;
-
- /* A read buffer must at least one max packet size in length */
-
- DEBUGASSERT(npackets > 0);
-
- /* For the buffer length to an even multiple of maxpacket */
-
- priv->chan[chidx].buflen = npackets * maxpacket;
- }
-
- /* If it is an OUT endpoint, then we need round up to include any
- * possible partial, final packet.
+ /* If the transfer size is greater than one packet, then xalculate the
+ * number of packets that will be received/sent, including any partial
+ * final packet.
*/
- else if (priv->chan[chidx].buflen > 0)
+ maxpacket = priv->chan[chidx].maxpacket;
+
+ if (priv->chan[chidx].buflen > maxpacket)
{
npackets = (priv->chan[chidx].buflen + maxpacket - 1) / maxpacket;
- }
- /* Otherwise, we are sending a single zero-length packet */
+ /* Clip if the buffer length if it exceeds the maximum number of
+ * packets that can be transferred (this should not happen).
+ */
+ if (npackets > STM32_MAX_PKTCOUNT)
+ {
+ npackets = STM32_MAX_PKTCOUNT;
+ priv->chan[chidx].buflen = STM32_MAX_PKTCOUNT * maxpacket;
+ }
+ }
else
{
+ /* One packet will be sent/received (might be a zero length packet) */
+
npackets = 1;
}
- /* Clip it the buffer length if it exceeds the maximum number of
- * packets that can be transferred (this should not happen).
+ /* If it is an IN transfer, then adjust the size of the buffer UP to
+ * a full number of packets. Hmmm... couldn't this cause an overrun
+ * into unallocated memory?
*/
- if (npackets > STM32_MAX_PKTCOUNT)
+#if 0 /* Think about this */
+ if (priv->chan[chidx].in)
{
- npackets = STM32_MAX_PKTCOUNT;
- priv->chan[chidx].buflen = STM32_MAX_PKTCOUNT * maxpacket;
+ /* Force the buffer length to an even multiple of maxpacket */
+
+ priv->chan[chidx].buflen = npackets * maxpacket;
}
+#endif
/* Setup the HCTSIZn register */
@@ -957,8 +1042,8 @@ static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, int chidx)
regval |= OTGFS_HCCHAR_CHENA;
stm32_putreg(STM32_OTGFS_HCCHAR(chidx), regval);
- /* If this is an out transfer, then we need to do more.. we need to copy the
- * outgoing data into the correct TxFIFO.
+ /* If this is an out transfer, then we need to do more.. we need to copy
+ * the outgoing data into the correct TxFIFO.
*/
if (!priv->chan[chidx].in && priv->chan[chidx].buflen > 0)
@@ -1016,11 +1101,11 @@ static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, int chidx)
/* Write packet into the Tx FIFO. */
- stm32_gint_wrpacket(priv, priv->chan[chidx].buffer, chidx, priv->chan[chidx].buflen);
+ stm32_gint_wrpacket(priv, priv->chan[chidx].buffer, chidx,
+ priv->chan[chidx].buflen);
}
}
-
/*******************************************************************************
* Name: stm32_getframe
*
@@ -1078,9 +1163,23 @@ static int stm32_ctrl_sendsetup(FAR struct stm32_usbhost_s *priv,
/* Wait for the transfer to complete */
ret = stm32_chan_wait(priv, chan);
+
+ /* Return on success and for all failures other than EAGAIN. EAGAIN
+ * means that the device NAKed the SETUP command and that we should
+ * try a few more times.
+ */
+
if (ret != -EAGAIN)
{
- udbg("Transfer failed: %d\n", ret);
+ /* Output some debug information if the transfer failed */
+
+ if (ret < 0)
+ {
+ udbg("Transfer failed: %d\n", ret);
+ }
+
+ /* Return the result in any event */
+
return ret;
}
@@ -1218,61 +1317,6 @@ static void stm32_gint_wrpacket(FAR struct stm32_usbhost_s *priv,
}
/*******************************************************************************
- * Name: stm32_gint_halttxchan
- *
- * Description:
- * Halt the Tx channel associated with 'chidx' by setting the CHannel DISable
- * (CHDIS) bit in in the HCCHAR register.
- *
- *******************************************************************************/
-
-static void stm32_gint_halttxchan(FAR struct stm32_usbhost_s *priv, int chidx)
-{
- uint32_t hcchar;
- uint32_t eptype;
- unsigned int avail;
-
- /* Prepare to set the CHannel DISable and the CHannel ENAble bits in the
- * HCCHAR register.
- */
-
- hcchar = stm32_getreg(STM32_OTGFS_HCCHAR(chidx));
- hcchar |= (OTGFS_HCCHAR_CHDIS | OTGFS_HCCHAR_CHENA);
-
- /* Get the endpoint type from the HCCHAR register */
-
- eptype = (hcchar & OTGFS_HCCHAR_EPTYP_MASK);
-
- /* Check for space in the Tx FIFO to issue the halt */
-
- if (eptype == OTGFS_HCCHAR_EPTYP_CTRL || eptype == OTGFS_HCCHAR_EPTYP_BULK)
- {
- /* Get the number of words available in the non-periodic Tx FIFO. */
-
- avail = stm32_getreg(STM32_OTGFS_HNPTXSTS) & OTGFS_HNPTXSTS_NPTXFSAV_MASK;
- }
- else /* if (eptype == OTGFS_HCCHAR_EPTYP_ISOC || eptype == OTGFS_HCCHAR_EPTYP_INTR) */
- {
- /* Get the number of words available in the non-periodic Tx FIFO. */
-
- avail = stm32_getreg(STM32_OTGFS_HPTXSTS) & OTGFS_HPTXSTS_PTXFSAVL_MASK;
- }
-
- /* Check if there is any space available in the Tx FIFO. */
-
- if (avail == 0)
- {
- /* The Tx FIFO is full... disable the channel */
-
- hcchar &= ~OTGFS_HCCHAR_CHENA;
- }
-
- /* Halt the channel by setting CHDIS in the HCCHAR */
-
- stm32_putreg(STM32_OTGFS_HCCHAR(chidx), hcchar);
-}
-
-/*******************************************************************************
* Name: stm32_gint_hcinisr
*
* Description:
@@ -1314,31 +1358,26 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv,
{
/* Clear the pending the ACK response received/transmitted (ACK) interrupt */
- hcint &= ~OTGFS_HCINT_ACK;
- stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint);
+ stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_ACK);
}
/* Check for a pending STALL response receive (STALL) interrupt */
else if ((pending & OTGFS_HCINT_STALL) != 0)
{
- /* Unmask the CHannel Halted (CHH) interrupt */
-
- hcintmsk |= OTGFS_HCINT_CHH;
- stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk);
-
/* Set the stall state */
chan->chstate = CHSTATE_STALL;
/* Clear the NAK and STALL Conditions. */
- hcint &= ~(OTGFS_HCINT_NAK | OTGFS_HCINT_STALL);
- stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint);
+ stm32_putreg(STM32_OTGFS_HCINT(chidx), (OTGFS_HCINT_NAK | OTGFS_HCINT_STALL));
- /* Halt the Tx channel */
+ /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is
+ * received on the channel.
+ */
- stm32_gint_halttxchan(priv, chidx);
+ stm32_chan_halt(priv, chidx);
/* When there is a STALL, clear any pending NAK so that it is nor
* processed below.
@@ -1351,19 +1390,15 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv,
else if ((pending & OTGFS_HCINT_DTERR) != 0)
{
- /* Unmask the CHannel Halted (CHH) interrupt */
-
- hcintmsk |= OTGFS_HCINT_CHH;
- stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk);
-
- /* Halt the Tx channel */
+ /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is
+ * received on the channel.
+ */
- stm32_gint_halttxchan(priv, chidx);
+ stm32_chan_halt(priv, chidx);
/* Clear the NAK and data toggle error conditions */
- hcint &= ~(OTGFS_HCINT_NAK | OTGFS_HCINT_DTERR);
- stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint);
+ stm32_putreg(STM32_OTGFS_HCINT(chidx), (OTGFS_HCINT_NAK | OTGFS_HCINT_DTERR));
/* Set the Data Toggle ERRor (DTERR) state */
@@ -1374,51 +1409,38 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv,
if ((pending & OTGFS_HCINT_FRMOR) != 0)
{
- /* Unmask the CHannel Halted (CHH) interrupt */
-
- hcintmsk |= OTGFS_HCINT_CHH;
- stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk);
-
- /* Halt the Tx channel */
+ /* Halt the channel (probably not necessary for FRMOR) */
- stm32_gint_halttxchan(priv, chidx);
+ stm32_chan_halt(priv, chidx);
/* Clear the FRaMe OverRun (FRMOR) condition */
- hcint &= ~OTGFS_HCINT_FRMOR;
- stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint);
+ stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_FRMOR);
}
/* Check for a pending TransFeR Completed (XFRC) interrupt */
else if ((pending & OTGFS_HCINT_XFRC) != 0)
{
- /* Set the trnansfer complete state and reset the error count */
+ /* Set the transfer complete state and reset the error count */
chan->chstate = CHSTATE_XFRC;
chan->nerrors = 0;
/* Clear the TransFeR Completed (XFRC) condition */
- hcint &= ~OTGFS_HCINT_XFRC;
- stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint);
+ stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_XFRC);
if ((eptype == OTGFS_HCCHAR_EPTYP_CTRL) ||
(eptype == OTGFS_HCCHAR_EPTYP_BULK))
{
- /* Unmask the CHannel Halted (CHH) interrupt */
-
- hcintmsk |= OTGFS_HCINT_CHH;
- stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk);
+ /* Halt the channel ( probably not necessary for XFRC) */
- /* Halt the Tx channel */
-
- stm32_gint_halttxchan(priv, chidx);
+ stm32_chan_halt(priv, chidx);
/* Clear any pending NAK condition */
- hcint &= ~OTGFS_HCINT_NAK;
- stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint);
+ stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_NAK);
/* Toggle the IN data state */
@@ -1443,6 +1465,7 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv,
{
/* Mask the CHannel Halted (CHH) interrupt */
+ hcintmsk = stm32_getreg(STM32_OTGFS_HCINTMSK(chidx));
hcintmsk &= ~OTGFS_HCINT_CHH;
stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk);
@@ -1478,32 +1501,27 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv,
/* Clear the CHannel Halted (CHH) condition */
- hcint &= ~OTGFS_HCINT_CHH;
- stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint);
+ stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_CHH);
}
/* Check for a pending Transaction ERror (TXERR) interrupt */
else if ((pending & OTGFS_HCINT_TXERR) != 0)
{
- /* Unmask the CHannel Halted (CHH) interrupt */
-
- hcintmsk |= OTGFS_HCINT_CHH;
- stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk);
-
/* Increment the error count and set the transaction error state */
chan->nerrors++;
chan->chstate = CHSTATE_TXERR;
- /* Halt the Tx channel */
+ /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is
+ * received on the channel.
+ */
- stm32_gint_halttxchan(priv, chidx);
+ stm32_chan_halt(priv, chidx);
/* Clear the Transaction ERror (TXERR) condition */
- hcint &= ~OTGFS_HCINT_TXERR;
- stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint);
+ stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_TXERR);
}
/* Check for a pending NAK response received (NAK) interrupt */
@@ -1514,14 +1532,9 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv,
if (eptype == OTGFS_HCCHAR_EPTYP_INTR)
{
- /* Unmask the CHannel Halted (CHH) interrupt */
-
- hcintmsk |= OTGFS_HCINT_CHH;
- stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk);
+ /* Halt the channel (probably not necessary on NAK) */
- /* Halt the Tx channel */
-
- stm32_gint_halttxchan(priv, chidx);
+ stm32_chan_halt(priv, chidx);
}
else if ((eptype == OTGFS_HCCHAR_EPTYP_CTRL) ||
(eptype == OTGFS_HCCHAR_EPTYP_BULK))
@@ -1541,8 +1554,7 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv,
/* Clear the NAK condition */
- hcint &= ~OTGFS_HCINT_NAK;
- stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint);
+ stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_NAK);
}
/* Check for a transfer complete event */
@@ -1584,27 +1596,20 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv,
{
/* Clear the pending the ACK response received/transmitted (ACK) interrupt */
- hcint &= ~OTGFS_HCINT_ACK;
- stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint);
+ stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_ACK);
}
/* Check for a pending FRaMe OverRun (FRMOR) interrupt */
else if ((pending & OTGFS_HCINT_FRMOR) != 0)
{
- /* Unmask the CHannel Halted (CHH) interrupt */
-
- hcintmsk |= OTGFS_HCINT_CHH;
- stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk);
+ /* Halt the channel (probably not necessary for FRMOR) */
- /* Halt the Tx channel */
-
- stm32_gint_halttxchan(priv, chidx);
+ stm32_chan_halt(priv, chidx);
/* Clear the pending the FRaMe OverRun (FRMOR) interrupt */
- hcint &= ~OTGFS_HCINT_FRMOR;
- stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint);
+ stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_FRMOR);
}
/* Check for a pending TransFeR Completed (XFRC) interrupt */
@@ -1613,19 +1618,13 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv,
{
chan->nerrors = 0;
- /* Unmask the CHannel Halted (CHH) interrupt */
-
- hcintmsk |= OTGFS_HCINT_CHH;
- stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk);
-
- /* Halt the Tx channel */
+ /* Halt the channel (shouldn't be necessary on XFRC) */
- stm32_gint_halttxchan(priv, chidx);
+ stm32_chan_halt(priv, chidx);
/* Clear the pending the TransFeR Completed (XFRC) interrupt */
- hcint &= ~OTGFS_HCINT_XFRC;
- stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint);
+ stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_XFRC);
/* Set the transfer completed state */
@@ -1638,17 +1637,13 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv,
{
/* Clear the pending the STALL response receiv (STALL) interrupt */
- hcint &= ~OTGFS_HCINT_STALL;
- stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint);
-
- /* Unmask the CHannel Halted (CHH) interrupt */
-
- hcintmsk |= OTGFS_HCINT_CHH;
- stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk);
+ stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_STALL);
- /* Halt the Tx channel */
+ /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is
+ * received on the channel.
+ */
- stm32_gint_halttxchan(priv, chidx);
+ stm32_chan_halt(priv, chidx);
/* Set the stall state */
@@ -1663,19 +1658,13 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv,
chan->nerrors = 0;
- /* Unmask the CHannel Halted (CHH) interrupt */
-
- hcintmsk |= OTGFS_HCINT_CHH;
- stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk);
-
- /* Halt the Tx channel */
+ /* Halt the channel (probably not necessary on NAK) */
- stm32_gint_halttxchan(priv, chidx);
+ stm32_chan_halt(priv, chidx);
/* Clear the pending the NAK response received (NAK) interrupt */
- hcint &= ~OTGFS_HCINT_NAK;
- stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint);
+ stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_NAK);
/* Set the NAK state */
@@ -1686,14 +1675,11 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv,
else if ((pending & OTGFS_HCINT_TXERR) != 0)
{
- /* Unmask the CHannel Halted (CHH) interrupt */
-
- hcintmsk |= OTGFS_HCINT_CHH;
- stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk);
-
- /* Halt the Tx channel */
+ /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is
+ * received on the channel.
+ */
- stm32_gint_halttxchan(priv, chidx);
+ stm32_chan_halt(priv, chidx);
/* Increment the number of errors */
@@ -1705,8 +1691,7 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv,
/* Clear the pending the Transaction ERror (TXERR) interrupt */
- hcint &= ~OTGFS_HCINT_TXERR;
- stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint);
+ stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_TXERR);
}
/* Check for a pending response received (xxx) interrupt */
@@ -1716,19 +1701,13 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv,
{
chan->nerrors = 0;
- /* Unmask the CHannel Halted (CHH) interrupt */
-
- hcintmsk |= OTGFS_HCINT_CHH;
- stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk);
-
- /* Halt the Tx channel */
+ /* Halt the channel */
- stm32_gint_halttxchan(priv, chidx);
+ stm32_chan_halt(priv, chidx);
/* Clear the pending the response received (xxx) interrupt */
- hcint &= ~OTGFS_HCINT_NYET;
- stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint);
+ stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_NYET);
/* Set the NYET state */
@@ -1740,14 +1719,11 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv,
else if (pending & OTGFS_HCINT_DTERR)
{
- /* Unmask the CHannel Halted (CHH) interrupt */
-
- hcintmsk |= OTGFS_HCINT_CHH;
- stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk);
-
- /* Halt the Tx channel */
+ /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is
+ * received on the channel.
+ */
- stm32_gint_halttxchan(priv, chidx);
+ stm32_chan_halt(priv, chidx);
/* Set the data toggle error state */
@@ -1755,8 +1731,7 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv,
/* Clear the pending the Data Toggle ERRor (DTERR) and NAK interrupts */
- hcint &= ~(OTGFS_HCINT_DTERR | OTGFS_HCINT_NAK);
- stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint);
+ stm32_putreg(STM32_OTGFS_HCINT(chidx), (OTGFS_HCINT_DTERR | OTGFS_HCINT_NAK));
}
/* Check for a pending CHannel Halted (CHH) interrupt */
@@ -1765,6 +1740,7 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv,
{
/* Mask the CHannel Halted (CHH) interrupt */
+ hcintmsk = stm32_getreg(STM32_OTGFS_HCINTMSK(chidx));
hcintmsk &= ~OTGFS_HCINT_CHH;
stm32_putreg(STM32_OTGFS_HCINTMSK(chidx), hcintmsk);
@@ -1815,8 +1791,7 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv,
/* Clear the pending the CHannel Halted (CHH) interrupt */
- hcint &= ~OTGFS_HCINT_CHH;
- stm32_putreg(STM32_OTGFS_HCINT(chidx), hcint);
+ stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_CHH);
}
/* Check for a transfer complete event */
@@ -2408,15 +2383,28 @@ static int stm32_gint_isr(int irq, FAR void *context)
* host mode
*/
- /* Get the unmasked bits in the GINT status */
+ /* Loop while there are pending interrupts to process. This loop may save a
+ * little interrupt handling overhead.
+ */
+
+ for (;;)
+ {
+ /* Get the unmasked bits in the GINT status */
- pending = stm32_getreg(STM32_OTGFS_GINTSTS);
- pending &= stm32_getreg(STM32_OTGFS_GINTMSK);
+ pending = stm32_getreg(STM32_OTGFS_GINTSTS);
+ pending &= stm32_getreg(STM32_OTGFS_GINTMSK);
- /* The process each pending, unmasked GINT interrupts */
+ /* Return from the interrupt when there are no furhter pending
+ * interrupts.
+ */
+
+ if (pending == 0)
+ {
+ return OK;
+ }
+
+ /* Otherwise, process each pending, unmasked GINT interrupts */
- if (pending != 0)
- {
ullvdbg("GINTSTS: %08x\n", pending);
/* Handle the start of frame interrupt */
@@ -2478,6 +2466,8 @@ static int stm32_gint_isr(int irq, FAR void *context)
}
}
+ /* We won't get here */
+
return OK;
}
@@ -2919,11 +2909,7 @@ static int stm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep)
stm32_takesem(&priv->exclsem);
- /* Halt the channel */
-
- stm32_gint_halttxchan(priv, chidx);
-
- /* Mark the channel avaiable */
+ /* Halt the channel and mark the channel avaiable */
stm32_chan_free(priv, chidx);