summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-03-20 14:25:56 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-03-20 14:25:56 -0600
commit641ed1fd58895554a604c5314fff44330c9e9bf0 (patch)
tree53c8fe235b020562e538d2972d09e2dce4976609
parente37095fc6e0b14e407f24c58b526445d7edcdece (diff)
downloadnuttx-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.c122
-rw-r--r--nuttx/arch/arm/src/sama5/sam_udphs.c13
-rw-r--r--nuttx/drivers/usbdev/usbmsc_scsi.c8
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)