STM32 F1 USB: Fix OUT SETUP command bug. From David Sidrane
This commit is contained in:
parent
55b592faf8
commit
d8d469fa58
@ -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
4
TODO
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user