STM32 F1 USB: Fix OUT SETUP command bug. From David Sidrane

This commit is contained in:
Gregory Nutt 2013-11-07 17:25:05 -06:00
parent 55b592faf8
commit d8d469fa58
3 changed files with 262 additions and 135 deletions

View File

@ -5992,3 +5992,6 @@
the STM32F429. From Ken Pettit (2013-11-7).
* configs/stm32f429i-disco: Support for the STM32F429I-Discovery
board from Ken Pettit (2013-11-7).
* arch/arm/src/stm32/stm32_usbdev.c: The long outstanding bug
involviing the handling of OUT SETUP commands has been fixed in
the STM32 F1 USB device driver by David Sidrane (2013-11-7).

4
TODO
View File

@ -961,6 +961,10 @@ o USB (drivers/usbdev, drivers/usbhost)
correctly supports OUT SETUP data following the same design as
per above.
Update 2013-11-7: David Sidrane has fixed with issue with the
STM32 F1 USB device driver. Still a few more to go before this
can be closed out.
Status: Open
Priority: High for class drivers that need EP0 data. For example, the
CDC/ACM serial driver might need the line coding data (that

View File

@ -77,6 +77,10 @@
# define CONFIG_USBDEV_EP0_MAXSIZE 64
#endif
#ifndef CONFIG_USBDEV_SETUP_MAXDATASIZE
# define CONFIG_USBDEV_SETUP_MAXDATASIZE CONFIG_USBDEV_EP0_MAXSIZE
#endif
#ifndef CONFIG_USB_PRI
# define CONFIG_USB_PRI NVIC_SYSH_PRIORITY_DEFAULT
#endif
@ -240,6 +244,8 @@
#define STM32_TRACEINTID_SUSP 0x001c
#define STM32_TRACEINTID_SYNCHFRAME 0x001d
#define STM32_TRACEINTID_WKUP 0x001e
#define STM32_TRACEINTID_EP0SETUPOUT 0x001f
#define STM32_TRACEINTID_EP0SETUPOUTDATA 0x0020
/* Ever-present MIN and MAX macros */
@ -270,8 +276,11 @@
enum stm32_ep0state_e
{
EP0STATE_IDLE = 0, /* No request in progress */
EP0STATE_RDREQUEST, /* Read request in progress */
EP0STATE_SETUP_OUT, /* Set up recived with data for device OUT in progress */
EP0STATE_SETUP_READY, /* Set up was recived prior and is in ctrl,
* now the data has arrived */
EP0STATE_WRREQUEST, /* Write request in progress */
EP0STATE_RDREQUEST, /* Read request in progress */
EP0STATE_STALLED /* We are stalled */
};
@ -336,7 +345,6 @@ struct stm32_usbdev_s
/* STM32-specific fields */
struct usb_ctrlreq_s ctrl; /* Last EP0 request */
uint8_t ep0state; /* State of EP0 (see enum stm32_ep0state_e) */
uint8_t rsmstate; /* Resume state (see enum stm32_rsmstate_e) */
uint8_t nesofs; /* ESOF counter (for resume support) */
@ -348,6 +356,27 @@ struct stm32_usbdev_s
uint16_t txstatus; /* " " " " " " " " */
uint16_t imask; /* Current interrupt mask */
/* E0 SETUP data buffering.
*
* ctrl
* The 8-byte SETUP request is received on the EP0 OUT endpoint and is
* saved.
*
* ep0data
* For OUT SETUP requests, the SETUP data phase must also complete before
* the SETUP command can be processed. The ep0 packet receipt logic
* stm32_ep0_rdrequest will save the accompanying EP0 OUT data in
* ep0data[] before the SETUP command is re-processed.
*
* ep0datlen
* Lenght of OUT DATA received in ep0data[]
*/
struct usb_ctrlreq_s ctrl; /* Last EP0 request */
uint8_t ep0data[CONFIG_USBDEV_SETUP_MAXDATASIZE];
uint16_t ep0datlen;
/* The endpoint list */
struct stm32_ep_s eplist[STM32_NENDPOINTS];
@ -438,6 +467,8 @@ static int stm32_wrrequest(struct stm32_usbdev_s *priv,
inline static int
stm32_wrrequest_ep0(struct stm32_usbdev_s *priv,
struct stm32_ep_s *privep);
static inline int
stm32_ep0_rdrequest(struct stm32_usbdev_s *priv);
static int stm32_rdrequest(struct stm32_usbdev_s *priv,
struct stm32_ep_s *privep);
static void stm32_cancelrequests(struct stm32_ep_s *privep);
@ -570,6 +601,8 @@ const struct trace_msg_t g_usb_trace_strings_intdecode[] =
TRACE_STR(STM32_TRACEINTID_SUSP ),
TRACE_STR(STM32_TRACEINTID_SYNCHFRAME ),
TRACE_STR(STM32_TRACEINTID_WKUP ),
TRACE_STR(STM32_TRACEINTID_EP0SETUPOUT ),
TRACE_STR(STM32_TRACEINTID_EP0SETUPOUTDATA ),
TRACE_STR_END
};
#endif
@ -1404,6 +1437,50 @@ static int stm32_wrrequest(struct stm32_usbdev_s *priv, struct stm32_ep_s *prive
return OK;
}
/*******************************************************************************
* Name: stm32_ep0_rdrequest
*
* Description:
* This function is called from the stm32_ep0out handler when the ep0state
* is EP0STATE_SETUP_OUT and uppon new incoming data is available in the endpoint
* 0's buffer. This function will simply copy the OUT data into ep0data.
*
*******************************************************************************/
static inline int stm32_ep0_rdrequest(struct stm32_usbdev_s *priv)
{
uint32_t src;
int pmalen;
int readlen;
/* Get the number of bytes to read from packet memory */
pmalen = stm32_geteprxcount(EP0);
ullvdbg("EP0: pmalen=%d\n", pmalen);
usbtrace(TRACE_READ(EP0), pmalen);
/* Read the data into our special buffer for SETUP data */
readlen = MIN(CONFIG_USBDEV_SETUP_MAXDATASIZE, pmalen);
src = stm32_geteprxaddr(EP0);
/* Receive the next packet */
stm32_copyfrompma(&priv->ep0data[0], src, readlen);
/* Now we can process the setup command */
priv->ep0state = EP0STATE_SETUP_READY;
priv->ep0datlen = readlen;
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EP0SETUPOUTDATA), readlen);
stm32_ep0setup(priv);
priv->ep0datlen = 0; /* mark the date consumed */
return OK;
}
/****************************************************************************
* Name: stm32_rdrequest
****************************************************************************/
@ -1505,7 +1582,8 @@ static void stm32_dispatchrequest(struct stm32_usbdev_s *priv)
{
/* Forward to the control request to the class driver implementation */
ret = CLASS_SETUP(priv->driver, &priv->usbdev, &priv->ctrl, NULL, 0);
ret = CLASS_SETUP(priv->driver, &priv->usbdev, &priv->ctrl,
priv->ep0data, priv->ep0datlen);
if (ret < 0)
{
/* Stall on failure */
@ -1671,6 +1749,11 @@ static void stm32_ep0setup(struct stm32_usbdev_s *priv)
ep0->stalled = 0;
ep0->txbusy = 0;
/* Check to see if called from the DATA phase of a SETUP Trasfer */
if (priv->ep0state != EP0STATE_SETUP_READY)
{
/* Not the data phase */
/* Get a 32-bit PMA address and use that to get the 8-byte setup request */
stm32_copyfrompma((uint8_t*)&priv->ctrl, stm32_geteprxaddr(EP0), USB_SIZEOF_CTRLREQ);
@ -1684,7 +1767,32 @@ static void stm32_ep0setup(struct stm32_usbdev_s *priv)
ullvdbg("SETUP: type=%02x req=%02x value=%04x index=%04x len=%04x\n",
priv->ctrl.type, priv->ctrl.req, value.w, index.w, len.w);
priv->ep0state = EP0STATE_IDLE;
/* Is this an setup with OUT and data of length > 0 */
if (USB_REQ_ISOUT(priv->ctrl.type) && len.w > 0)
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EP0SETUPOUT), len.w);
/* At this point priv->ctrl is the setup packet. Just ACK the
* setup packet So we can get the data.
*
* REVISIT: I suspect that this should not be here?
*/
stm32_epwrite(priv, ep0, response.b, 0);
/* Enable and Wait for the data phase. */
priv->rxstatus = USB_EPR_STATRX_VALID;
priv->ep0state = EP0STATE_SETUP_OUT;
return;
}
else
{
priv->ep0state = EP0STATE_SETUP_READY;
}
}
/* Dispatch any non-standard requests */
@ -2126,6 +2234,18 @@ static void stm32_ep0out(struct stm32_usbdev_s *priv)
priv->ep0state = ((ret == OK) ? EP0STATE_RDREQUEST : EP0STATE_IDLE);
break;
case EP0STATE_SETUP_OUT: /* SETUP was waiting for data */
ret = stm32_ep0_rdrequest(priv); /* Off load the data and run the
* last set up command with the OUT
* data
*/
priv->ep0state = EP0STATE_IDLE; /* There is no notion of reciving OUT
* data greater then the length of
* CONFIG_USBDEV_SETUP_MAXDATASIZE
* so we are done
*/
break;
default:
/* Unexpected state OR host aborted the OUT transfer before it
* completed, STALL the endpoint in either case