summaryrefslogtreecommitdiff
path: root/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-04-07 19:38:13 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-04-07 19:38:13 +0000
commit45ad2f7a8b237cf58518b874326078659ff90011 (patch)
tree10738af642eec9353c15851c0c46dc7b76cc370a /nuttx/arch/arm/src/stm32/stm32_otgfsdev.c
parentd147bb611f61ceaff9a8db9aeebfdf17805f94ef (diff)
downloadpx4-nuttx-45ad2f7a8b237cf58518b874326078659ff90011.tar.gz
px4-nuttx-45ad2f7a8b237cf58518b874326078659ff90011.tar.bz2
px4-nuttx-45ad2f7a8b237cf58518b874326078659ff90011.zip
Add partial TxFIFO logic to STM32 OTG FS device driver
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4570 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/arch/arm/src/stm32/stm32_otgfsdev.c')
-rwxr-xr-xnuttx/arch/arm/src/stm32/stm32_otgfsdev.c270
1 files changed, 194 insertions, 76 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c b/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c
index 19bd3f17b..8e6bb3888 100755
--- a/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c
+++ b/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c
@@ -375,16 +375,19 @@ static bool stm32_addlast(FAR struct stm32_ep_s *privep,
/* Special endpoint 0 data transfer logic */
static inline void stm32_ep0xfer(uint8_t epphy, FAR uint8_t *data, uint32_t nbytes);
-static void stm32_ep0read(FAR uint8_t *dest, uint16_t len);
-static void stm32_ep0configsetup(FAR struct stm32_usbdev_s *priv)
+static void stm32_ep0configsetup(FAR struct stm32_usbdev_s *priv);
-/* IN request handling */
+/* IN request and TxFIFO handling */
+static void stm32_epwritefifo(FAR struct stm32_ep_s *privep,
+ FAR uint8_t *buf, int nbytes);
static int stm32_wrrequest(FAR struct stm32_usbdev_s *priv,
FAR struct stm32_ep_s *privep);
-/* OUT request handling */
+/* OUT request and RxFIFO handling */
+static void stm32_epreadfifo(FAR struct stm32_ep_s *privep,
+ FAR uint8_t *dest, uint16_t len);
static void stm32_epoutcomplete(FAR struct stm32_usbdev_s *priv,
FAR struct stm32_ep_s *privep);
static inline void stm32_epoutreceive(FAR struct stm32_ep_s *privep, int bcnt);
@@ -426,6 +429,7 @@ static inline void stm32_epoutinterrupt(FAR struct stm32_usbdev_s *priv);
static inline void stm32_runtestmode(FAR struct stm32_usbdev_s *priv);
static inline void stm32_epin(FAR struct stm32_usbdev_s *priv, uint8_t epno);
+static inline void stm32_txfifoempty(FAR struct stm32_usbdev_s *priv, int epno);
static inline void stm32_epininterrupt(FAR struct stm32_usbdev_s *priv);
/* Other second level interrupt processing */
@@ -692,61 +696,64 @@ static inline void stm32_ep0xfer(uint8_t epphy, uint8_t *buf, uint32_t nbytes)
}
/*******************************************************************************
- * Name: stm32_ep0read
+ * Name: stm32_ep0configsetup
*
* Description:
- * Read a Setup packet from the DTD.
+ * Setup to receive a SETUP packet.
*
*******************************************************************************/
-static void stm32_ep0read(FAR uint8_t *dest, uint16_t len)
+static void stm32_ep0configsetup(FAR struct stm32_usbdev_s *priv)
{
- uint32_t regaddr;
- int i;
+ uint32_t regval;
- /* Get the address of the EP0 FIFO */
+ regval = (USB_SIZEOF_CTRLREQ * 3 << OTGFS_DOEPTSIZ0_XFRSIZ_SHIFT) ||
+ (OTGFS_DOEPTSIZ0_PKTCNT) ||
+ (3 << OTGFS_DOEPTSIZ0_STUPCNT_SHIFT);
+ stm32_putreg(regval, STM32_OTGFS_DOEPTSIZ0);
+}
- regaddr = STM32_OTGFS_DFIFO_DEP(0);
+/****************************************************************************
+ * Name: stm32_epwritefifo
+ *
+ * Description:
+ * Send data to the endpoint's TxFIFO.
+ *
+ ****************************************************************************/
- /* Read 32-bits and write 4 x 8-bits at time (to avoid unaligned accesses) */
+static void stm32_epwritefifo(FAR struct stm32_ep_s *privep,
+ FAR uint8_t *buf, int nbytes)
+{
+ uint32_t regaddr;
+ uint32_t regval;
+ int nwords;
+ int i;
- for (i = 0; i < len; i += 4)
- {
- union
- {
- uint32_t w;
- uint8_t b[4];
- } data;
+ /* Convert the number of bytes to words */
- /* Read 1 x 32-bits of EP0 packet data */
+ nwords = (nbytes + 3) >> 2;
- data.w = stm32_getreg(regaddr);
+ /* Get the TxFIFO for this endpoint (same as the endpoint number) */
- /* Write 4 x 8-bits of EP0 packet data */
+ regaddr = STM32_OTGFS_DFIFO_DEP(privep->epphy);
- *dest++ = data.b[0];
- *dest++ = data.b[1];
- *dest++ = data.b[2];
- *dest++ = data.b[3];
- }
-}
+ /* Then transfer each word to the TxFIFO */
-/*******************************************************************************
- * Name: stm32_ep0configsetup
- *
- * Description:
- * Setup to receive a SETUP packet.
- *
- *******************************************************************************/
+ for (i = 0; i < nwords; i++)
+ {
+ /* Read four bytes from the source buffer (to avoid unaligned accesses)
+ * and pack these into one 32-bit word (little endian).
+ */
-static void stm32_ep0configsetup(FAR struct stm32_usbdev_s *priv)
-{
- uint32_t regval;
+ regval = (uint32_t)*buf++;
+ regval |= ((uint32_t)*buf++) << 8;
+ regval |= ((uint32_t)*buf++) << 16;
+ regval |= ((uint32_t)*buf++) << 24;
- regval = (USB_SIZEOF_CTRLREQ * 3 << OTGFS_DOEPTSIZ0_XFRSIZ_SHIFT) ||
- (OTGFS_DOEPTSIZ0_PKTCNT) ||
- (3 << OTGFS_DOEPTSIZ0_STUPCNT_SHIFT);
- stm32_putreg(regval, STM32_OTGFS_DOEPTSIZ0);
+ /* Then write the packed data to the TxFIFO */
+
+ stm32_putreg(regval, regaddr);
+ }
}
/****************************************************************************
@@ -757,16 +764,20 @@ static void stm32_ep0configsetup(FAR struct stm32_usbdev_s *priv)
*
****************************************************************************/
-static int stm32_wrrequest(struct stm32_usbdev_s *priv, struct stm32_ep_s *privep)
+static int stm32_wrrequest(FAR struct stm32_usbdev_s *priv,
+ FAR struct stm32_ep_s *privep)
{
struct stm32_req_s *privreq;
+ uint32_t regaddr;
+ uint32_t regval;
uint8_t *buf;
uint8_t epno;
int nbytes;
+ int nwords;
int bytesleft;
- /* We get here when an IN endpoint interrupt occurs. So now we know that
- * there is no TX transfer in progress.
+ /* We get here when an IN endpoint or Tx FIFO empty interrupt occurs. So
+ * now we know that there is no TX transfer in progress.
*/
privep->active = false;
@@ -789,57 +800,102 @@ static int stm32_wrrequest(struct stm32_usbdev_s *priv, struct stm32_ep_s *prive
ullvdbg("epno=%d req=%p: len=%d xfrd=%d nullpkt=%d\n",
epno, privreq, privreq->req.len, privreq->req.xfrd, privep->zlp);
- /* Get the number of bytes left to be sent in the packet */
+ /* Loop while there are still bytes to be transferred (or a zero-length-
+ * packet, ZLP, to be sent). The loop will also be terminated if there
+ * is insufficient space remaining in the TxFIFO to send a complete
+ * packet.
+ */
- bytesleft = privreq->req.len - privreq->req.xfrd;
- nbytes = bytesleft;
+ while (privreq->req.xfrd < privreq->req.len || privep->zlp)
+ {
+ /* Get the number of bytes left to be sent in the request */
- /* Send the next packet */
+ bytesleft = privreq->req.len - privreq->req.xfrd;
+ nbytes = bytesleft;
- if (nbytes > 0)
- {
- /* Either send the maxpacketsize or all of the remaining data in
- * the request.
+ /* Limit the size of the transfer to one full packet and handle
+ * zero-length packets (ZLPs).
*/
- privep->zlp = 0;
- if (nbytes >= privep->ep.maxpacket)
+ if (nbytes > 0)
{
- nbytes = privep->ep.maxpacket;
-
- /* Handle the case where this packet is exactly the
- * maxpacketsize. Do we need to send a zero-length packet
- * in this case?
+ /* Either send the maxpacketsize or all of the remaining data in
+ * the request.
*/
- if (bytesleft == privep->ep.maxpacket &&
- (privreq->req.flags & USBDEV_REQFLAGS_NULLPKT) != 0)
+ privep->zlp = 0;
+ if (nbytes >= privep->ep.maxpacket)
{
- privep->zlp = 1;
+ nbytes = privep->ep.maxpacket;
+
+ /* Handle the case where this packet is exactly the
+ * maxpacketsize. Do we need to send a zero-length packet
+ * in this case?
+ */
+
+ if (bytesleft == privep->ep.maxpacket &&
+ (privreq->req.flags & USBDEV_REQFLAGS_NULLPKT) != 0)
+ {
+#warning "How, exactly, do I need to handle zero-length packets?"
+ privep->zlp = 1;
+ }
}
}
- }
- /* Send the packet (might be a null packet nbytes == 0) */
+ /* Get the transfer size in 32-bit words */
- buf = privreq->req.buf + privreq->req.xfrd;
- stm32_epwrite(priv, privep, buf, nbytes);
- privep->active = true;
+ nwords = (nbytes + 3) >> 2;
- /* Update for the next data IN interrupt */
+ /* Get the number of 32-bit words available in the TxFIFO. The
+ * DXTFSTS indicates the amount of free space available in the
+ * endpoint TxFIFO. Values are in terms of 32-bit words:
+ *
+ * 0: Endpoint TxFIFO is full
+ * 1: 1 word available
+ * 2: 2 words available
+ * n: n words available
+ */
+
+ regaddr = STM32_OTGFS_DTXFSTS(privep->epphy);
+ regval = stm32_getreg(regaddr);
+
+ /* And terminate the loop if there is insufficient space in the TxFIFO
+ * hold the entire packet.
+ */
+
+ if ((regval & OTGFS_DTXFSTS_MASK) < nwords)
+ {
+ /* The TxFIFO is full */
+
+ break;
+ }
+
+ /* Transfer data to the TxFIFO */
+
+ buf = privreq->req.buf + privreq->req.xfrd;
+ stm32_epwritefifo(privep, buf, nbytes);
+
+ /* If it was not before, the OUT endpoint is now actively transferring
+ * data.
+ */
+
+ privep->active = true;
- privreq->req.xfrd += nbytes;
- bytesleft = privreq->req.len - privreq->req.xfrd;
+ /* Update for the next time through the loop */
+
+ privreq->req.xfrd += nbytes;
+ }
/* If all of the bytes were sent (including any final null packet)
* then we are finished with the transfer
*/
- if (bytesleft == 0 && !privep->zlp)
+ if (privreq->req.xfrd >= privreq->req.len && !privep->zlp)
{
usbtrace(TRACE_COMPLETE(USB_EPNO(privep->ep.eplog)), privreq->req.xfrd);
- privep->zlp = 0;
stm32_reqcomplete(privep, OK);
+
+ privep->zlp = 0;
privep->active = false;
}
@@ -847,6 +903,47 @@ static int stm32_wrrequest(struct stm32_usbdev_s *priv, struct stm32_ep_s *prive
}
/*******************************************************************************
+ * Name: stm32_epreadfifo
+ *
+ * Description:
+ * Read packet from the EP0 RxFIFO.
+ *
+ *******************************************************************************/
+
+static void stm32_epreadfifo(FAR struct stm32_ep_s *privep,
+ FAR uint8_t *dest, uint16_t len)
+{
+ uint32_t regaddr;
+ int i;
+
+ /* Get the address of the endpoint FIFO */
+
+ regaddr = STM32_OTGFS_DFIFO_DEP(privep->epphy);
+
+ /* Read 32-bits and write 4 x 8-bits at time (to avoid unaligned accesses) */
+
+ for (i = 0; i < len; i += 4)
+ {
+ union
+ {
+ uint32_t w;
+ uint8_t b[4];
+ } data;
+
+ /* Read 1 x 32-bits of EP0 packet data */
+
+ data.w = stm32_getreg(regaddr);
+
+ /* Write 4 x 8-bits of EP0 packet data */
+
+ *dest++ = data.b[0];
+ *dest++ = data.b[1];
+ *dest++ = data.b[2];
+ *dest++ = data.b[3];
+ }
+}
+
+/*******************************************************************************
* Name: stm32_epoutcomplete
*
* Description:
@@ -943,7 +1040,7 @@ static inline void stm32_epoutreceive(FAR struct stm32_ep_s *privep, int bcnt)
/* Transfer the data from the RxFIFO to the request's data buffer */
- stm32_ep0read(dest, readlen);
+ stm32_epreadfifo(privep, dest, readlen);
/* Update the number of bytes transferred */
@@ -973,7 +1070,7 @@ static void stm32_epoutsetup(FAR struct stm32_usbdev_s *priv,
* just return, leaving the newly received request in the request queue.
*/
- if (!priv->active)
+ if (!privep->active)
{
/* Loop until a valid request is found (or the request queue is empty).
* The loop is only need to look at the request queue again is an invalid
@@ -2173,6 +2270,26 @@ static inline void stm32_epin(FAR struct stm32_usbdev_s *priv, uint8_t epno)
}
}
+/****************************************************************************
+ * Name: stm32_txfifoempty
+ *
+ * Description:
+ * TxFIFO empty interrupt handling
+ *
+ ****************************************************************************/
+
+static inline void stm32_txfifoempty(FAR struct stm32_usbdev_s *priv, int epno)
+{
+ FAR struct stm32_ep_s *privep = &priv->epin[epno];
+
+ /* Continue processing the write request queue. This may mean sending
+ * more dat from the exisiting request or terminating the current requests
+ * and (perhaps) starting the IN transfer from the next write request.
+ */
+
+ stm32_wrrequest(priv, privep);
+}
+
/*******************************************************************************
* Name: stm32_epininterrupt
*
@@ -2482,7 +2599,8 @@ static inline void stm32_rxinterrupt(FAR struct stm32_usbdev_s *priv)
* last SETUP packet will be processed.
*/
- stm32_ep0read((FAR uint8_t*)&priv->ctrlreq, USB_SIZEOF_CTRLREQ);
+ stm32_epreadfifo(&priv->epout[EP0], (FAR uint8_t*)&priv->ctrlreq,
+ USB_SIZEOF_CTRLREQ);
/* The SETUP data has been processed */