diff options
author | patacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679> | 2012-04-04 23:53:19 +0000 |
---|---|---|
committer | patacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679> | 2012-04-04 23:53:19 +0000 |
commit | 1758844830c72c7fe7e86ee139541c4bdb27e907 (patch) | |
tree | 21050f99a891662fa9b04f21295d4ce107ff8beb /nuttx | |
parent | 424ec5656c99375d35c94e20d10db0d135a98ca6 (diff) | |
download | px4-firmware-1758844830c72c7fe7e86ee139541c4bdb27e907.tar.gz px4-firmware-1758844830c72c7fe7e86ee139541c4bdb27e907.tar.bz2 px4-firmware-1758844830c72c7fe7e86ee139541c4bdb27e907.zip |
STM32 OTG FS device driver update
git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@4557 7fd9a85b-ad96-42d3-883c-3090e2eb8679
Diffstat (limited to 'nuttx')
-rw-r--r-- | nuttx/arch/arm/src/stm32/chip/stm32_usbotgfs.h | 7 | ||||
-rwxr-xr-x | nuttx/arch/arm/src/stm32/stm32_otgfsdev.c | 1437 |
2 files changed, 714 insertions, 730 deletions
diff --git a/nuttx/arch/arm/src/stm32/chip/stm32_usbotgfs.h b/nuttx/arch/arm/src/stm32/chip/stm32_usbotgfs.h index 1eb57ed76..1dc9c6526 100644 --- a/nuttx/arch/arm/src/stm32/chip/stm32_usbotgfs.h +++ b/nuttx/arch/arm/src/stm32/chip/stm32_usbotgfs.h @@ -738,6 +738,13 @@ /* Bits 13-31 Reserved, must be kept at reset value */ /* Device control register */ +#define OTGFS_TESTMODE_DISABLED (0) /* Test mode disabled */ +#define OTGFS_TESTMODE_J (1) /* Test_J mode */ +#define OTGFS_TESTMODE_K (2) /* Test_K mode */ +#define OTGFS_TESTMODE_SE0_NAK (3) /* Test_SE0_NAK mode */ +#define OTGFS_TESTMODE_PACKET (4) /* Test_Packet mode */ +#define OTGFS_TESTMODE_FORCE (5) /* Test_Force_Enable */ + #define OTGFS_DCTL_RWUSIG (1 << 0) /* Bit 0: Remote wakeup signaling */ #define OTGFS_DCTL_SDIS (1 << 1) /* Bit 1: Soft disconnect */ #define OTGFS_DCTL_GINSTS (1 << 2) /* Bit 2: Global IN NAK status */ diff --git a/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c b/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c index 56622e9a0..d7e83a32e 100755 --- a/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c +++ b/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c @@ -98,25 +98,7 @@ # define CONFIG_USBDEV_EP3_TXFIFO_SIZE 128 #endif -/* Enable reading SOF from interrupt handler vs. simply reading on demand. Probably - * a bad idea... Unless there is some issue with sampling the SOF from hardware - * asynchronously. - */ - -#ifdef CONFIG_STM32_USBDEV_FRAME_INTERRUPT -# define USB_FRAME_INT USBDEV_USBINTR_SRE -#else -# define USB_FRAME_INT 0 -#endif - -#ifdef CONFIG_DEBUG -# define USB_ERROR_INT USBDEV_USBINTR_UEE -#else -# define USB_ERROR_INT 0 -#endif - /* Debug ***********************************************************************/ - /* Trace error codes */ #define STM32_TRACEERR_ALLOCFAIL 0x0001 @@ -131,19 +113,20 @@ #define STM32_TRACEERR_BADSETADDRESS 0x000a #define STM32_TRACEERR_BADSETCONFIG 0x000b #define STM32_TRACEERR_BADSETFEATURE 0x000c -#define STM32_TRACEERR_BINDFAILED 0x000d -#define STM32_TRACEERR_DISPATCHSTALL 0x000e -#define STM32_TRACEERR_DRIVER 0x000f -#define STM32_TRACEERR_DRIVERREGISTERED 0x0010 -#define STM32_TRACEERR_EP0SETUPSTALLED 0x0011 -#define STM32_TRACEERR_EPINNULLPACKET 0x0012 -#define STM32_TRACEERR_EPOUTNULLPACKET 0x0013 -#define STM32_TRACEERR_INVALIDCTRLREQ 0x0014 -#define STM32_TRACEERR_INVALIDPARMS 0x0015 -#define STM32_TRACEERR_IRQREGISTRATION 0x0016 -#define STM32_TRACEERR_NOEP 0x0017 -#define STM32_TRACEERR_NOTCONFIGURED 0x0018 -#define STM32_TRACEERR_REQABORTED 0x0019 +#define STM32_TRACEERR_BADTESTMODE 0x000d +#define STM32_TRACEERR_BINDFAILED 0x000e +#define STM32_TRACEERR_DISPATCHSTALL 0x000f +#define STM32_TRACEERR_DRIVER 0x0010 +#define STM32_TRACEERR_DRIVERREGISTERED 0x0011 +#define STM32_TRACEERR_EP0SETUPSTALLED 0x0012 +#define STM32_TRACEERR_EPINNULLPACKET 0x0013 +#define STM32_TRACEERR_EPOUTNULLPACKET 0x0014 +#define STM32_TRACEERR_INVALIDCTRLREQ 0x0015 +#define STM32_TRACEERR_INVALIDPARMS 0x0016 +#define STM32_TRACEERR_IRQREGISTRATION 0x0017 +#define STM32_TRACEERR_NOEP 0x0018 +#define STM32_TRACEERR_NOTCONFIGURED 0x0019 +#define STM32_TRACEERR_REQABORTED 0x001a /* Trace interrupt codes */ @@ -166,79 +149,48 @@ #define STM32_TRACEINTID_EPOUT_XFRC 0x0200 /* EPOUT second level decode */ #define STM32_TRACEINTID_EPOUT_EPDISD 0x0201 #define STM32_TRACEINTID_EPOUT_SETUP 0x0202 -#define STM32_TRACEINTID_EPIN_XFRC 0x0210 /* EPIN second level decode */ -#define STM32_TRACEINTID_EPIN_TOC 0x0211 -#define STM32_TRACEINTID_EPIN_ITTXFE 0x0212 -#define STM32_TRACEINTID_EPIN_INEPNE 0x0213 -#define STM32_TRACEINTID_EPIN_EPDISD 0x0214 -#define STM32_TRACEINTID_EPIN_TXFE 0x0215 - -#define STM32_TRACEINTID_CLEARFEATURE 0x0220 /* Subsequence interrupt decode */ -#define STM32_TRACEINTID_DEVGETSTATUS 0x0221 -#define STM32_TRACEINTID_DISPATCH 0x0222 -#define STM32_TRACEINTID_EP0COMPLETE 0x0223 -#define STM32_TRACEINTID_EP0NAK 0x0224 -#define STM32_TRACEINTID_EP0SETUP 0x0225 -#define STM32_TRACEINTID_EPGETSTATUS 0x0226 -#define STM32_TRACEINTID_EPIN 0x0227 -#define STM32_TRACEINTID_EPINQEMPTY 0x0228 -#define STM32_TRACEINTID_EP0INSETADDRESS 0x0229 -#define STM32_TRACEINTID_EPOUT 0x022a -#define STM32_TRACEINTID_EPOUTQEMPTY 0x022b -#define STM32_TRACEINTID_EP0SETUPSETADDRESS 0x022c -#define STM32_TRACEINTID_GETCONFIG 0x022d -#define STM32_TRACEINTID_GETSETDESC 0x022e -#define STM32_TRACEINTID_GETSETIF 0x022f -#define STM32_TRACEINTID_GETSTATUS 0x0230 -#define STM32_TRACEINTID_IFGETSTATUS 0x0231 -#define STM32_TRACEINTID_SETCONFIG 0x0232 -#define STM32_TRACEINTID_SETFEATURE 0x0233 -#define STM32_TRACEINTID_SYNCHFRAME 0x0234 - -/* Hardware interface **********************************************************/ -/* Endpoint Transfer Descriptor */ -/* DTD nextdesc field */ - -#define DTD_NEXTDESC_INVALID (1 << 0) /* Bit 0 : Next Descriptor Invalid */ - -/* DTD config field */ - -#define DTD_CONFIG_LENGTH(n) ((n) << 16) /* Bits 16-31 : Total bytes to transfer */ -#define DTD_CONFIG_IOC (1 << 15) /* Bit 15 : Interrupt on Completion */ -#define DTD_CONFIG_MULT_VARIABLE (0 << 10) /* Bits 10-11 : Number of packets executed per transacation descriptor (override) */ -#define DTD_CONFIG_MULT_NUM(n) ((n) << 10) -#define DTD_CONFIG_ACTIVE (1 << 7) /* Bit 7 : Status Active */ -#define DTD_CONFIG_HALTED (1 << 6) /* Bit 6 : Status Halted */ -#define DTD_CONFIG_BUFFER_ERROR (1 << 5) /* Bit 6 : Status Buffer Error */ -#define DTD_CONFIG_TRANSACTION_ERROR (1 << 3) /* Bit 3 : Status Transaction Error */ - -/* Queue head (DQH) */ -/* DQH capability field */ - -#define DQH_CAPABILITY_MULT_VARIABLE (0 << 30) /* Bits 30-31 : Number of packets executed per transaction descriptor */ -#define DQH_CAPABILITY_MULT_NUM(n) ((n) << 30) -#define DQH_CAPABILITY_ZLT (1 << 29) /* Bit 29 : Zero Length Termination Select */ -#define DQH_CAPABILITY_MAX_PACKET(n) ((n) << 16) /* Bits 16-29 : Maximum packet size of associated endpoint (<1024) */ -#define DQH_CAPABILITY_IOS (1 << 15) /* Bit 15 : Interrupt on Setup */ +#define STM32_TRACEINTID_DISPATCH 0x0203 + +#define STM32_TRACEINTID_GETSTATUS 0x0210 /* EPOUT third level decode */ +#define STM32_TRACEINTID_EPGETSTATUS 0x0211 +#define STM32_TRACEINTID_DEVGETSTATUS 0x0212 +#define STM32_TRACEINTID_IFGETSTATUS 0x0213 +#define STM32_TRACEINTID_CLEARFEATURE 0x0214 +#define STM32_TRACEINTID_SETFEATURE 0x0215 +#define STM32_TRACEINTID_SETADDRESS 0x0216 +#define STM32_TRACEINTID_GETSETDESC 0x0217 +#define STM32_TRACEINTID_GETCONFIG 0x0218 +#define STM32_TRACEINTID_SETCONFIG 0x0219 +#define STM32_TRACEINTID_GETSETIF 0x021a +#define STM32_TRACEINTID_SYNCHFRAME 0x021b + +#define STM32_TRACEINTID_EPIN_XFRC 0x0300 /* EPIN second level decode */ +#define STM32_TRACEINTID_EPIN_TOC 0x0301 +#define STM32_TRACEINTID_EPIN_ITTXFE 0x0302 +#define STM32_TRACEINTID_EPIN_INEPNE 0x0303 +#define STM32_TRACEINTID_EPIN_EPDISD 0x0304 +#define STM32_TRACEINTID_EPIN_TXFE 0x0305 + +#define STM32_TRACEINTID_EP0COMPLETE 0x0400 /* Request handling */ +#define STM32_TRACEINTID_EPINCOMPLETE 0x0401 +#define STM32_TRACEINTID_EPINQEMPTY 0x0402 +#define STM32_TRACEINTID_EPOUTCOMPLETE 0x0403 +#define STM32_TRACEINTID_EPOUTQEMPTY 0x0404 /* Endpoints ******************************************************************/ /* Number of endpoints */ -#define STM32_NENDPOINTS (4) /* ep0-3 x2 for IN and OUT */ +#define STM32_NENDPOINTS (4) /* ep0-3 x 2 for IN and OUT */ /* Odd physical endpoint numbers are IN; even are OUT */ -#define STM32_EPPHYIN(epphy) (((epphy)&1)!=0) -#define STM32_EPPHYOUT(epphy) (((epphy)&1)==0) - -#define STM32_EPPHYIN2LOG(epphy) (((uint8_t)(epphy)>>1)|USB_DIR_IN) -#define STM32_EPPHYOUT2LOG(epphy) (((uint8_t)(epphy)>>1)|USB_DIR_OUT) +#define STM32_EPPHYIN2LOG(epphy) ((uint8_t)(epphy)|USB_DIR_IN) +#define STM32_EPPHYOUT2LOG(epphy) ((uint8_t)(epphy)|USB_DIR_OUT) -/* Endpoint 0 is special... */ +/* Endpoint 0 */ -#define STM32_EP0_OUT (0) -#define STM32_EP0_IN (1) +#define EP0 (0) /* Each endpoint has somewhat different characteristics */ @@ -254,19 +206,10 @@ #define STM32_MAXPACKET (64) /* Max packet size (1-64) */ -/* The address of the endpoint control register */ - -#define STM32_USBDEV_ENDPTCTRL(epphy) (STM32_USBDEV_ENDPTCTRL0 + ((epphy)>>1)*4) - -/* Endpoint bit position in SETUPSTAT, PRIME, FLUSH, STAT, COMPLETE registers */ - -#define STM32_ENDPTSHIFT(epphy) (STM32_EPPHYIN(epphy) ? (16 + ((epphy) >> 1)) : ((epphy) >> 1)) -#define STM32_ENDPTMASK(epphy) (1 << STM32_ENDPTSHIFT(epphy)) -#define STM32_ENDPTMASK_ALL 0x000f000f - /* Delays **********************************************************************/ #define STM32_READY_DELAY 200000 +#define STM32_FLUSH_DELAY 200000 /* Request queue operations ****************************************************/ @@ -314,35 +257,6 @@ struct stm32_ctrlreq_s uint16_t len; }; -/* This represents a Endpoint Transfer Descriptor - note these must be 32 byte - * aligned. - */ - -struct stm32_dtd_s -{ - volatile uint32_t nextdesc; /* Address of the next DMA descripto in RAM */ - volatile uint32_t config; /* Misc. bit encoded configuration information */ - uint32_t buffer0; /* Buffer start address */ - uint32_t buffer1; /* Buffer start address */ - uint32_t buffer2; /* Buffer start address */ - uint32_t buffer3; /* Buffer start address */ - uint32_t buffer4; /* Buffer start address */ - uint32_t xfer_len; /* Software only - transfer len that was queued */ -}; - -/* This represents a queue head - note these must be aligned to a 2048 byte - * boundary. - */ - -struct stm32_dqh_s -{ - uint32_t capability; /* Endpoint capability */ - uint32_t currdesc; /* Current dTD pointer */ - struct stm32_dtd_s overlay; /* DTD overlay */ - volatile uint32_t setup[2]; /* Set-up buffer */ - uint32_t gap[4]; /* align to 64 bytes */ -}; - /* A container for a request so that the request may be retained in a list */ struct stm32_req_s @@ -368,6 +282,7 @@ struct stm32_ep_s struct stm32_req_s *head; /* Request list for this endpoint */ struct stm32_req_s *tail; uint8_t epphy; /* Physical EP address */ + uint8_t configured:1; /* 1: Endpoint has been configured */ uint8_t active:1; /* 1: A request is being processed */ uint8_t stalled:1; /* 1: Endpoint is stalled */ uint8_t isin:1; /* 1: IN Endpoint */ @@ -393,23 +308,19 @@ struct stm32_usbdev_s uint8_t stalled:1; /* 1: Protocol stalled */ uint8_t selfpowered:1; /* 1: Device is self powered */ - uint8_t paddrset:1; /* 1: Peripheral addr has been set */ uint8_t connected:1; /* 1: Host connected */ + uint8_t addressed:1; /* 1: Peripheral address has been set */ + uint8_t configured:1; /* 1: Class driver has been configured */ uint8_t wakeup:1; /* 1: Device remote wake-up */ + uint8_t dotest:1; /* 1: Test mode selected */ uint8_t devstate; /* See enum stm32_devstate_e */ uint8_t ep0state; /* See enum stm32_ep0state_e */ uint8_t savestate; /* Saved devstate */ uint8_t ep0resp[2]; /* buffer for EP0 short transfers */ - uint8_t paddr; /* Address assigned by SETADDRESS */ - uint8_t devcfg; /* Selected configuration index */ uint8_t testmode; /* Selected test mode */ - uint32_t softprio; /* Bitset of high priority interrupts */ uint32_t epavail; /* Bitset of available endpoints */ -#ifdef CONFIG_STM32_USBDEV_FRAME_INTERRUPT - uint32_t sof; /* Last start-of-frame */ -#endif struct usb_ctrlreq_s ctrlreq; /* Received SETUP request */ /* The endpoint list */ @@ -432,14 +343,10 @@ static void stm32_putreg(uint32_t val, uint32_t addr); # define stm32_putreg(val,addr) putreg32(val,addr) #endif -static inline void stm32_clrbits(uint32_t mask, uint32_t addr); -static inline void stm32_setbits(uint32_t mask, uint32_t addr); -static inline void stm32_chgbits(uint32_t mask, uint32_t val, uint32_t addr); - /* Request queue operations ****************************************************/ -static FAR struct stm32_req_s *stm32_rqdequeue(FAR struct stm32_ep_s *privep); -static bool stm32_rqenqueue(FAR struct stm32_ep_s *privep, +static FAR struct stm32_req_s *stm32_remfirst(FAR struct stm32_ep_s *privep); +static bool stm32_addlast(FAR struct stm32_ep_s *privep, FAR struct stm32_req_s *req); /* Low level data transfers and request operations *****************************/ @@ -447,11 +354,8 @@ static bool stm32_rqenqueue(FAR struct stm32_ep_s *privep, static inline void stm32_ep0xfer(uint8_t epphy, uint8_t *data, uint32_t nbytes); static void stm32_ep0read(FAR uint8_t *dest, uint16_t len) -static inline void stm32_set_address(struct stm32_usbdev_s *priv, uint16_t address); - static void stm32_flushep(struct stm32_ep_s *privep); -static int stm32_progressep(struct stm32_ep_s *privep); static inline void stm32_abortrequest(struct stm32_ep_s *privep, struct stm32_req_s *privreq, int16_t result); static void stm32_reqcomplete(struct stm32_ep_s *privep, @@ -467,25 +371,31 @@ static void stm32_cancelrequests(struct stm32_ep_s *privep, int16_t statu static struct stm32_ep_s *stm32_epfindbyaddr(struct stm32_usbdev_s *priv, uint16_t eplog); -static void stm32_dispatchrequest(struct stm32_usbdev_s *priv, +static int stm32_dispatchrequest(struct stm32_usbdev_s *priv, const struct usb_ctrlreq_s *ctrl); static void stm32_ep0configure(struct stm32_usbdev_s *priv); static void stm32_usbreset(struct stm32_usbdev_s *priv); -static inline void stm32_ep0state(struct stm32_usbdev_s *priv, uint16_t state); -static void stm32_ep0setup(struct stm32_usbdev_s *priv); - static void stm32_ep0complete(struct stm32_usbdev_s *priv, uint8_t epphy); static bool stm32_epcomplete(struct stm32_usbdev_s *priv, uint8_t epphy); /* Second level IN endpoint interrupt processing */ +static inline void stm32_runtestmode(FAR struct stm32_usbdev_s *priv); static inline void stm32_epin(FAR struct stm32_usbdev_s *priv, uint8_t epno); static inline void stm32_epininterrupt(FAR struct stm32_usbdev_s *priv); /* Second level OUT endpoint interrupt processing */ -static inline void stm32_epout(FAR struct stm32_usbdev_s *priv, uint8_t epno); +static inline void stm32_setaddress(struct stm32_usbdev_s *priv, + uint16_t address); +static inline void stm32_testmode(FAR struct stm32_usbdev_s *priv, + uint16_t index); +static inline void stm32_stdrequest(struct stm32_usbdev_s *priv, + FAR struct stm32_ctrlreq_s *ctrlreq); +static inline void stm32_ep0setup(struct stm32_usbdev_s *priv); +static inline void stm32_epout(FAR struct stm32_usbdev_s *priv, + uint8_t epno); static inline void stm32_epoutinterrupt(FAR struct stm32_usbdev_s *priv); /* First level interrupt processing */ @@ -549,9 +459,6 @@ static void stm32_hwinitialize(FAR struct stm32_usbdev_s *priv); static struct stm32_usbdev_s g_otgfsdev; -static struct stm32_dqh_s __attribute__((aligned(2048))) g_qh[STM32_NENDPOINTS]; -static struct stm32_dtd_s __attribute__((aligned(32))) g_td[STM32_NENDPOINTS]; - static const struct usbdev_epops_s g_epops = { .configure = stm32_epconfigure, @@ -669,60 +576,14 @@ static void stm32_putreg(uint32_t val, uint32_t addr) #endif /******************************************************************************* - * Name: stm32_clrbits - * - * Description: - * Clear bits in a register - * - *******************************************************************************/ - -static inline void stm32_clrbits(uint32_t mask, uint32_t addr) -{ - uint32_t reg = stm32_getreg(addr); - reg &= ~mask; - stm32_putreg(reg, addr); -} - -/******************************************************************************* - * Name: stm32_setbits + * Name: stm32_remfirst * * Description: - * Set bits in a register + * Remove a request from the head of an endpoint request queue * *******************************************************************************/ -static inline void stm32_setbits(uint32_t mask, uint32_t addr) -{ - uint32_t reg = stm32_getreg(addr); - reg |= mask; - stm32_putreg(reg, addr); -} - -/******************************************************************************* - * Name: stm32_chgbits - * - * Description: - * Change bits in a register - * - *******************************************************************************/ - -static inline void stm32_chgbits(uint32_t mask, uint32_t val, uint32_t addr) -{ - uint32_t reg = stm32_getreg(addr); - reg &= ~mask; - reg |= val; - stm32_putreg(reg, addr); -} - -/******************************************************************************* - * Name: stm32_rqdequeue - * - * Description: - * Remove a request from an endpoint request queue - * - *******************************************************************************/ - -static FAR struct stm32_req_s *stm32_rqdequeue(FAR struct stm32_ep_s *privep) +static FAR struct stm32_req_s *stm32_remfirst(FAR struct stm32_ep_s *privep) { FAR struct stm32_req_s *ret = privep->head; @@ -741,15 +602,15 @@ static FAR struct stm32_req_s *stm32_rqdequeue(FAR struct stm32_ep_s *privep) } /******************************************************************************* - * Name: stm32_rqenqueue + * Name: stm32_addlast * * Description: - * Add a request from an endpoint request queue + * Add a request to the end of an endpoint request queue * *******************************************************************************/ -static bool stm32_rqenqueue(FAR struct stm32_ep_s *privep, - FAR struct stm32_req_s *req) +static bool stm32_addlast(FAR struct stm32_ep_s *privep, + FAR struct stm32_req_s *req) { bool is_empty = !privep->head; @@ -821,23 +682,6 @@ static void stm32_ep0read(FAR uint8_t *dest, uint16_t len) } /******************************************************************************* - * Name: stm32_set_address - * - * Description: - * Set the devices USB address - * - *******************************************************************************/ - -static inline void stm32_set_address(struct stm32_usbdev_s *priv, uint16_t address) -{ - priv->paddr = address; - priv->paddrset = address != 0; - - stm32_chgbits(USBDEV_DEVICEADDR_MASK, priv->paddr << USBDEV_DEVICEADDR_SHIFT, - STM32_USBDEV_DEVICEADDR); -} - -/******************************************************************************* * Name: stm32_flushep * * Description: @@ -847,14 +691,14 @@ static inline void stm32_set_address(struct stm32_usbdev_s *priv, uint16_t addre static void stm32_flushep(struct stm32_ep_s *privep) { - uint32_t mask = STM32_ENDPTMASK(privep->epphy); - do + if (privep->isin) { - stm32_putreg (mask, STM32_USBDEV_ENDPTFLUSH); - while ((stm32_getreg(STM32_USBDEV_ENDPTFLUSH) & mask) != 0) - ; + stm32_flushtxfifo(priv, OTGFS_GRSTCTL_TXFNUM_D(privep->epphy); + } + else + { + stm32_flushrxfifo(priv); } - while ((stm32_getreg(STM32_USBDEV_ENDPTSTATUS) & mask) != 0); } /******************************************************************************* @@ -896,7 +740,7 @@ static void stm32_reqcomplete(struct stm32_ep_s *privep, */ bool stalled = privep->stalled; - if (privep->epphy == STM32_EP0_IN) + if (privep->epphy == EP0) { privep->stalled = privep->dev->stalled; } @@ -1114,7 +958,7 @@ static void stm32_cancelrequests(struct stm32_ep_s *privep, int16_t status) // FIXME: only report the error status if the transfer hasn't completed usbtrace(TRACE_COMPLETE(privep->epphy), (stm32_rqpeek(privep))->req.xfrd); - stm32_reqcomplete(privep, stm32_rqdequeue(privep), status); + stm32_reqcomplete(privep, stm32_remfirst(privep), status); } } @@ -1128,37 +972,39 @@ static void stm32_cancelrequests(struct stm32_ep_s *privep, int16_t status) *******************************************************************************/ static struct stm32_ep_s *stm32_epfindbyaddr(struct stm32_usbdev_s *priv, - uint16_t eplog) + uint16_t eplog) { struct stm32_ep_s *privep; + uint8_t epphy = USB_EPNO(eplog); int i; - /* Endpoint zero is a special case */ - - if (USB_EPNO(eplog) == 0) + if (epphy >= STM32_NENDPOINTS) { - return &priv->epin[EP0]; + return NULL; } - /* Handle the remaining */ + /* Is this an IN or an OUT endpoint? */ - for (i = 1; i < STM32_NENDPOINTS; i++) + if (USB_ISEPIN(eplog)) { - privep = &priv->epin[i]; - - /* Same logical endpoint number? (includes direction bit) */ + privep = &priv->epin[epphy]; + } + else + { + privep = &priv->epout[epphy]; + } - if (eplog == privep->ep.eplog) - { - /* Return endpoint found */ + /* Verify that the endpoint has been configured */ - return privep; - } + if (!privep->configured) + { + return NULL; } - /* Return endpoint not found */ + /* Return endpoint reference */ - return NULL; + DEBUGASSERT(privep->epphy == epphy); + return privep; } /******************************************************************************* @@ -1170,8 +1016,8 @@ static struct stm32_ep_s *stm32_epfindbyaddr(struct stm32_usbdev_s *priv, * *******************************************************************************/ -static void stm32_dispatchrequest(struct stm32_usbdev_s *priv, - const struct usb_ctrlreq_s *ctrl) +static int stm32_dispatchrequest(struct stm32_usbdev_s *priv, + const struct usb_ctrlreq_s *ctrl) { int ret = -EIO; @@ -1190,6 +1036,8 @@ static void stm32_dispatchrequest(struct stm32_usbdev_s *priv, usbtrace(TRACE_DEVERROR(STM32_TRACEERR_DISPATCHSTALL), 0); priv->stalled = true; } + + return ret; } /******************************************************************************* @@ -1203,20 +1051,10 @@ static void stm32_dispatchrequest(struct stm32_usbdev_s *priv, static void stm32_ep0configure(struct stm32_usbdev_s *priv) { /* Enable ep0 IN and ep0 OUT */ - - g_qh[STM32_EP0_OUT].capability = (DQH_CAPABILITY_MAX_PACKET(CONFIG_USBDEV_EP0_MAXSIZE) | - DQH_CAPABILITY_IOS | - DQH_CAPABILITY_ZLT); - - g_qh[STM32_EP0_IN ].capability = (DQH_CAPABILITY_MAX_PACKET(CONFIG_USBDEV_EP0_MAXSIZE) | - DQH_CAPABILITY_IOS | - DQH_CAPABILITY_ZLT); - - g_qh[STM32_EP0_OUT].currdesc = DTD_NEXTDESC_INVALID; - g_qh[STM32_EP0_IN ].currdesc = DTD_NEXTDESC_INVALID; +#waning "Missing Logic" /* Enable EP0 */ - stm32_setbits (USBDEV_ENDPTCTRL0_RXE | USBDEV_ENDPTCTRL0_TXE, STM32_USBDEV_ENDPTCTRL0); +#waning "Missing Logic" } /******************************************************************************* @@ -1264,7 +1102,7 @@ static void stm32_usbreset(struct stm32_usbdev_s *priv) /* Set USB address to 0 */ - stm32_set_address (priv, 0); + stm32_setaddress(priv, 0); /* EndPoint 0 initialization */ @@ -1275,29 +1113,450 @@ static void stm32_usbreset(struct stm32_usbdev_s *priv) } /******************************************************************************* - * Name: stm32_setstate + * Name: stm32_ep0complete * * Description: - * Sets the EP0 state and manages the NAK interrupts + * Transfer complete handler for Endpoint 0 * *******************************************************************************/ -static inline void stm32_ep0state(struct stm32_usbdev_s *priv, uint16_t state) +static void stm32_ep0complete(struct stm32_usbdev_s *priv, uint8_t epphy) { - priv->ep0state = state; + FAR struct stm32_ep_s *privep = &priv->epin[epphy]; + + usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EP0COMPLETE), (uint16_t)priv->ep0state); - switch (state) + switch (priv->ep0state) { - case EP0STATE_NAK_IN: - stm32_putreg (STM32_ENDPTMASK(STM32_EP0_IN), STM32_USBDEV_ENDPTNAKEN); + case EP0STATE_DATA_IN: + if (stm32_rqempty(privep)) + { + return; + } + + if (stm32_epcomplete(priv, epphy)) + { + priv->ep0state = EP0STATE_NAK_OUT; + } + break; + + case EP0STATE_DATA_OUT: + if (stm32_rqempty(privep)) + { + return; + } + + if (stm32_epcomplete(priv, epphy)) + { + priv->ep0state = EP0STATE_NAK_IN; + } break; - case EP0STATE_NAK_OUT: - stm32_putreg (STM32_ENDPTMASK(STM32_EP0_OUT), STM32_USBDEV_ENDPTNAKEN); + + case EP0STATE_SHORTWRITE: + priv->ep0state = EP0STATE_NAK_OUT; break; + + case EP0STATE_STATUS_IN: + priv->ep0state = EP0STATE_IDLE; + break; + + case EP0STATE_STATUS_OUT: + priv->ep0state = EP0STATE_IDLE; + break; + default: - stm32_putreg(0, STM32_USBDEV_ENDPTNAKEN); +#ifdef CONFIG_DEBUG + DEBUGASSERT(priv->ep0state != EP0STATE_DATA_IN && + priv->ep0state != EP0STATE_DATA_OUT && + priv->ep0state != EP0STATE_SHORTWRITE && + priv->ep0state != EP0STATE_STATUS_IN && + priv->ep0state != EP0STATE_STATUS_OUT); +#endif + priv->stalled = true; + break; + } + + if (priv->stalled) + { + usbtrace(TRACE_DEVERROR(STM32_TRACEERR_EP0SETUPSTALLED), priv->ep0state); + stm32_ep0stall(priv); + } +} + +/******************************************************************************* + * Name: stm32_epcomplete + * + * Description: + * Transfer complete handler for Endpoints other than 0 + * returns whether the request at the head has completed + * + *******************************************************************************/ + +bool stm32_epcomplete(struct stm32_usbdev_s *priv, uint8_t epphy) +{ + struct stm32_ep_s *privep = &priv->epin[epphy]; + struct stm32_req_s *privreq = privep->head; + + if (privreq == NULL) /* This shouldn't really happen */ + { + if (privep->isin) + { + usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPINQEMPTY), 0); + } + else + { + usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPOUTQEMPTY), 0); + | + return true; + } + + int xfrd = dtd->xfer_len - (dtd->config >> 16); + + privreq->req.xfrd += xfrd; + + bool complete = true; + if (privep->isin) + { + /* write(IN) completes when request finished, unless we need to terminate with a ZLP */ + + bool need_zlp = (xfrd == privep->ep.maxpacket) && ((privreq->req.flags & USBDEV_REQFLAGS_NULLPKT) != 0); + + complete = (privreq->req.xfrd >= privreq->req.len && !need_zlp); + + usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPINCOMPLETE), complete); + } + else + { + /* read(OUT) completes when request filled, or a short transfer is received */ + + usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPOUTCOMPLETE), complete); + } + + /* If the transfer is complete, then dequeue and progress any further queued requests */ + + if (complete) + { + privreq = stm32_remfirst (privep); + } + + if (!stm32_rqempty(privep)) + { + stm32_???(privep); + } + + /* Now it's safe to call the completion callback as it may well submit a new request */ + + if (complete) + { + usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd); + stm32_reqcomplete(privep, privreq, OK); + } + + return complete; +} + +/******************************************************************************* + * Name: stm32_runtestmode + * + * Description: + * Execute the test mode setup by the SET FEATURE request + * + *******************************************************************************/ + +static inline void stm32_runtestmode(FAR struct stm32_usbdev_s *priv) +{ + uint32_t regval = stm32_gettreg(TM32_OTGFS_DCTL); + regval &= OTGFS_DCTL_TCTL_MASK; + regval |= (uint32_t)priv->testmode << OTGFS_DCTL_TCTL_SHIFT; + stm32_putreg(regval , STM32_OTGFS_DCTL); + + priv->dotest = 0; + priv->testmode = OTGFS_TESTMODE_DISABLED; +} + +/******************************************************************************* + * Name: stm32_epin + * + * Description: + * This is part of the IN endpoint interrupt processing. This function + * handles the IN event for a single endpoint. + * + *******************************************************************************/ + +static inline void stm32_epin(FAR struct stm32_usbdev_s *priv, uint8_t epno) +{ + FAR struct stm32_ep_s *privep; + + /* Endpoint 0 is a special case. */ + + if (epno == 0) + { + privep = &priv->epin[EP0]; + + /* In the EP0STATE_DATA_IN state, we are sending data from request + * buffer. In that case, we must continue the request processing. + */ + + if (priv->ep0state == EP0STATE_DATA_OUT) + { + /* Continue processing data from the EP0 OUT request queue */ + + (void)stm32_wrrequest(priv, privep); + } + + /* If we are not actively processing an OUT request, then we + * need to setup to receive the next control request. + */ + + if (!privep->active) + { + stm32_recvctlstatus(priv); + } + + /* Test mode is another special case */ + + if (priv->dotest) + { + stm32_runtestmode(priv); + } + } + + /* For other endpoints, the only possibility is that we are continuing + * or finishing an IN request. + */ + + else if (priv->devstate == DEVSTATE_CONFIGURED) + { + /* Continue processing data from the EP0 OUT request queue */ + + (void)stm32_wrrequest(priv, privep); + } + return OK; +} + +/******************************************************************************* + * Name: stm32_epininterrupt + * + * Description: + * USB IN endpoint interrupt handler + * + *******************************************************************************/ + +static inline void stm32_epininterrupt(FAR struct stm32_usbdev_s *priv) +{ + uint32_t diepint; + uint32_t daint; + uint32_t mask; + uint32_t empty; + int epno; + + /* Get the pending, enabled interrupts for the IN endpoint from the endpoint + * interrupt status register. + */ + + daint = stm32_getreg(STM32_OTGFS_DAINT); + daint &= stm32_getreg(STM32_OTGFS_DAINTMSK); + daint &= OTGFS_DAINT_IEP_MASK; + + /* Process each pending IN endpoint interrupt */ + + epno = 0; + while (daint) + { + /* Is an IN interrupt pending for this endpoint? */ + + if ((daint & 1) != 0) + { + /* Get IN interrupt mask register. Bits 0-6 correspond to enabled + * interrupts as will be found in the DIEPINT interrupt status + * register. + */ + + mask = stm32_getreg(STM32_OTGFS_DIEPMSK); + + /* Check for FIFO not empty. Bits n corresponds to endpoint n. + * That condition corresponds to bit 7 of the DIEPINT interrupt + * status register. + */ + + empty = stm32_getreg(STM32_OTGFS_DIEPEMPMSK); + if ((empty & OTGFS_DIEPEMPMSK(epno)) != )) + { + mask |= OTGFS_DIEPINT_TXFE; + } + + /* Now, read the interrupt status and mask out all disabled + * interrupts. + */ + + diepint = stm32_getreg(STM32_OTGFS_DIEPINT(epno)) & mask; + + /* Decode and process the enabled, pending interrupts */ + /* Transfer completed interrupt */ + + if ((diepint & OTGFS_DIEPINT_XFRC) != 0) + { + usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPIN_XFRC), (uint16_t)diepint); + + empty &= ~OTGFS_DIEPEMPMSK(epno); + stm32_putreg(empty, STM32_OTGFS_DIEPEMPMSK); + stm32_putreg(OTGFS_DIEPINT_XFRC, STM32_OTGFS_DIEPINT(epno)); + + /* IN complete */ + + stm32_epin(priv, epno); + } + + /* Timeout condition */ + + if ((diepint & OTGFS_DIEPINT_TOC) != 0) + { + usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPIN_TOC), (uint16_t)diepint); + stm32_putreg(OTGFS_DIEPINT_TOC, STM32_OTGFS_DIEPINT(epno)); + } + + /* IN token received when TxFIFO is empty */ + + if ((diepint & OTGFS_DIEPINT_ITTXFE) != 0) + { + usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPIN_ITTXFE), (uint16_t)diepint); + stm32_putreg(OTGFS_DIEPINT_ITTXFE, STM32_OTGFS_DIEPINT(epno)); + } + + /* IN endpoint NAK effective */ + + if ((diepint & OTGFS_DIEPINT_INEPNE) != 0) + { + usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPIN_INEPNE), (uint16_t)diepint); + stm32_putreg(OTGFS_DIEPINT_INEPNE, STM32_OTGFS_DIEPINT(epno)); + } + + /* Endpoint disabled interrupt */ + + if ((diepint & OTGFS_DIEPINT_EPDISD) != 0) + { + usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPIN_EPDISD), (uint16_t)diepint); + stm32_putreg(OTGFS_DIEPINT_EPDISD, STM32_OTGFS_DIEPINT(epno)); + } + + /* Transmit FIFO empty */ + + if ((diepint & OTGFS_DIEPINT_TXFE) != 0) + { + usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPIN_TXFE), (uint16_t)diepint); + stm32_txfifoempty(priv, epno); + stm32_putreg(OTGFS_DIEPINT_TXFE, STM32_OTGFS_DIEPINT(epno)); + } + } + + epno++; + daint >>= 1; + } + + return 1; +} + +/******************************************************************************* + * Name: stm32_setaddress + * + * Description: + * Set the devices USB address + * + *******************************************************************************/ + +static inline void stm32_setaddress(struct stm32_usbdev_s *priv, uint16_t address) +{ + uint32_t regval; + uint8_t address; + + if ((req->index == 0) && (req->len == 0)) + { + if (priv->devstate == DEVSTATE_CONFIGURED) + { + stm32_ep0stall(priv, req); + } + else + { + /* Set the device address in the DCFG register */ + + regval = stm32_getreg(STM32_OTGFS_DCFG); + regval &= ~OTGFS_DCFG_DAD_MASK; + regval |= (address << OTGFS_DCFG_DAD_SHIFT); + stm32_putreg(regval, STM32_OTGFS_DCFG); + + /* Send a null packet in response */ + + stm32_ep0nullpacket(priv); + + /* Are we now addressed? (i.e., do we have a non-NULL device + * address? + */ + + if (address != 0) + { + priv->devstate = DEVSTATE_ADDRESSED; + priv->addressed = true; + } + else + { + priv->devstate = DEVSTATE_DEFAULT; + priv->addressed = false; + } + } + } + else + { + stm32_ep0stall(priv, req); + } +} + +/******************************************************************************* + * Name: stm32_testmode + * + * Description: + * Select test mode + * + *******************************************************************************/ + +static inline void stm32_testmode(FAR struct stm32_usbdev_s *priv, uint16_t index) +{ + uint32_t regval; + uint8_t testmode; + + regval = stm32_getreg(STM32_OTGFS_DCTL); + + testmode = index >> 8; + switch (testmode) + { + case 1: + priv->testmode = OTGFS_TESTMODE_J; + break; + + case 2: + priv->testmode = OTGFS_TESTMODE_K; break; + + case 3: + priv->testmode = OTGFS_TESTMODE_SE0_NAK; + break; + + case 4: + priv->testmode = OTGFS_TESTMODE_PACKET; + break; + + case 5: + priv->testmode = OTGFS_TESTMODE_FORCE; + break; + + default: + usbtrace(TRACE_DEVERROR(STM32_TRACEERR_BADTESTMODE), testmode); + priv->dotest = false; + priv->testmode = OTGFS_TESTMODE_DISABLED + priv->stalled = true; } + + priv->dotest = true; + stm32_ep0nullpacket(priv); } /******************************************************************************* @@ -1327,8 +1586,10 @@ static inline void stm32_stdrequest(struct stm32_usbdev_s *priv, */ usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_GETSTATUS), 0); - if (!priv->paddrset || ctrlreq->len != 2 || - (ctrlreq->type & USB_REQ_DIR_IN) == 0 || ctrlreq->value != 0) + if (!priv->addressed || + ctrlreq->len != 2 || + (ctrlreq->type & USB_REQ_DIR_IN) == 0 || + ctrlreq->value != 0) { priv->stalled = true; } @@ -1349,7 +1610,7 @@ static inline void stm32_stdrequest(struct stm32_usbdev_s *priv, { if (privep->stalled) { - priv->ep0resp[0] = 1; /* Stalled */ + priv->ep0resp[0] = (1 << USB_FEATURE_ENDPOINTHALT); } else { @@ -1358,8 +1619,8 @@ static inline void stm32_stdrequest(struct stm32_usbdev_s *priv, priv->ep0resp[1] = 0; - stm32_ep0xfer(STM32_EP0_IN, priv->ep0resp, 2); - stm32_ep0state(priv, EP0STATE_SHORTWRITE); + stm32_ep0xfer(EP0, priv->ep0resp, 2); + priv->ep0state = EP0STATE_SHORTWRITE; } } break; @@ -1370,14 +1631,14 @@ static inline void stm32_stdrequest(struct stm32_usbdev_s *priv, { usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_DEVGETSTATUS), 0); - /* Features: Remote Wakeup=YES; selfpowered=? */ - - priv->ep0resp[0] = (priv->selfpowered << USB_FEATURE_SELFPOWERED) | - (1 << USB_FEATURE_REMOTEWAKEUP); - priv->ep0resp[1] = 0; - - stm32_ep0xfer(STM32_EP0_IN, priv->ep0resp, 2); - stm32_ep0state(priv, EP0STATE_SHORTWRITE); + /* Features: Remote Wakeup and selfpowered */ + + priv->ep0resp[0] = (priv->selfpowered << USB_FEATURE_SELFPOWERED); + priv->ep0resp[0] |= (priv->wakeup << USB_FEATURE_REMOTEWAKEUP); + priv->ep0resp[1] = 0; + + stm32_ep0xfer(EP0, priv->ep0resp, 2); + priv->ep0state = EP0STATE_SHORTWRITE; } else { @@ -1393,8 +1654,8 @@ static inline void stm32_stdrequest(struct stm32_usbdev_s *priv, priv->ep0resp[0] = 0; priv->ep0resp[1] = 0; - stm32_ep0xfer(STM32_EP0_IN, priv->ep0resp, 2); - stm32_ep0state(priv, EP0STATE_SHORTWRITE); + stm32_ep0xfer(EP0, priv->ep0resp, 2); + priv->ep0state = EP0STATE_SHORTWRITE; } break; @@ -1418,15 +1679,29 @@ static inline void stm32_stdrequest(struct stm32_usbdev_s *priv, */ usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_CLEARFEATURE), 0); - if ((ctrlreq->type & USB_REQ_RECIPIENT_MASK) != USB_REQ_RECIPIENT_ENDPOINT) + if (priv->addressed != 0 && ctrlreq->len == 0) { - stm32_dispatchrequest(priv, &priv->ctrlreq); - } - else if (priv->paddrset != 0 && ctrlreq->value == USB_FEATURE_ENDPOINTHALT && ctrlreq->len == 0 && + uint8_t recipient = ctrlreq->type & USB_REQ_RECIPIENT_MASK; + if (recipient == USB_REQ_RECIPIENT_ENDPOINT + ctrlreq->value == USB_FEATURE_ENDPOINTHALT && (privep = stm32_epfindbyaddr(priv, ctrlreq->index)) != NULL) - { - stm32_epclrstall(priv, &privep->ep); - stm32_ep0state(priv, EP0STATE_NAK_IN); + { + stm32_epclrstall(priv, &privep->ep); + stm32_ep0nullpacket(priv); + priv->ep0state = EP0STATE_NAK_IN; + } + else if (recipient == USB_REQ_RECIPIENT_DEVICE && + ctrlreq->value == USB_FEATURE_REMOTEWAKEUP) + { + priv->wakeup = 0; + stm32_ep0nullpacket(priv); + } + else + { + /* Actually, I think we could just stall here. */ + + (void)stm32_dispatchrequest(priv, &priv->ctrlreq); + } } else { @@ -1445,20 +1720,40 @@ static inline void stm32_stdrequest(struct stm32_usbdev_s *priv, */ usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SETFEATURE), 0); - if (((ctrlreq->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE) && - ctrlreq->value == USB_FEATURE_TESTMODE) - { - ullvdbg("test mode: %d\n", ctrlreq->index); - } - else if ((ctrlreq->type & USB_REQ_RECIPIENT_MASK) != USB_REQ_RECIPIENT_ENDPOINT) + if (priv->addressed != 0 && ctrlreq->len == 0) { - stm32_dispatchrequest(priv, &priv->ctrlreq); - } - else if (priv->paddrset != 0 && ctrlreq->value == USB_FEATURE_ENDPOINTHALT && ctrlreq->len == 0 && + uint8_t recipient = ctrlreq->type & USB_REQ_RECIPIENT_MASK; + if (recipient == USB_REQ_RECIPIENT_ENDPOINT + ctrlreq->value == USB_FEATURE_ENDPOINTHALT && (privep = stm32_epfindbyaddr(priv, ctrlreq->index)) != NULL) - { - stm32_epsetstall(priv, privep); - stm32_ep0state(priv, EP0STATE_NAK_IN); + { + stm32_epsetstall(priv, privep); + stm32_ep0nullpacket(priv); + priv->ep0state = EP0STATE_NAK_IN; + } + else if (recipient == USB_REQ_RECIPIENT_DEVICE + ctrlreq->value == USB_FEATURE_REMOTEWAKEUP) + { + priv->wakeup = 1; + stm32_ep0nullpacket(priv); + } + else if (recipient == USB_REQ_RECIPIENT_DEVICE && + ctrlreq->value == USB_FEATURE_TESTMODE && + ((req->index & 0xff) == 0)) + { + stm32_testmode(priv, ctrlreq->index); + } + else if (priv->configured) + { + /* Actually, I think we could just stall here. */ + + (void)stm32_dispatchrequest(priv, &priv->ctrlreq); + } + else + { + usbtrace(TRACE_DEVERROR(STM32_TRACEERR_BADSETFEATURE), 0); + priv->stalled = true; + } } else { @@ -1476,17 +1771,18 @@ static inline void stm32_stdrequest(struct stm32_usbdev_s *priv, * len: 0; data = none */ - usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EP0SETUPSETADDRESS), ctrlreq->value); - if ((ctrlreq->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE && - ctrlreq->index == 0 && ctrlreq->len == 0 && ctrlreq->value < 128) + usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SETADDRESS), ctrlreq->value); + if ((ctrlreq->type &USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE && + ctrlreq->index == 0 && + ctrlreq->len == 0 && + ctrlreq->value < 128) { /* Save the address. We cannot actually change to the next address until * the completion of the status phase. */ - - priv->paddr = priv->ctrlreq->value[0]; - priv->paddrset = false; - stm32_ep0state(priv, EP0STATE_NAK_IN); + + stm32_setaddress(priv, (uint16_t)priv->ctrlreq->value[0]); + priv->ep0state = EP0STATE_NAK_IN; } else { @@ -1514,7 +1810,7 @@ static inline void stm32_stdrequest(struct stm32_usbdev_s *priv, usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_GETSETDESC), 0); if ((ctrlreq->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE) { - stm32_dispatchrequest(priv, &priv->ctrlreq); + (void)stm32_dispatchrequest(priv, &priv->ctrlreq); } else { @@ -1533,10 +1829,13 @@ static inline void stm32_stdrequest(struct stm32_usbdev_s *priv, { usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_GETCONFIG), 0); - if (priv->paddrset && (ctrlreq->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE && - ctrlreq->value == 0 && ctrlreq->index == 0 && ctrlreq->len == 1) + if (priv->addressed && + (ctrlreq->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE && + ctrlreq->value == 0 && + ctrlreq->index == 0 && + ctrlreq->len == 1) { - stm32_dispatchrequest(priv, &priv->ctrlreq); + (void)stm32_dispatchrequest(priv, &priv->ctrlreq); } else { @@ -1555,10 +1854,34 @@ static inline void stm32_stdrequest(struct stm32_usbdev_s *priv, { usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SETCONFIG), 0); - if ((ctrlreq->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE && - ctrlreq->index == 0 && ctrlreq->len == 0) + if (priv->addressed && + (ctrlreq->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE && + ctrlreq->index == 0 && + ctrlreq->len == 0) { - stm32_dispatchrequest(priv, &priv->ctrlreq); + /* Give the configuration to the class driver */ + + ret = stm32_dispatchrequest(priv, &priv->ctrlreq); + + /* If the class driver accepted the configuration, then mark the + * device state as configured (or not, depending on the + * configuration). + */ + + if (ret == OK) + { + uint8_t cfg = (uint8_t)req->value; + if (cfg != 0) + { + priv->devstate = DEVSTATE_CONFIGURED; + priv->configured = true; + } + else + { + priv->devstate = DEVSTATE_ADDRESSED; + priv->configured = false; + } + } } else { @@ -1584,7 +1907,7 @@ static inline void stm32_stdrequest(struct stm32_usbdev_s *priv, { usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_GETSETIF), 0); - stm32_dispatchrequest(priv, &priv->ctrlreq); + (void)stm32_dispatchrequest(priv, &priv->ctrlreq); } break; @@ -1627,13 +1950,13 @@ static inline void stm32_ep0setup(struct stm32_usbdev_s *priv) * because of the setup packet. */ - stm32_cancelrequests(&priv->epin[STM32_EP0_OUT], -EPROTO); - stm32_cancelrequests(&priv->epin[STM32_EP0_IN], -EPROTO); + stm32_cancelrequests(&priv->epout[EP0], -EPROTO); + stm32_cancelrequests(&priv->epin[EP0], -EPROTO); /* Assume NOT stalled */ - priv->epin[STM32_EP0_OUT].stalled = false; - priv->epin[STM32_EP0_IN].stalled = false; + priv->epout[EP0].stalled = false; + priv->epin[EP0].stalled = false; priv->stalled = false; /* Read EP0 setup data */ @@ -1642,7 +1965,7 @@ static inline void stm32_ep0setup(struct stm32_usbdev_s *priv) /* Starting a control request - update state */ - stm32_ep0state(priv, (priv->ctrlreq.type & USB_REQ_DIR_IN) ? EP0STATE_SETUP_IN : EP0STATE_SETUP_OUT); + priv->ep0state = (priv->ctrlreq.type & USB_REQ_DIR_IN) ? EP0STATE_SETUP_IN : EP0STATE_SETUP_OUT; /* And extract the little-endian 16-bit values to host order */ @@ -1661,7 +1984,7 @@ static inline void stm32_ep0setup(struct stm32_usbdev_s *priv) { /* Dispatch any non-standard requests */ - stm32_dispatchrequest(priv, &priv->ctrlreq); + (void)stm32_dispatchrequest(priv, &priv->ctrlreq); } else { @@ -1678,342 +2001,6 @@ static inline void stm32_ep0setup(struct stm32_usbdev_s *priv) } /******************************************************************************* - * Name: stm32_ep0complete - * - * Description: - * Transfer complete handler for Endpoint 0 - * - *******************************************************************************/ - -static void stm32_ep0complete(struct stm32_usbdev_s *priv, uint8_t epphy) -{ - FAR struct stm32_ep_s *privep = &priv->epin[epphy]; - - usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EP0COMPLETE), (uint16_t)priv->ep0state); - - switch (priv->ep0state) - { - case EP0STATE_DATA_IN: - if (stm32_rqempty(privep)) - { - return; - } - - if (stm32_epcomplete(priv, epphy)) - { - stm32_ep0state(priv, EP0STATE_NAK_OUT); - } - break; - - case EP0STATE_DATA_OUT: - if (stm32_rqempty(privep)) - { - return; - } - - if (stm32_epcomplete(priv, epphy)) - { - stm32_ep0state(priv, EP0STATE_NAK_IN); - } - break; - - case EP0STATE_SHORTWRITE: - stm32_ep0state(priv, EP0STATE_NAK_OUT); - break; - - case EP0STATE_STATUS_IN: - stm32_ep0state(priv, EP0STATE_IDLE); - - /* If we've received a SETADDRESS packet, then we set the address - * now that the status phase has completed. - */ - - if (! priv->paddrset && priv->paddr != 0) - { - usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EP0INSETADDRESS), (uint16_t)priv->paddr); - stm32_set_address (priv, priv->paddr); - } - break; - - case EP0STATE_STATUS_OUT: - stm32_ep0state(priv, EP0STATE_IDLE); - break; - - default: -#ifdef CONFIG_DEBUG - DEBUGASSERT(priv->ep0state != EP0STATE_DATA_IN && - priv->ep0state != EP0STATE_DATA_OUT && - priv->ep0state != EP0STATE_SHORTWRITE && - priv->ep0state != EP0STATE_STATUS_IN && - priv->ep0state != EP0STATE_STATUS_OUT); -#endif - priv->stalled = true; - break; - } - - if (priv->stalled) - { - usbtrace(TRACE_DEVERROR(STM32_TRACEERR_EP0SETUPSTALLED), priv->ep0state); - stm32_ep0stall(priv); - } -} - -/******************************************************************************* - * Name: stm32_epcomplete - * - * Description: - * Transfer complete handler for Endpoints other than 0 - * returns whether the request at the head has completed - * - *******************************************************************************/ - -bool stm32_epcomplete(struct stm32_usbdev_s *priv, uint8_t epphy) -{ - struct stm32_ep_s *privep = &priv->epin[epphy]; - struct stm32_req_s *privreq = privep->head; - - if (privreq == NULL) /* This shouldn't really happen */ - { - if (STM32_EPPHYOUT(privep->epphy)) - { - usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPINQEMPTY), 0); - } - else - { - usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPOUTQEMPTY), 0); - | - return true; - } - - int xfrd = dtd->xfer_len - (dtd->config >> 16); - - privreq->req.xfrd += xfrd; - - bool complete = true; - if (STM32_EPPHYOUT(privep->epphy)) - { - /* read(OUT) completes when request filled, or a short transfer is received */ - - usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPIN), complete); - } - else - { - /* write(IN) completes when request finished, unless we need to terminate with a ZLP */ - - bool need_zlp = (xfrd == privep->ep.maxpacket) && ((privreq->req.flags & USBDEV_REQFLAGS_NULLPKT) != 0); - - complete = (privreq->req.xfrd >= privreq->req.len && !need_zlp); - - usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPOUT), complete); - } - - /* If the transfer is complete, then dequeue and progress any further queued requests */ - - if (complete) - { - privreq = stm32_rqdequeue (privep); - } - - if (!stm32_rqempty(privep)) - { - stm32_???(privep); - } - - /* Now it's safe to call the completion callback as it may well submit a new request */ - - if (complete) - { - usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd); - stm32_reqcomplete(privep, privreq, OK); - } - - return complete; -} - -/******************************************************************************* - * Name: stm32_epin - * - * Description: - * This is part of the IN endpoint interrupt processing. This function - * handles the IN event for a single endpoint. - * - *******************************************************************************/ - -static inline void stm32_epin(FAR struct stm32_usbdev_s *priv, uint8_t epno) -{ - FAR struct stm32_ep_s *privep; - - /* Endpoint 0 is a special case. */ - - if (epno == 0) - { - privep = &priv->epin[EP0]; - - /* In the EP0STATE_DATA_IN state, we are sending data from request - * buffer. In that case, we must continue the request processing. - */ - - if (priv->ep0state == EP0STATE_DATA_OUT) - { - /* Continue processing data from the EP0 OUT request queue */ - - (void)stm32_wrrequest(priv, privep); - } - - /* If we are not actively processing an OUT request, then we - * need to setup to receive the next control request. - */ - - if (!privep->active) - { - stm32_recvctlstatus(priv); - } - - /* Test mode is another special case */ - - if (priv->testmode) - { - stm32_runtestmode(priv); - priv->testmode = 0; - } - } - - /* For other endpoints, the only possibility is that we are continuing - * or finishing an IN request. - */ - - else if (priv->devstate == DEVSTATE_CONFIGURED) - { - /* Continue processing data from the EP0 OUT request queue */ - - (void)stm32_wrrequest(priv, privep); - } - return OK; -} - -/******************************************************************************* - * Name: stm32_epininterrupt - * - * Description: - * USB IN endpoint interrupt handler - * - *******************************************************************************/ - -static inline void stm32_epininterrupt(FAR struct stm32_usbdev_s *priv) -{ - uint32_t diepint; - uint32_t daint; - uint32_t mask; - uint32_t empty; - int epno; - - /* Get the pending, enabled interrupts for the IN endpoint from the endpoint - * interrupt status register. - */ - - daint = stm32_getreg(STM32_OTGFS_DAINT); - daint &= stm32_getreg(STM32_OTGFS_DAINTMSK); - daint &= OTGFS_DAINT_IEP_MASK; - - /* Process each pending IN endpoint interrupt */ - - epno = 0; - while (daint) - { - /* Is an IN interrupt pending for this endpoint? */ - - if ((daint & 1) != 0) - { - /* Get IN interrupt mask register. Bits 0-6 correspond to enabled - * interrupts as will be found in the DIEPINT interrupt status - * register. - */ - - mask = stm32_getreg(STM32_OTGFS_DIEPMSK); - - /* Check for FIFO not empty. Bits n corresponds to endpoint n. - * That condition corresponds to bit 7 of the DIEPINT interrupt - * status register. - */ - - empty = stm32_getreg(STM32_OTGFS_DIEPEMPMSK); - if ((empty & OTGFS_DIEPEMPMSK(epno)) != )) - { - mask |= OTGFS_DIEPINT_TXFE; - } - - /* Now, read the interrupt status and mask out all disabled - * interrupts. - */ - - diepint = stm32_getreg(STM32_OTGFS_DIEPINT(epno)) & mask; - - /* Decode and process the enabled, pending interrupts */ - /* Transfer completed interrupt */ - - if ((diepint & OTGFS_DIEPINT_XFRC) != 0) - { - usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPIN_XFRC), (uint16_t)diepint); - - empty &= ~OTGFS_DIEPEMPMSK(epno); - stm32_putreg(empty, STM32_OTGFS_DIEPEMPMSK); - stm32_putreg(OTGFS_DIEPINT_XFRC, STM32_OTGFS_DIEPINT(epno)); - - /* IN complete */ - - stm32_epin(priv, epno); - } - - /* Timeout condition */ - - if ((diepint & OTGFS_DIEPINT_TOC) != 0) - { - usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPIN_TOC), (uint16_t)diepint); - stm32_putreg(OTGFS_DIEPINT_TOC, STM32_OTGFS_DIEPINT(epno)); - } - - /* IN token received when TxFIFO is empty */ - - if ((diepint & OTGFS_DIEPINT_ITTXFE) != 0) - { - usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPIN_ITTXFE), (uint16_t)diepint); - stm32_putreg(OTGFS_DIEPINT_ITTXFE, STM32_OTGFS_DIEPINT(epno)); - } - - /* IN endpoint NAK effective */ - - if ((diepint & OTGFS_DIEPINT_INEPNE) != 0) - { - usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPIN_INEPNE), (uint16_t)diepint); - stm32_putreg(OTGFS_DIEPINT_INEPNE, STM32_OTGFS_DIEPINT(epno)); - } - - /* Endpoint disabled interrupt */ - - if ((diepint & OTGFS_DIEPINT_EPDISD) != 0) - { - usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPIN_EPDISD), (uint16_t)diepint); - stm32_putreg(OTGFS_DIEPINT_EPDISD, STM32_OTGFS_DIEPINT(epno)); - } - - /* Transmit FIFO empty */ - - if ((diepint & OTGFS_DIEPINT_TXFE) != 0) - { - usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPIN_TXFE), (uint16_t)diepint); - stm32_txfifoempty(priv, epno); - stm32_putreg(OTGFS_DIEPINT_TXFE, STM32_OTGFS_DIEPINT(epno)); - } - } - - epno++; - daint >>= 1; - } - - return 1; -} - -/******************************************************************************* * Name: stm32_epout * * Description: @@ -2325,52 +2312,49 @@ static int stm32_epconfigure(FAR struct usbdev_ep_s *ep, /* Initialise EP capabilities */ uint16_t maxsize = GETUINT16(desc->mxpacketsize); - if ((desc->attr & USB_EP_ATTR_XFERTYPE_MASK) == USB_EP_ATTR_XFER_ISOC) - { - g_qh[privep->epphy].capability = (DQH_CAPABILITY_MAX_PACKET(maxsize) | - DQH_CAPABILITY_IOS | - DQH_CAPABILITY_ZLT); - } - else - { - g_qh[privep->epphy].capability = (DQH_CAPABILITY_MAX_PACKET(maxsize) | - DQH_CAPABILITY_ZLT); - } +#warning "Missing Logic" /* Setup Endpoint Control Register */ - if (STM32_EPPHYIN(privep->epphy)) + if (privep->isin) { /* Reset the data toggles */ - - uint32_t cfg = USBDEV_ENDPTCTRL_TXR; +#warning "Missing logic" /* Set the endpoint type */ switch (desc->attr & USB_EP_ATTR_XFERTYPE_MASK) { - case USB_EP_ATTR_XFER_CONTROL: cfg |= USBDEV_ENDPTCTRL_TXT_CTRL; break; - case USB_EP_ATTR_XFER_ISOC: cfg |= USBDEV_ENDPTCTRL_TXT_ISOC; break; - case USB_EP_ATTR_XFER_BULK: cfg |= USBDEV_ENDPTCTRL_TXT_BULK; break; - case USB_EP_ATTR_XFER_INT: cfg |= USBDEV_ENDPTCTRL_TXT_INTR; break; + case USB_EP_ATTR_XFER_CONTROL: + break; + case USB_EP_ATTR_XFER_ISOC: + break; + case USB_EP_ATTR_XFER_BULK: + break; + case USB_EP_ATTR_XFER_INT: + break; } - stm32_chgbits (0xFFFF0000, cfg, STM32_USBDEV_ENDPTCTRL(privep->epphy)); +#warning "Missing logic" } else { /* Reset the data toggles */ - - uint32_t cfg = USBDEV_ENDPTCTRL_RXR; +#warning "Missing logic" /* Set the endpoint type */ switch (desc->attr & USB_EP_ATTR_XFERTYPE_MASK) { - case USB_EP_ATTR_XFER_CONTROL: cfg |= USBDEV_ENDPTCTRL_RXT_CTRL; break; - case USB_EP_ATTR_XFER_ISOC: cfg |= USBDEV_ENDPTCTRL_RXT_ISOC; break; - case USB_EP_ATTR_XFER_BULK: cfg |= USBDEV_ENDPTCTRL_RXT_BULK; break; + case USB_EP_ATTR_XFER_CONTROL: + break; + case USB_EP_ATTR_XFER_ISOC: + break; + case USB_EP_ATTR_XFER_BULK: + break; + case USB_EP_ATTR_XFER_INT: + break; } - stm32_chgbits (0x0000FFFF, cfg, STM32_USBDEV_ENDPTCTRL(privep->epphy)); +#warning "Missing logic" } /* Reset endpoint status */ @@ -2379,13 +2363,13 @@ static int stm32_epconfigure(FAR struct usbdev_ep_s *ep, /* Enable the endpoint */ - if (STM32_EPPHYIN(privep->epphy)) + if (privep->isin) { - stm32_setbits(USBDEV_ENDPTCTRL_TXE, STM32_USBDEV_ENDPTCTRL(privep->epphy)); +#warning "Missing logic" } else { - stm32_setbits(USBDEV_ENDPTCTRL_RXE, STM32_USBDEV_ENDPTCTRL(privep->epphy)); +#warning "Missing logic" } return OK; @@ -2417,13 +2401,13 @@ static int stm32_epdisable(FAR struct usbdev_ep_s *ep) /* Disable Endpoint */ - if (STM32_EPPHYIN(privep->epphy)) + if (privep->isin) { - stm32_clrbits (USBDEV_ENDPTCTRL_TXE, STM32_USBDEV_ENDPTCTRL(privep->epphy)); +#warning "Missing logic" } else { - stm32_clrbits (USBDEV_ENDPTCTRL_RXE, STM32_USBDEV_ENDPTCTRL(privep->epphy)); +#warning "Missing logic" } privep->stalled = true; @@ -2577,18 +2561,18 @@ static int stm32_epsubmit(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *r { /* Add the new request to the request queue for the endpoint */ - if (STM32_EPPHYIN(privep->epphy)) - { - usbtrace(TRACE_INREQQUEUED(privep->epphy), privreq->req.len); - } - else + if (stm32_addlast(privep, privreq)) { - usbtrace(TRACE_OUTREQQUEUED(privep->epphy), privreq->req.len); - } - - if (stm32_rqenqueue(privep, privreq)) - { - stm32_progressep(privep); + if (privep->isin) + { + usbtrace(TRACE_INREQQUEUED(privep->epphy), privreq->req.len); + stm32_wrrequest(priv, privep); + } + else + { + usbtrace(TRACE_OUTREQQUEUED(privep->epphy), privreq->req.len); + stm32_rdrequest(priv, privep); + } } } @@ -2965,21 +2949,10 @@ static void stm32_freeep(FAR struct usbdev_s *dev, FAR struct usbdev_ep_s *ep) static int stm32_getframe(struct usbdev_s *dev) { -#ifdef CONFIG_STM32_USBDEV_FRAME_INTERRUPT - FAR struct stm32_usbdev_s *priv = (FAR struct stm32_usbdev_s *)dev; - - /* Return last valid value of SOF read by the interrupt handler */ - - usbtrace(TRACE_DEVGETFRAME, (uint16_t)priv->sof); - return priv->sof; -#else /* Return the last frame number detected by the hardware */ usbtrace(TRACE_DEVGETFRAME, 0); - - /* FIXME: this actually returns the micro frame number! */ - return (int)stm32_getreg(STM32_USBDEV_FRINDEX_OFFSET); -#endif +#warning "Missing logic" } /******************************************************************************* @@ -2997,7 +2970,7 @@ static int stm32_wakeup(struct usbdev_s *dev) usbtrace(TRACE_DEVWAKEUP, 0); flags = irqsave(); - stm32_setbits(USBDEV_PRTSC1_FPR, STM32_USBDEV_PORTSC1); +#warning "Missing logic" irqrestore(flags); return OK; } @@ -3042,15 +3015,19 @@ static int stm32_pullup(struct usbdev_s *dev, bool enable) irqstate_t flags = irqsave(); if (enable) - stm32_setbits (USBDEV_USBCMD_RS, STM32_USBDEV_USBCMD); + { +#warning "Missing logic" + } else - stm32_clrbits (USBDEV_USBCMD_RS, STM32_USBDEV_USBCMD); + { +#warning "Missing logic" + } irqrestore(flags); return OK; } /******************************************************************************* - * Name: stm32_swinitialize + * Name: stm32_flushtxfifo * * Description: * Flush the specific TX fifo. @@ -3069,7 +3046,7 @@ static int stm32_flushtxfifo(FAR struct stm32_usbdev_s *priv, uint32_t txfnum) /* Wait for the FLUSH to complete */ - for (timeout = 0; timeout < 200000; timeout++) + for (timeout = 0; timeout < STM32_FLUSH_DELAY; timeout++) { regval = stm32_getreg(STM32_OTGFS_GRSTCTL); if ((regval & OTGFS_GRSTCTL_TXFFLSH) == 0) @@ -3085,7 +3062,7 @@ static int stm32_flushtxfifo(FAR struct stm32_usbdev_s *priv, uint32_t txfnum) } /******************************************************************************* - * Name: stm32_swinitialize + * Name: stm32_flushrxfifo * * Description: * Flush the RX fifo. @@ -3103,7 +3080,7 @@ static int stm32_flushrxfifo(FAR struct stm32_usbdev_s *priv) /* Wait for the FLUSH to complete */ - for (timeout = 0; timeout < 200000; timeout++) + for (timeout = 0; timeout < STM32_FLUSH_DELAY; timeout++) { regval = stm32_getreg(STM32_OTGFS_GRSTCTL); if ((regval & OTGFS_GRSTCTL_RXFFLSH) == 0) @@ -3134,7 +3111,7 @@ static void stm32_swinitialize(FAR struct stm32_usbdev_s *priv) memset(priv, 0, sizeof(struct stm32_usbdev_s)); priv->usbdev.ops = &g_devops; - priv->usbdev.ep0 = &priv->epin[STM32_EP0_IN].ep; + priv->usbdev.ep0 = &priv->epin[EP0].ep; priv->epavail = STM32_EPALLSET; /* Initialize the endpoint lists */ |