summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-09-01 16:56:22 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-09-01 16:56:22 -0600
commit32413d841f60664d0bf77150bcdee16b625ee7a1 (patch)
tree9181b296ccf4f89e4fce206d8cac064c367e52ce
parent971522bc3e3897fabbbe86fe0993ab30ebc4466f (diff)
downloadpx4-nuttx-32413d841f60664d0bf77150bcdee16b625ee7a1.tar.gz
px4-nuttx-32413d841f60664d0bf77150bcdee16b625ee7a1.tar.bz2
px4-nuttx-32413d841f60664d0bf77150bcdee16b625ee7a1.zip
SAMA5 UDPHS: Clean up some write request handling
-rw-r--r--nuttx/arch/arm/src/sama5/sam_udphs.c161
1 files changed, 91 insertions, 70 deletions
diff --git a/nuttx/arch/arm/src/sama5/sam_udphs.c b/nuttx/arch/arm/src/sama5/sam_udphs.c
index c687388c6..c94a45d17 100644
--- a/nuttx/arch/arm/src/sama5/sam_udphs.c
+++ b/nuttx/arch/arm/src/sama5/sam_udphs.c
@@ -303,7 +303,6 @@ struct sam_ep_s
volatile uint8_t bank; /* Current reception bank (0 or 1) */
uint8_t stalled:1; /* true: Endpoint is stalled */
uint8_t halted:1; /* true: Endpoint feature halted */
- uint8_t txbusy:1; /* true: TX endpoint FIFO full */
uint8_t txnullpkt:1; /* Null packet needed at end of transfer */
};
@@ -900,22 +899,12 @@ static int sam_req_wrdma(struct sam_usbdev_s *priv, struct sam_ep_s *privep,
/* Switch to the sending state */
privep->epstate = UDPHS_EPSTATE_SENDING;
- privep->txnullpkt = 0;
privreq->inflight = 0;
- privreq->req.xfrd = 0;
/* Get the endpoint number */
epno = USB_EPNO(privep->ep.eplog);
- /* Either (1) we are committed to sending the null packet (because
- * txnullpkt == 1 && nbytes == 0), or (2) we havenot yet sent the last
- * packet (nbytes > 0). In either case, it is appropriate to clear
- * txnullpkt now.
- */
-
- privep->txnullpkt = 0;
-
/* How many bytes remain to be transferred in the request? */
remaining = privreq->req.len - privreq->req.xfrd - privreq->inflight;
@@ -1222,7 +1211,7 @@ static int sam_req_wrnodma(struct sam_usbdev_s *priv, struct sam_ep_s *privep,
* be cleared when the next data out interrupt is received.
*/
- privep->txbusy = true;
+ privep->epstate = UDPHS_EPSTATE_SENDING;
}
return OK;
@@ -1252,86 +1241,117 @@ static int sam_req_write(struct sam_usbdev_s *priv, struct sam_ep_s *privep)
* there is no TX transfer in progress.
*/
- privep->txbusy = false;
+ while (privep->epstate == UDPHS_EPSTATE_IDLE);
+ {
+ /* Check the request from the head of the endpoint request queue */
- /* Check the request from the head of the endpoint request queue */
+ privreq = sam_rqpeek(privep);
+ if (!privreq)
+ {
+ /* There is no TX transfer in progress and no new pending TX
+ * requests to send.
+ */
- privreq = sam_rqpeek(privep);
- if (!privreq)
- {
- /* There is no TX transfer in progress and no new pending TX
- * requests to send.
- */
+ usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_EPINQEMPTY), 0);
+ return -ENOENT;
+ }
- usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_EPINQEMPTY), 0);
- return -ENOENT;
- }
+ epno = USB_EPNO(privep->ep.eplog);
+ ullvdbg("epno=%d req=%p: len=%d xfrd=%d inflight=%dnullpkt=%d\n",
+ epno, privreq, privreq->req.len, privreq->req.xfrd,
+ privreq->inflight, privep->txnullpkt);
- epno = USB_EPNO(privep->ep.eplog);
- ullvdbg("epno=%d req=%p: len=%d xfrd=%d inflight=%dnullpkt=%d\n",
- epno, privreq, privreq->req.len, privreq->req.xfrd,
- privreq->inflight, privep->txnullpkt);
+ /* Were there bytes in flight? */
- /* Were there bytes in flight? */
+ if (privreq->inflight)
+ {
+ privreq->req.xfrd += privreq->inflight;
+ privreq->inflight = 0;
+ }
- if (privreq->inflight)
- {
- privreq->req.xfrd += privreq->inflight;
- privreq->inflight = 0;
- }
+ /* Get the number of bytes left to be sent in the packet */
- /* Get the number of bytes left to be sent in the packet */
+ bytesleft = privreq->req.len - privreq->req.xfrd;
+ if (bytesleft > 0)
+ {
+ /* If the size is exactly a full packet, then note if we need to
+ * send a zero length packet next.
+ */
- bytesleft = privreq->req.len - privreq->req.xfrd;
+ if (bytesleft == privep->ep.maxpacket &&
+ (privreq->req.flags & USBDEV_REQFLAGS_NULLPKT) != 0)
+ {
+ /* Next time we get here, bytesleft will be zero and txnullpkt
+ * will be set.
+ */
- /* Either (1) we are committed to sending the null packet (because txnullpkt == 1
- * && nbytes == 0), or (2) we have not yet send the last packet (nbytes > 0).
- * In either case, it is appropriate to clearn txnullpkt now.
- */
+ privep->txnullpkt = 1;
+ }
+ else
+ {
+ /* No zero packet is forthcoming (maybe later) */
- privep->txnullpkt = 0;
+ privep->txnullpkt = 0;
+ }
- /* If we are not sending a NULL packet, then clip the size to maxpacket
- * and check if we need to send a following NULL packet.
- */
+ /* The way that we handle the transfer is going to depend on
+ * whether or not this endpoint supports DMA.
+ */
- if (bytesleft > privep->ep.maxpacket &&
- (privreq->req.flags & USBDEV_REQFLAGS_NULLPKT) != 0)
- {
- privep->txnullpkt = 1;
- }
+ if ((SAM_EPSET_DMA & SAM_EP_BIT(epno)) != 0)
+ {
+ ret = sam_req_wrdma(priv, privep, privreq);
+ }
+ else
+ {
+ ret = sam_req_wrnodma(priv, privep, privreq);
+ }
- /* The way that we handle the transfer is going to depend on whether
- * or not this endpoint supports DMA.
- */
+ /* Check if the transfer was successfully initiated */
- if ((SAM_EPSET_DMA & SAM_EP_BIT(epno)) != 0)
- {
- ret = sam_req_wrdma(priv, privep, privreq);
- }
- else
- {
- ret = sam_req_wrnodma(priv, privep, privreq);
- }
+ if (ret < 0)
+ {
+ return ret;
+ }
+ }
+
+ /* No data to send... is there a trailing zero length packet transfer
+ * pending?
+ */
+
+ else if (privep->txnullpkt)
+ {
+ /* If we get here, then we sent the last of the data on the
+ * previous pass and we need to send the zero length packet now.
+ *
+ * A Zero Length Packet can be sent by setting just the TXRDY flag
+ * in* the UDPHS_EPTSETSTAx register
+ */
+
+ privep->epstate = UDPHS_EPSTATE_SENDING;
+ privep->txnullpkt = 0;
+ privreq->inflight = 0;
+ sam_putreg(UDPHS_EPTSETSTA_TXRDY, SAM_UDPHS_EPTSETSTA(epno));
+ }
- if (ret == OK)
- {
/* If all of the bytes were sent (including any final null packet)
* then we are finished with the request buffer).
*/
- if (privreq->req.len == privreq->req.xfrd && !privep->txnullpkt)
+ if (privreq->req.len >= privreq->req.xfrd &&
+ privep->epstate == UDPHS_EPSTATE_IDLE)
{
/* Return the write request to the class driver */
- usbtrace(TRACE_COMPLETE(USB_EPNO(privep->ep.eplog)), privreq->req.xfrd);
+ usbtrace(TRACE_COMPLETE(USB_EPNO(privep->ep.eplog)),
+ privreq->req.xfrd);
/* Get the endpoint type */
regval = sam_getreg(SAM_UDPHS_EPTCFG(epno));
eptype = regval & UDPHS_EPTCFG_TYPE_MASK;
- /* Disable interrupst on non-control endpoints */
+ /* Disable interrupts on non-control endpoints */
if (eptype != UDPHS_EPTCFG_TYPE_CTRL8)
{
@@ -1346,7 +1366,7 @@ static int sam_req_write(struct sam_usbdev_s *priv, struct sam_ep_s *privep)
}
}
- return ret;
+ return OK;
}
/****************************************************************************
@@ -1367,6 +1387,9 @@ static int sam_req_rdnodma(struct sam_usbdev_s *priv, struct sam_ep_s *privep,
int readlen;
int epno;
+ privep->epstate = UDPHS_EPSTATE_IDLE;
+ privreq->inflight = 0;
+
/* Get the number of bytes that can be received. This is the size of the
* user-provided request buffer, minus the number of bytes already
* transferred to the user-buffer.
@@ -1379,6 +1402,7 @@ static int sam_req_rdnodma(struct sam_usbdev_s *priv, struct sam_ep_s *privep,
*/
readlen = MIN(remaining, pktsize);
+ privreq->req.xfrd += readlen;
/* Get the source and destination transfer addresses */
@@ -1394,7 +1418,6 @@ static int sam_req_rdnodma(struct sam_usbdev_s *priv, struct sam_ep_s *privep,
*dest++ = *fifo++;
}
- privreq->req.xfrd += readlen;
return OK;
}
@@ -1666,7 +1689,7 @@ static void sam_ep0_setup(struct sam_usbdev_s *priv)
/* Assume NOT stalled; no TX in progress */
ep0->stalled = 0;
- ep0->txbusy = 0;
+ ep0->epstate = UDPHS_EPSTATE_IDLE;
/* And extract the little-endian 16-bit values to host order */
@@ -2655,7 +2678,6 @@ static void sam_ep_reset(struct sam_usbdev_s *priv, uint8_t epno)
privep->epstate = UDPHS_EPSTATE_DISABLED;
privep->stalled = false;
privep->halted = false;
- privep->txbusy = false;
privep->txnullpkt = false;
privep->bank = 0;
}
@@ -3112,7 +3134,7 @@ static int sam_ep_submit(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
/* If the IN endpoint FIFO is available, then transfer the data now */
- if (!privep->txbusy)
+ if (privep->epstate == UDPHS_EPSTATE_IDLE)
{
ret = sam_req_write(priv, privep);
}
@@ -3586,7 +3608,6 @@ static void sam_reset(struct sam_usbdev_s *priv)
privep->stalled = false;
privep->halted = false;
- privep->txbusy = false;
privep->txnullpkt = false;
}