SAMA5 UDPHS: Fix bad setup for sam_req_write call introduce in last commit

This commit is contained in:
Gregory Nutt
2013-09-05 15:51:27 -06:00
parent d0923ee830
commit 6dae945fb0
+79 -55
View File
@@ -145,31 +145,32 @@
#define SAM_TRACEERR_BADCLEARFEATURE 0x0002 #define SAM_TRACEERR_BADCLEARFEATURE 0x0002
#define SAM_TRACEERR_BADDEVGETSTATUS 0x0003 #define SAM_TRACEERR_BADDEVGETSTATUS 0x0003
#define SAM_TRACEERR_BADEPGETSTATUS 0x0004 #define SAM_TRACEERR_BADEPGETSTATUS 0x0004
#define SAM_TRACEERR_BADEPNO 0x0005 #define SAM_TRACEERR_BADEOBSTATE 0x0005
#define SAM_TRACEERR_BADEPTYPE 0x0006 #define SAM_TRACEERR_BADEPNO 0x0006
#define SAM_TRACEERR_BADGETCONFIG 0x0007 #define SAM_TRACEERR_BADEPTYPE 0x0007
#define SAM_TRACEERR_BADGETSETDESC 0x0008 #define SAM_TRACEERR_BADGETCONFIG 0x0008
#define SAM_TRACEERR_BADGETSTATUS 0x0009 #define SAM_TRACEERR_BADGETSETDESC 0x0009
#define SAM_TRACEERR_BADSETADDRESS 0x000a #define SAM_TRACEERR_BADGETSTATUS 0x000a
#define SAM_TRACEERR_BADSETCONFIG 0x000b #define SAM_TRACEERR_BADSETADDRESS 0x000b
#define SAM_TRACEERR_BADSETFEATURE 0x000c #define SAM_TRACEERR_BADSETCONFIG 0x000c
#define SAM_TRACEERR_BINDFAILED 0x000d #define SAM_TRACEERR_BADSETFEATURE 0x000d
#define SAM_TRACEERR_DISPATCHSTALL 0x000e #define SAM_TRACEERR_BINDFAILED 0x000e
#define SAM_TRACEERR_DMAERR 0x000f #define SAM_TRACEERR_DISPATCHSTALL 0x000f
#define SAM_TRACEERR_DRIVER 0x0010 #define SAM_TRACEERR_DMAERR 0x0010
#define SAM_TRACEERR_DRIVERREGISTERED 0x0011 #define SAM_TRACEERR_DRIVER 0x0011
#define SAM_TRACEERR_ENDBUFST 0x0012 #define SAM_TRACEERR_DRIVERREGISTERED 0x0012
#define SAM_TRACEERR_EP0SETUPOUTSIZE 0x0013 #define SAM_TRACEERR_ENDBUFST 0x0013
#define SAM_TRACEERR_EP0SETUPSTALLED 0x0014 #define SAM_TRACEERR_EP0SETUPOUTSIZE 0x0014
#define SAM_TRACEERR_EPOUTNULLPACKET 0x0015 #define SAM_TRACEERR_EP0SETUPSTALLED 0x0015
#define SAM_TRACEERR_EPRESERVE 0x0016 #define SAM_TRACEERR_EPOUTNULLPACKET 0x0016
#define SAM_TRACEERR_EPTCFGMAPD 0x0017 #define SAM_TRACEERR_EPRESERVE 0x0017
#define SAM_TRACEERR_INVALIDCTRLREQ 0x0018 #define SAM_TRACEERR_EPTCFGMAPD 0x0018
#define SAM_TRACEERR_INVALIDPARMS 0x0019 #define SAM_TRACEERR_INVALIDCTRLREQ 0x0019
#define SAM_TRACEERR_IRQREGISTRATION 0x001a #define SAM_TRACEERR_INVALIDPARMS 0x001a
#define SAM_TRACEERR_NOTCONFIGURED 0x001b #define SAM_TRACEERR_IRQREGISTRATION 0x001b
#define SAM_TRACEERR_REQABORTED 0x001c #define SAM_TRACEERR_NOTCONFIGURED 0x001c
#define SAM_TRACEERR_TXRDYERR 0x001d #define SAM_TRACEERR_REQABORTED 0x001d
#define SAM_TRACEERR_TXRDYERR 0x001e
/* Trace interrupt codes */ /* Trace interrupt codes */
@@ -573,6 +574,7 @@ const struct trace_msg_t g_usb_trace_strings_deverror[] =
TRACE_STR(SAM_TRACEERR_BADCLEARFEATURE), TRACE_STR(SAM_TRACEERR_BADCLEARFEATURE),
TRACE_STR(SAM_TRACEERR_BADDEVGETSTATUS), TRACE_STR(SAM_TRACEERR_BADDEVGETSTATUS),
TRACE_STR(SAM_TRACEERR_BADEPGETSTATUS), TRACE_STR(SAM_TRACEERR_BADEPGETSTATUS),
TRACE_STR(SAM_TRACEERR_BADEOBSTATE),
TRACE_STR(SAM_TRACEERR_BADEPNO), TRACE_STR(SAM_TRACEERR_BADEPNO),
TRACE_STR(SAM_TRACEERR_BADEPTYPE), TRACE_STR(SAM_TRACEERR_BADEPTYPE),
TRACE_STR(SAM_TRACEERR_BADGETCONFIG), TRACE_STR(SAM_TRACEERR_BADGETCONFIG),
@@ -1281,9 +1283,10 @@ static void sam_req_wrsetup(struct sam_usbdev_s *priv,
* *
* Description: * Description:
* Process the next queued write request. This function is called in one * Process the next queued write request. This function is called in one
* of three contexts: (1) When a new write request is submitted (with * of three contexts: (1) When the endpoint is IDLE and a new write request
* interrupts disabled, (2) from interrupt handling when a previous * is submitted (with interrupts disabled), (2) from interrupt handling
* transfer completes, or (3) resuming a stalled IN endpoint. * when the current transfer completes (either DMA or FIFO), or (3) when
* resuming a stalled IN or control endpoint.
* *
* Calling rules: * Calling rules:
* *
@@ -1543,8 +1546,13 @@ static void sam_req_rddisable(uint8_t epno)
* Name: sam_req_read * Name: sam_req_read
* *
* Description: * Description:
* Called only from interrupt handling logic when on OUT packet is received * Complete the last read request, return the read request to the class
* on an endpoint in the RECEIVING state. * implementation, and try to started the next queued read request.
*
* This function is called in one of three contexts: (1) When the endpoint
* is IDLE and a new read request is submitted (with interrupts disabled),
* (2) from interrupt handling when the current transfer completes (either
* DMA or FIFO), or (3) when resuming a stalled OUT or control endpoint.
* *
* There is a fundamental difference between receiving packets via DMA and * There is a fundamental difference between receiving packets via DMA and
* via the FIFO: * via the FIFO:
@@ -1552,10 +1560,11 @@ static void sam_req_rddisable(uint8_t epno)
* - When receiving data via DMA, then data has already been transferred * - When receiving data via DMA, then data has already been transferred
* and this function is called on the terminating event. The transfer * and this function is called on the terminating event. The transfer
* is complete and we just need to check for end of request events and * is complete and we just need to check for end of request events and
* if we need to setup the next tranfer. * if we need to setup the tranfer for the next request.
* - When receiving via the FIFO, then transfer is not complete. The * - When receiving via the FIFO, the transfer is not complete. The
* data is in the FIFO and must be transferred from the FIFO to the * data is in the FIFO and must be transferred from the FIFO to the
* request buffer. No setup is needed for the next transfer. * request buffer. No setup is needed for the next transfer other than
* assuring that the endpoint RXRDY_TXTK interrupt is enabled.
* *
* Calling rules: * Calling rules:
* *
@@ -2372,15 +2381,11 @@ static void sam_dma_interrupt(struct sam_usbdev_s *priv, int epno)
usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_DMAEOB), (uint16_t)dmastatus); usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_DMAEOB), (uint16_t)dmastatus);
/* BUFF_COUNT holds the number of untransmitted bytes. BUFF_COUNT is /* BUFF_COUNT holds the number of untransmitted bytes. BUFF_COUNT is
* equal to zero in case of good transfer. * equal to zero in case of good transfer. BUFF_COUNT was set to
* * the 'inflight' count when the DMA started and the BUFF_COUNT has
* BUFF_COUNT was set to the 'inflight' count when the DMA started and * now decremented to zero
* the BUFF_COUNT has now decremented to zero
*/ */
xfrsize = privreq->inflight;
privreq->inflight = 0;
/* This is just debug logic that only does any if USB debug or tracing /* This is just debug logic that only does any if USB debug or tracing
* are enabled. This just verifies taht BUFF_COUNT is zero. * are enabled. This just verifies taht BUFF_COUNT is zero.
*/ */
@@ -2398,15 +2403,21 @@ static void sam_dma_interrupt(struct sam_usbdev_s *priv, int epno)
if (privep->epstate == UDPHS_EPSTATE_SENDING) if (privep->epstate == UDPHS_EPSTATE_SENDING)
{ {
/* This is an IN endpoint. Continuing processing the write /* This is an IN endpoint. Continuing processing the write
* request * request. We must call sam_req_write in the IDLE state
* with the number of bytes transferred in 'inflight'
*/ */
DEBUGASSERT(USB_ISEPIN(privep->ep.eplog)); DEBUGASSERT(USB_ISEPIN(privep->ep.eplog));
privep->epstate = UDPHS_EPSTATE_IDLE; privep->epstate = UDPHS_EPSTATE_IDLE;
(void)sam_req_write(priv, privep); (void)sam_req_write(priv, privep);
} }
else else if (privep->epstate == UDPHS_EPSTATE_RECEIVING)
{ {
/* privreg->inflight holds the total transfer size */
xfrsize = privreq->inflight;
privreq->inflight = 0;
/* This is an OUT endpoint. Invalidate the data cache for /* This is an OUT endpoint. Invalidate the data cache for
* region that just completed DMA. This will force the * region that just completed DMA. This will force the
* buffer data to be reloaded from RAM. when it is accessed * buffer data to be reloaded from RAM. when it is accessed
@@ -2416,11 +2427,20 @@ static void sam_dma_interrupt(struct sam_usbdev_s *priv, int epno)
buf = &privreq->req.buf[privreq->req.xfrd]; buf = &privreq->req.buf[privreq->req.xfrd];
cp15_invalidate_dcache((uintptr_t)buf, (uintptr_t)buf + xfrsize); cp15_invalidate_dcache((uintptr_t)buf, (uintptr_t)buf + xfrsize);
/* Continuing processing the read request */ /* Complete this transfer, return the request to the class
* implementation, and try to start the next, queue read request.
* We must call sam_req_read in the IDLE state, 'inflight' is
* ignored (should be zero) and the transfer size is passed as
* an argument to sam_req_read().
*/
privep->epstate = UDPHS_EPSTATE_IDLE; privep->epstate = UDPHS_EPSTATE_IDLE;
(void)sam_req_read(priv, privep, xfrsize); (void)sam_req_read(priv, privep, xfrsize);
} }
else
{
usbtrace(TRACE_DEVERROR(SAM_TRACEERR_BADEOBSTATE), bufcnt);
}
} }
/* Check for end of channel transfer. END_TR_ST is set by hardware when /* Check for end of channel transfer. END_TR_ST is set by hardware when
@@ -2454,6 +2474,7 @@ static void sam_dma_interrupt(struct sam_usbdev_s *priv, int epno)
bufcnt = ((dmastatus & UDPHS_DMASTATUS_BUFCNT_MASK) bufcnt = ((dmastatus & UDPHS_DMASTATUS_BUFCNT_MASK)
>> UDPHS_DMASTATUS_BUFCNT_SHIFT); >> UDPHS_DMASTATUS_BUFCNT_SHIFT);
xfrsize = privreq->inflight - bufcnt; xfrsize = privreq->inflight - bufcnt;
privreq->inflight = 0;
/* Invalidate the data cache for region that just completed DMA. /* Invalidate the data cache for region that just completed DMA.
* This will force the buffer data to be reloaded from RAM. * This will force the buffer data to be reloaded from RAM.
@@ -2462,18 +2483,12 @@ static void sam_dma_interrupt(struct sam_usbdev_s *priv, int epno)
buf = &privreq->req.buf[privreq->req.xfrd]; buf = &privreq->req.buf[privreq->req.xfrd];
cp15_invalidate_dcache((uintptr_t)buf, (uintptr_t)buf + xfrsize); cp15_invalidate_dcache((uintptr_t)buf, (uintptr_t)buf + xfrsize);
/* Complete this transfer now and return the request to the class /* Complete this transfer, return the request to the class
* implementation. * implementation, and try to start the next, queue read request.
*/ */
privep->epstate = UDPHS_EPSTATE_IDLE; privep->epstate = UDPHS_EPSTATE_IDLE;
privreq->req.xfrd += xfrsize; (void)sam_req_read(priv, privep, xfrsize);
privreq->inflight = 0;
sam_req_complete(privep, OK);
/* Now, try to start the next, queue read request */
(void)sam_req_read(priv, privep, 0);
} }
else else
{ {
@@ -3704,13 +3719,22 @@ static int sam_ep_stall(struct usbdev_ep_s *ep, bool resume)
/* Resuming any blocked data transfers on the endpoint */ /* Resuming any blocked data transfers on the endpoint */
if (USB_ISEPIN(ep->eplog)) if (epno == 0 || USB_ISEPIN(ep->eplog))
{ {
/* IN endpoint */ /* IN endpoint (or EP0). Restart any queued write requests */
/* Restart any queued write requests */
(void)sam_req_write(priv, privep); (void)sam_req_write(priv, privep);
} }
if ((epno == 0 && privep->epstate == UDPHS_EPSTATE_IDLE) ||
USB_ISEPOUT(ep->eplog))
{
/* OUT endpoint (or EP0 with no write request started).
* Restart any queued read requests.
*/
(void)sam_req_read(priv, privep, 0);
}
} }
} }