diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2014-03-20 14:25:56 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2014-03-20 14:25:56 -0600 |
commit | 641ed1fd58895554a604c5314fff44330c9e9bf0 (patch) | |
tree | 53c8fe235b020562e538d2972d09e2dce4976609 | |
parent | e37095fc6e0b14e407f24c58b526445d7edcdece (diff) | |
download | nuttx-641ed1fd58895554a604c5314fff44330c9e9bf0.tar.gz nuttx-641ed1fd58895554a604c5314fff44330c9e9bf0.tar.bz2 nuttx-641ed1fd58895554a604c5314fff44330c9e9bf0.zip |
SAM4E UDP: Several fixes related to bulk endpoint transfers
-rw-r--r-- | nuttx/arch/arm/src/sam34/sam_udp.c | 122 | ||||
-rw-r--r-- | nuttx/arch/arm/src/sama5/sam_udphs.c | 13 | ||||
-rw-r--r-- | nuttx/drivers/usbdev/usbmsc_scsi.c | 8 |
3 files changed, 47 insertions, 96 deletions
diff --git a/nuttx/arch/arm/src/sam34/sam_udp.c b/nuttx/arch/arm/src/sam34/sam_udp.c index 17aee4385..85d92785c 100644 --- a/nuttx/arch/arm/src/sam34/sam_udp.c +++ b/nuttx/arch/arm/src/sam34/sam_udp.c @@ -296,6 +296,7 @@ struct sam_ep_s struct sam_usbdev_s *dev; /* Reference to private driver data */ struct sam_rqhead_s reqq; /* Read/write request queue */ + struct sam_rqhead_s pendq; /* Write requests pending stall sent */ volatile uint8_t epstate; /* State of the endpoint (see enum sam_epstate_e) */ uint8_t stalled:1; /* true: Endpoint is stalled */ uint8_t pending:1; /* true: IN Endpoint stall is pending */ @@ -373,9 +374,6 @@ static struct sam_req_s * sam_req_dequeue(struct sam_rqhead_s *queue); static void sam_req_enqueue(struct sam_rqhead_s *queue, struct sam_req_s *req); -static inline void - sam_req_abort(struct sam_ep_s *privep, - struct sam_req_s *privreq, int16_t result); static void sam_req_complete(struct sam_ep_s *privep, int16_t result); static void sam_req_wrsetup(struct sam_usbdev_s *priv, struct sam_ep_s *privep, struct sam_req_s *privreq); @@ -793,25 +791,6 @@ static void sam_req_enqueue(struct sam_rqhead_s *queue, struct sam_req_s *req) } /**************************************************************************** - * Name: sam_req_abort - ****************************************************************************/ - -static inline void -sam_req_abort(struct sam_ep_s *privep, struct sam_req_s *privreq, int16_t result) -{ - usbtrace(TRACE_DEVERROR(SAM_TRACEERR_REQABORTED), - (uint16_t)USB_EPNO(privep->ep.eplog)); - - /* Save the result in the request structure */ - - privreq->req.result = result; - - /* Callback to the request completion handler */ - - privreq->req.callback(&privep->ep, &privreq->req); -} - -/**************************************************************************** * Name: sam_req_complete ****************************************************************************/ @@ -861,7 +840,6 @@ static void sam_req_wrsetup(struct sam_usbdev_s *priv, volatile uint32_t *fifo; uint8_t epno; int nbytes; - int bytesleft; /* Get the unadorned endpoint number */ @@ -873,17 +851,7 @@ static void sam_req_wrsetup(struct sam_usbdev_s *priv, /* Get the number of bytes remaining to be sent. */ - bytesleft = privreq->req.len - privreq->req.xfrd; - - /* Clip the requested transfer size to the number of bytes actually - * available - */ - - nbytes = bytesleft; - if (nbytes > bytesleft) - { - nbytes = bytesleft; - } + nbytes = privreq->req.len - privreq->req.xfrd; /* If we are not sending a zero length packet, then clip the size to * maxpacket and check if we need to send a following zero length packet. @@ -897,7 +865,7 @@ static void sam_req_wrsetup(struct sam_usbdev_s *priv, if (nbytes >= privep->ep.maxpacket) { - nbytes = privep->ep.maxpacket; + nbytes = privep->ep.maxpacket; } /* This is the new number of bytes "in-flight" */ @@ -974,9 +942,10 @@ static int sam_req_write(struct sam_usbdev_s *priv, struct sam_ep_s *privep) epno = USB_EPNO(privep->ep.eplog); /* We get here when an IN endpoint interrupt occurs. So now we know that - * there is no TX transfer in progress. + * there is no TX transfer in progress (epstate should be IDLE). */ + DEBUGASSERT(privep->epstate == UDP_EPSTATE_IDLE); while (privep->epstate == UDP_EPSTATE_IDLE) { /* Check the request from the head of the endpoint request queue */ @@ -990,10 +959,6 @@ static int sam_req_write(struct sam_usbdev_s *priv, struct sam_ep_s *privep) usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_EPINQEMPTY), 0); - /* Clear any pending the TXCOMP interrupt */ - - sam_csr_clrbits(epno, UDPEP_CSR_TXCOMP); - /* Was there a pending endpoint stall? */ if (privep->pending) @@ -1040,7 +1005,7 @@ static int sam_req_write(struct sam_usbdev_s *priv, struct sam_ep_s *privep) privep->zlpneeded = false; } - /* Perform the write operation */ + /* Perform the write operation. epstate will become SENDING. */ sam_req_wrsetup(priv, privep, privreq); } @@ -1080,27 +1045,16 @@ static int sam_req_write(struct sam_usbdev_s *priv, struct sam_ep_s *privep) /* If all of the bytes were sent (including any final zero length * packet) then we are finished with the request buffer), then we can - * return the request buffer to the class driver. The transfer is not - * finished yet, however. There are still bytes in flight. The - * transfer is truly finished when we are called again and the + * return the request buffer to the class driver. The transfer may + * not finished yet, however. There may still be bytes in flight. + * The transfer is truly finished when we are called again and the * request buffer is empty. */ if (privreq->req.len >= privreq->req.xfrd && privep->epstate == UDP_EPSTATE_IDLE) { - /* TXCOMP must be cleared after the last packet has been set. - * TXCOMP was set by the USB device when it has received an ACK - * PID signal for the Data IN packet. An interrupt is pending - * while TXCOMP is set. - * - * REVISIT: This function might be called before TXCOMP is - * actually received. - */ - - //sam_csr_clrbits(epno, UDPEP_CSR_TXCOMP); - - /* Return the write request to the class driver */ + /* Return the write request to the class driver */ usbtrace(TRACE_COMPLETE(USB_EPNO(privep->ep.eplog)), privreq->req.xfrd); @@ -1970,6 +1924,10 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno) { usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_TXCOMP), (uint16_t)csr); + /* Clear the TXCOMP interrupt */ + + sam_csr_clrbits(epno, UDPEP_CSR_TXCOMP); + /* Sending state. This is the completion of a "normal" write request * transfer. In this case, we need to resume request processing in * order to send the next outgoing packet. @@ -1978,9 +1936,7 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno) if (privep->epstate == UDP_EPSTATE_SENDING || privep->epstate == UDP_EPSTATE_EP0STATUSIN) { - /* Continue/resume processing the write requests. TXCOMP will - * be cleared by sam_req_write(). - */ + /* Continue/resume processing the write requests */ privep->epstate = UDP_EPSTATE_IDLE; (void)sam_req_write(priv, privep); @@ -2002,19 +1958,12 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno) privep->epstate = UDP_EPSTATE_IDLE; sam_setdevaddr(priv, priv->devaddr); - - /* Acknowledge the TXCOMP interrupt */ - - sam_csr_clrbits(epno, UDPEP_CSR_TXCOMP); } else { - /* Unexpected TXCOMP interrupt. Complain and acknowledge the - * TXCOMP interrupt. - */ + /* Unexpected TXCOMP interrupt */ usbtrace(TRACE_DEVERROR(SAM_TRACEERR_TXCOMPERR), privep->epstate); - sam_csr_clrbits(epno, UDPEP_CSR_TXCOMP); } } @@ -2587,7 +2536,7 @@ static int sam_ep_stall(struct sam_ep_s *privep) sam_csr_setbits(epno, UDPEP_CSR_FORCESTALL); } - + irqrestore(flags); return OK; } @@ -2599,6 +2548,7 @@ static int sam_ep_stall(struct sam_ep_s *privep) static int sam_ep_resume(struct sam_ep_s *privep) { struct sam_usbdev_s *priv; + struct sam_req_s *req; irqstate_t flags; uint8_t epno; @@ -2623,18 +2573,24 @@ static int sam_ep_resume(struct sam_ep_s *privep) privep->pending = false; privep->epstate = UDP_EPSTATE_IDLE; - /* Clear FORCESTALL request - * REVISIT: Data sheet says to reset toggle to DATA0 only on OUT - * endpoints. - */ + /* Clear FORCESTALL request */ - sam_csr_clrbits(epno, UDPEP_CSR_DTGLE | UDPEP_CSR_FORCESTALL); + sam_csr_clrbits(epno, UDPEP_CSR_FORCESTALL); /* Reset the endpoint FIFO */ sam_putreg(UDP_RSTEP(epno), SAM_UDP_RSTEP); sam_putreg(0, SAM_UDP_RSTEP); + /* Copy any requests in the pending request queue to the working + * request queue. + */ + + while ((req = sam_req_dequeue(&privep->pendq)) != NULL) + { + sam_req_enqueue(&privep->reqq, req); + } + /* Resuming any blocked data transfers on the endpoint */ if (epno == 0 || USB_ISEPIN(privep->ep.eplog)) @@ -3099,16 +3055,20 @@ static int sam_ep_submit(struct usbdev_ep_s *ep, struct usbdev_req_s *req) if (USB_ISEPIN(ep->eplog) || epno == EP0) { - /* If the endpoint is stalled (or there is a stall pending), then fail - * any attempts to write through the endpoint. - */ + /* Check if the endpoint is stalled (or there is a stall pending) */ if (privep->stalled || privep->pending) { - sam_req_abort(privep, privreq, -EBUSY); - ulldbg("ERROR: stalled\n"); - ret = -EPERM; + /* Yes.. in this case, save the new they will get in a special + * "pending" they will get queue until the stall is cleared. + */ + + ulldbg("Pending stall clear\n"); + sam_req_enqueue(&privep->pendq, privreq); + usbtrace(TRACE_INREQQUEUED(epno), req->len); + ret = OK; } + else { /* Add the new request to the request queue for the IN endpoint */ @@ -3213,10 +3173,10 @@ static int sam_ep_stallresume(struct usbdev_ep_s *ep, bool resume) { /* Are there any unfinished write requests in the request queue? */ - if (!sam_rqempty(&privep->reqq))) + if (!sam_rqempty(&privep->reqq)) { /* Just set a flag to indicate that the endpoint must be - * stalled on the next TXCOMP interrupt when the requeust + * stalled on the next TXCOMP interrupt when the request * queue becomes empty. */ diff --git a/nuttx/arch/arm/src/sama5/sam_udphs.c b/nuttx/arch/arm/src/sama5/sam_udphs.c index 63eb1a4f8..c2b033aad 100644 --- a/nuttx/arch/arm/src/sama5/sam_udphs.c +++ b/nuttx/arch/arm/src/sama5/sam_udphs.c @@ -1205,7 +1205,6 @@ static void sam_req_wrsetup(struct sam_usbdev_s *priv, uint8_t *fifo; uint8_t epno; int nbytes; - int bytesleft; /* Get the unadorned endpoint number */ @@ -1217,17 +1216,7 @@ static void sam_req_wrsetup(struct sam_usbdev_s *priv, /* Get the number of bytes remaining to be sent. */ - bytesleft = privreq->req.len - privreq->req.xfrd; - - /* Clip the requested transfer size to the number of bytes actually - * available - */ - - nbytes = bytesleft; - if (nbytes > bytesleft) - { - nbytes = bytesleft; - } + nbytes = privreq->req.len - privreq->req.xfrd; /* If we are not sending a zero length packet, then clip the size to * maxpacket and check if we need to send a following zero length packet. diff --git a/nuttx/drivers/usbdev/usbmsc_scsi.c b/nuttx/drivers/usbdev/usbmsc_scsi.c index 06f1d8bb8..9347638ef 100644 --- a/nuttx/drivers/usbdev/usbmsc_scsi.c +++ b/nuttx/drivers/usbdev/usbmsc_scsi.c @@ -593,7 +593,7 @@ static inline int usbmsc_cmdinquiry(FAR struct usbmsc_dev_s *priv, else { memset(response, 0, SCSIRESP_INQUIRY_SIZEOF); - priv->nreqbytes = SCSIRESP_INQUIRY_SIZEOF; + priv->nreqbytes = SCSIRESP_INQUIRY_SIZEOF; #ifdef CONFIG_USBMSC_REMOVABLE response->flags1 = SCSIRESP_INQUIRYFLAGS1_RMB; @@ -1963,9 +1963,10 @@ static int usbmsc_cmdparsestate(FAR struct usbmsc_dev_s *priv) */ usbtrace(TRACE_CLASSSTATE(USBMSC_CLASSSTATE_CMDPARSECMDFINISH), priv->cdb[0]); - priv->thstate = USBMSC_STATE_CMDFINISH; + priv->thstate = USBMSC_STATE_CMDFINISH; ret = OK; } + return ret; } @@ -2053,6 +2054,7 @@ static int usbmsc_cmdreadstate(FAR struct usbmsc_dev_s *priv) priv->nreqbytes = 0; return -ENOMEM; } + req = privreq->req; /* Transfer all of the data that will (1) fit into the request buffer, OR (2) @@ -2305,7 +2307,7 @@ static int usbmsc_cmdfinishstate(FAR struct usbmsc_dev_s *priv) if (priv->cbwlen > 0) { /* On most commands (the exception is outgoing, write commands), - * the data has not not yet been sent. + * the data has not yet been sent. */ if (priv->nreqbytes > 0) |