summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2009-11-02 15:04:47 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2009-11-02 15:04:47 +0000
commit1c1ac75d6785b77ef102ad415e54bbb72a6db423 (patch)
tree9fb1c72a45351c702ffe0f585a720f0761ba512e
parentf18c07323c6f83f2f6d02f192c8f12f17264278b (diff)
downloadnuttx-1c1ac75d6785b77ef102ad415e54bbb72a6db423.tar.gz
nuttx-1c1ac75d6785b77ef102ad415e54bbb72a6db423.tar.bz2
nuttx-1c1ac75d6785b77ef102ad415e54bbb72a6db423.zip
Fix RX status setup
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2208 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_usbdev.c158
1 files changed, 84 insertions, 74 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_usbdev.c b/nuttx/arch/arm/src/stm32/stm32_usbdev.c
index 0ee59badf..cf13be77f 100644
--- a/nuttx/arch/arm/src/stm32/stm32_usbdev.c
+++ b/nuttx/arch/arm/src/stm32/stm32_usbdev.c
@@ -192,16 +192,17 @@
#define STM32_TRACEERR_DISPATCHSTALL 0x000e
#define STM32_TRACEERR_DRIVER 0x000f
#define STM32_TRACEERR_DRIVERREGISTERED 0x0010
-#define STM32_TRACEERR_EP0SETUPSTALLED 0x0011
-#define STM32_TRACEERR_EPBUFFER 0x0012
-#define STM32_TRACEERR_EPDISABLED 0x0013
-#define STM32_TRACEERR_EPOUTNULLPACKET 0x0014
-#define STM32_TRACEERR_EPRESERVE 0x0015
-#define STM32_TRACEERR_INVALIDCTRLREQ 0x0016
-#define STM32_TRACEERR_INVALIDPARMS 0x0017
-#define STM32_TRACEERR_IRQREGISTRATION 0x0018
-#define STM32_TRACEERR_NOTCONFIGURED 0x0019
-#define STM32_TRACEERR_REQABORTED 0x001a
+#define STM32_TRACEERR_EP0BADCTR 0x0011
+#define STM32_TRACEERR_EP0SETUPSTALLED 0x0012
+#define STM32_TRACEERR_EPBUFFER 0x0013
+#define STM32_TRACEERR_EPDISABLED 0x0014
+#define STM32_TRACEERR_EPOUTNULLPACKET 0x0015
+#define STM32_TRACEERR_EPRESERVE 0x0016
+#define STM32_TRACEERR_INVALIDCTRLREQ 0x0017
+#define STM32_TRACEERR_INVALIDPARMS 0x0018
+#define STM32_TRACEERR_IRQREGISTRATION 0x0019
+#define STM32_TRACEERR_NOTCONFIGURED 0x001a
+#define STM32_TRACEERR_REQABORTED 0x001b
/* Trace interrupt codes */
@@ -266,10 +267,9 @@
enum stm32_devstate_e
{
- DEVSTATE_INIT,
+ DEVSTATE_IDLE = 0, /* No request in progress */
DEVSTATE_RDREQUEST, /* Read request in progress */
DEVSTATE_WRREQUEST, /* Write request in progress */
- DEVSTATE_IDLE, /* No request in progress */
DEVSTATE_STALLED /* We are stalled */
};
@@ -439,7 +439,6 @@ static int stm32_rdrequest(struct stm32_usbdev_s *priv,
/* Interrupt level processing ***********************************************/
static int stm32_dispatchrequest(struct stm32_usbdev_s *priv);
-static void stm32_ep0post(struct stm32_usbdev_s *priv);
static void stm32_ep0setup(struct stm32_usbdev_s *priv);
static void stm32_ep0out(struct stm32_usbdev_s *priv,
struct stm32_ep_s *privep);
@@ -1027,8 +1026,6 @@ static void stm32_copytopma(const ubyte *buffer, uint16 pma, uint16 nbytes)
int nwords = (nbytes + 1) >> 1;
int i;
- ullvdbg("pma=%08x, nbytes=%d\n", pma, nbytes);
-
/* Copy loop. Source=user buffer, Dest=packet memory */
dest = (uint16*)(STM32_USBCANRAM_BASE + ((uint32)pma << 1));
@@ -1059,8 +1056,6 @@ stm32_copyfrompma(ubyte *buffer, uint16 pma, uint16 nbytes)
int nwords = (nbytes + 1) >> 1;
int i;
- ullvdbg("pma=%08x, nbytes=%d\n", pma, nbytes);
-
/* Copy loop. Source=packet memory, Dest=user buffer */
src = (uint32*)(STM32_USBCANRAM_BASE + ((uint32)pma << 1));
@@ -1243,7 +1238,6 @@ static int stm32_wrrequest(struct stm32_usbdev_s *priv, struct stm32_ep_s *prive
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPINQEMPTY), 0);
priv->devstate = DEVSTATE_IDLE;
- priv->txstatus = USB_EPR_STATTX_STALL;
return OK;
}
@@ -1373,8 +1367,11 @@ static int stm32_rdrequest(struct stm32_usbdev_s *priv, struct stm32_ep_s *prive
privreq->req.xfrd += readlen;
if (privreq->req.xfrd >= privreq->req.len)
{
+ /* Complete the transfer and mark the state IDLE. The endpoint
+ * RX will be marked valid when the data phase completes.
+ */
+
usbtrace(TRACE_COMPLETE(epno), privreq->req.xfrd);
- priv->rxstatus = USB_EPR_STATRX_VALID; /* Re-enable for next data reception */
stm32_reqcomplete(privep, OK);
priv->devstate = DEVSTATE_IDLE;
}
@@ -1425,21 +1422,6 @@ static int stm32_dispatchrequest(struct stm32_usbdev_s *priv)
}
/****************************************************************************
- * Name: stm32_ep0post
- ****************************************************************************/
-
-static void stm32_ep0post(struct stm32_usbdev_s *priv)
-{
- stm32_seteprxcount(EP0, STM32_EP0MAXPACKET);
- if (priv->devstate == DEVSTATE_STALLED)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_EP0SETUPSTALLED), priv->devstate);
- priv->rxstatus = USB_EPR_STATRX_STALL;
- priv->txstatus = USB_EPR_STATTX_STALL;
- }
-}
-
-/****************************************************************************
* Name: stm32_ep0setup
****************************************************************************/
@@ -1488,7 +1470,7 @@ static void stm32_ep0setup(struct stm32_usbdev_s *priv)
ullvdbg("SETUP: type=%02x req=%02x value=%04x index=%04x len=%04x\n",
priv->ctrl.type, priv->ctrl.req, value.w, index.w, len.w);
- priv->devstate = DEVSTATE_INIT;
+ priv->devstate = DEVSTATE_IDLE;
/* Dispatch any non-standard requests */
@@ -1914,8 +1896,6 @@ static void stm32_ep0setup(struct stm32_usbdev_s *priv)
stm32_epwrite(priv, ep0, response.b, nbytes);
priv->devstate = DEVSTATE_IDLE;
}
-
- stm32_ep0post(priv);
}
/****************************************************************************
@@ -1953,8 +1933,6 @@ static void stm32_ep0in(struct stm32_usbdev_s *priv)
{
priv->devstate = DEVSTATE_STALLED;
}
-
- stm32_ep0post(priv);
}
/****************************************************************************
@@ -1978,8 +1956,6 @@ static void stm32_ep0out(struct stm32_usbdev_s *priv, struct stm32_ep_s *privep)
priv->devstate = DEVSTATE_STALLED;
break;
}
-
- stm32_ep0post(priv);
}
/****************************************************************************
@@ -2033,12 +2009,14 @@ static void stm32_lptransfer(struct stm32_usbdev_s *priv)
{
/* Decode and service control endpoint interrupt */
- /* Save RX & TX status */
+ /* Initialize RX and TX status. For EP0 SETUP these should
+ * both by set to NAK by the hardware
+ */
priv->rxstatus = stm32_geteprxstatus(EP0);
priv->txstatus = stm32_geteptxstatus(EP0);
- /* Then set both to NAK */
+ /* Then set both to NAK (possibly unnecessary) */
stm32_seteprxstatus(EP0, USB_EPR_STATRX_NAK);
stm32_seteptxstatus(EP0, USB_EPR_STATTX_NAK);
@@ -2054,63 +2032,95 @@ static void stm32_lptransfer(struct stm32_usbdev_s *priv)
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EP0IN), istr);
stm32_clrepctrtx(EP0);
stm32_ep0in(priv);
-
- /* Set TX and RX status */
-
- stm32_seteprxstatus(EP0, priv->rxstatus);
- stm32_seteptxstatus(EP0, priv->txstatus);
}
else
{
/* EP0 OUT: host-to-device (DIR=1) */
epval = stm32_getreg(STM32_USB_EPR(EP0));
+
+ /* CTR_TX is set when an IN transaction successfully
+ * completes on an endpoint
+ */
+
if ((epval & USB_EPR_CTR_TX) != 0)
{
- /* CTR_TX is set when an IN transaction successfully
- * completes on an endpoint
- */
-
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EP0INDONE), epval);
stm32_clrepctrtx(EP0);
stm32_ep0in(priv);
-
- /* Set TX and RX status */
-
- stm32_seteprxstatus(EP0, priv->rxstatus);
- stm32_seteptxstatus(EP0, priv->txstatus);
}
+
+ /* SETUP is set by the hardware when the last completed
+ * transaction was a control endpoint SETUP
+ */
+
else if ((epval & USB_EPR_SETUP) != 0)
{
- /* SETUP is set by the hardware when the last completed
- * transaction was a control endpoint SETUP
- */
-
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EP0SETUPDONE), epval);
stm32_clrepctrrx(EP0);
stm32_ep0setup(priv);
+ }
- /* Set TX and RX status */
+ /* Set by the hardware when an OUT/SETUP transaction successfully
+ * completed on this endpoint.
+ */
- stm32_seteprxstatus(EP0, priv->rxstatus);
- stm32_seteptxstatus(EP0, priv->txstatus);
- }
else if ((epval & USB_EPR_CTR_RX) != 0)
{
- /* Set by the hardware when an OUT/SETUP transaction successfully
- * completed on this endpoint.
- */
-
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EP0OUTDONE), epval);
stm32_clrepctrrx(EP0);
stm32_ep0out(priv, privep);
+ }
- /* Set TX and RX status */
+ /* None of the above */
- stm32_seteprxstatus(EP0, priv->rxstatus);
- stm32_seteptxstatus(EP0, priv->txstatus);
+ else
+ {
+ usbtrace(TRACE_DEVERROR(STM32_TRACEERR_EP0BADCTR), epval);
+ return; /* Does this ever happen? */
}
}
+
+ /* Make sure that the EP0 packet size is still OK (superstitious?) */
+
+ stm32_seteprxcount(EP0, STM32_EP0MAXPACKET);
+
+ /* Now figure out the new RX/TX status. Here are all possible
+ * consequences of the above EP0 operations:
+ *
+ * rxstatus txstatus devstate MEANING
+ * -------- -------- --------- ---------------------------------
+ * NAK NAK IDLE Nothing happened
+ * NAK VALID IDLE EP0 response sent from USBDEV driver
+ * NAK VALID WRREQUEST EP0 response sent from class driver
+ * NAK --- STALL Some protocol error occurred
+ *
+ * First handle the STALL condition:
+ */
+
+ if (priv->devstate == DEVSTATE_STALLED)
+ {
+ usbtrace(TRACE_DEVERROR(STM32_TRACEERR_EP0SETUPSTALLED), priv->devstate);
+ priv->rxstatus = USB_EPR_STATRX_STALL;
+ priv->txstatus = USB_EPR_STATTX_STALL;
+ }
+
+ /* Was a transmission started? If so, txstatus will be VALID. The
+ * only special case to handle is when both are set to NAK. In that
+ * case, we need to for RX status to VALID in order to accept the next
+ * SETUP request.
+ */
+
+ else if (priv->rxstatus == USB_EPR_STATRX_NAK &&
+ priv->txstatus == USB_EPR_STATTX_NAK)
+ {
+ priv->rxstatus = USB_EPR_STATRX_VALID;
+ }
+
+ /* Now set the new TX and RX status */
+
+ stm32_seteprxstatus(EP0, priv->rxstatus);
+ stm32_seteptxstatus(EP0, priv->txstatus);
}
else
{
@@ -2339,7 +2349,7 @@ static int stm32_lpinterrupt(int irq, void *context)
}
exit_lpinterrupt:
- usbtrace(TRACE_INTEXIT(STM32_TRACEINTID_LPINTERRUPT), 0);
+ usbtrace(TRACE_INTEXIT(STM32_TRACEINTID_LPINTERRUPT), stm32_getreg(STM32_USB_EP0R));
return OK;
}
@@ -3251,7 +3261,7 @@ static void stm32_reset(struct stm32_usbdev_s *priv)
/* Reset the device state structure */
- priv->devstate = DEVSTATE_INIT;
+ priv->devstate = DEVSTATE_IDLE;
priv->rsmstate = RSMSTATE_IDLE;
priv->rxpending = FALSE;