aboutsummaryrefslogtreecommitdiff
path: root/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/arch/arm/src/stm32/stm32_otgfsdev.c')
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_otgfsdev.c5541
1 files changed, 0 insertions, 5541 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c b/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c
deleted file mode 100644
index 0fcd463e0..000000000
--- a/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c
+++ /dev/null
@@ -1,5541 +0,0 @@
-/*******************************************************************************
- * arch/arm/src/stm32/stm32_usbdev.c
- *
- * Copyright (C) 2012 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- *******************************************************************************/
-
-/*******************************************************************************
- * Included Files
- *******************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <sys/types.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <debug.h>
-
-#include <nuttx/arch.h>
-#include <nuttx/usb/usb.h>
-#include <nuttx/usb/usbdev.h>
-#include <nuttx/usb/usbdev_trace.h>
-
-#include <arch/irq.h>
-#include <arch/board/board.h>
-
-#include "chip.h"
-#include "up_arch.h"
-#include "up_internal.h"
-
-#include "stm32_otgfs.h"
-
-#if defined(CONFIG_USBDEV) && defined(CONFIG_STM32_OTGFS)
-
-/*******************************************************************************
- * Definitions
- *******************************************************************************/
-/* Configuration ***************************************************************/
-
-#ifndef CONFIG_USBDEV_EP0_MAXSIZE
-# define CONFIG_USBDEV_EP0_MAXSIZE 64
-#endif
-
-#ifndef CONFIG_USBDEV_SETUP_MAXDATASIZE
-# define CONFIG_USBDEV_SETUP_MAXDATASIZE CONFIG_USBDEV_EP0_MAXSIZE
-#endif
-
-#ifndef CONFIG_USBDEV_MAXPOWER
-# define CONFIG_USBDEV_MAXPOWER 100 /* mA */
-#endif
-
-/* There is 1.25Kb of FIFO memory. The default partitions this memory
- * so that there is a TxFIFO allocated for each endpoint and with more
- * memory provided for the common RxFIFO. A more knowledge-able
- * configuration would not allocate any TxFIFO space to OUT endpoints.
- */
-
-#ifndef CONFIG_USBDEV_RXFIFO_SIZE
-# define CONFIG_USBDEV_RXFIFO_SIZE 512
-#endif
-
-#ifndef CONFIG_USBDEV_EP0_TXFIFO_SIZE
-# define CONFIG_USBDEV_EP0_TXFIFO_SIZE 192
-#endif
-
-#ifndef CONFIG_USBDEV_EP1_TXFIFO_SIZE
-# define CONFIG_USBDEV_EP1_TXFIFO_SIZE 192
-#endif
-
-#ifndef CONFIG_USBDEV_EP2_TXFIFO_SIZE
-# define CONFIG_USBDEV_EP2_TXFIFO_SIZE 192
-#endif
-
-#ifndef CONFIG_USBDEV_EP3_TXFIFO_SIZE
-# define CONFIG_USBDEV_EP3_TXFIFO_SIZE 192
-#endif
-
-#if (CONFIG_USBDEV_RXFIFO_SIZE + CONFIG_USBDEV_EP0_TXFIFO_SIZE + \
- CONFIG_USBDEV_EP2_TXFIFO_SIZE + CONFIG_USBDEV_EP3_TXFIFO_SIZE) > 1280
-# error "FIFO allocations exceed FIFO memory size"
-#endif
-
-/* The actual FIFO addresses that we use must be aligned to 4-byte boundaries;
- * FIFO sizes must be provided in units of 32-bit words.
- */
-
-#define STM32_RXFIFO_BYTES ((CONFIG_USBDEV_RXFIFO_SIZE + 3) & ~3)
-#define STM32_RXFIFO_WORDS ((CONFIG_USBDEV_RXFIFO_SIZE + 3) >> 2)
-
-#define STM32_EP0_TXFIFO_BYTES ((CONFIG_USBDEV_EP0_TXFIFO_SIZE + 3) & ~3)
-#define STM32_EP0_TXFIFO_WORDS ((CONFIG_USBDEV_EP0_TXFIFO_SIZE + 3) >> 2)
-
-#if STM32_EP0_TXFIFO_WORDS < 16 || STM32_EP0_TXFIFO_WORDS > 256
-# error "CONFIG_USBDEV_EP0_TXFIFO_SIZE is out of range"
-#endif
-
-#define STM32_EP1_TXFIFO_BYTES ((CONFIG_USBDEV_EP1_TXFIFO_SIZE + 3) & ~3)
-#define STM32_EP1_TXFIFO_WORDS ((CONFIG_USBDEV_EP1_TXFIFO_SIZE + 3) >> 2)
-
-#if STM32_EP1_TXFIFO_WORDS < 16
-# error "CONFIG_USBDEV_EP1_TXFIFO_SIZE is out of range"
-#endif
-
-#define STM32_EP2_TXFIFO_BYTES ((CONFIG_USBDEV_EP2_TXFIFO_SIZE + 3) & ~3)
-#define STM32_EP2_TXFIFO_WORDS ((CONFIG_USBDEV_EP2_TXFIFO_SIZE + 3) >> 2)
-
-#if STM32_EP2_TXFIFO_WORDS < 16
-# error "CONFIG_USBDEV_EP2_TXFIFO_SIZE is out of range"
-#endif
-
-#define STM32_EP3_TXFIFO_BYTES ((CONFIG_USBDEV_EP3_TXFIFO_SIZE + 3) & ~3)
-#define STM32_EP3_TXFIFO_WORDS ((CONFIG_USBDEV_EP3_TXFIFO_SIZE + 3) >> 2)
-
-#if STM32_EP3_TXFIFO_WORDS < 16
-# error "CONFIG_USBDEV_EP3_TXFIFO_SIZE is out of range"
-#endif
-
-/* Debug ***********************************************************************/
-/* Trace error codes */
-
-#define STM32_TRACEERR_ALLOCFAIL 0x01
-#define STM32_TRACEERR_BADCLEARFEATURE 0x02
-#define STM32_TRACEERR_BADDEVGETSTATUS 0x03
-#define STM32_TRACEERR_BADEPNO 0x04
-#define STM32_TRACEERR_BADEPGETSTATUS 0x05
-#define STM32_TRACEERR_BADGETCONFIG 0x06
-#define STM32_TRACEERR_BADGETSETDESC 0x07
-#define STM32_TRACEERR_BADGETSTATUS 0x08
-#define STM32_TRACEERR_BADSETADDRESS 0x09
-#define STM32_TRACEERR_BADSETCONFIG 0x0a
-#define STM32_TRACEERR_BADSETFEATURE 0x0b
-#define STM32_TRACEERR_BADTESTMODE 0x0c
-#define STM32_TRACEERR_BINDFAILED 0x0d
-#define STM32_TRACEERR_DISPATCHSTALL 0x0e
-#define STM32_TRACEERR_DRIVER 0x0f
-#define STM32_TRACEERR_DRIVERREGISTERED 0x10
-#define STM32_TRACEERR_EP0NOSETUP 0x11
-#define STM32_TRACEERR_EP0SETUPSTALLED 0x12
-#define STM32_TRACEERR_EPINNULLPACKET 0x13
-#define STM32_TRACEERR_EPOUTNULLPACKET 0x14
-#define STM32_TRACEERR_INVALIDCTRLREQ 0x15
-#define STM32_TRACEERR_INVALIDPARMS 0x16
-#define STM32_TRACEERR_IRQREGISTRATION 0x17
-#define STM32_TRACEERR_NOEP 0x18
-#define STM32_TRACEERR_NOTCONFIGURED 0x19
-#define STM32_TRACEERR_EPOUTQEMPTY 0x1a
-#define STM32_TRACEERR_EPINREQEMPTY 0x1b
-#define STM32_TRACEERR_NOOUTSETUP 0x1c
-#define STM32_TRACEERR_POLLTIMEOUT 0x1d
-
-/* Trace interrupt codes */
-
-#define STM32_TRACEINTID_USB 1 /* USB Interrupt entry/exit */
-#define STM32_TRACEINTID_INTPENDING 2 /* On each pass through the loop */
-
-#define STM32_TRACEINTID_EPOUT (10 + 0) /* First level interrupt decode */
-#define STM32_TRACEINTID_EPIN (10 + 1)
-#define STM32_TRACEINTID_MISMATCH (10 + 2)
-#define STM32_TRACEINTID_WAKEUP (10 + 3)
-#define STM32_TRACEINTID_SUSPEND (10 + 4)
-#define STM32_TRACEINTID_SOF (10 + 5)
-#define STM32_TRACEINTID_RXFIFO (10 + 6)
-#define STM32_TRACEINTID_DEVRESET (10 + 7)
-#define STM32_TRACEINTID_ENUMDNE (10 + 8)
-#define STM32_TRACEINTID_IISOIXFR (10 + 9)
-#define STM32_TRACEINTID_IISOOXFR (10 + 10)
-#define STM32_TRACEINTID_SRQ (10 + 11)
-#define STM32_TRACEINTID_OTG (10 + 12)
-
-#define STM32_TRACEINTID_EPOUT_XFRC (40 + 0) /* EPOUT second level decode */
-#define STM32_TRACEINTID_EPOUT_EPDISD (40 + 1)
-#define STM32_TRACEINTID_EPOUT_SETUP (40 + 2)
-#define STM32_TRACEINTID_DISPATCH (40 + 3)
-
-#define STM32_TRACEINTID_GETSTATUS (50 + 0) /* EPOUT third level decode */
-#define STM32_TRACEINTID_EPGETSTATUS (50 + 1)
-#define STM32_TRACEINTID_DEVGETSTATUS (50 + 2)
-#define STM32_TRACEINTID_IFGETSTATUS (50 + 3)
-#define STM32_TRACEINTID_CLEARFEATURE (50 + 4)
-#define STM32_TRACEINTID_SETFEATURE (50 + 5)
-#define STM32_TRACEINTID_SETADDRESS (50 + 6)
-#define STM32_TRACEINTID_GETSETDESC (50 + 7)
-#define STM32_TRACEINTID_GETCONFIG (50 + 8)
-#define STM32_TRACEINTID_SETCONFIG (50 + 9)
-#define STM32_TRACEINTID_GETSETIF (50 + 10)
-#define STM32_TRACEINTID_SYNCHFRAME (50 + 11)
-
-#define STM32_TRACEINTID_EPIN_XFRC (70 + 0) /* EPIN second level decode */
-#define STM32_TRACEINTID_EPIN_TOC (70 + 1)
-#define STM32_TRACEINTID_EPIN_ITTXFE (70 + 2)
-#define STM32_TRACEINTID_EPIN_EPDISD (70 + 3)
-#define STM32_TRACEINTID_EPIN_TXFE (70 + 4)
-
-#define STM32_TRACEINTID_EPIN_EMPWAIT (80 + 0) /* EPIN second level decode */
-
-#define STM32_TRACEINTID_OUTNAK (90 + 0) /* RXFLVL second level decode */
-#define STM32_TRACEINTID_OUTRECVD (90 + 1)
-#define STM32_TRACEINTID_OUTDONE (90 + 2)
-#define STM32_TRACEINTID_SETUPDONE (90 + 3)
-#define STM32_TRACEINTID_SETUPRECVD (90 + 4)
-
-/* Endpoints ******************************************************************/
-
-/* Number of endpoints */
-
-#define STM32_NENDPOINTS (4) /* ep0-3 x 2 for IN and OUT */
-
-/* Odd physical endpoint numbers are IN; even are OUT */
-
-#define STM32_EPPHYIN2LOG(epphy) ((uint8_t)(epphy)|USB_DIR_IN)
-#define STM32_EPPHYOUT2LOG(epphy) ((uint8_t)(epphy)|USB_DIR_OUT)
-
-/* Endpoint 0 */
-
-#define EP0 (0)
-
-/* The set of all enpoints available to the class implementation (1-3) */
-
-#define STM32_EP_AVAILABLE (0x0e) /* All available endpoints */
-
-/* Maximum packet sizes for full speed endpoints */
-
-#define STM32_MAXPACKET (64) /* Max packet size (1-64) */
-
-/* Delays **********************************************************************/
-
-#define STM32_READY_DELAY 200000
-#define STM32_FLUSH_DELAY 200000
-
-/* Request queue operations ****************************************************/
-
-#define stm32_rqempty(ep) ((ep)->head == NULL)
-#define stm32_rqpeek(ep) ((ep)->head)
-
-/* Standard stuff **************************************************************/
-
-#ifndef MIN
-# define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-#ifndef MAX
-# define MAX(a,b) ((a) > (b) ? (a) : (b))
-#endif
-
-/*******************************************************************************
- * Private Types
- *******************************************************************************/
-
-/* Overall device state */
-
-enum stm32_devstate_e
-{
- DEVSTATE_DEFAULT = 0, /* Power-up, unconfigured state. This state simply
- * means that the device is not yet been given an
- * address.
- * SET: At initialization, uninitialization,
- * reset, and whenever the device address
- * is set to zero
- * TESTED: Never
- */
- DEVSTATE_ADDRESSED, /* Device address has been assigned, not no
- * configuration has yet been selected.
- * SET: When either a non-zero device address
- * is first assigned or when the device
- * is unconfigured (with configuration == 0)
- * TESTED: never
- */
- DEVSTATE_CONFIGURED, /* Address assigned and configured:
- * SET: When the device has been addressed and
- * an non-zero configuration has been selected.
- * TESTED: In many places to assure that the USB device
- * has been properly configured by the host.
- */
-};
-
-/* Endpoint 0 states */
-
-enum stm32_ep0state_e
-{
- EP0STATE_IDLE = 0, /* Idle State, leave on receiving a SETUP packet or
- * epsubmit:
- * SET: In stm32_epin() and stm32_epout() when
- * we revert from request processing to
- * SETUP processing.
- * TESTED: Never
- */
- EP0STATE_SETUP_OUT, /* OUT SETUP packet received. Waiting for the DATA
- * OUT phase of SETUP Packet to complete before
- * processing a SETUP command (without a USB request):
- * SET: Set in stm32_rxinterrupt() when SETUP OUT
- * packet is received.
- * TESTED: In stm32_ep0out_receive()
- */
- EP0STATE_SETUP_READY, /* IN SETUP packet received -OR- OUT SETUP packet and
- * accompanying data have been received. Processing
- * of SETUP command will happen soon.
- * SET: (1) stm32_ep0out_receive() when the OUT
- * SETUP data phase completes, or (2)
- * stm32_rxinterrupt() when an IN SETUP is
- * packet received.
- * TESTED: Tested in stm32_epout_interrupt() when
- * SETUP phase is done to see if the SETUP
- * command is ready to be processed. Also
- * tested in stm32_ep0out_setup() just to
- * double-check that we have a SETUP request
- * and any accompanying data.
- */
- EP0STATE_SETUP_PROCESS, /* SETUP Packet is being processed by stm32_ep0out_setup():
- * SET: When SETUP packet received in EP0 OUT
- * TESTED: Never
- */
- EP0STATE_SETUPRESPONSE, /* Short SETUP response write (without a USB request):
- * SET: When SETUP response is sent by
- * stm32_ep0in_setupresponse()
- * TESTED: Never
- */
- EP0STATE_DATA_IN, /* Waiting for data out stage (with a USB request):
- * SET: In stm32_epin_request() when a write
- * request is processed on EP0.
- * TESTED: In stm32_epin() to see if we should
- * revert to SETUP processing.
- */
- EP0STATE_DATA_OUT /* Waiting for data in phase to complete ( with a
- * USB request)
- * SET: In stm32_epout_request() when a read
- * request is processed on EP0.
- * TESTED: In stm32_epout() to see if we should
- * revert to SETUP processing
- */
-};
-
-/* Parsed control request */
-
-struct stm32_ctrlreq_s
-{
- uint8_t type;
- uint8_t req;
- uint16_t value;
- uint16_t index;
- uint16_t len;
-};
-
-/* A container for a request so that the request may be retained in a list */
-
-struct stm32_req_s
-{
- struct usbdev_req_s req; /* Standard USB request */
- struct stm32_req_s *flink; /* Supports a singly linked list */
-};
-
-/* This is the internal representation of an endpoint */
-
-struct stm32_ep_s
-{
- /* Common endpoint fields. This must be the first thing defined in the
- * structure so that it is possible to simply cast from struct usbdev_ep_s
- * to struct stm32_ep_s.
- */
-
- struct usbdev_ep_s ep; /* Standard endpoint structure */
-
- /* STM32-specific fields */
-
- struct stm32_usbdev_s *dev; /* Reference to private driver data */
- struct stm32_req_s *head; /* Request list for this endpoint */
- struct stm32_req_s *tail;
- uint8_t epphy; /* Physical EP address */
- uint8_t eptype:2; /* Endpoint type */
- 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 */
- uint8_t odd:1; /* 1: Odd frame */
- uint8_t zlp:1; /* 1: Transmit a zero-length-packet (IN EPs only) */
-};
-
-/* This structure retains the state of the USB device controller */
-
-struct stm32_usbdev_s
-{
- /* Common device fields. This must be the first thing defined in the
- * structure so that it is possible to simply cast from struct usbdev_s
- * to struct stm32_usbdev_s.
- */
-
- struct usbdev_s usbdev;
-
- /* The bound device class driver */
-
- struct usbdevclass_driver_s *driver;
-
- /* STM32-specific fields */
-
- uint8_t stalled:1; /* 1: Protocol stalled */
- uint8_t selfpowered:1; /* 1: Device is self powered */
- 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:4; /* See enum stm32_devstate_e */
- uint8_t ep0state:4; /* See enum stm32_ep0state_e */
- uint8_t testmode:4; /* Selected test mode */
- uint8_t epavail:4; /* Bitset of available endpoints */
-
- /* E0 SETUP data buffering.
- *
- * ctrlreq:
- * 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 pack receipt logic will save
- * the accompanying EP0 IN data in ep0data[] before the SETUP command is
- * processed.
- *
- * For IN SETUP requests, the DATA phase will occurr AFTER the SETUP
- * control request is processed. In that case, ep0data[] may be used as
- * the response buffer.
- *
- * ep0datlen
- * Lenght of OUT DATA received in ep0data[] (Not used with OUT data)
- */
-
- struct usb_ctrlreq_s ctrlreq;
- uint8_t ep0data[CONFIG_USBDEV_SETUP_MAXDATASIZE];
- uint16_t ep0datlen;
-
- /* The endpoint lists */
-
- struct stm32_ep_s epin[STM32_NENDPOINTS];
- struct stm32_ep_s epout[STM32_NENDPOINTS];
-};
-
-/*******************************************************************************
- * Private Function Prototypes
- *******************************************************************************/
-
-/* Register operations ********************************************************/
-
-#if defined(CONFIG_STM32_USBDEV_REGDEBUG) && defined(CONFIG_DEBUG)
-static uint32_t stm32_getreg(uint32_t addr);
-static void stm32_putreg(uint32_t val, uint32_t addr);
-#else
-# define stm32_getreg(addr) getreg32(addr)
-# define stm32_putreg(val,addr) putreg32(val,addr)
-#endif
-
-/* Request queue operations ****************************************************/
-
-static FAR struct stm32_req_s *stm32_req_remfirst(FAR struct stm32_ep_s *privep);
-static bool stm32_req_addlast(FAR struct stm32_ep_s *privep,
- FAR struct stm32_req_s *req);
-
-/* Low level data transfers and request operations *****************************/
-/* Special endpoint 0 data transfer logic */
-
-static void stm32_ep0in_setupresponse(FAR struct stm32_usbdev_s *priv,
- FAR uint8_t *data, uint32_t nbytes);
-static inline void stm32_ep0in_transmitzlp(FAR struct stm32_usbdev_s *priv);
-static void stm32_ep0in_activate(void);
-
-static void stm32_ep0out_ctrlsetup(FAR struct stm32_usbdev_s *priv);
-
-/* IN request and TxFIFO handling */
-
-static void stm32_txfifo_write(FAR struct stm32_ep_s *privep,
- FAR uint8_t *buf, int nbytes);
-static void stm32_epin_transfer(FAR struct stm32_ep_s *privep,
- FAR uint8_t *buf, int nbytes);
-static void stm32_epin_request(FAR struct stm32_usbdev_s *priv,
- FAR struct stm32_ep_s *privep);
-
-/* OUT request and RxFIFO handling */
-
-static void stm32_rxfifo_read(FAR struct stm32_ep_s *privep,
- FAR uint8_t *dest, uint16_t len);
-static void stm32_rxfifo_discard(FAR struct stm32_ep_s *privep, int len);
-static void stm32_epout_complete(FAR struct stm32_usbdev_s *priv,
- FAR struct stm32_ep_s *privep);
-static inline void stm32_ep0out_receive(FAR struct stm32_ep_s *privep, int bcnt);
-static inline void stm32_epout_receive(FAR struct stm32_ep_s *privep, int bcnt);
-static void stm32_epout_request(FAR struct stm32_usbdev_s *priv,
- FAR struct stm32_ep_s *privep);
-
-/* General request handling */
-
-static void stm32_ep_flush(FAR struct stm32_ep_s *privep);
-static void stm32_req_complete(FAR struct stm32_ep_s *privep,
- int16_t result);
-static void stm32_req_cancel(FAR struct stm32_ep_s *privep,
- int16_t status);
-
-/* Interrupt handling **********************************************************/
-
-static struct stm32_ep_s *stm32_ep_findbyaddr(struct stm32_usbdev_s *priv,
- uint16_t eplog);
-static int stm32_req_dispatch(FAR struct stm32_usbdev_s *priv,
- FAR const struct usb_ctrlreq_s *ctrl);
-static void stm32_usbreset(FAR struct stm32_usbdev_s *priv);
-
-/* Second level OUT endpoint interrupt processing */
-
-static inline void stm32_ep0out_testmode(FAR struct stm32_usbdev_s *priv,
- uint16_t index);
-static inline void stm32_ep0out_stdrequest(struct stm32_usbdev_s *priv,
- FAR struct stm32_ctrlreq_s *ctrlreq);
-static inline void stm32_ep0out_setup(struct stm32_usbdev_s *priv);
-static inline void stm32_epout(FAR struct stm32_usbdev_s *priv,
- uint8_t epno);
-static inline void stm32_epout_interrupt(FAR struct stm32_usbdev_s *priv);
-
-/* Second level IN endpoint interrupt processing */
-
-static inline void stm32_epin_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_epin_txfifoempty(FAR struct stm32_usbdev_s *priv, int epno);
-static inline void stm32_epin_interrupt(FAR struct stm32_usbdev_s *priv);
-
-/* Other second level interrupt processing */
-
-static inline void stm32_resumeinterrupt(FAR struct stm32_usbdev_s *priv);
-static inline void stm32_suspendinterrupt(FAR struct stm32_usbdev_s *priv);
-static inline void stm32_rxinterrupt(FAR struct stm32_usbdev_s *priv);
-static inline void stm32_enuminterrupt(FAR struct stm32_usbdev_s *priv);
-#ifdef CONFIG_USBDEV_ISOCHRONOUS
-static inline void stm32_isocininterrupt(FAR struct stm32_usbdev_s *priv);
-static inline void stm32_isocoutinterrupt(FAR struct stm32_usbdev_s *priv);
-#endif
-#ifdef CONFIG_USBDEV_VBUSSENSING
-static inline void stm32_sessioninterrupt(FAR struct stm32_usbdev_s *priv);
-static inline void stm32_otginterrupt(FAR struct stm32_usbdev_s *priv);
-#endif
-
-/* First level interrupt processing */
-
-static int stm32_usbinterrupt(int irq, FAR void *context);
-
-/* Endpoint operations *********************************************************/
-/* Global OUT NAK controls */
-
-static void stm32_enablegonak(FAR struct stm32_ep_s *privep);
-static void stm32_disablegonak(FAR struct stm32_ep_s *privep);
-
-/* Endpoint configuration */
-
-static int stm32_epout_configure(FAR struct stm32_ep_s *privep,
- uint8_t eptype, uint16_t maxpacket);
-static int stm32_epin_configure(FAR struct stm32_ep_s *privep,
- uint8_t eptype, uint16_t maxpacket);
-static int stm32_ep_configure(FAR struct usbdev_ep_s *ep,
- FAR const struct usb_epdesc_s *desc, bool last);
-static void stm32_ep0_configure(FAR struct stm32_usbdev_s *priv);
-
-/* Endpoint disable */
-
-static void stm32_epout_disable(FAR struct stm32_ep_s *privep);
-static void stm32_epin_disable(FAR struct stm32_ep_s *privep);
-static int stm32_ep_disable(FAR struct usbdev_ep_s *ep);
-
-/* Endpoint request management */
-
-static FAR struct usbdev_req_s *stm32_ep_allocreq(FAR struct usbdev_ep_s *ep);
-static void stm32_ep_freereq(FAR struct usbdev_ep_s *ep,
- FAR struct usbdev_req_s *);
-
-/* Endpoint buffer management */
-
-#ifdef CONFIG_USBDEV_DMA
-static void *stm32_ep_allocbuffer(FAR struct usbdev_ep_s *ep, unsigned bytes);
-static void stm32_ep_freebuffer(FAR struct usbdev_ep_s *ep, FAR void *buf);
-#endif
-
-/* Endpoint request submission */
-
-static int stm32_ep_submit(FAR struct usbdev_ep_s *ep,
- struct usbdev_req_s *req);
-
-/* Endpoint request cancellation */
-
-static int stm32_ep_cancel(FAR struct usbdev_ep_s *ep,
- struct usbdev_req_s *req);
-
-/* Stall handling */
-
-static int stm32_epout_setstall(FAR struct stm32_ep_s *privep);
-static int stm32_epin_setstall(FAR struct stm32_ep_s *privep);
-static int stm32_ep_setstall(FAR struct stm32_ep_s *privep);
-static int stm32_ep_clrstall(FAR struct stm32_ep_s *privep);
-static int stm32_ep_stall(FAR struct usbdev_ep_s *ep, bool resume);
-static void stm32_ep0_stall(FAR struct stm32_usbdev_s *priv);
-
-/* Endpoint allocation */
-
-static FAR struct usbdev_ep_s *stm32_ep_alloc(FAR struct usbdev_s *dev,
- uint8_t epno, bool in, uint8_t eptype);
-static void stm32_ep_free(FAR struct usbdev_s *dev,
- FAR struct usbdev_ep_s *ep);
-
-/* USB device controller operations ********************************************/
-
-static int stm32_getframe(struct usbdev_s *dev);
-static int stm32_wakeup(struct usbdev_s *dev);
-static int stm32_selfpowered(struct usbdev_s *dev, bool selfpowered);
-static int stm32_pullup(struct usbdev_s *dev, bool enable);
-static void stm32_setaddress(struct stm32_usbdev_s *priv,
- uint16_t address);
-static int stm32_txfifo_flush(uint32_t txfnum);
-static int stm32_rxfifo_flush(void);
-
-/* Initialization **************************************************************/
-
-static void stm32_swinitialize(FAR struct stm32_usbdev_s *priv);
-static void stm32_hwinitialize(FAR struct stm32_usbdev_s *priv);
-
-/*******************************************************************************
- * Private Data
- *******************************************************************************/
-/* Since there is only a single USB interface, all status information can be
- * be simply retained in a single global instance.
- */
-
-static struct stm32_usbdev_s g_otgfsdev;
-
-static const struct usbdev_epops_s g_epops =
-{
- .configure = stm32_ep_configure,
- .disable = stm32_ep_disable,
- .allocreq = stm32_ep_allocreq,
- .freereq = stm32_ep_freereq,
-#ifdef CONFIG_USBDEV_DMA
- .allocbuffer = stm32_ep_allocbuffer,
- .freebuffer = stm32_ep_freebuffer,
-#endif
- .submit = stm32_ep_submit,
- .cancel = stm32_ep_cancel,
- .stall = stm32_ep_stall,
-};
-
-static const struct usbdev_ops_s g_devops =
-{
- .allocep = stm32_ep_alloc,
- .freeep = stm32_ep_free,
- .getframe = stm32_getframe,
- .wakeup = stm32_wakeup,
- .selfpowered = stm32_selfpowered,
- .pullup = stm32_pullup,
-};
-
-/* Device error strings that may be enabled for more desciptive USB trace
- * output.
- */
-
-#ifdef CONFIG_USBDEV_TRACE_STRINGS
-const struct trace_msg_t g_usb_trace_strings_deverror[] =
-{
- TRACE_STR(STM32_TRACEERR_ALLOCFAIL ),
- TRACE_STR(STM32_TRACEERR_BADCLEARFEATURE ),
- TRACE_STR(STM32_TRACEERR_BADDEVGETSTATUS ),
- TRACE_STR(STM32_TRACEERR_BADEPNO ),
- TRACE_STR(STM32_TRACEERR_BADEPGETSTATUS ),
- TRACE_STR(STM32_TRACEERR_BADGETCONFIG ),
- TRACE_STR(STM32_TRACEERR_BADGETSETDESC ),
- TRACE_STR(STM32_TRACEERR_BADGETSTATUS ),
- TRACE_STR(STM32_TRACEERR_BADSETADDRESS ),
- TRACE_STR(STM32_TRACEERR_BADSETCONFIG ),
- TRACE_STR(STM32_TRACEERR_BADSETFEATURE ),
- TRACE_STR(STM32_TRACEERR_BADTESTMODE ),
- TRACE_STR(STM32_TRACEERR_BINDFAILED ),
- TRACE_STR(STM32_TRACEERR_DISPATCHSTALL ),
- TRACE_STR(STM32_TRACEERR_DRIVER ),
- TRACE_STR(STM32_TRACEERR_DRIVERREGISTERED),
- TRACE_STR(STM32_TRACEERR_EP0NOSETUP ),
- TRACE_STR(STM32_TRACEERR_EP0SETUPSTALLED ),
- TRACE_STR(STM32_TRACEERR_EPINNULLPACKET ),
- TRACE_STR(STM32_TRACEERR_EPOUTNULLPACKET ),
- TRACE_STR(STM32_TRACEERR_INVALIDCTRLREQ ),
- TRACE_STR(STM32_TRACEERR_INVALIDPARMS ),
- TRACE_STR(STM32_TRACEERR_IRQREGISTRATION ),
- TRACE_STR(STM32_TRACEERR_NOEP ),
- TRACE_STR(STM32_TRACEERR_NOTCONFIGURED ),
- TRACE_STR(STM32_TRACEERR_EPOUTQEMPTY ),
- TRACE_STR(STM32_TRACEERR_EPINREQEMPTY ),
- TRACE_STR(STM32_TRACEERR_NOOUTSETUP ),
- TRACE_STR(STM32_TRACEERR_POLLTIMEOUT ),
- TRACE_STR_END
-};
-#endif
-
-/* Interrupt event strings that may be enabled for more desciptive USB trace
- * output.
- */
-
-#ifdef CONFIG_USBDEV_TRACE_STRINGS
-const struct trace_msg_t g_usb_trace_strings_intdecode[] =
-{
- TRACE_STR(STM32_TRACEINTID_USB ),
- TRACE_STR(STM32_TRACEINTID_INTPENDING ),
- TRACE_STR(STM32_TRACEINTID_EPOUT ),
- TRACE_STR(STM32_TRACEINTID_EPIN ),
- TRACE_STR(STM32_TRACEINTID_MISMATCH ),
- TRACE_STR(STM32_TRACEINTID_WAKEUP ),
- TRACE_STR(STM32_TRACEINTID_SUSPEND ),
- TRACE_STR(STM32_TRACEINTID_SOF ),
- TRACE_STR(STM32_TRACEINTID_RXFIFO ),
- TRACE_STR(STM32_TRACEINTID_DEVRESET ),
- TRACE_STR(STM32_TRACEINTID_ENUMDNE ),
- TRACE_STR(STM32_TRACEINTID_IISOIXFR ),
- TRACE_STR(STM32_TRACEINTID_IISOOXFR ),
- TRACE_STR(STM32_TRACEINTID_SRQ ),
- TRACE_STR(STM32_TRACEINTID_OTG ),
- TRACE_STR(STM32_TRACEINTID_EPOUT_XFRC ),
- TRACE_STR(STM32_TRACEINTID_EPOUT_EPDISD),
- TRACE_STR(STM32_TRACEINTID_EPOUT_SETUP ),
- TRACE_STR(STM32_TRACEINTID_DISPATCH ),
- TRACE_STR(STM32_TRACEINTID_GETSTATUS ),
- TRACE_STR(STM32_TRACEINTID_EPGETSTATUS ),
- TRACE_STR(STM32_TRACEINTID_DEVGETSTATUS),
- TRACE_STR(STM32_TRACEINTID_IFGETSTATUS ),
- TRACE_STR(STM32_TRACEINTID_CLEARFEATURE),
- TRACE_STR(STM32_TRACEINTID_SETFEATURE ),
- TRACE_STR(STM32_TRACEINTID_SETADDRESS ),
- TRACE_STR(STM32_TRACEINTID_GETSETDESC ),
- TRACE_STR(STM32_TRACEINTID_GETCONFIG ),
- TRACE_STR(STM32_TRACEINTID_SETCONFIG ),
- TRACE_STR(STM32_TRACEINTID_GETSETIF ),
- TRACE_STR(STM32_TRACEINTID_SYNCHFRAME ),
- TRACE_STR(STM32_TRACEINTID_EPIN_XFRC ),
- TRACE_STR(STM32_TRACEINTID_EPIN_TOC ),
- TRACE_STR(STM32_TRACEINTID_EPIN_ITTXFE ),
- TRACE_STR(STM32_TRACEINTID_EPIN_EPDISD ),
- TRACE_STR(STM32_TRACEINTID_EPIN_TXFE ),
- TRACE_STR(STM32_TRACEINTID_EPIN_EMPWAIT),
- TRACE_STR(STM32_TRACEINTID_OUTNAK ),
- TRACE_STR(STM32_TRACEINTID_OUTRECVD ),
- TRACE_STR(STM32_TRACEINTID_OUTDONE ),
- TRACE_STR(STM32_TRACEINTID_SETUPDONE ),
- TRACE_STR(STM32_TRACEINTID_SETUPRECVD ),
- TRACE_STR_END
-};
-#endif
-
-/*******************************************************************************
- * Public Data
- *******************************************************************************/
-
-/*******************************************************************************
- * Private Functions
- *******************************************************************************/
-
-/*******************************************************************************
- * Name: stm32_getreg
- *
- * Description:
- * Get the contents of an STM32 register
- *
- *******************************************************************************/
-
-#if defined(CONFIG_STM32_USBDEV_REGDEBUG) && defined(CONFIG_DEBUG)
-static uint32_t stm32_getreg(uint32_t addr)
-{
- static uint32_t prevaddr = 0;
- static uint32_t preval = 0;
- static uint32_t count = 0;
-
- /* Read the value from the register */
-
- uint32_t val = getreg32(addr);
-
- /* Is this the same value that we read from the same registe last time? Are
- * we polling the register? If so, suppress some of the output.
- */
-
- if (addr == prevaddr && val == preval)
- {
- if (count == 0xffffffff || ++count > 3)
- {
- if (count == 4)
- {
- lldbg("...\n");
- }
- return val;
- }
- }
-
- /* No this is a new address or value */
-
- else
- {
- /* Did we print "..." for the previous value? */
-
- if (count > 3)
- {
- /* Yes.. then show how many times the value repeated */
-
- lldbg("[repeats %d more times]\n", count-3);
- }
-
- /* Save the new address, value, and count */
-
- prevaddr = addr;
- preval = val;
- count = 1;
- }
-
- /* Show the register value read */
-
- lldbg("%08x->%08x\n", addr, val);
- return val;
-}
-#endif
-
-/*******************************************************************************
- * Name: stm32_putreg
- *
- * Description:
- * Set the contents of an STM32 register to a value
- *
- *******************************************************************************/
-
-#if defined(CONFIG_STM32_USBDEV_REGDEBUG) && defined(CONFIG_DEBUG)
-static void stm32_putreg(uint32_t val, uint32_t addr)
-{
- /* Show the register value being written */
-
- lldbg("%08x<-%08x\n", addr, val);
-
- /* Write the value */
-
- putreg32(val, addr);
-}
-#endif
-
-/*******************************************************************************
- * Name: stm32_req_remfirst
- *
- * Description:
- * Remove a request from the head of an endpoint request queue
- *
- *******************************************************************************/
-
-static FAR struct stm32_req_s *stm32_req_remfirst(FAR struct stm32_ep_s *privep)
-{
- FAR struct stm32_req_s *ret = privep->head;
-
- if (ret)
- {
- privep->head = ret->flink;
- if (!privep->head)
- {
- privep->tail = NULL;
- }
-
- ret->flink = NULL;
- }
-
- return ret;
-}
-
-/*******************************************************************************
- * Name: stm32_req_addlast
- *
- * Description:
- * Add a request to the end of an endpoint request queue
- *
- *******************************************************************************/
-
-static bool stm32_req_addlast(FAR struct stm32_ep_s *privep,
- FAR struct stm32_req_s *req)
-{
- bool is_empty = !privep->head;
-
- req->flink = NULL;
- if (is_empty)
- {
- privep->head = req;
- privep->tail = req;
- }
- else
- {
- privep->tail->flink = req;
- privep->tail = req;
- }
- return is_empty;
-}
-
-/*******************************************************************************
- * Name: stm32_ep0in_setupresponse
- *
- * Description:
- * Schedule a short transfer on Endpoint 0 (IN or OUT)
- *
- *******************************************************************************/
-
-static void stm32_ep0in_setupresponse(FAR struct stm32_usbdev_s *priv,
- FAR uint8_t *buf, uint32_t nbytes)
-{
- stm32_epin_transfer(&priv->epin[EP0], buf, nbytes);
- priv->ep0state = EP0STATE_SETUPRESPONSE;
- stm32_ep0out_ctrlsetup(priv);
-}
-
-/****************************************************************************
- * Name: stm32_ep0in_transmitzlp
- *
- * Description:
- * Send a zero length packet (ZLP) on endpoint 0 IN
- *
- ****************************************************************************/
-
-static inline void stm32_ep0in_transmitzlp(FAR struct stm32_usbdev_s *priv)
-{
- stm32_ep0in_setupresponse(priv, NULL, 0);
-}
-
-/*******************************************************************************
- * Name: stm32_ep0in_activate
- *
- * Description:
- * Activate the endpoint 0 IN endpoint.
- *
- *******************************************************************************/
-
-static void stm32_ep0in_activate(void)
-{
- uint32_t regval;
-
- /* Set the max packet size of the IN EP. */
-
- regval = stm32_getreg(STM32_OTGFS_DIEPCTL0);
- regval &= ~OTGFS_DIEPCTL0_MPSIZ_MASK;
-
-#if CONFIG_USBDEV_EP0_MAXSIZE == 8
- regval |= OTGFS_DIEPCTL0_MPSIZ_8;
-#elif CONFIG_USBDEV_EP0_MAXSIZE == 16
- regval |= OTGFS_DIEPCTL0_MPSIZ_16;
-#elif CONFIG_USBDEV_EP0_MAXSIZE == 32
- regval |= OTGFS_DIEPCTL0_MPSIZ_32;
-#elif CONFIG_USBDEV_EP0_MAXSIZE == 64
- regval |= OTGFS_DIEPCTL0_MPSIZ_64;
-#else
-# error "Unsupported value of CONFIG_USBDEV_EP0_MAXSIZE"
-#endif
-
- stm32_putreg(regval, STM32_OTGFS_DIEPCTL0);
-
- /* Clear global IN NAK */
-
- regval = stm32_getreg(STM32_OTGFS_DCTL);
- regval |= OTGFS_DCTL_CGINAK;
- stm32_putreg(regval, STM32_OTGFS_DCTL);
-}
-
-/*******************************************************************************
- * Name: stm32_ep0out_ctrlsetup
- *
- * Description:
- * Setup to receive a SETUP packet.
- *
- *******************************************************************************/
-
-static void stm32_ep0out_ctrlsetup(FAR struct stm32_usbdev_s *priv)
-{
- uint32_t regval;
-
- /* Setup the hardware to perform the SETUP transfer */
-
- regval = (USB_SIZEOF_CTRLREQ * 3 << OTGFS_DOEPTSIZ0_XFRSIZ_SHIFT) |
- (OTGFS_DOEPTSIZ0_PKTCNT) |
- (3 << OTGFS_DOEPTSIZ0_STUPCNT_SHIFT);
- stm32_putreg(regval, STM32_OTGFS_DOEPTSIZ0);
-
- /* Then clear NAKing and enable the transfer */
-
- regval = stm32_getreg(STM32_OTGFS_DOEPCTL0);
- regval |= (OTGFS_DOEPCTL0_CNAK | OTGFS_DOEPCTL0_EPENA);
- stm32_putreg(regval, STM32_OTGFS_DOEPCTL0);
-}
-
-/****************************************************************************
- * Name: stm32_txfifo_write
- *
- * Description:
- * Send data to the endpoint's TxFIFO.
- *
- ****************************************************************************/
-
-static void stm32_txfifo_write(FAR struct stm32_ep_s *privep,
- FAR uint8_t *buf, int nbytes)
-{
- uint32_t regaddr;
- uint32_t regval;
- int nwords;
- int i;
-
- /* Convert the number of bytes to words */
-
- nwords = (nbytes + 3) >> 2;
-
- /* Get the TxFIFO for this endpoint (same as the endpoint number) */
-
- regaddr = STM32_OTGFS_DFIFO_DEP(privep->epphy);
-
- /* Then transfer each word to the TxFIFO */
-
- for (i = 0; i < nwords; i++)
- {
- /* Read four bytes from the source buffer (to avoid unaligned accesses)
- * and pack these into one 32-bit word (little endian).
- */
-
- regval = (uint32_t)*buf++;
- regval |= ((uint32_t)*buf++) << 8;
- regval |= ((uint32_t)*buf++) << 16;
- regval |= ((uint32_t)*buf++) << 24;
-
- /* Then write the packet data to the TxFIFO */
-
- stm32_putreg(regval, regaddr);
- }
-}
-
-/****************************************************************************
- * Name: stm32_epin_transfer
- *
- * Description:
- * Start the Tx data transfer
- *
- ****************************************************************************/
-
-static void stm32_epin_transfer(FAR struct stm32_ep_s *privep,
- FAR uint8_t *buf, int nbytes)
-{
- uint32_t pktcnt;
- uint32_t regval;
-
- /* Read the DIEPSIZx register */
-
- regval = stm32_getreg(STM32_OTGFS_DIEPTSIZ(privep->epphy));
-
- /* Clear the XFRSIZ, PKTCNT, and MCNT field of the DIEPSIZx register */
-
- regval &= ~(OTGFS_DIEPTSIZ_XFRSIZ_MASK | OTGFS_DIEPTSIZ_PKTCNT_MASK |
- OTGFS_DIEPTSIZ_MCNT_MASK);
-
- /* Are we sending a zero length packet (ZLP) */
-
- if (nbytes == 0)
- {
- /* Yes.. leave the transfer size at zero and set the packet count to 1 */
-
- pktcnt = 1;
- }
- else
- {
- /* No.. Program the transfer size and packet count . First calculate:
- *
- * xfrsize = The total number of bytes to be sent.
- * pktcnt = the number of packets (of maxpacket bytes) required to
- * perform the transfer.
- */
-
- pktcnt = ((uint32_t)nbytes + (privep->ep.maxpacket - 1)) / privep->ep.maxpacket;
- }
-
- /* Set the XFRSIZ and PKTCNT */
-
- regval |= (pktcnt << OTGFS_DIEPTSIZ_PKTCNT_SHIFT);
- regval |= ((uint32_t)nbytes << OTGFS_DIEPTSIZ_XFRSIZ_SHIFT);
-
- /* If this is an isconchronous endpoint, then set the multi-count field to
- * the PKTCNT as well.
- */
-
- if (privep->eptype == USB_EP_ATTR_XFER_ISOC)
- {
- regval |= (pktcnt << OTGFS_DIEPTSIZ_MCNT_SHIFT);
- }
-
- /* Save DIEPSIZx register value */
-
- stm32_putreg(regval, STM32_OTGFS_DIEPTSIZ(privep->epphy));
-
- /* Read the DIEPCTLx register */
-
- regval = stm32_getreg(STM32_OTGFS_DIEPCTL(privep->epphy));
-
- /* If this is an isochronous endpoint, then set the even/odd frame bit
- * the DIEPCTLx register.
- */
-
- if (privep->eptype == USB_EP_ATTR_XFER_ISOC)
- {
- /* Check bit 0 of the frame number of the received SOF and set the
- * even/odd frame to match.
- */
-
- uint32_t status = stm32_getreg(STM32_OTGFS_DSTS);
- if ((status & OTGFS_DSTS_SOFFN0) == OTGFS_DSTS_SOFFN_EVEN)
- {
- regval |= OTGFS_DIEPCTL_SEVNFRM;
- }
- else
- {
- regval |= OTGFS_DIEPCTL_SODDFRM;
- }
- }
-
- /* EP enable, IN data in FIFO */
-
- regval &= ~OTGFS_DIEPCTL_EPDIS;
- regval |= (OTGFS_DIEPCTL_CNAK | OTGFS_DIEPCTL_EPENA);
- stm32_putreg(regval, STM32_OTGFS_DIEPCTL(privep->epphy));
-
- /* Transfer the data to the TxFIFO. At this point, the caller has already
- * assured that there is sufficient space in the TxFIFO to hold the transfer
- * we can just blindly continue.
- */
-
- stm32_txfifo_write(privep, buf, nbytes);
-}
-
-/****************************************************************************
- * Name: stm32_epin_request
- *
- * Description:
- * Begin or continue write request processing.
- *
- ****************************************************************************/
-
-static void stm32_epin_request(FAR struct stm32_usbdev_s *priv,
- FAR struct stm32_ep_s *privep)
-{
- struct stm32_req_s *privreq;
- uint32_t regaddr;
- uint32_t regval;
- uint8_t *buf;
- int nbytes;
- int nwords;
- int bytesleft;
-
- /* We get here in one of four possible ways. From three interrupting
- * events:
- *
- * 1. From stm32_epin as part of the transfer complete interrupt processing
- * This interrupt indicates that the last transfer has completed.
- * 2. As part of the ITTXFE interrupt processing. That interrupt indicates
- * that an IN token was received when the associated TxFIFO was empty.
- * 3. From stm32_epin_txfifoempty as part of the TXFE interrupt processing.
- * The TXFE interrupt is only enabled when the TxFIFO is full and the
- * software must wait for space to become available in the TxFIFO.
- *
- * And this function may be called immediately when the write request is
- * queue to start up the next transaction.
- *
- * 4. From stm32_ep_submit when a new write request is received WHILE the
- * endpoint is not active (privep->active == false).
- */
-
- /* Check the request from the head of the endpoint request queue */
-
- privreq = stm32_rqpeek(privep);
- if (!privreq)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_EPINREQEMPTY), privep->epphy);
-
- /* There is no TX transfer in progress and no new pending TX
- * requests to send. To stop transmitting any data on a particular
- * IN endpoint, the application must set the IN NAK bit. To set this
- * bit, the following field must be programmed.
- */
-
- regaddr = STM32_OTGFS_DIEPCTL(privep->epphy);
- regval = stm32_getreg(regaddr);
- regval |= OTGFS_DIEPCTL_SNAK;
- stm32_putreg(regval, regaddr);
-
- /* The endpoint is no longer active */
-
- privep->active = false;
- return;
- }
-
- ullvdbg("EP%d req=%p: len=%d xfrd=%d zlp=%d\n",
- privep->epphy, privreq, privreq->req.len,
- privreq->req.xfrd, privep->zlp);
-
- /* Check for a special case: If we are just starting a request (xfrd==0) and
- * the class driver is trying to send a zero-length packet (len==0). Then set
- * the ZLP flag so that the packet will be sent.
- */
-
- if (privreq->req.len == 0)
- {
- /* The ZLP flag is set TRUE whenever we want to force the driver to
- * send a zero-length-packet on the next pass through the loop (below).
- * The flag is cleared whenever a packet is sent in the loop below.
- */
-
- privep->zlp = true;
- }
-
- /* Add one more packet to the TxFIFO. We will wait for the transfer
- * complete event before we add the next packet (or part of a packet
- * to the TxFIFO).
- *
- * The documentation says that we can can multiple packets to the TxFIFO,
- * but it seems that we need to get the transfer complete event before
- * we can add the next (or maybe I have got something wrong?)
- */
-
-#if 0
- while (privreq->req.xfrd < privreq->req.len || privep->zlp)
-#else
- if (privreq->req.xfrd < privreq->req.len || privep->zlp)
-#endif
- {
- /* Get the number of bytes left to be sent in the request */
-
- bytesleft = privreq->req.len - privreq->req.xfrd;
- nbytes = bytesleft;
-
- /* Assume no zero-length-packet on the next pass through this loop */
-
- privep->zlp = false;
-
- /* Limit the size of the transfer to one full packet and handle
- * zero-length packets (ZLPs).
- */
-
- if (nbytes > 0)
- {
- /* Either send the maxpacketsize or all of the remaining data in
- * the request.
- */
-
- if (nbytes >= privep->ep.maxpacket)
- {
- nbytes = privep->ep.maxpacket;
-
- /* Handle the case where this packet is exactly the
- * maxpacketsize. Do we need to send a zero-length packet
- * in this case?
- */
-
- if (bytesleft == privep->ep.maxpacket &&
- (privreq->req.flags & USBDEV_REQFLAGS_NULLPKT) != 0)
- {
- /* The ZLP flag is set TRUE whenever we want to force
- * the driver to send a zero-length-packet on the next
- * pass through this loop. The flag is cleared (above)
- * whenever we are committed to sending any packet and
- * set here when we want to force one more pass through
- * the loop.
- */
-
- privep->zlp = true;
- }
- }
- }
-
- /* Get the transfer size in 32-bit words */
-
- nwords = (nbytes + 3) >> 2;
-
- /* Get the number of 32-bit words available in the TxFIFO. The
- * DXTFSTS indicates the amount of free space available in the
- * endpoint TxFIFO. Values are in terms of 32-bit words:
- *
- * 0: Endpoint TxFIFO is full
- * 1: 1 word available
- * 2: 2 words available
- * n: n words available
- */
-
- regaddr = STM32_OTGFS_DTXFSTS(privep->epphy);
-
- /* Check for space in the TxFIFO. If space in the TxFIFO is not
- * available, then set up an interrupt to resume the transfer when
- * the TxFIFO is empty.
- */
-
- regval = stm32_getreg(regaddr);
- if ((regval & OTGFS_DTXFSTS_MASK) < nwords)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPIN_EMPWAIT), (uint16_t)regval);
-
- /* There is insufficent space in the TxFIFO. Wait for a TxFIFO
- * empty interrupt and try again.
- */
-
- uint32_t empmsk = stm32_getreg(STM32_OTGFS_DIEPEMPMSK);
- empmsk |= OTGFS_DIEPEMPMSK(privep->epphy);
- stm32_putreg(empmsk, STM32_OTGFS_DIEPEMPMSK);
-
- /* Terminate the transfer. We will try again when the TxFIFO empty
- * interrupt is received.
- */
-
- return;
- }
-
- /* Transfer data to the TxFIFO */
-
- buf = privreq->req.buf + privreq->req.xfrd;
- stm32_epin_transfer(privep, buf, nbytes);
-
- /* If it was not before, the OUT endpoint is now actively transferring
- * data.
- */
-
- privep->active = true;
-
- /* EP0 is a special case */
-
- if (privep->epphy == EP0)
- {
- priv->ep0state = EP0STATE_DATA_IN;
- }
-
- /* Update for the next time through the loop */
-
- privreq->req.xfrd += nbytes;
- }
-
- /* Note that the ZLP, if any, must be sent as a separate transfer. The need
- * for a ZLP is indicated by privep->zlp. If all of the bytes were sent
- * (including any final null packet) then we are finished with the transfer
- */
-
- if (privreq->req.xfrd >= privreq->req.len && !privep->zlp)
- {
- usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd);
-
- /* We are finished with the request (although the transfer has not
- * yet completed).
- */
-
- stm32_req_complete(privep, OK);
- }
-}
-
-/*******************************************************************************
- * Name: stm32_rxfifo_read
- *
- * Description:
- * Read packet from the RxFIFO into a read request.
- *
- *******************************************************************************/
-
-static void stm32_rxfifo_read(FAR struct stm32_ep_s *privep,
- FAR uint8_t *dest, uint16_t len)
-{
- uint32_t regaddr;
- int i;
-
- /* Get the address of the RxFIFO. Note: there is only one RxFIFO so
- * we might as well use the addess associated with EP0.
- */
-
- regaddr = STM32_OTGFS_DFIFO_DEP(EP0);
-
- /* Read 32-bits and write 4 x 8-bits at time (to avoid unaligned accesses) */
-
- for (i = 0; i < len; i += 4)
- {
- union
- {
- uint32_t w;
- uint8_t b[4];
- } data;
-
- /* Read 1 x 32-bits of EP0 packet data */
-
- data.w = stm32_getreg(regaddr);
-
- /* Write 4 x 8-bits of EP0 packet data */
-
- *dest++ = data.b[0];
- *dest++ = data.b[1];
- *dest++ = data.b[2];
- *dest++ = data.b[3];
- }
-}
-
-/*******************************************************************************
- * Name: stm32_rxfifo_discard
- *
- * Description:
- * Discard packet data from the RxFIFO.
- *
- *******************************************************************************/
-
-static void stm32_rxfifo_discard(FAR struct stm32_ep_s *privep, int len)
-{
- if (len > 0)
- {
- uint32_t regaddr;
- int i;
-
- /* Get the address of the RxFIFO Note: there is only one RxFIFO so
- * we might as well use the addess associated with EP0.
- */
-
- regaddr = STM32_OTGFS_DFIFO_DEP(EP0);
-
- /* Read 32-bits at time */
-
- for (i = 0; i < len; i += 4)
- {
- volatile uint32_t data = stm32_getreg(regaddr);
- (void)data;
- }
- }
-}
-
-/*******************************************************************************
- * Name: stm32_epout_complete
- *
- * Description:
- * This function is called when an OUT transfer complete interrupt is
- * received. It completes the read request at the head of the endpoint's
- * request queue.
- *
- *******************************************************************************/
-
-static void stm32_epout_complete(FAR struct stm32_usbdev_s *priv,
- FAR struct stm32_ep_s *privep)
-{
- struct stm32_req_s *privreq;
-
- /* Since a transfer just completed, there must be a read request at the head of
- * the endpoint request queue.
- */
-
- privreq = stm32_rqpeek(privep);
- DEBUGASSERT(privreq);
-
- if (!privreq)
- {
- /* An OUT transfer completed, but no packet to receive the data. This
- * should not happen.
- */
-
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_EPOUTQEMPTY), privep->epphy);
- privep->active = false;
- return;
- }
-
- ullvdbg("EP%d: len=%d xfrd=%d\n",
- privep->epphy, privreq->req.len, privreq->req.xfrd);
-
- /* Return the completed read request to the class driver and mark the state
- * IDLE.
- */
-
- usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd);
- stm32_req_complete(privep, OK);
- privep->active = false;
-
- /* Now set up the next read request (if any) */
-
- stm32_epout_request(priv, privep);
-}
-
-/*******************************************************************************
- * Name: stm32_ep0out_receive
- *
- * Description:
- * This function is called from the RXFLVL interrupt handler when new incoming
- * data is available in the endpoint's RxFIFO. This function will simply
- * copy the incoming data into pending request's data buffer.
- *
- *******************************************************************************/
-
-static inline void stm32_ep0out_receive(FAR struct stm32_ep_s *privep, int bcnt)
-{
- FAR struct stm32_usbdev_s *priv;
-
- /* Sanity Checking */
-
- DEBUGASSERT(privep && privep->ep.priv);
- priv = (FAR struct stm32_usbdev_s *)privep->ep.priv;
-
- ullvdbg("EP0: bcnt=%d\n", bcnt);
- usbtrace(TRACE_READ(EP0), bcnt);
-
- /* Verify that an OUT SETUP request as received before this data was
- * received in the RxFIFO.
- */
-
- if (priv->ep0state == EP0STATE_SETUP_OUT)
- {
- /* Read the data into our special buffer for SETUP data */
-
- int readlen = MIN(CONFIG_USBDEV_SETUP_MAXDATASIZE, bcnt);
- stm32_rxfifo_read(privep, priv->ep0data, readlen);
-
- /* Do we have to discard any excess bytes? */
-
- stm32_rxfifo_discard(privep, bcnt - readlen);
-
- /* Now we can process the setup command */
-
- privep->active = false;
- priv->ep0state = EP0STATE_SETUP_READY;
- priv->ep0datlen = readlen;
-
- stm32_ep0out_setup(priv);
- }
- else
- {
- /* This is an error. We don't have any idea what to do with the EP0
- * data in this case. Just read and discard it so that the RxFIFO
- * does not become constipated.
- */
-
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_NOOUTSETUP), priv->ep0state);
- stm32_rxfifo_discard(privep, bcnt);
- privep->active = false;
- }
-}
-
-/*******************************************************************************
- * Name: stm32_epout_receive
- *
- * Description:
- * This function is called from the RXFLVL interrupt handler when new incoming
- * data is available in the endpoint's RxFIFO. This function will simply
- * copy the incoming data into pending request's data buffer.
- *
- *******************************************************************************/
-
-static inline void stm32_epout_receive(FAR struct stm32_ep_s *privep, int bcnt)
-{
- struct stm32_req_s *privreq;
- uint8_t *dest;
- int buflen;
- int readlen;
-
- /* Get a reference to the request at the head of the endpoint's request
- * queue.
- */
-
- privreq = stm32_rqpeek(privep);
- if (!privreq)
- {
- /* Incoming data is available in the RxFIFO, but there is no read setup
- * to receive the receive the data. This should not happen for data
- * endpoints; those endpoints should have been NAKing any OUT data tokens.
- *
- * We should get here normally on OUT data phase following an OUT
- * SETUP command. EP0 data will still receive data in this case and it
- * should not be NAKing.
- */
-
- if (privep->epphy == 0)
- {
- stm32_ep0out_receive(privep, bcnt);
- }
- else
- {
- /* Otherwise, the data is lost. This really should not happen if
- * NAKing is working as expected.
- */
-
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_EPOUTQEMPTY), privep->epphy);
-
- /* Discard the data in the RxFIFO */
-
- stm32_rxfifo_discard(privep, bcnt);
- }
-
- privep->active = false;
- return;
- }
-
- ullvdbg("EP%d: len=%d xfrd=%d\n", privep->epphy, privreq->req.len, privreq->req.xfrd);
- usbtrace(TRACE_READ(privep->epphy), bcnt);
-
- /* Get the number of bytes to transfer from the RxFIFO */
-
- buflen = privreq->req.len - privreq->req.xfrd;
- DEBUGASSERT(buflen > 0 && buflen >= bcnt);
- readlen = MIN(buflen, bcnt);
-
- /* Get the destination of the data transfer */
-
- dest = privreq->req.buf + privreq->req.xfrd;
-
- /* Transfer the data from the RxFIFO to the request's data buffer */
-
- stm32_rxfifo_read(privep, dest, readlen);
-
- /* If there were more bytes in the RxFIFO than could be held in the read
- * request, then we will have to discard those.
- */
-
- stm32_rxfifo_discard(privep, bcnt - readlen);
-
- /* Update the number of bytes transferred */
-
- privreq->req.xfrd += readlen;
-}
-
-/*******************************************************************************
- * Name: stm32_epout_request
- *
- * Description:
- * This function is called when either (1) new read request is received, or
- * (2) a pending receive request completes. If there is no read in pending,
- * then this function will initiate the next OUT (read) operation.
- *
- *******************************************************************************/
-
-static void stm32_epout_request(FAR struct stm32_usbdev_s *priv,
- FAR struct stm32_ep_s *privep)
-{
- struct stm32_req_s *privreq;
- uint32_t regaddr;
- uint32_t regval;
- uint32_t xfrsize;
- uint32_t pktcnt;
-
- /* Make sure that there is not already a pending request request. If there is,
- * just return, leaving the newly received request in the request queue.
- */
-
- if (!privep->active)
- {
- /* Loop until a valid request is found (or the request queue is empty).
- * The loop is only need to look at the request queue again is an invalid
- * read request is encountered.
- */
-
- for (;;)
- {
- /* Get a reference to the request at the head of the endpoint's request queue */
-
- privreq = stm32_rqpeek(privep);
- if (!privreq)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_EPOUTQEMPTY), privep->epphy);
-
- /* There are no read requests to be setup. Configure the hardware to
- * NAK any incoming packets. (This should already be the case. I
- * think that the hardware will automatically NAK after a transfer is
- * completed until SNAK is cleared).
- */
-
- regaddr = STM32_OTGFS_DOEPCTL(privep->epphy);
- regval = stm32_getreg(regaddr);
- regval |= OTGFS_DOEPCTL_SNAK;
- stm32_putreg(regval, regaddr);
-
- /* This endpoint is no longer actively transferring */
-
- privep->active = false;
- return;
- }
-
- ullvdbg("EP%d: len=%d\n", privep->epphy, privreq->req.len);
-
- /* Ignore any attempt to receive a zero length packet (this really
- * should not happen.
- */
-
- if (privreq->req.len <= 0)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_EPOUTNULLPACKET), 0);
- stm32_req_complete(privep, OK);
- }
-
- /* Otherwise, we have a usable read request... break out of the loop */
-
- else
- {
- break;
- }
- }
-
- /* Setup the pending read into the request buffer. First calculate:
- *
- * pktcnt = the number of packets (of maxpacket bytes) required to
- * perform the transfer.
- * xfrsize = The total number of bytes required (in units of
- * maxpacket bytes).
- */
-
- pktcnt = (privreq->req.len + (privep->ep.maxpacket - 1)) / privep->ep.maxpacket;
- xfrsize = pktcnt * privep->ep.maxpacket;
-
- /* Then setup the hardware to perform this transfer */
-
- regaddr = STM32_OTGFS_DOEPTSIZ(privep->epphy);
- regval = stm32_getreg(regaddr);
- regval &= ~(OTGFS_DOEPTSIZ_XFRSIZ_MASK | OTGFS_DOEPTSIZ_PKTCNT_MASK);
- regval |= (xfrsize << OTGFS_DOEPTSIZ_XFRSIZ_SHIFT);
- regval |= (pktcnt << OTGFS_DOEPTSIZ_PKTCNT_SHIFT);
- stm32_putreg(regval, regaddr);
-
- /* Then enable the transfer */
-
- regaddr = STM32_OTGFS_DOEPCTL(privep->epphy);
- regval = stm32_getreg(regaddr);
-
- /* When an isochronous transfer is enabled the Even/Odd frame bit must
- * also be set appropriately.
- */
-
-#ifdef CONFIG_USBDEV_ISOCHRONOUS
- if (privep->eptype == USB_EP_ATTR_XFER_ISOC)
- {
- if (privep->odd)
- {
- regval |= OTGFS_DOEPCTL_SODDFRM;
- }
- else
- {
- regval |= OTGFS_DOEPCTL_SEVNFRM;
- }
- }
-#endif
-
- /* Clearing NAKing and enable the transfer. */
-
- regval |= (OTGFS_DOEPCTL_CNAK | OTGFS_DOEPCTL_EPENA);
- stm32_putreg(regval, regaddr);
-
- /* A transfer is now active on this endpoint */
-
- privep->active = true;
-
- /* EP0 is a special case. We need to know when to switch back to
- * normal SETUP processing.
- */
-
- if (privep->epphy == EP0)
- {
- priv->ep0state = EP0STATE_DATA_OUT;
- }
- }
-}
-
-/*******************************************************************************
- * Name: stm32_ep_flush
- *
- * Description:
- * Flush any primed descriptors from this ep
- *
- *******************************************************************************/
-
-static void stm32_ep_flush(struct stm32_ep_s *privep)
-{
- if (privep->isin)
- {
- stm32_txfifo_flush(OTGFS_GRSTCTL_TXFNUM_D(privep->epphy));
- }
- else
- {
- stm32_rxfifo_flush();
- }
-}
-
-/*******************************************************************************
- * Name: stm32_req_complete
- *
- * Description:
- * Handle termination of the request at the head of the endpoint request queue.
- *
- *******************************************************************************/
-
-static void stm32_req_complete(struct stm32_ep_s *privep, int16_t result)
-{
- FAR struct stm32_req_s *privreq;
-
- /* Remove the request at the head of the request list */
-
- privreq = stm32_req_remfirst(privep);
- DEBUGASSERT(privreq != NULL);
-
- /* If endpoint 0, temporarily reflect the state of protocol stalled
- * in the callback.
- */
-
- bool stalled = privep->stalled;
- if (privep->epphy == EP0)
- {
- privep->stalled = privep->dev->stalled;
- }
-
- /* Save the result in the request structure */
-
- privreq->req.result = result;
-
- /* Callback to the request completion handler */
-
- privreq->req.callback(&privep->ep, &privreq->req);
-
- /* Restore the stalled indication */
-
- privep->stalled = stalled;
-}
-
-/*******************************************************************************
- * Name: stm32_req_cancel
- *
- * Description:
- * Cancel all pending requests for an endpoint
- *
- *******************************************************************************/
-
-static void stm32_req_cancel(struct stm32_ep_s *privep, int16_t status)
-{
- if (!stm32_rqempty(privep))
- {
- stm32_ep_flush(privep);
- }
-
- while (!stm32_rqempty(privep))
- {
- usbtrace(TRACE_COMPLETE(privep->epphy),
- (stm32_rqpeek(privep))->req.xfrd);
- stm32_req_complete(privep, status);
- }
-}
-
-/*******************************************************************************
- * Name: stm32_ep_findbyaddr
- *
- * Description:
- * Find the physical endpoint structure corresponding to a logic endpoint
- * address
- *
- *******************************************************************************/
-
-static struct stm32_ep_s *stm32_ep_findbyaddr(struct stm32_usbdev_s *priv,
- uint16_t eplog)
-{
- struct stm32_ep_s *privep;
- uint8_t epphy = USB_EPNO(eplog);
-
- if (epphy >= STM32_NENDPOINTS)
- {
- return NULL;
- }
-
- /* Is this an IN or an OUT endpoint? */
-
- if (USB_ISEPIN(eplog))
- {
- privep = &priv->epin[epphy];
- }
- else
- {
- privep = &priv->epout[epphy];
- }
-
- /* Return endpoint reference */
-
- DEBUGASSERT(privep->epphy == epphy);
- return privep;
-}
-
-/*******************************************************************************
- * Name: stm32_req_dispatch
- *
- * Description:
- * Provide unhandled setup actions to the class driver. This is logically part
- * of the USB interrupt handler.
- *
- *******************************************************************************/
-
-static int stm32_req_dispatch(struct stm32_usbdev_s *priv,
- const struct usb_ctrlreq_s *ctrl)
-{
- int ret = -EIO;
-
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_DISPATCH), 0);
- if (priv->driver)
- {
- /* Forward to the control request to the class driver implementation */
-
- ret = CLASS_SETUP(priv->driver, &priv->usbdev, ctrl,
- priv->ep0data, priv->ep0datlen);
- }
-
- if (ret < 0)
- {
- /* Stall on failure */
-
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_DISPATCHSTALL), 0);
- priv->stalled = true;
- }
-
- return ret;
-}
-
-/*******************************************************************************
- * Name: stm32_usbreset
- *
- * Description:
- * Reset Usb engine
- *
- *******************************************************************************/
-
-static void stm32_usbreset(struct stm32_usbdev_s *priv)
-{
- FAR struct stm32_ep_s *privep;
- uint32_t regval;
- int i;
-
- /* Clear the Remote Wake-up Signaling */
-
- regval = stm32_getreg(STM32_OTGFS_DCTL);
- regval &= ~OTGFS_DCTL_RWUSIG;
- stm32_putreg(regval, STM32_OTGFS_DCTL);
-
- /* Flush the EP0 Tx FIFO */
-
- stm32_txfifo_flush(OTGFS_GRSTCTL_TXFNUM_D(EP0));
-
- /* Tell the class driver that we are disconnected. The class
- * driver should then accept any new configurations.
- */
-
- if (priv->driver)
- {
- CLASS_DISCONNECT(priv->driver, &priv->usbdev);
- }
- priv->epavail = STM32_EP_AVAILABLE;
-
- /* Disable all end point interrupts */
-
- for (i = 0; i < STM32_NENDPOINTS ; i++)
- {
- /* Disable endpoint interrupts */
-
- stm32_putreg(0xff, STM32_OTGFS_DIEPINT(i));
- stm32_putreg(0xff, STM32_OTGFS_DOEPINT(i));
-
- /* Return write requests to the class implementation */
-
- privep = &priv->epin[i];
- stm32_req_cancel(privep, -ESHUTDOWN);
-
- /* Reset IN endpoint status */
-
- privep->stalled = false;
-
- /* Return read requests to the class implementation */
-
- privep = &priv->epout[i];
- stm32_req_cancel(privep, -ESHUTDOWN);
-
- /* Reset endpoint status */
-
- privep->stalled = false;
- }
-
- stm32_putreg(0xffffffff, STM32_OTGFS_DAINT);
-
- /* Mask all device endpoint interrupts except EP0 */
-
- regval = (OTGFS_DAINT_IEP(EP0) | OTGFS_DAINT_OEP(EP0));
- stm32_putreg(regval, STM32_OTGFS_DAINTMSK);
-
- /* Unmask OUT interrupts */
-
- regval = (OTGFS_DOEPMSK_XFRCM | OTGFS_DOEPMSK_STUPM | OTGFS_DOEPMSK_EPDM);
- stm32_putreg(regval, STM32_OTGFS_DOEPMSK);
-
- /* Unmask IN interrupts */
-
- regval = (OTGFS_DIEPMSK_XFRCM | OTGFS_DIEPMSK_EPDM | OTGFS_DIEPMSK_TOM);
- stm32_putreg(regval, STM32_OTGFS_DIEPMSK);
-
- /* Reset device address to 0 */
-
- stm32_setaddress(priv, 0);
- priv->devstate = DEVSTATE_DEFAULT;
- priv->usbdev.speed = USB_SPEED_FULL;
-
- /* Re-configure EP0 */
-
- stm32_ep0_configure(priv);
-
- /* Setup EP0 to receive SETUP packets */
-
- stm32_ep0out_ctrlsetup(priv);
-}
-
-/*******************************************************************************
- * Name: stm32_ep0out_testmode
- *
- * Description:
- * Select test mode
- *
- *******************************************************************************/
-
-static inline void stm32_ep0out_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_ep0in_transmitzlp(priv);
-}
-
-/*******************************************************************************
- * Name: stm32_ep0out_stdrequest
- *
- * Description:
- * Handle a stanard request on EP0. Pick off the things of interest to the
- * USB device controller driver; pass what is left to the class driver.
- *
- *******************************************************************************/
-
-static inline void stm32_ep0out_stdrequest(struct stm32_usbdev_s *priv,
- FAR struct stm32_ctrlreq_s *ctrlreq)
-{
- FAR struct stm32_ep_s *privep;
-
- /* Handle standard request */
-
- switch (ctrlreq->req)
- {
- case USB_REQ_GETSTATUS:
- {
- /* type: device-to-host; recipient = device, interface, endpoint
- * value: 0
- * index: zero interface endpoint
- * len: 2; data = status
- */
-
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_GETSTATUS), 0);
- if (!priv->addressed ||
- ctrlreq->len != 2 ||
- USB_REQ_ISOUT(ctrlreq->type) ||
- ctrlreq->value != 0)
- {
- priv->stalled = true;
- }
- else
- {
- switch (ctrlreq->type & USB_REQ_RECIPIENT_MASK)
- {
- case USB_REQ_RECIPIENT_ENDPOINT:
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPGETSTATUS), 0);
- privep = stm32_ep_findbyaddr(priv, ctrlreq->index);
- if (!privep)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_BADEPGETSTATUS), 0);
- priv->stalled = true;
- }
- else
- {
- if (privep->stalled)
- {
- priv->ep0data[0] = (1 << USB_FEATURE_ENDPOINTHALT);
- }
- else
- {
- priv->ep0data[0] = 0; /* Not stalled */
- }
-
- priv->ep0data[1] = 0;
- stm32_ep0in_setupresponse(priv, priv->ep0data, 2);
- }
- }
- break;
-
- case USB_REQ_RECIPIENT_DEVICE:
- {
- if (ctrlreq->index == 0)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_DEVGETSTATUS), 0);
-
- /* Features: Remote Wakeup and selfpowered */
-
- priv->ep0data[0] = (priv->selfpowered << USB_FEATURE_SELFPOWERED);
- priv->ep0data[0] |= (priv->wakeup << USB_FEATURE_REMOTEWAKEUP);
- priv->ep0data[1] = 0;
-
- stm32_ep0in_setupresponse(priv, priv->ep0data, 2);
- }
- else
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_BADDEVGETSTATUS), 0);
- priv->stalled = true;
- }
- }
- break;
-
- case USB_REQ_RECIPIENT_INTERFACE:
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_IFGETSTATUS), 0);
- priv->ep0data[0] = 0;
- priv->ep0data[1] = 0;
-
- stm32_ep0in_setupresponse(priv, priv->ep0data, 2);
- }
- break;
-
- default:
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_BADGETSTATUS), 0);
- priv->stalled = true;
- }
- break;
- }
- }
- }
- break;
-
- case USB_REQ_CLEARFEATURE:
- {
- /* type: host-to-device; recipient = device, interface or endpoint
- * value: feature selector
- * index: zero interface endpoint;
- * len: zero, data = none
- */
-
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_CLEARFEATURE), 0);
- if (priv->addressed != 0 && 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_ep_findbyaddr(priv, ctrlreq->index)) != NULL)
- {
- stm32_ep_clrstall(privep);
- stm32_ep0in_transmitzlp(priv);
- }
- else if (recipient == USB_REQ_RECIPIENT_DEVICE &&
- ctrlreq->value == USB_FEATURE_REMOTEWAKEUP)
- {
- priv->wakeup = 0;
- stm32_ep0in_transmitzlp(priv);
- }
- else
- {
- /* Actually, I think we could just stall here. */
-
- (void)stm32_req_dispatch(priv, &priv->ctrlreq);
- }
- }
- else
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_BADCLEARFEATURE), 0);
- priv->stalled = true;
- }
- }
- break;
-
- case USB_REQ_SETFEATURE:
- {
- /* type: host-to-device; recipient = device, interface, endpoint
- * value: feature selector
- * index: zero interface endpoint;
- * len: 0; data = none
- */
-
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SETFEATURE), 0);
- if (priv->addressed != 0 && 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_ep_findbyaddr(priv, ctrlreq->index)) != NULL)
- {
- stm32_ep_setstall(privep);
- stm32_ep0in_transmitzlp(priv);
- }
- else if (recipient == USB_REQ_RECIPIENT_DEVICE &&
- ctrlreq->value == USB_FEATURE_REMOTEWAKEUP)
- {
- priv->wakeup = 1;
- stm32_ep0in_transmitzlp(priv);
- }
- else if (recipient == USB_REQ_RECIPIENT_DEVICE &&
- ctrlreq->value == USB_FEATURE_TESTMODE &&
- ((ctrlreq->index & 0xff) == 0))
- {
- stm32_ep0out_testmode(priv, ctrlreq->index);
- }
- else if (priv->configured)
- {
- /* Actually, I think we could just stall here. */
-
- (void)stm32_req_dispatch(priv, &priv->ctrlreq);
- }
- else
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_BADSETFEATURE), 0);
- priv->stalled = true;
- }
- }
- else
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_BADSETFEATURE), 0);
- priv->stalled = true;
- }
- }
- break;
-
- case USB_REQ_SETADDRESS:
- {
- /* type: host-to-device; recipient = device
- * value: device address
- * index: 0
- * len: 0; data = none
- */
-
- 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 &&
- priv->devstate != DEVSTATE_CONFIGURED)
- {
- /* Save the address. We cannot actually change to the next address until
- * the completion of the status phase.
- */
-
- stm32_setaddress(priv, (uint16_t)priv->ctrlreq.value[0]);
- stm32_ep0in_transmitzlp(priv);
- }
- else
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_BADSETADDRESS), 0);
- priv->stalled = true;
- }
- }
- break;
-
- case USB_REQ_GETDESCRIPTOR:
- /* type: device-to-host; recipient = device
- * value: descriptor type and index
- * index: 0 or language ID;
- * len: descriptor len; data = descriptor
- */
-
- case USB_REQ_SETDESCRIPTOR:
- /* type: host-to-device; recipient = device
- * value: descriptor type and index
- * index: 0 or language ID;
- * len: descriptor len; data = descriptor
- */
-
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_GETSETDESC), 0);
- if ((ctrlreq->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE)
- {
- (void)stm32_req_dispatch(priv, &priv->ctrlreq);
- }
- else
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_BADGETSETDESC), 0);
- priv->stalled = true;
- }
- }
- break;
-
- case USB_REQ_GETCONFIGURATION:
- /* type: device-to-host; recipient = device
- * value: 0;
- * index: 0;
- * len: 1; data = configuration value
- */
-
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_GETCONFIG), 0);
- if (priv->addressed &&
- (ctrlreq->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE &&
- ctrlreq->value == 0 &&
- ctrlreq->index == 0 &&
- ctrlreq->len == 1)
- {
- (void)stm32_req_dispatch(priv, &priv->ctrlreq);
- }
- else
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_BADGETCONFIG), 0);
- priv->stalled = true;
- }
- }
- break;
-
- case USB_REQ_SETCONFIGURATION:
- /* type: host-to-device; recipient = device
- * value: configuration value
- * index: 0;
- * len: 0; data = none
- */
-
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SETCONFIG), 0);
- if (priv->addressed &&
- (ctrlreq->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE &&
- ctrlreq->index == 0 &&
- ctrlreq->len == 0)
- {
- /* Give the configuration to the class driver */
-
- int ret = stm32_req_dispatch(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)ctrlreq->value;
- if (cfg != 0)
- {
- priv->devstate = DEVSTATE_CONFIGURED;
- priv->configured = true;
- }
- else
- {
- priv->devstate = DEVSTATE_ADDRESSED;
- priv->configured = false;
- }
- }
- }
- else
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_BADSETCONFIG), 0);
- priv->stalled = true;
- }
- }
- break;
-
- case USB_REQ_GETINTERFACE:
- /* type: device-to-host; recipient = interface
- * value: 0
- * index: interface;
- * len: 1; data = alt interface
- */
-
- case USB_REQ_SETINTERFACE:
- /* type: host-to-device; recipient = interface
- * value: alternate setting
- * index: interface;
- * len: 0; data = none
- */
-
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_GETSETIF), 0);
- (void)stm32_req_dispatch(priv, &priv->ctrlreq);
- }
- break;
-
- case USB_REQ_SYNCHFRAME:
- /* type: device-to-host; recipient = endpoint
- * value: 0
- * index: endpoint;
- * len: 2; data = frame number
- */
-
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SYNCHFRAME), 0);
- }
- break;
-
- default:
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_INVALIDCTRLREQ), 0);
- priv->stalled = true;
- }
- break;
- }
-}
-
-/*******************************************************************************
- * Name: stm32_ep0out_setup
- *
- * Description:
- * USB Ctrl EP Setup Event. This is logically part of the USB interrupt
- * handler. This event occurs when a setup packet is receive on EP0 OUT.
- *
- *******************************************************************************/
-
-static inline void stm32_ep0out_setup(struct stm32_usbdev_s *priv)
-{
- struct stm32_ctrlreq_s ctrlreq;
-
- /* Verify that a SETUP was received */
-
- if (priv->ep0state != EP0STATE_SETUP_READY)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_EP0NOSETUP), priv->ep0state);
- return;
- }
-
- /* Terminate any pending requests */
-
- stm32_req_cancel(&priv->epout[EP0], -EPROTO);
- stm32_req_cancel(&priv->epin[EP0], -EPROTO);
-
- /* Assume NOT stalled */
-
- priv->epout[EP0].stalled = false;
- priv->epin[EP0].stalled = false;
- priv->stalled = false;
-
- /* Starting to process a control request - update state */
-
- priv->ep0state = EP0STATE_SETUP_PROCESS;
-
- /* And extract the little-endian 16-bit values to host order */
-
- ctrlreq.type = priv->ctrlreq.type;
- ctrlreq.req = priv->ctrlreq.req;
- ctrlreq.value = GETUINT16(priv->ctrlreq.value);
- ctrlreq.index = GETUINT16(priv->ctrlreq.index);
- ctrlreq.len = GETUINT16(priv->ctrlreq.len);
-
- ullvdbg("type=%02x req=%02x value=%04x index=%04x len=%04x\n",
- ctrlreq.type, ctrlreq.req, ctrlreq.value, ctrlreq.index, ctrlreq.len);
-
- /* Check for a standard request */
-
- if ((ctrlreq.type & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD)
- {
- /* Dispatch any non-standard requests */
-
- (void)stm32_req_dispatch(priv, &priv->ctrlreq);
- }
- else
- {
- /* Handle standard requests. */
-
- stm32_ep0out_stdrequest(priv, &ctrlreq);
- }
-
- /* Check if the setup processing resulted in a STALL */
-
- if (priv->stalled)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_EP0SETUPSTALLED), priv->ep0state);
- stm32_ep0_stall(priv);
- }
-
- /* Reset state/data associated with thie SETUP request */
-
- priv->ep0datlen = 0;
-}
-
-/*******************************************************************************
- * Name: stm32_epout
- *
- * Description:
- * This is part of the OUT endpoint interrupt processing. This function
- * handles the OUT event for a single endpoint.
- *
- *******************************************************************************/
-
-static inline void stm32_epout(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->epout[EP0];
-
- /* In the EP0STATE_DATA_OUT state, we are receiving data into the
- * 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 */
-
- stm32_epout_complete(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_ep0out_ctrlsetup(priv);
- priv->ep0state = EP0STATE_IDLE;
- }
- }
- }
-
- /* For other endpoints, the only possibility is that we are continuing
- * or finishing an OUT request.
- */
-
- else if (priv->devstate == DEVSTATE_CONFIGURED)
- {
- stm32_epout_complete(priv, &priv->epout[epno]);
- }
-}
-
-/*******************************************************************************
- * Name: stm32_epout_interrupt
- *
- * Description:
- * USB OUT endpoint interrupt handler. The core generates this interrupt when
- * there is an interrupt is pending on one of the OUT endpoints of the core.
- * The driver must read the OTGFS DAINT register to determine the exact number
- * of the OUT endpoint on which the interrupt occurred, and then read the
- * corresponding OTGFS DOEPINTx register to determine the exact cause of the
- * interrupt.
- *
- *******************************************************************************/
-
-static inline void stm32_epout_interrupt(FAR struct stm32_usbdev_s *priv)
-{
- uint32_t daint;
- uint32_t regval;
- uint32_t doepint;
- int epno;
-
- /* Get the pending, enabled interrupts for the OUT endpoint from the endpoint
- * interrupt status register.
- */
-
- regval = stm32_getreg(STM32_OTGFS_DAINT);
- regval &= stm32_getreg(STM32_OTGFS_DAINTMSK);
- daint = (regval & OTGFS_DAINT_OEP_MASK) >> OTGFS_DAINT_OEP_SHIFT;
-
- /* Process each pending IN endpoint interrupt */
-
- epno = 0;
- while (daint)
- {
- /* Is an OUT interrupt pending for this endpoint? */
-
- if ((daint & 1) != 0)
- {
- /* Yes.. get the OUT endpoint interrupt status */
-
- doepint = stm32_getreg(STM32_OTGFS_DOEPINT(epno));
- doepint &= stm32_getreg(STM32_OTGFS_DOEPMSK);
-
- /* Transfer completed interrupt. This interrupt is trigged when
- * stm32_rxinterrupt() removes the last packet data from the RxFIFO.
- * In this case, core internally sets the NAK bit for this endpoint to
- * prevent it from receiving any more packets.
- */
-
- if ((doepint & OTGFS_DOEPINT_XFRC) != 0)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPOUT_XFRC), (uint16_t)doepint);
-
- /* Clear the bit in DOEPINTn for this interrupt */
-
- stm32_putreg(OTGFS_DOEPINT_XFRC, STM32_OTGFS_DOEPINT(epno));
-
- /* Handle the RX transfer data ready event */
-
- stm32_epout(priv, epno);
- }
-
- /* Endpoint disabled interrupt (ignored because this interrrupt is
- * used in polled mode by the endpoint disable logic).
- */
-#if 1
- /* REVISIT: */
- if ((doepint & OTGFS_DOEPINT_EPDISD) != 0)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPOUT_EPDISD), (uint16_t)doepint);
-
- /* Clear the bit in DOEPINTn for this interrupt */
-
- stm32_putreg(OTGFS_DOEPINT_EPDISD, STM32_OTGFS_DOEPINT(epno));
- }
-#endif
- /* Setup Phase Done (control EPs) */
-
- if ((doepint & OTGFS_DOEPINT_SETUP) != 0)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPOUT_SETUP), priv->ep0state);
-
- /* Handle the receipt of the IN SETUP packets now (OUT setup
- * packet processing may be delayed until the accompanying
- * OUT DATA is received)
- */
-
- if (priv->ep0state == EP0STATE_SETUP_READY)
- {
- stm32_ep0out_setup(priv);
- }
- stm32_putreg(OTGFS_DOEPINT_SETUP, STM32_OTGFS_DOEPINT(epno));
- }
- }
-
- epno++;
- daint >>= 1;
- }
-}
-
-/*******************************************************************************
- * Name: stm32_epin_runtestmode
- *
- * Description:
- * Execute the test mode setup by the SET FEATURE request
- *
- *******************************************************************************/
-
-static inline void stm32_epin_runtestmode(FAR struct stm32_usbdev_s *priv)
-{
- uint32_t regval = stm32_getreg(STM32_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 = &priv->epin[epno];
-
- /* Endpoint 0 is a special case. */
-
- if (epno == 0)
- {
- /* 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_IN)
- {
- /* Continue processing data from the EP0 OUT request queue */
-
- stm32_epin_request(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_ep0out_ctrlsetup(priv);
- priv->ep0state = EP0STATE_IDLE;
- }
- }
-
- /* Test mode is another special case */
-
- if (priv->dotest)
- {
- stm32_epin_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 endpoint write request queue */
-
- stm32_epin_request(priv, privep);
- }
-}
-
-/****************************************************************************
- * Name: stm32_epin_txfifoempty
- *
- * Description:
- * TxFIFO empty interrupt handling
- *
- ****************************************************************************/
-
-static inline void stm32_epin_txfifoempty(FAR struct stm32_usbdev_s *priv, int epno)
-{
- FAR struct stm32_ep_s *privep = &priv->epin[epno];
-
- /* Continue processing the write request queue. This may mean sending
- * more data from the exisiting request or terminating the current requests
- * and (perhaps) starting the IN transfer from the next write request.
- */
-
- stm32_epin_request(priv, privep);
-}
-
-/*******************************************************************************
- * Name: stm32_epin_interrupt
- *
- * Description:
- * USB IN endpoint interrupt handler. The core generates this interrupt when
- * an interrupt is pending on one of the IN endpoints of the core. The driver
- * must read the OTGFS DAINT register to determine the exact number of the IN
- * endpoint on which the interrupt occurred, and then read the corresponding
- * OTGFS DIEPINTx register to determine the exact cause of the interrupt.
- *
- *******************************************************************************/
-
-static inline void stm32_epin_interrupt(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 if the TxFIFO not empty interrupt is enabled for this
- * endpoint in the DIEPMSK register. Bits n corresponds to
- * endpoint n in the register. That condition corresponds to
- * bit 7 of the DIEPINT interrupt status register. There is
- * no TXFE bit in the mask register, so we fake one here.
- */
-
- empty = stm32_getreg(STM32_OTGFS_DIEPEMPMSK);
- if ((empty & OTGFS_DIEPEMPMSK(epno)) != 0)
- {
- 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);
-
- /* It is possible that logic may be waiting for a the
- * TxFIFO to become empty. We disable the TxFIFO empty
- * interrupt here; it will be re-enabled if there is still
- * insufficient space in the TxFIFO.
- */
-
- empty &= ~OTGFS_DIEPEMPMSK(epno);
- stm32_putreg(empty, STM32_OTGFS_DIEPEMPMSK);
- stm32_putreg(OTGFS_DIEPINT_XFRC, STM32_OTGFS_DIEPINT(epno));
-
- /* IN transfer 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. Applies to non-periodic IN
- * endpoints only. This interrupt indicates that an IN token was received
- * when the associated TxFIFO (periodic/non-periodic) was empty. This
- * interrupt is asserted on the endpoint for which the IN token was
- * received.
- */
-
- if ((diepint & OTGFS_DIEPINT_ITTXFE) != 0)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPIN_ITTXFE), (uint16_t)diepint);
- stm32_epin_request(priv, &priv->epin[epno]);
- stm32_putreg(OTGFS_DIEPINT_ITTXFE, STM32_OTGFS_DIEPINT(epno));
- }
-
- /* IN endpoint NAK effective (ignored as this used only in polled
- * mode)
- */
-#if 0
- 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));
- }
-#endif
- /* Endpoint disabled interrupt (ignored as this used only in polled
- * mode)
- */
-#if 0
- 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));
- }
-#endif
- /* Transmit FIFO empty */
-
- if ((diepint & OTGFS_DIEPINT_TXFE) != 0)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPIN_TXFE), (uint16_t)diepint);
-
- /* If we were waiting for TxFIFO to become empty, the we might have both
- * XFRC and TXFE interrupts pending. Since we do the same thing for both
- * cases, ignore the TXFE if we have already processed the XFRC.
- */
-
- if ((diepint & OTGFS_DIEPINT_XFRC) == 0)
- {
- /* Mask further FIFO empty interrupts. This will be re-enabled
- * whenever we need to wait for a FIFO event.
- */
-
- empty &= ~OTGFS_DIEPEMPMSK(epno);
- stm32_putreg(empty, STM32_OTGFS_DIEPEMPMSK);
-
- /* Handle TxFIFO empty */
-
- stm32_epin_txfifoempty(priv, epno);
- }
-
- /* Clear the pending TxFIFO empty interrupt */
-
- stm32_putreg(OTGFS_DIEPINT_TXFE, STM32_OTGFS_DIEPINT(epno));
- }
- }
-
- epno++;
- daint >>= 1;
- }
-}
-
-/*******************************************************************************
- * Name: stm32_resumeinterrupt
- *
- * Description:
- * Resume/remote wakeup detected interrupt
- *
- *******************************************************************************/
-
-static inline void stm32_resumeinterrupt(FAR struct stm32_usbdev_s *priv)
-{
- uint32_t regval;
-
- /* Restart the PHY clock and un-gate USB core clock (HCLK) */
-
-#ifdef CONFIG_USBDEV_LOWPOWER
- regval = stm32_getreg(STM32_OTGFS_PCGCCTL);
- regval &= ~(OTGFS_PCGCCTL_STPPCLK | OTGFS_PCGCCTL_GATEHCLK);
- stm32_putreg(regval, STM32_OTGFS_PCGCCTL);
-#endif
-
- /* Clear remote wake-up signaling */
-
- regval = stm32_getreg(STM32_OTGFS_DCTL);
- regval &= ~OTGFS_DCTL_RWUSIG;
- stm32_putreg(regval, STM32_OTGFS_DCTL);
-
- /* Restore full power -- whatever that means for this particular board */
-
- stm32_usbsuspend((struct usbdev_s *)priv, true);
-
- /* Notify the class driver of the resume event */
-
- if (priv->driver)
- {
- CLASS_RESUME(priv->driver, &priv->usbdev);
- }
-}
-
-/*******************************************************************************
- * Name: stm32_suspendinterrupt
- *
- * Description:
- * USB suspend interrupt
- *
- *******************************************************************************/
-
-static inline void stm32_suspendinterrupt(FAR struct stm32_usbdev_s *priv)
-{
-#ifdef CONFIG_USBDEV_LOWPOWER
- uint32_t regval;
-#endif
-
- /* Notify the class driver of the suspend event */
-
- if (priv->driver)
- {
- CLASS_SUSPEND(priv->driver, &priv->usbdev);
- }
-
-#ifdef CONFIG_USBDEV_LOWPOWER
- /* OTGFS_DSTS_SUSPSTS is set as long as the suspend condition is detected
- * on USB. Check if we are still have the suspend condition, that we are
- * connected to the host, and that we have been configured.
- */
-
- regval = stm32_getreg(STM32_OTGFS_DSTS);
-
- if ((regval & OTGFS_DSTS_SUSPSTS) != 0 && devstate == DEVSTATE_CONFIGURED)
- {
- /* Switch off OTG FS clocking. Setting OTGFS_PCGCCTL_STPPCLK stops the
- * PHY clock.
- */
-
- regval = stm32_getreg(STM32_OTGFS_PCGCCTL);
- regval |= OTGFS_PCGCCTL_STPPCLK;
- stm32_putreg(regval, STM32_OTGFS_PCGCCTL);
-
- /* Setting OTGFS_PCGCCTL_GATEHCLK gate HCLK to modules other than
- * the AHB Slave and Master and wakeup logic.
- */
-
- regval |= OTGFS_PCGCCTL_GATEHCLK;
- stm32_putreg(regval, STM32_OTGFS_PCGCCTL);
- }
-#endif
-
- /* Let the board-specific logic know that we have entered the suspend
- * state
- */
-
- stm32_usbsuspend((FAR struct usbdev_s *)priv, false);
-}
-
-/*******************************************************************************
- * Name: stm32_rxinterrupt
- *
- * Description:
- * RxFIFO non-empty interrupt. This interrupt indicates that there is at
- * least one packet pending to be read from the RxFIFO.
- *
- *******************************************************************************/
-
-static inline void stm32_rxinterrupt(FAR struct stm32_usbdev_s *priv)
-{
- FAR struct stm32_ep_s *privep;
- uint32_t regval;
- int bcnt;
- int epphy;
-
- /* Disable the Rx status queue level interrupt */
-
- regval = stm32_getreg(STM32_OTGFS_GINTMSK);
- regval &= ~OTGFS_GINT_RXFLVL;
- stm32_putreg(regval, STM32_OTGFS_GINTMSK);
-
- /* Get the status from the top of the FIFO */
-
- regval = stm32_getreg(STM32_OTGFS_GRXSTSP);
-
- /* Decode status fields */
-
- epphy = (regval & OTGFS_GRXSTSD_EPNUM_MASK) >> OTGFS_GRXSTSD_EPNUM_SHIFT;
- privep = &priv->epout[epphy];
-
- /* Handle the RX event according to the packet status field */
-
- switch (regval & OTGFS_GRXSTSD_PKTSTS_MASK)
- {
- /* Global OUT NAK. This indicate that the global OUT NAK bit has taken
- * effect.
- *
- * PKTSTS = Global OUT NAK, BCNT = 0, EPNUM = Don't Care, DPID = Don't
- * Care.
- */
-
- case OTGFS_GRXSTSD_PKTSTS_OUTNAK:
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_OUTNAK), 0);
- }
- break;
-
- /* OUT data packet received.
- *
- * PKTSTS = DataOUT, BCNT = size of the received data OUT packet,
- * EPNUM = EPNUM on which the packet was received, DPID = Actual Data PID.
- */
-
- case OTGFS_GRXSTSD_PKTSTS_OUTRECVD:
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_OUTRECVD), epphy);
- bcnt = (regval & OTGFS_GRXSTSD_BCNT_MASK) >> OTGFS_GRXSTSD_BCNT_SHIFT;
- if (bcnt > 0)
- {
- stm32_epout_receive(privep, bcnt);
- }
- }
- break;
-
- /* OUT transfer completed. This indicates that an OUT data transfer for
- * the specified OUT endpoint has completed. After this entry is popped
- * from the receive FIFO, the core asserts a Transfer Completed interrupt
- * on the specified OUT endpoint.
- *
- * PKTSTS = Data OUT Transfer Done, BCNT = 0, EPNUM = OUT EP Num on
- * which the data transfer is complete, DPID = Don't Care.
- */
-
- case OTGFS_GRXSTSD_PKTSTS_OUTDONE:
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_OUTDONE), epphy);
- }
- break;
-
- /* SETUP transaction completed. This indicates that the Setup stage for
- * the specified endpoint has completed and the Data stage has started.
- * After this entry is popped from the receive FIFO, the core asserts a
- * Setup interrupt on the specified control OUT endpoint (triggers an
- * interrupt).
- *
- * PKTSTS = Setup Stage Done, BCNT = 0, EPNUM = Control EP Num,
- * DPID = Don't Care.
- */
-
- case OTGFS_GRXSTSD_PKTSTS_SETUPDONE:
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SETUPDONE), epphy);
- }
- break;
-
- /* SETUP data packet received. This indicates that a SETUP packet for the
- * specified endpoint is now available for reading from the receive FIFO.
- *
- * PKTSTS = SETUP, BCNT = 8, EPNUM = Control EP Num, DPID = D0.
- */
-
- case OTGFS_GRXSTSD_PKTSTS_SETUPRECVD:
- {
- uint16_t datlen;
-
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SETUPRECVD), epphy);
-
- /* Read EP0 setup data. NOTE: If multiple SETUP packets are received,
- * the last one overwrites the previous setup packets and only that
- * last SETUP packet will be processed.
- */
-
- stm32_rxfifo_read(&priv->epout[EP0], (FAR uint8_t*)&priv->ctrlreq,
- USB_SIZEOF_CTRLREQ);
-
- /* Was this an IN or an OUT SETUP packet. If it is an OUT SETUP,
- * then we need to wait for the completion of the data phase to
- * process the setup command. If it is an IN SETUP packet, then
- * we must processing the command BEFORE we enter the DATA phase.
- *
- * If the data associated with the OUT SETUP packet is zero length,
- * then, of course, we don't need to wait.
- */
-
- datlen = GETUINT16(priv->ctrlreq.len);
- if (USB_REQ_ISOUT(priv->ctrlreq.type) && datlen > 0)
- {
- /* Clear NAKSTS so that we can receive the data */
-
- regval = stm32_getreg(STM32_OTGFS_DOEPCTL0);
- regval |= OTGFS_DOEPCTL0_CNAK;
- stm32_putreg(regval, STM32_OTGFS_DOEPCTL0);
-
- /* Wait for the data phase. */
-
- priv->ep0state = EP0STATE_SETUP_OUT;
- }
- else
- {
- /* We can process the setup data as soon as SETUP done word is
- * popped of the RxFIFO.
- */
-
- priv->ep0state = EP0STATE_SETUP_READY;
- }
- }
- break;
-
- default:
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_INVALIDPARMS),
- (regval & OTGFS_GRXSTSD_PKTSTS_MASK) >> OTGFS_GRXSTSD_PKTSTS_SHIFT);
- }
- break;
- }
-
- /* Enable the Rx Status Queue Level interrupt */
-
- regval = stm32_getreg(STM32_OTGFS_GINTMSK);
- regval |= OTGFS_GINT_RXFLVL;
- stm32_putreg(regval, STM32_OTGFS_GINTMSK);
-}
-
-/*******************************************************************************
- * Name: stm32_enuminterrupt
- *
- * Description:
- * Enumeration done interrupt
- *
- *******************************************************************************/
-
-static inline void stm32_enuminterrupt(FAR struct stm32_usbdev_s *priv)
-{
- uint32_t regval;
-
- /* Activate EP0 */
-
- stm32_ep0in_activate();
-
- /* Set USB turn-around time for the full speed device with internal PHY interface. */
-
- regval = stm32_getreg(STM32_OTGFS_GUSBCFG);
- regval &= ~OTGFS_GUSBCFG_TRDT_MASK;
- regval |= OTGFS_GUSBCFG_TRDT(5);
- stm32_putreg(regval, STM32_OTGFS_GUSBCFG);
-}
-
-/*******************************************************************************
- * Name: stm32_isocininterrupt
- *
- * Description:
- * Incomplete isochronous IN transfer interrupt. Assertion of the incomplete
- * isochronous IN transfer interrupt indicates an incomplete isochronous IN
- * transfer on at least one of the isochronous IN endpoints.
- *
- *******************************************************************************/
-
-#ifdef CONFIG_USBDEV_ISOCHRONOUS
-static inline void stm32_isocininterrupt(FAR struct stm32_usbdev_s *priv)
-{
- int i;
-
- /* The application must read the endpoint control register for all isochronous
- * IN endpoints to detect endpoints with incomplete IN data transfers.
- */
-
- for (i = 0; i < STM32_NENDPOINTS; i++)
- {
- /* Is this an isochronous IN endpoint? */
-
- privep = &priv->epin[i];
- if (privep->eptype != USB_EP_ATTR_XFER_ISOC)
- {
- /* No... keep looking */
-
- continue;
- }
-
- /* Is there an active read request on the isochronous OUT endpoint? */
-
- if (!privep->active)
- {
- /* No.. the endpoint is not actively transmitting data */
-
- continue;
- }
-
- /* Check if this is the endpoint that had the incomplete transfer */
-
- regaddr = STM32_OTGFS_DIEPCTL(privep->epphy);
- doepctl = stm32_getreg(regaddr);
- dsts = stm32_getreg(STM32_OTGFS_DSTS);
-
- /* EONUM = 0:even frame, 1:odd frame
- * SOFFN = Frame number of the received SOF
- */
-
- eonum = ((doepctl & OTGFS_DIEPCTL_EONUM) != 0);
- soffn = ((dsts & OTGFS_DSTS_SOFFN0) != 0);
-
- if (eonum != soffn)
- {
- /* Not this endpoint */
-
- continue;
- }
-
- /* For isochronous IN endpoints with incomplete transfers,
- * the application must discard the data in the memory and
- * disable the endpoint.
- */
-
- stm32_req_complete(privep, -EIO);
-#warning "Will clear OTGFS_DIEPCTL_USBAEP too"
- stm32_epin_disable(privep);
- break;
- }
-}
-#endif
-
-/*******************************************************************************
- * Name: stm32_isocoutinterrupt
- *
- * Description:
- * Incomplete periodic transfer interrupt
- *
- *******************************************************************************/
-
-#ifdef CONFIG_USBDEV_ISOCHRONOUS
-static inline void stm32_isocoutinterrupt(FAR struct stm32_usbdev_s *priv)
-{
- FAR struct stm32_ep_s *privep;
- FAR struct stm32_req_s *privreq;
- uint32_t regaddr;
- uint32_t doepctl;
- uint32_t dsts;
- bool eonum;
- bool soffn;
-
- /* When it receives an IISOOXFR interrupt, the application must read the
- * control registers of all isochronous OUT endpoints to determine which
- * endpoints had an incomplete transfer in the current microframe. An
- * endpoint transfer is incomplete if both the following conditions are true:
- *
- * DOEPCTLx:EONUM = DSTS:SOFFN[0], and
- * DOEPCTLx:EPENA = 1
- */
-
- for (i = 0; i < STM32_NENDPOINTS; i++)
- {
- /* Is this an isochronous OUT endpoint? */
-
- privep = &priv->epout[i];
- if (privep->eptype != USB_EP_ATTR_XFER_ISOC)
- {
- /* No... keep looking */
-
- continue;
- }
-
- /* Is there an active read request on the isochronous OUT endpoint? */
-
- if (!privep->active)
- {
- /* No.. the endpoint is not actively transmitting data */
-
- continue;
- }
-
- /* Check if this is the endpoint that had the incomplete transfer */
-
- regaddr = STM32_OTGFS_DOEPCTL(privep->epphy);
- doepctl = stm32_getreg(regaddr);
- dsts = stm32_getreg(STM32_OTGFS_DSTS);
-
- /* EONUM = 0:even frame, 1:odd frame
- * SOFFN = Frame number of the received SOF
- */
-
- eonum = ((doepctl & OTGFS_DOEPCTL_EONUM) != 0);
- soffn = ((dsts & OTGFS_DSTS_SOFFN0) != 0);
-
- if (eonum != soffn)
- {
- /* Not this endpoint */
-
- continue;
- }
-
- /* For isochronous OUT endpoints with incomplete transfers,
- * the application must discard the data in the memory and
- * disable the endpoint.
- */
-
- stm32_req_complete(privep, -EIO);
-#warning "Will clear OTGFS_DOEPCTL_USBAEP too"
- stm32_epout_disable(privep);
- break;
- }
-}
-#endif
-
-/*******************************************************************************
- * Name: stm32_sessioninterrupt
- *
- * Description:
- * Session request/new session detected interrupt
- *
- *******************************************************************************/
-
-#ifdef CONFIG_USBDEV_VBUSSENSING
-static inline void stm32_sessioninterrupt(FAR struct stm32_usbdev_s *priv)
-{
-#warning "Missing logic"
-}
-#endif
-
-/*******************************************************************************
- * Name: stm32_otginterrupt
- *
- * Description:
- * OTG interrupt
- *
- *******************************************************************************/
-
-#ifdef CONFIG_USBDEV_VBUSSENSING
-static inline void stm32_otginterrupt(FAR struct stm32_usbdev_s *priv)
-{
- uint32_t regval;
-
- /* Check for session end detected */
-
- regval = stm32_getreg(STM32_OTGFS_GOTGINT);
- if ((regval & OTGFS_GOTGINT_SEDET) != 0)
- {
-#warning "Missing logic"
- }
-
- /* Clear OTG interrupt */
-
- stm32_putreg(retval, STM32_OTGFS_GOTGINT);
-}
-#endif
-
-/*******************************************************************************
- * Name: stm32_usbinterrupt
- *
- * Description:
- * USB interrupt handler
- *
- *******************************************************************************/
-
-static int stm32_usbinterrupt(int irq, FAR void *context)
-{
- /* At present, there is only a single OTG FS device support. Hence it is
- * pre-allocated as g_otgfsdev. However, in most code, the private data
- * structure will be referenced using the 'priv' pointer (rather than the
- * global data) in order to simplify any future support for multiple devices.
- */
-
- FAR struct stm32_usbdev_s *priv = &g_otgfsdev;
- uint32_t regval;
-
- usbtrace(TRACE_INTENTRY(STM32_TRACEINTID_USB), 0);
-
- /* Assure that we are in device mode */
-
- DEBUGASSERT((stm32_getreg(STM32_OTGFS_GINTSTS) & OTGFS_GINTSTS_CMOD) == OTGFS_GINTSTS_DEVMODE);
-
- /* Get the state of all enabled interrupts. We will do this repeatedly
- * some interrupts (like RXFLVL) will generate additional interrupting
- * events.
- */
-
- for (;;)
- {
- /* Get the set of pending, un-masked interrupts */
-
- regval = stm32_getreg(STM32_OTGFS_GINTSTS);
- regval &= stm32_getreg(STM32_OTGFS_GINTMSK);
-
- /* Break out of the loop when there are no further pending (and
- * unmasked) interrupts to be processes.
- */
-
- if (regval == 0)
- {
- break;
- }
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_INTPENDING), (uint16_t)regval);
-
- /* OUT endpoint interrupt. The core sets this bit to indicate that an
- * interrupt is pending on one of the OUT endpoints of the core.
- */
-
- if ((regval & OTGFS_GINT_OEP) != 0)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPOUT), (uint16_t)regval);
- stm32_epout_interrupt(priv);
- stm32_putreg(OTGFS_GINT_OEP, STM32_OTGFS_GINTSTS);
- }
-
- /* IN endpoint interrupt. The core sets this bit to indicate that
- * an interrupt is pending on one of the IN endpoints of the core.
- */
-
- if ((regval & OTGFS_GINT_IEP) != 0)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPIN), (uint16_t)regval);
- stm32_epin_interrupt(priv);
- stm32_putreg(OTGFS_GINT_IEP, STM32_OTGFS_GINTSTS);
- }
-
- /* Host/device mode mismatch error interrupt */
-
-#ifdef CONFIG_DEBUG_USB
- if ((regval & OTGFS_GINT_MMIS) != 0)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_MISMATCH), (uint16_t)regval);
- stm32_putreg(OTGFS_GINT_MMIS, STM32_OTGFS_GINTSTS);
- }
-#endif
-
- /* Resume/remote wakeup detected interrupt */
-
- if ((regval & OTGFS_GINT_WKUP) != 0)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_WAKEUP), (uint16_t)regval);
- stm32_resumeinterrupt(priv);
- stm32_putreg(OTGFS_GINT_WKUP, STM32_OTGFS_GINTSTS);
- }
-
- /* USB suspend interrupt */
-
- if ((regval & OTGFS_GINT_USBSUSP) != 0)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SUSPEND), (uint16_t)regval);
- stm32_suspendinterrupt(priv);
- stm32_putreg(OTGFS_GINT_USBSUSP, STM32_OTGFS_GINTSTS);
- }
-
- /* Start of frame interrupt */
-
-#ifdef CONFIG_USBDEV_SOFINTERRUPT
- if ((regval & OTGFS_GINT_SOF) != 0)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SOF), (uint16_t)regval);
- stm32_putreg(OTGFS_GINT_SOF, STM32_OTGFS_GINTSTS);
- }
-#endif
-
- /* RxFIFO non-empty interrupt. Indicates that there is at least one
- * packet pending to be read from the RxFIFO.
- */
-
- if ((regval & OTGFS_GINT_RXFLVL) != 0)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_RXFIFO), (uint16_t)regval);
- stm32_rxinterrupt(priv);
- stm32_putreg(OTGFS_GINT_RXFLVL, STM32_OTGFS_GINTSTS);
- }
-
- /* USB reset interrupt */
-
- if ((regval & OTGFS_GINT_USBRST) != 0)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_DEVRESET), (uint16_t)regval);
-
- /* Perform the device reset */
-
- stm32_usbreset(priv);
- usbtrace(TRACE_INTEXIT(STM32_TRACEINTID_USB), 0);
- stm32_putreg(OTGFS_GINT_USBRST, STM32_OTGFS_GINTSTS);
- return OK;
- }
-
- /* Enumeration done interrupt */
-
- if ((regval & OTGFS_GINT_ENUMDNE) != 0)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_ENUMDNE), (uint16_t)regval);
- stm32_enuminterrupt(priv);
- stm32_putreg(OTGFS_GINT_ENUMDNE, STM32_OTGFS_GINTSTS);
- }
-
- /* Incomplete isochronous IN transfer interrupt. When the core finds
- * non-empty any of the isochronous IN endpoint FIFOs scheduled for
- * the current frame non-empty, the core generates an IISOIXFR
- * interrupt.
- */
-
-#ifdef CONFIG_USBDEV_ISOCHRONOUS
- if ((regval & OTGFS_GINT_IISOIXFR) != 0)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_IISOIXFR), (uint16_t)regval);
- stm32_isocininterrupt(priv);
- stm32_putreg(OTGFS_GINT_IISOIXFR, STM32_OTGFS_GINTSTS);
- }
-
- /* Incomplete isochronous OUT transfer. For isochronous OUT
- * endpoints, the XFRC interrupt may not always be asserted. If the
- * core drops isochronous OUT data packets, the application could fail
- * to detect the XFRC interrupt. The incomplete Isochronous OUT data
- * interrupt indicates that an XFRC interrupt was not asserted on at
- * least one of the isochronous OUT endpoints. At this point, the
- * endpoint with the incomplete transfer remains enabled, but no active
- * transfers remain in progress on this endpoint on the USB.
- */
-
- if ((regval & OTGFS_GINT_IISOOXFR) != 0)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_IISOOXFR), (uint16_t)regval);
- stm32_isocoutinterrupt(priv);
- stm32_putreg(OTGFS_GINT_IISOOXFR, STM32_OTGFS_GINTSTS);
- }
-#endif
-
- /* Session request/new session detected interrupt */
-
-#ifdef CONFIG_USBDEV_VBUSSENSING
- if ((regval & OTGFS_GINT_SRQ) != 0)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SRQ), (uint16_t)regval);
- stm32_sessioninterrupt(priv);
- stm32_putreg(OTGFS_GINT_SRQ, STM32_OTGFS_GINTSTS);
- }
-
- /* OTG interrupt */
-
- if ((regval & OTGFS_GINT_OTG) != 0)
- {
- usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_OTG), (uint16_t)regval);
- stm32_otginterrupt(priv);
- stm32_putreg(OTGFS_GINT_OTG, STM32_OTGFS_GINTSTS);
- }
-#endif
- }
-
- usbtrace(TRACE_INTEXIT(STM32_TRACEINTID_USB), 0);
- return OK;
-}
-
-/*******************************************************************************
- * Endpoint operations
- *******************************************************************************/
-
-/*******************************************************************************
- * Name: stm32_enablegonak
- *
- * Description:
- * Enable global OUT NAK mode
- *
- *******************************************************************************/
-
-static void stm32_enablegonak(FAR struct stm32_ep_s *privep)
-{
- uint32_t regval;
-
- /* First, make sure that there is no GNOAKEFF interrupt pending. */
-
-#if 0
- stm32_putreg(OTGFS_GINT_GONAKEFF, STM32_OTGFS_GINTSTS);
-#endif
-
- /* Enable Global OUT NAK mode in the core. */
-
- regval = stm32_getreg(STM32_OTGFS_DCTL);
- regval |= OTGFS_DCTL_SGONAK;
- stm32_putreg(regval, STM32_OTGFS_DCTL);
-
-#if 0
- /* Wait for the GONAKEFF interrupt that indicates that the OUT NAK
- * mode is in effect. When the interrupt handler pops the OUTNAK word
- * from the RxFIFO, the core sets the GONAKEFF interrupt.
- */
-
- while ((stm32_getreg(STM32_OTGFS_GINTSTS) & OTGFS_GINT_GONAKEFF) == 0);
- stm32_putreg(OTGFS_GINT_GONAKEFF, STM32_OTGFS_GINTSTS);
-
-#else
- /* Since we are in the interrupt handler, we cannot wait inline for the
- * GONAKEFF because it cannot occur until service th RXFLVL global interrupt
- * and pop the OUTNAK word from the RxFIFO.
- *
- * Perhaps it is sufficient to wait for Global OUT NAK status to be reported
- * in OTGFS DCTL register?
- */
-
- while ((stm32_getreg(STM32_OTGFS_DCTL) & OTGFS_DCTL_GONSTS) == 0);
-#endif
-}
-
-/*******************************************************************************
- * Name: stm32_disablegonak
- *
- * Description:
- * Disable global OUT NAK mode
- *
- *******************************************************************************/
-
-static void stm32_disablegonak(FAR struct stm32_ep_s *privep)
-{
- uint32_t regval;
-
- /* Set the "Clear the Global OUT NAK bit" to disable global OUT NAK mode */
-
- regval = stm32_getreg(STM32_OTGFS_DCTL);
- regval |= OTGFS_DCTL_CGONAK;
- stm32_putreg(regval, STM32_OTGFS_DCTL);
-}
-
-/*******************************************************************************
- * Name: stm32_epout_configure
- *
- * Description:
- * Configure an OUT endpoint, making it usable
- *
- * Input Parameters:
- * privep - a pointer to an internal endpoint structure
- * eptype - The type of the endpoint
- * maxpacket - The max packet size of the endpoint
- *
- *******************************************************************************/
-
-static int stm32_epout_configure(FAR struct stm32_ep_s *privep, uint8_t eptype,
- uint16_t maxpacket)
-{
- uint32_t mpsiz;
- uint32_t regaddr;
- uint32_t regval;
-
- usbtrace(TRACE_EPCONFIGURE, privep->epphy);
-
- /* For EP0, the packet size is encoded */
-
- if (privep->epphy == EP0)
- {
- DEBUGASSERT(eptype == USB_EP_ATTR_XFER_CONTROL);
-
- /* Map the size in bytes to the encoded value in the register */
-
- switch (maxpacket)
- {
- case 8:
- mpsiz = OTGFS_DOEPCTL0_MPSIZ_8;
- break;
-
- case 16:
- mpsiz = OTGFS_DOEPCTL0_MPSIZ_16;
- break;
-
- case 32:
- mpsiz = OTGFS_DOEPCTL0_MPSIZ_32;
- break;
-
- case 64:
- mpsiz = OTGFS_DOEPCTL0_MPSIZ_64;
- break;
-
- default:
- udbg("Unsupported maxpacket: %d\n", maxpacket);
- return -EINVAL;
- }
- }
-
- /* For other endpoints, the packet size is in bytes */
-
- else
- {
- mpsiz = (maxpacket << OTGFS_DOEPCTL_MPSIZ_SHIFT);
- }
-
- /* If the endpoint is already active don't change the endpoint control
- * register.
- */
-
- regaddr = STM32_OTGFS_DOEPCTL(privep->epphy);
- regval = stm32_getreg(regaddr);
- if ((regval & OTGFS_DOEPCTL_USBAEP) == 0)
- {
- if (regval & OTGFS_DOEPCTL_NAKSTS)
- {
- regval |= OTGFS_DOEPCTL_CNAK;
- }
-
- regval &= ~(OTGFS_DOEPCTL_MPSIZ_MASK | OTGFS_DOEPCTL_EPTYP_MASK);
- regval |= mpsiz;
- regval |= (eptype << OTGFS_DOEPCTL_EPTYP_SHIFT);
- regval |= (OTGFS_DOEPCTL_SD0PID | OTGFS_DOEPCTL_USBAEP);
- stm32_putreg(regval, regaddr);
-
- /* Save the endpoint configuration */
-
- privep->ep.maxpacket = maxpacket;
- privep->eptype = eptype;
- privep->stalled = false;
- }
-
- /* Enable the interrupt for this endpoint */
-
- regval = stm32_getreg(STM32_OTGFS_DAINTMSK);
- regval |= OTGFS_DAINT_OEP(privep->epphy);
- stm32_putreg(regval, STM32_OTGFS_DAINTMSK);
- return OK;
-}
-
-/*******************************************************************************
- * Name: stm32_epin_configure
- *
- * Description:
- * Configure an IN endpoint, making it usable
- *
- * Input Parameters:
- * privep - a pointer to an internal endpoint structure
- * eptype - The type of the endpoint
- * maxpacket - The max packet size of the endpoint
- *
- *******************************************************************************/
-
-static int stm32_epin_configure(FAR struct stm32_ep_s *privep, uint8_t eptype,
- uint16_t maxpacket)
-{
- uint32_t mpsiz;
- uint32_t regaddr;
- uint32_t regval;
-
- usbtrace(TRACE_EPCONFIGURE, privep->epphy);
-
- /* For EP0, the packet size is encoded */
-
- if (privep->epphy == EP0)
- {
- DEBUGASSERT(eptype == USB_EP_ATTR_XFER_CONTROL);
-
- /* Map the size in bytes to the encoded value in the register */
-
- switch (maxpacket)
- {
- case 8:
- mpsiz = OTGFS_DIEPCTL0_MPSIZ_8;
- break;
-
- case 16:
- mpsiz = OTGFS_DIEPCTL0_MPSIZ_16;
- break;
-
- case 32:
- mpsiz = OTGFS_DIEPCTL0_MPSIZ_32;
- break;
-
- case 64:
- mpsiz = OTGFS_DIEPCTL0_MPSIZ_64;
- break;
-
- default:
- udbg("Unsupported maxpacket: %d\n", maxpacket);
- return -EINVAL;
- }
- }
-
- /* For other endpoints, the packet size is in bytes */
-
- else
- {
- mpsiz = (maxpacket << OTGFS_DIEPCTL_MPSIZ_SHIFT);
- }
-
-
- /* If the endpoint is already active don't change the endpoint control
- * register.
- */
-
- regaddr = STM32_OTGFS_DIEPCTL(privep->epphy);
- regval = stm32_getreg(regaddr);
- if ((regval & OTGFS_DIEPCTL_USBAEP) == 0)
- {
- if (regval & OTGFS_DIEPCTL_NAKSTS)
- {
- regval |= OTGFS_DIEPCTL_CNAK;
- }
-
- regval &= ~(OTGFS_DIEPCTL_MPSIZ_MASK | OTGFS_DIEPCTL_EPTYP_MASK | OTGFS_DIEPCTL_TXFNUM_MASK);
- regval |= mpsiz;
- regval |= (eptype << OTGFS_DIEPCTL_EPTYP_SHIFT);
- regval |= (eptype << OTGFS_DIEPCTL_TXFNUM_SHIFT);
- regval |= (OTGFS_DIEPCTL_SD0PID | OTGFS_DIEPCTL_USBAEP);
- stm32_putreg(regval, regaddr);
-
- /* Save the endpoint configuration */
-
- privep->ep.maxpacket = maxpacket;
- privep->eptype = eptype;
- privep->stalled = false;
- }
-
- /* Enable the interrupt for this endpoint */
-
- regval = stm32_getreg(STM32_OTGFS_DAINTMSK);
- regval |= OTGFS_DAINT_IEP(privep->epphy);
- stm32_putreg(regval, STM32_OTGFS_DAINTMSK);
-
- return OK;
-}
-
-/*******************************************************************************
- * Name: stm32_ep_configure
- *
- * Description:
- * Configure endpoint, making it usable
- *
- * Input Parameters:
- * ep - the struct usbdev_ep_s instance obtained from allocep()
- * desc - A struct usb_epdesc_s instance describing the endpoint
- * last - true if this this last endpoint to be configured. Some hardware
- * needs to take special action when all of the endpoints have been
- * configured.
- *
- *******************************************************************************/
-
-static int stm32_ep_configure(FAR struct usbdev_ep_s *ep,
- FAR const struct usb_epdesc_s *desc,
- bool last)
-{
- FAR struct stm32_ep_s *privep = (FAR struct stm32_ep_s *)ep;
- uint16_t maxpacket;
- uint8_t eptype;
- int ret;
-
- usbtrace(TRACE_EPCONFIGURE, privep->epphy);
- DEBUGASSERT(desc->addr == ep->eplog);
-
- /* Initialize EP capabilities */
-
- maxpacket = GETUINT16(desc->mxpacketsize);
- eptype = desc->attr & USB_EP_ATTR_XFERTYPE_MASK;
-
- /* Setup Endpoint Control Register */
-
- if (privep->isin)
- {
- ret = stm32_epin_configure(privep, eptype, maxpacket);
- }
- else
- {
- ret = stm32_epout_configure(privep, eptype, maxpacket);
- }
-
- return ret;
-}
-
-/*******************************************************************************
- * Name: stm32_ep0_configure
- *
- * Description:
- * Reset Usb engine
- *
- *******************************************************************************/
-
-static void stm32_ep0_configure(FAR struct stm32_usbdev_s *priv)
-{
- /* Enable EP0 IN and OUT */
-
- (void)stm32_epin_configure(&priv->epin[EP0], USB_EP_ATTR_XFER_CONTROL,
- CONFIG_USBDEV_EP0_MAXSIZE);
- (void)stm32_epout_configure(&priv->epout[EP0], USB_EP_ATTR_XFER_CONTROL,
- CONFIG_USBDEV_EP0_MAXSIZE);
-}
-
-/*******************************************************************************
- * Name: stm32_epout_disable
- *
- * Description:
- * Diable an OUT endpoint will no longer be used
- *
- *******************************************************************************/
-
-static void stm32_epout_disable(FAR struct stm32_ep_s *privep)
-{
- uint32_t regaddr;
- uint32_t regval;
- irqstate_t flags;
-
- usbtrace(TRACE_EPDISABLE, privep->epphy);
-
- /* Is this an IN or an OUT endpoint */
-
- /* Before disabling any OUT endpoint, the application must enable
- * Global OUT NAK mode in the core.
- */
-
- flags = irqsave();
- stm32_enablegonak(privep);
-
- /* Disable the required OUT endpoint by setting the EPDIS and SNAK bits
- * int DOECPTL register.
- */
-
- regaddr = STM32_OTGFS_DOEPCTL(privep->epphy);
- regval = stm32_getreg(regaddr);
- regval &= ~OTGFS_DOEPCTL_USBAEP;
- regval |= (OTGFS_DOEPCTL_EPDIS | OTGFS_DOEPCTL_SNAK);
- stm32_putreg(regval, regaddr);
-
- /* Wait for the EPDISD interrupt which indicates that the OUT
- * endpoint is completely disabled.
- */
-
-#if 0 /* Doesn't happen */
- regaddr = STM32_OTGFS_DOEPINT(privep->epphy);
- while ((stm32_getreg(regaddr) & OTGFS_DOEPINT_EPDISD) == 0);
-#else
- /* REVISIT: */
- up_mdelay(50);
-#endif
-
- /* Then disble the Global OUT NAK mode to continue receiving data
- * from other non-disabled OUT endpoints.
- */
-
- stm32_disablegonak(privep);
-
- /* Disable endpoint interrupts */
-
- regval = stm32_getreg(STM32_OTGFS_DAINTMSK);
- regval &= ~OTGFS_DAINT_OEP(privep->epphy);
- stm32_putreg(regval, STM32_OTGFS_DAINTMSK);
-
- /* Cancel any queued read requests */
-
- stm32_req_cancel(privep, -ESHUTDOWN);
-
- irqrestore(flags);
-}
-
-/*******************************************************************************
- * Name: stm32_epin_disable
- *
- * Description:
- * Disable an IN endpoint when it will no longer be used
- *
- *******************************************************************************/
-
-static void stm32_epin_disable(FAR struct stm32_ep_s *privep)
-{
- uint32_t regaddr;
- uint32_t regval;
- irqstate_t flags;
-
- usbtrace(TRACE_EPDISABLE, privep->epphy);
-
- /* After USB reset, the endpoint will already be deactivated by the
- * hardware. Trying to disable again will just hang in the wait.
- */
-
- regaddr = STM32_OTGFS_DIEPCTL(privep->epphy);
- regval = stm32_getreg(regaddr);
- if ((regval & OTGFS_DIEPCTL_USBAEP) == 0)
- {
- return;
- }
-
- /* Make sure that there is no pending IPEPNE interrupt (because we are
- * to poll this bit below).
- */
-
- stm32_putreg(OTGFS_DIEPINT_INEPNE, STM32_OTGFS_DIEPINT(privep->epphy));
-
- /* Set the endpoint in NAK mode */
-
- regaddr = STM32_OTGFS_DIEPCTL(privep->epphy);
- regval = stm32_getreg(regaddr);
- regval &= ~OTGFS_DIEPCTL_USBAEP;
- regval |= (OTGFS_DIEPCTL_EPDIS | OTGFS_DIEPCTL_SNAK);
- stm32_putreg(regval, regaddr);
-
- /* Wait for the INEPNE interrupt that indicates that we are now in NAK mode */
-
- regaddr = STM32_OTGFS_DIEPINT(privep->epphy);
- while ((stm32_getreg(regaddr) & OTGFS_DIEPINT_INEPNE) == 0);
- stm32_putreg(OTGFS_DIEPINT_INEPNE, regaddr);
-
- /* Deactivate and disable the endpoint by setting the EPIS and SNAK bits
- * the DIEPCTLx register.
- */
-
- flags = irqsave();
- regaddr = STM32_OTGFS_DIEPCTL(privep->epphy);
- regval = stm32_getreg(regaddr);
- regval &= ~OTGFS_DIEPCTL_USBAEP;
- regval |= (OTGFS_DIEPCTL_EPDIS | OTGFS_DIEPCTL_SNAK);
- stm32_putreg(regval, regaddr);
-
- /* Wait for the EPDISD interrupt which indicates that the IN
- * endpoint is completely disabled.
- */
-
- regaddr = STM32_OTGFS_DIEPINT(privep->epphy);
- while ((stm32_getreg(regaddr) & OTGFS_DIEPINT_EPDISD) == 0);
-
- /* Flush any data remaining in the TxFIFO */
-
- stm32_txfifo_flush(OTGFS_GRSTCTL_TXFNUM_D(privep->epphy));
-
- /* Disable endpoint interrupts */
-
- regval = stm32_getreg(STM32_OTGFS_DAINTMSK);
- regval &= ~OTGFS_DAINT_IEP(privep->epphy);
- stm32_putreg(regval, STM32_OTGFS_DAINTMSK);
-
- /* Cancel any queued write requests */
-
- stm32_req_cancel(privep, -ESHUTDOWN);
-
- irqrestore(flags);
-}
-
-/*******************************************************************************
- * Name: stm32_ep_disable
- *
- * Description:
- * The endpoint will no longer be used
- *
- *******************************************************************************/
-
-static int stm32_ep_disable(FAR struct usbdev_ep_s *ep)
-{
- FAR struct stm32_ep_s *privep = (FAR struct stm32_ep_s *)ep;
-
-#ifdef CONFIG_DEBUG
- if (!ep)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_INVALIDPARMS), 0);
- return -EINVAL;
- }
-#endif
- usbtrace(TRACE_EPDISABLE, privep->epphy);
-
- /* Is this an IN or an OUT endpoint */
-
- if (privep->isin)
- {
- /* Disable the IN endpoint */
-
- stm32_epin_disable(privep);
- }
- else
- {
- /* Disable the OUT endpoint */
-
- stm32_epout_disable(privep);
- }
-
- return OK;
-}
-
-/*******************************************************************************
- * Name: stm32_ep_allocreq
- *
- * Description:
- * Allocate an I/O request
- *
- *******************************************************************************/
-
-static FAR struct usbdev_req_s *stm32_ep_allocreq(FAR struct usbdev_ep_s *ep)
-{
- FAR struct stm32_req_s *privreq;
-
-#ifdef CONFIG_DEBUG
- if (!ep)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_INVALIDPARMS), 0);
- return NULL;
- }
-#endif
- usbtrace(TRACE_EPALLOCREQ, ((FAR struct stm32_ep_s *)ep)->epphy);
-
- privreq = (FAR struct stm32_req_s *)malloc(sizeof(struct stm32_req_s));
- if (!privreq)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_ALLOCFAIL), 0);
- return NULL;
- }
-
- memset(privreq, 0, sizeof(struct stm32_req_s));
- return &privreq->req;
-}
-
-/*******************************************************************************
- * Name: stm32_ep_freereq
- *
- * Description:
- * Free an I/O request
- *
- *******************************************************************************/
-
-static void stm32_ep_freereq(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req)
-{
- FAR struct stm32_req_s *privreq = (FAR struct stm32_req_s *)req;
-
-#ifdef CONFIG_DEBUG
- if (!ep || !req)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_INVALIDPARMS), 0);
- return;
- }
-#endif
-
- usbtrace(TRACE_EPFREEREQ, ((FAR struct stm32_ep_s *)ep)->epphy);
- free(privreq);
-}
-
-/*******************************************************************************
- * Name: stm32_ep_allocbuffer
- *
- * Description:
- * Allocate an I/O buffer
- *
- *******************************************************************************/
-
-#ifdef CONFIG_USBDEV_DMA
-static void *stm32_ep_allocbuffer(FAR struct usbdev_ep_s *ep, unsigned bytes)
-{
- usbtrace(TRACE_EPALLOCBUFFER, privep->epphy);
-
-#ifdef CONFIG_USBDEV_DMAMEMORY
- return usbdev_dma_alloc(bytes);
-#else
- return malloc(bytes);
-#endif
-}
-#endif
-
-/*******************************************************************************
- * Name: stm32_ep_freebuffer
- *
- * Description:
- * Free an I/O buffer
- *
- *******************************************************************************/
-
-#ifdef CONFIG_USBDEV_DMA
-static void stm32_ep_freebuffer(FAR struct usbdev_ep_s *ep, FAR void *buf)
-{
- usbtrace(TRACE_EPFREEBUFFER, privep->epphy);
-
-#ifdef CONFIG_USBDEV_DMAMEMORY
- usbdev_dma_free(buf);
-#else
- free(buf);
-#endif
-}
-#endif
-
-/*******************************************************************************
- * Name: stm32_ep_submit
- *
- * Description:
- * Submit an I/O request to the endpoint
- *
- *******************************************************************************/
-
-static int stm32_ep_submit(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req)
-{
- FAR struct stm32_req_s *privreq = (FAR struct stm32_req_s *)req;
- FAR struct stm32_ep_s *privep = (FAR struct stm32_ep_s *)ep;
- FAR struct stm32_usbdev_s *priv;
- irqstate_t flags;
- int ret = OK;
-
- /* Some sanity checking */
-
-#ifdef CONFIG_DEBUG
- if (!req || !req->callback || !req->buf || !ep)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_INVALIDPARMS), 0);
- ullvdbg("req=%p callback=%p buf=%p ep=%p\n", req, req->callback, req->buf, ep);
- return -EINVAL;
- }
-#endif
-
- usbtrace(TRACE_EPSUBMIT, privep->epphy);
- priv = privep->dev;
-
-#ifdef CONFIG_DEBUG
- if (!priv->driver)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_NOTCONFIGURED), priv->usbdev.speed);
- return -ESHUTDOWN;
- }
-#endif
-
- /* Handle the request from the class driver */
-
- req->result = -EINPROGRESS;
- req->xfrd = 0;
-
- /* Disable Interrupts */
-
- flags = irqsave();
-
- /* If we are stalled, then drop all requests on the floor */
-
- if (privep->stalled)
- {
- ret = -EBUSY;
- }
- else
- {
- /* Add the new request to the request queue for the endpoint. */
-
- if (stm32_req_addlast(privep, privreq) && !privep->active)
- {
- /* If a request was added to an IN endpoint, then attempt to send
- * the request data buffer now.
- */
-
- if (privep->isin)
- {
- usbtrace(TRACE_INREQQUEUED(privep->epphy), privreq->req.len);
-
- /* If the endpoint is not busy with another write request,
- * then process the newly received write request now.
- */
-
- if (!privep->active)
- {
- stm32_epin_request(priv, privep);
- }
- }
-
- /* If the request was added to an OUT endoutput, then attempt to
- * setup a read into the request data buffer now (this will, of
- * course, fail if there is already a read in place).
- */
-
- else
- {
- usbtrace(TRACE_OUTREQQUEUED(privep->epphy), privreq->req.len);
- stm32_epout_request(priv, privep);
- }
- }
- }
-
- irqrestore(flags);
- return ret;
-}
-
-/*******************************************************************************
- * Name: stm32_ep_cancel
- *
- * Description:
- * Cancel an I/O request previously sent to an endpoint
- *
- *******************************************************************************/
-
-static int stm32_ep_cancel(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req)
-{
- FAR struct stm32_ep_s *privep = (FAR struct stm32_ep_s *)ep;
- FAR struct stm32_usbdev_s *priv;
- irqstate_t flags;
-
-#ifdef CONFIG_DEBUG
- if (!ep || !req)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_INVALIDPARMS), 0);
- return -EINVAL;
- }
-#endif
-
- usbtrace(TRACE_EPCANCEL, privep->epphy);
- priv = privep->dev;
-
- flags = irqsave();
-
- /* FIXME: if the request is the first, then we need to flush the EP
- * otherwise just remove it from the list
- *
- * but ... all other implementations cancel all requests ...
- */
-
- stm32_req_cancel(privep, -ESHUTDOWN);
- irqrestore(flags);
- return OK;
-}
-
-/*******************************************************************************
- * Name: stm32_epout_setstall
- *
- * Description:
- * Stall an OUT endpoint
- *
- *******************************************************************************/
-
-static int stm32_epout_setstall(FAR struct stm32_ep_s *privep)
-{
-#if 1
- /* This implementation follows the requirements from the STM32 F4 reference
- * manual.
- */
-
- uint32_t regaddr;
- uint32_t regval;
-
- /* Put the core in the Global OUT NAK mode */
-
- stm32_enablegonak(privep);
-
- /* Disable and STALL the OUT endpoint by setting the EPDIS and STALL bits
- * in the DOECPTL register.
- */
-
- regaddr = STM32_OTGFS_DOEPCTL(privep->epphy);
- regval = stm32_getreg(regaddr);
- regval |= (OTGFS_DOEPCTL_EPDIS | OTGFS_DOEPCTL_STALL);
- stm32_putreg(regval, regaddr);
-
- /* Wait for the EPDISD interrupt which indicates that the OUT
- * endpoint is completely disabled.
- */
-
-#if 0 /* Doesn't happen */
- regaddr = STM32_OTGFS_DOEPINT(privep->epphy);
- while ((stm32_getreg(regaddr) & OTGFS_DOEPINT_EPDISD) == 0);
-#else
- /* REVISIT: */
- up_mdelay(50);
-#endif
-
- /* Disable Global OUT NAK mode */
-
- stm32_disablegonak(privep);
-
- /* The endpoint is now stalled */
-
- privep->stalled = true;
- return OK;
-#else
- /* This implementation follows the STMicro code example. */
- /* REVISIT: */
-
- uint32_t regaddr;
- uint32_t regval;
-
- /* Stall the OUT endpoint by setting the STALL bit in the DOECPTL register. */
-
- regaddr = STM32_OTGFS_DOEPCTL(privep->epphy);
- regval = stm32_getreg(regaddr);
- regval |= OTGFS_DOEPCTL_STALL;
- stm32_putreg(regval, regaddr);
-
- /* The endpoint is now stalled */
-
- privep->stalled = true;
- return OK;
-#endif
-}
-
-/*******************************************************************************
- * Name: stm32_epin_setstall
- *
- * Description:
- * Stall an IN endpoint
- *
- *******************************************************************************/
-
-static int stm32_epin_setstall(FAR struct stm32_ep_s *privep)
-{
- uint32_t regaddr;
- uint32_t regval;
-
- /* Get the IN endpoint device control register */
-
- regaddr = STM32_OTGFS_DIEPCTL(privep->epphy);
- regval = stm32_getreg(regaddr);
-
- /* Then stall the endpoint */
-
- regval |= OTGFS_DIEPCTL_STALL;
- stm32_putreg(regval, regaddr);
-
- /* The endpoint is now stalled */
-
- privep->stalled = true;
- return OK;
-}
-
-/*******************************************************************************
- * Name: stm32_ep_setstall
- *
- * Description:
- * Stall an endpoint
- *
- *******************************************************************************/
-
-static int stm32_ep_setstall(FAR struct stm32_ep_s *privep)
-{
- usbtrace(TRACE_EPSTALL, privep->epphy);
-
- /* Is this an IN endpoint? */
-
- if (privep->isin == 1)
- {
- return stm32_epin_setstall(privep);
- }
- else
- {
- return stm32_epout_setstall(privep);
- }
-}
-
-/*******************************************************************************
- * Name: stm32_ep_clrstall
- *
- * Description:
- * Resume a stalled endpoint
- *
- *******************************************************************************/
-
-static int stm32_ep_clrstall(FAR struct stm32_ep_s *privep)
-{
- uint32_t regaddr;
- uint32_t regval;
- uint32_t stallbit;
- uint32_t data0bit;
-
- usbtrace(TRACE_EPRESUME, privep->epphy);
-
- /* Is this an IN endpoint? */
-
- if (privep->isin == 1)
- {
- /* Clear the stall bit in the IN endpoint device control register */
-
- regaddr = STM32_OTGFS_DIEPCTL(privep->epphy);
- stallbit = OTGFS_DIEPCTL_STALL;
- data0bit = OTGFS_DIEPCTL_SD0PID;
- }
- else
- {
- /* Clear the stall bit in the IN endpoint device control register */
-
- regaddr = STM32_OTGFS_DOEPCTL(privep->epphy);
- stallbit = OTGFS_DOEPCTL_STALL;
- data0bit = OTGFS_DOEPCTL_SD0PID;
- }
-
- /* Clear the stall bit */
-
- regval = stm32_getreg(regaddr);
- regval &= ~stallbit;
-
- /* Set the DATA0 pid for interrupt and bulk endpoints */
-
- if (privep->eptype == USB_EP_ATTR_XFER_INT ||
- privep->eptype == USB_EP_ATTR_XFER_BULK)
- {
- /* Writing this bit sets the DATA0 PID */
-
- regval |= data0bit;
- }
-
- stm32_putreg(regval, regaddr);
-
- /* The endpoint is no longer stalled */
-
- privep->stalled = false;
- return OK;
-}
-
-/*******************************************************************************
- * Name: stm32_ep_stall
- *
- * Description:
- * Stall or resume an endpoint
- *
- *******************************************************************************/
-
-static int stm32_ep_stall(FAR struct usbdev_ep_s *ep, bool resume)
-{
- FAR struct stm32_ep_s *privep = (FAR struct stm32_ep_s *)ep;
- irqstate_t flags;
- int ret;
-
- /* Set or clear the stall condition as requested */
-
- flags = irqsave();
- if (resume)
- {
- ret = stm32_ep_clrstall(privep);
- }
- else
- {
- ret = stm32_ep_setstall(privep);
- }
- irqrestore(flags);
-
- return ret;
-}
-
-/*******************************************************************************
- * Name: stm32_ep0_stall
- *
- * Description:
- * Stall endpoint 0
- *
- *******************************************************************************/
-
-static void stm32_ep0_stall(FAR struct stm32_usbdev_s *priv)
-{
- stm32_epin_setstall(&priv->epin[EP0]);
- stm32_epout_setstall(&priv->epout[EP0]);
- priv->stalled = true;
- stm32_ep0out_ctrlsetup(priv);
-}
-
-/*******************************************************************************
- * Device operations
- *******************************************************************************/
-
-/*******************************************************************************
- * Name: stm32_ep_alloc
- *
- * Description:
- * Allocate an endpoint matching the parameters.
- *
- * Input Parameters:
- * eplog - 7-bit logical endpoint number (direction bit ignored). Zero means
- * that any endpoint matching the other requirements will suffice. The
- * assigned endpoint can be found in the eplog field.
- * in - true: IN (device-to-host) endpoint requested
- * eptype - Endpoint type. One of {USB_EP_ATTR_XFER_ISOC, USB_EP_ATTR_XFER_BULK,
- * USB_EP_ATTR_XFER_INT}
- *
- *******************************************************************************/
-
-static FAR struct usbdev_ep_s *stm32_ep_alloc(FAR struct usbdev_s *dev,
- uint8_t eplog, bool in,
- uint8_t eptype)
-{
- FAR struct stm32_usbdev_s *priv = (FAR struct stm32_usbdev_s *)dev;
- uint8_t epavail;
- irqstate_t flags;
- int epphy;
- int epno = 0;
-
- usbtrace(TRACE_DEVALLOCEP, (uint16_t)eplog);
-
- /* Ignore any direction bits in the logical address */
-
- epphy = USB_EPNO(eplog);
-
- /* Get the set of available endpoints */
-
- flags = irqsave();
- epavail = priv->epavail;
-
- /* A physical address of 0 means that any endpoint will do */
-
- if (epphy > 0)
- {
- /* Otherwise, we will return the endpoint structure only for the requested
- * 'logical' endpoint. All of the other checks will still be performed.
- *
- * First, verify that the logical endpoint is in the range supported by
- * by the hardware.
- */
-
- if (epphy >= STM32_NENDPOINTS)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_BADEPNO), (uint16_t)epphy);
- return NULL;
- }
-
- /* Remove all of the candidate endpoints from the bitset except for the
- * this physical endpoint number.
- */
-
- epavail &= (1 << epphy);
- }
-
- /* Is there an available endpoint? */
-
- if (epavail)
- {
- /* Yes.. Select the lowest numbered endpoint in the set of available
- * endpoints.
- */
-
- for (epno = 1; epno < STM32_NENDPOINTS; epno++)
- {
- uint8_t bit = 1 << epno;
- if ((epavail & bit) != 0)
- {
- /* Mark the endpoint no longer available */
-
- priv->epavail &= ~(1 << epno);
-
- /* And return the pointer to the standard endpoint structure */
-
- irqrestore(flags);
- return in ? &priv->epin[epno].ep : &priv->epout[epno].ep;
- }
- }
-
- /* We should not get here */
- }
-
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_NOEP), (uint16_t)eplog);
- irqrestore(flags);
- return NULL;
-}
-
-/*******************************************************************************
- * Name: stm32_ep_free
- *
- * Description:
- * Free the previously allocated endpoint
- *
- *******************************************************************************/
-
-static void stm32_ep_free(FAR struct usbdev_s *dev, FAR struct usbdev_ep_s *ep)
-{
- FAR struct stm32_usbdev_s *priv = (FAR struct stm32_usbdev_s *)dev;
- FAR struct stm32_ep_s *privep = (FAR struct stm32_ep_s *)ep;
- irqstate_t flags;
-
- usbtrace(TRACE_DEVFREEEP, (uint16_t)privep->epphy);
-
- if (priv && privep)
- {
- /* Mark the endpoint as available */
-
- flags = irqsave();
- priv->epavail |= (1 << privep->epphy);
- irqrestore(flags);
- }
-}
-
-/*******************************************************************************
- * Name: stm32_getframe
- *
- * Description:
- * Returns the current frame number
- *
- *******************************************************************************/
-
-static int stm32_getframe(struct usbdev_s *dev)
-{
- uint32_t regval;
-
- usbtrace(TRACE_DEVGETFRAME, 0);
-
- /* Return the last frame number of the last SOF detected by the hardware */
-
- regval = stm32_getreg(STM32_OTGFS_DSTS);
- return (int)((regval & OTGFS_DSTS_SOFFN_MASK) >> OTGFS_DSTS_SOFFN_SHIFT);
-}
-
-/*******************************************************************************
- * Name: stm32_wakeup
- *
- * Description:
- * Exit suspend mode.
- *
- *******************************************************************************/
-
-static int stm32_wakeup(struct usbdev_s *dev)
-{
- FAR struct stm32_usbdev_s *priv = (FAR struct stm32_usbdev_s *)dev;
- uint32_t regval;
- irqstate_t flags;
-
- usbtrace(TRACE_DEVWAKEUP, 0);
-
- /* Is wakeup enabled? */
-
- flags = irqsave();
- if (priv->wakeup)
- {
- /* Yes... is the core suspended? */
-
- regval = stm32_getreg(STM32_OTGFS_DSTS);
- if ((regval & OTGFS_DSTS_SUSPSTS) != 0)
- {
- /* Re-start the PHY clock and un-gate USB core clock (HCLK) */
-
-#ifdef CONFIG_USBDEV_LOWPOWER
- regval = stm32_getreg(STM32_OTGFS_PCGCCTL);
- regval &= ~(OTGFS_PCGCCTL_STPPCLK | OTGFS_PCGCCTL_GATEHCLK);
- stm32_putreg(regval, STM32_OTGFS_PCGCCTL);
-#endif
- /* Activate Remote wakeup signaling */
-
- regval = stm32_getreg(STM32_OTGFS_DCTL);
- regval |= OTGFS_DCTL_RWUSIG;
- stm32_putreg(regval, STM32_OTGFS_DCTL);
- up_mdelay(5);
- regval &= ~OTGFS_DCTL_RWUSIG;
- stm32_putreg(regval, STM32_OTGFS_DCTL);
- }
- }
-
- irqrestore(flags);
- return OK;
-}
-
-/*******************************************************************************
- * Name: stm32_selfpowered
- *
- * Description:
- * Sets/clears the device selfpowered feature
- *
- *******************************************************************************/
-
-static int stm32_selfpowered(struct usbdev_s *dev, bool selfpowered)
-{
- FAR struct stm32_usbdev_s *priv = (FAR struct stm32_usbdev_s *)dev;
-
- usbtrace(TRACE_DEVSELFPOWERED, (uint16_t)selfpowered);
-
-#ifdef CONFIG_DEBUG
- if (!dev)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_INVALIDPARMS), 0);
- return -ENODEV;
- }
-#endif
-
- priv->selfpowered = selfpowered;
- return OK;
-}
-
-/*******************************************************************************
- * Name: stm32_pullup
- *
- * Description:
- * Software-controlled connect to/disconnect from USB host
- *
- *******************************************************************************/
-
-static int stm32_pullup(struct usbdev_s *dev, bool enable)
-{
- uint32_t regval;
-
- usbtrace(TRACE_DEVPULLUP, (uint16_t)enable);
-
- irqstate_t flags = irqsave();
- regval = stm32_getreg(STM32_OTGFS_DCTL);
- if (enable)
- {
- /* Connect the device by clearing the soft disconnect bit in the DCTL
- * register
- */
-
- regval &= ~OTGFS_DCTL_SDIS;
- }
- else
- {
- /* Connect the device by setting the soft disconnect bit in the DCTL
- * register
- */
-
- regval |= OTGFS_DCTL_SDIS;
- }
-
- stm32_putreg(regval, STM32_OTGFS_DCTL);
- up_mdelay(3);
-
- irqrestore(flags);
- return OK;
-}
-
-/*******************************************************************************
- * Name: stm32_setaddress
- *
- * Description:
- * Set the devices USB address
- *
- *******************************************************************************/
-
-static void stm32_setaddress(struct stm32_usbdev_s *priv, uint16_t address)
-{
- uint32_t regval;
-
- /* Set the device address in the DCFG register */
-
- regval = stm32_getreg(STM32_OTGFS_DCFG);
- regval &= ~OTGFS_DCFG_DAD_MASK;
- regval |= ((uint32_t)address << OTGFS_DCFG_DAD_SHIFT);
- stm32_putreg(regval, STM32_OTGFS_DCFG);
-
- /* 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;
- }
-}
-
-/*******************************************************************************
- * Name: stm32_txfifo_flush
- *
- * Description:
- * Flush the specific TX fifo.
- *
- *******************************************************************************/
-
-static int stm32_txfifo_flush(uint32_t txfnum)
-{
- uint32_t regval;
- uint32_t timeout;
-
- /* Initiate the TX FIFO flush operation */
-
- regval = OTGFS_GRSTCTL_TXFFLSH | txfnum;
- stm32_putreg(regval, STM32_OTGFS_GRSTCTL);
-
- /* Wait for the FLUSH to complete */
-
- for (timeout = 0; timeout < STM32_FLUSH_DELAY; timeout++)
- {
- regval = stm32_getreg(STM32_OTGFS_GRSTCTL);
- if ((regval & OTGFS_GRSTCTL_TXFFLSH) == 0)
- {
- break;
- }
- }
-
- /* Wait for 3 PHY Clocks */
-
- up_udelay(3);
- return OK;
-}
-
-/*******************************************************************************
- * Name: stm32_rxfifo_flush
- *
- * Description:
- * Flush the RX fifo.
- *
- *******************************************************************************/
-
-static int stm32_rxfifo_flush(void)
-{
- uint32_t regval;
- uint32_t timeout;
-
- /* Initiate the RX FIFO flush operation */
-
- stm32_putreg(OTGFS_GRSTCTL_RXFFLSH, STM32_OTGFS_GRSTCTL);
-
- /* Wait for the FLUSH to complete */
-
- for (timeout = 0; timeout < STM32_FLUSH_DELAY; timeout++)
- {
- regval = stm32_getreg(STM32_OTGFS_GRSTCTL);
- if ((regval & OTGFS_GRSTCTL_RXFFLSH) == 0)
- {
- break;
- }
- }
-
- /* Wait for 3 PHY Clocks */
-
- up_udelay(3);
- return OK;
-}
-
-/*******************************************************************************
- * Name: stm32_swinitialize
- *
- * Description:
- * Initialize all driver data structures.
- *
- *******************************************************************************/
-
-static void stm32_swinitialize(FAR struct stm32_usbdev_s *priv)
-{
- FAR struct stm32_ep_s *privep;
- int i;
-
- /* Initialize the device state structure */
-
- memset(priv, 0, sizeof(struct stm32_usbdev_s));
-
- priv->usbdev.ops = &g_devops;
- priv->usbdev.ep0 = &priv->epin[EP0].ep;
- priv->epavail = STM32_EP_AVAILABLE;
-
- priv->epin[EP0].ep.priv = priv;
- priv->epout[EP0].ep.priv = priv;
-
- /* Initialize the endpoint lists */
-
- for (i = 0; i < STM32_NENDPOINTS; i++)
- {
- /* Set endpoint operations, reference to driver structure (not
- * really necessary because there is only one controller), and
- * the physical endpoint number (which is just the index to the
- * endpoint).
- */
-
- privep = &priv->epin[i];
- privep->ep.ops = &g_epops;
- privep->dev = priv;
- privep->isin = 1;
-
- /* The index, i, is the physical endpoint address; Map this
- * to a logical endpoint address usable by the class driver.
- */
-
- privep->epphy = i;
- privep->ep.eplog = STM32_EPPHYIN2LOG(i);
-
- /* Control until endpoint is activated */
-
- privep->eptype = USB_EP_ATTR_XFER_CONTROL;
- privep->ep.maxpacket = CONFIG_USBDEV_EP0_MAXSIZE;
- }
-
- /* Initialize the endpoint lists */
-
- for (i = 0; i < STM32_NENDPOINTS; i++)
- {
- /* Set endpoint operations, reference to driver structure (not
- * really necessary because there is only one controller), and
- * the physical endpoint number (which is just the index to the
- * endpoint).
- */
-
- privep = &priv->epout[i];
- privep->ep.ops = &g_epops;
- privep->dev = priv;
-
- /* The index, i, is the physical endpoint address; Map this
- * to a logical endpoint address usable by the class driver.
- */
-
- privep->epphy = i;
- privep->ep.eplog = STM32_EPPHYOUT2LOG(i);
-
- /* Control until endpoint is activated */
-
- privep->eptype = USB_EP_ATTR_XFER_CONTROL;
- privep->ep.maxpacket = CONFIG_USBDEV_EP0_MAXSIZE;
- }
-}
-
-/*******************************************************************************
- * Name: stm32_hwinitialize
- *
- * Description:
- * Configure the OTG FS core for operation.
- *
- *******************************************************************************/
-
-static void stm32_hwinitialize(FAR struct stm32_usbdev_s *priv)
-{
- uint32_t regval;
- uint32_t timeout;
- uint32_t address;
- int i;
-
- /* At startup the core is in FS mode. */
-
- /* Disable global interrupts by clearing the GINTMASK bit in the GAHBCFG
- * register; Set the TXFELVL bit in the GAHBCFG register so that TxFIFO
- * interrupts will occur when the TxFIFO is truly empty (not just half full).
- */
-
- stm32_putreg(OTGFS_GAHBCFG_TXFELVL, STM32_OTGFS_GAHBCFG);
-
- /* Common USB OTG core initialization */
- /* Reset after a PHY select and set Host mode. First, wait for AHB master
- * IDLE state.
- */
-
- for (timeout = 0; timeout < STM32_READY_DELAY; timeout++)
- {
- up_udelay(3);
- regval = stm32_getreg(STM32_OTGFS_GRSTCTL);
- if ((regval & OTGFS_GRSTCTL_AHBIDL) != 0)
- {
- break;
- }
- }
-
- /* Then perform the core soft reset. */
-
- stm32_putreg(OTGFS_GRSTCTL_CSRST, STM32_OTGFS_GRSTCTL);
- for (timeout = 0; timeout < STM32_READY_DELAY; timeout++)
- {
- regval = stm32_getreg(STM32_OTGFS_GRSTCTL);
- if ((regval & OTGFS_GRSTCTL_CSRST) == 0)
- {
- break;
- }
- }
-
- /* Wait for 3 PHY Clocks */
-
- up_udelay(3);
-
- /* Deactivate the power down */
-
- regval = (OTGFS_GCCFG_PWRDWN | OTGFS_GCCFG_VBUSASEN | OTGFS_GCCFG_VBUSBSEN);
-#ifndef CONFIG_USBDEV_VBUSSENSING
- regval |= OTGFS_GCCFG_NOVBUSSENS;
-#endif
-#ifdef CONFIG_STM32_OTGFS_SOFOUTPUT
- regval |= OTGFS_GCCFG_SOFOUTEN;
-#endif
- stm32_putreg(regval, STM32_OTGFS_GCCFG);
- up_mdelay(20);
-
- /* Force Device Mode */
-
- regval = stm32_getreg(STM32_OTGFS_GUSBCFG);
- regval &= ~OTGFS_GUSBCFG_FHMOD;
- regval |= OTGFS_GUSBCFG_FDMOD;
- stm32_putreg(regval, STM32_OTGFS_GUSBCFG);
- up_mdelay(50);
-
- /* Initialize device mode */
- /* Restart the Phy Clock */
-
- stm32_putreg(0, STM32_OTGFS_PCGCCTL);
-
- /* Device configuration register */
-
- regval = stm32_getreg(STM32_OTGFS_DCFG);
- regval &= ~OTGFS_DCFG_PFIVL_MASK;
- regval |= OTGFS_DCFG_PFIVL_80PCT;
- stm32_putreg(regval, STM32_OTGFS_DCFG);
-
- /* Set full speed phy */
-
- regval = stm32_getreg(STM32_OTGFS_DCFG);
- regval &= ~OTGFS_DCFG_DSPD_MASK;
- regval |= OTGFS_DCFG_DSPD_FS;
- stm32_putreg(regval, STM32_OTGFS_DCFG);
-
- /* Set Rx FIFO size */
-
- stm32_putreg(STM32_RXFIFO_WORDS, STM32_OTGFS_GRXFSIZ);
-
- /* EP0 TX */
-
- address = STM32_RXFIFO_WORDS;
- regval = (address << OTGFS_DIEPTXF0_TX0FD_SHIFT) |
- (STM32_EP0_TXFIFO_WORDS << OTGFS_DIEPTXF0_TX0FSA_SHIFT);
- stm32_putreg(regval, STM32_OTGFS_DIEPTXF0);
-
- /* EP1 TX */
-
- address += STM32_EP0_TXFIFO_WORDS;
- regval = (address << OTGFS_DIEPTXF_INEPTXSA_SHIFT) |
- (STM32_EP1_TXFIFO_WORDS << OTGFS_DIEPTXF_INEPTXFD_SHIFT);
- stm32_putreg(regval, STM32_OTGFS_DIEPTXF1);
-
- /* EP2 TX */
-
- address += STM32_EP1_TXFIFO_WORDS;
- regval = (address << OTGFS_DIEPTXF_INEPTXSA_SHIFT) |
- (STM32_EP2_TXFIFO_WORDS << OTGFS_DIEPTXF_INEPTXFD_SHIFT);
- stm32_putreg(regval, STM32_OTGFS_DIEPTXF2);
-
- /* EP3 TX */
-
- address += STM32_EP2_TXFIFO_WORDS;
- regval = (address << OTGFS_DIEPTXF_INEPTXSA_SHIFT) |
- (STM32_EP3_TXFIFO_WORDS << OTGFS_DIEPTXF_INEPTXFD_SHIFT);
- stm32_putreg(regval, STM32_OTGFS_DIEPTXF3);
-
- /* Flush the FIFOs */
-
- stm32_txfifo_flush(OTGFS_GRSTCTL_TXFNUM_DALL);
- stm32_rxfifo_flush();
-
- /* Clear all pending Device Interrupts */
-
- stm32_putreg(0, STM32_OTGFS_DIEPMSK);
- stm32_putreg(0, STM32_OTGFS_DOEPMSK);
- stm32_putreg(0, STM32_OTGFS_DIEPEMPMSK);
- stm32_putreg(0xffffffff, STM32_OTGFS_DAINT);
- stm32_putreg(0, STM32_OTGFS_DAINTMSK);
-
- /* Configure all IN endpoints */
-
- for (i = 0; i < STM32_NENDPOINTS; i++)
- {
- regval = stm32_getreg(STM32_OTGFS_DIEPCTL(i));
- if ((regval & OTGFS_DIEPCTL_EPENA) != 0)
- {
- /* The endpoint is already enabled */
-
- regval = OTGFS_DIEPCTL_EPENA | OTGFS_DIEPCTL_SNAK;
- }
- else
- {
- regval = 0;
- }
-
- stm32_putreg(regval, STM32_OTGFS_DIEPCTL(i));
- stm32_putreg(0, STM32_OTGFS_DIEPTSIZ(i));
- stm32_putreg(0xff, STM32_OTGFS_DIEPINT(i));
- }
-
- /* Configure all OUT endpoints */
-
- for (i = 0; i < STM32_NENDPOINTS; i++)
- {
- regval = stm32_getreg(STM32_OTGFS_DOEPCTL(i));
- if ((regval & OTGFS_DOEPCTL_EPENA) != 0)
- {
- /* The endpoint is already enabled */
-
- regval = OTGFS_DOEPCTL_EPENA | OTGFS_DOEPCTL_SNAK;
- }
- else
- {
- regval = 0;
- }
-
- stm32_putreg(regval, STM32_OTGFS_DOEPCTL(i));
- stm32_putreg(0, STM32_OTGFS_DOEPTSIZ(i));
- stm32_putreg(0xff, STM32_OTGFS_DOEPINT(i));
- }
-
- /* Disable all interrupts. */
-
- stm32_putreg(0, STM32_OTGFS_GINTMSK);
-
- /* Clear any pending USB_OTG Interrupts */
-
- stm32_putreg(0xffffffff, STM32_OTGFS_GOTGINT);
-
- /* Clear any pending interrupts */
-
- stm32_putreg(0xbfffffff, STM32_OTGFS_GINTSTS);
-
- /* Enable the interrupts in the INTMSK */
-
- regval = (OTGFS_GINT_RXFLVL | OTGFS_GINT_USBSUSP | OTGFS_GINT_ENUMDNE |
- OTGFS_GINT_IEP | OTGFS_GINT_OEP | OTGFS_GINT_USBRST);
-
-#ifdef CONFIG_USBDEV_ISOCHRONOUS
- regval |= (OTGFS_GINT_IISOIXFR | OTGFS_GINT_IISOOXFR);
-#endif
-
-#ifdef CONFIG_USBDEV_SOFINTERRUPT
- regval |= OTGFS_GINT_SOF;
-#endif
-
-#ifdef CONFIG_USBDEV_VBUSSENSING
- regval |= (OTGFS_GINT_OTG | OTGFS_GINT_SRQ);
-#endif
-
-#ifdef CONFIG_DEBUG_USB
- regval |= OTGFS_GINT_MMIS;
-#endif
-
- stm32_putreg(regval, STM32_OTGFS_GINTMSK);
-
- /* Enable the USB global interrupt by setting GINTMSK in the global OTG
- * FS AHB configuration register; Set the TXFELVL bit in the GAHBCFG
- * register so that TxFIFO interrupts will occur when the TxFIFO is truly
- * empty (not just half full).
- */
-
- stm32_putreg(OTGFS_GAHBCFG_GINTMSK | OTGFS_GAHBCFG_TXFELVL,
- STM32_OTGFS_GAHBCFG);
-}
-
-/*******************************************************************************
- * Public Functions
- *******************************************************************************/
-
-/*******************************************************************************
- * Name: up_usbinitialize
- *
- * Description:
- * Initialize USB hardware.
- *
- * Assumptions:
- * - This function is called very early in the initialization sequence
- * - PLL and GIO pin initialization is not performed here but should been in
- * the low-level boot logic: PLL1 must be configured for operation at 48MHz
- * and P0.23 and PO.31 in PINSEL1 must be configured for Vbus and USB connect
- * LED.
- *
- *******************************************************************************/
-
-void up_usbinitialize(void)
-{
- /* At present, there is only a single OTG FS device support. Hence it is
- * pre-allocated as g_otgfsdev. However, in most code, the private data
- * structure will be referenced using the 'priv' pointer (rather than the
- * global data) in order to simplify any future support for multiple devices.
- */
-
- FAR struct stm32_usbdev_s *priv = &g_otgfsdev;
- int ret;
-
- usbtrace(TRACE_DEVINIT, 0);
-
- /* Here we assume that:
- *
- * 1. GPIOA and OTG FS peripheral clocking has already been enabled as part
- * of the boot sequence.
- * 2. Board-specific logic has already enabled other board specific GPIOs
- * for things like soft pull-up, VBUS sensing, power controls, and over-
- * current detection.
- */
-
- /* Configure OTG FS alternate function pins
- *
- * PIN* SIGNAL DIRECTION
- * ---- ----------- ----------
- * PA8 OTG_FS_SOF SOF clock output
- * PA9 OTG_FS_VBUS VBUS input for device, Driven by external regulator by
- * host (not an alternate function)
- * PA10 OTG_FS_ID OTG ID pin (only needed in Dual mode)
- * PA11 OTG_FS_DM D- I/O
- * PA12 OTG_FS_DP D+ I/O
- *
- * *Pins may vary from device-to-device.
- */
-
- stm32_configgpio(GPIO_OTGFS_DM);
- stm32_configgpio(GPIO_OTGFS_DP);
- stm32_configgpio(GPIO_OTGFS_ID); /* Only needed for OTG */
-
- /* SOF output pin configuration is configurable. */
-
-#ifdef CONFIG_STM32_OTGFS_SOFOUTPUT
- stm32_configgpio(GPIO_OTGFS_SOF);
-#endif
-
- /* Uninitialize the hardware so that we know that we are starting from a
- * known state. */
-
- up_usbuninitialize();
-
- /* Initialie the driver data structure */
-
- stm32_swinitialize(priv);
-
- /* Attach the OTG FS interrupt handler */
-
- ret = irq_attach(STM32_IRQ_OTGFS, stm32_usbinterrupt);
- if (ret < 0)
- {
- udbg("irq_attach failed\n", ret);
- goto errout;
- }
-
- /* Initialize the USB OTG core */
-
- stm32_hwinitialize(priv);
-
- /* Disconnect device */
-
- stm32_pullup(&priv->usbdev, false);
-
- /* Reset/Re-initialize the USB hardware */
-
- stm32_usbreset(priv);
-
- /* Enable USB controller interrupts at the NVIC */
-
- up_enable_irq(STM32_IRQ_OTGFS);
-
- /* Set the interrrupt priority */
-
- up_prioritize_irq(STM32_IRQ_OTGFS, CONFIG_OTGFS_PRI);
- return;
-
-errout:
- up_usbuninitialize();
-}
-
-/*******************************************************************************
- * Name: up_usbuninitialize
- *******************************************************************************/
-
-void up_usbuninitialize(void)
-{
- /* At present, there is only a single OTG FS device support. Hence it is
- * pre-allocated as g_otgfsdev. However, in most code, the private data
- * structure will be referenced using the 'priv' pointer (rather than the
- * global data) in order to simplify any future support for multiple devices.
- */
-
- FAR struct stm32_usbdev_s *priv = &g_otgfsdev;
- irqstate_t flags;
- int i;
-
- usbtrace(TRACE_DEVUNINIT, 0);
-
- if (priv->driver)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_DRIVERREGISTERED), 0);
- usbdev_unregister(priv->driver);
- }
-
- /* Disconnect device */
-
- flags = irqsave();
- stm32_pullup(&priv->usbdev, false);
- priv->usbdev.speed = USB_SPEED_UNKNOWN;
-
- /* Disable and detach IRQs */
-
- up_disable_irq(STM32_IRQ_OTGFS);
- irq_detach(STM32_IRQ_OTGFS);
-
- /* Disable all endpoint interrupts */
-
- for (i = 0; i < STM32_NENDPOINTS; i++)
- {
- stm32_putreg(0xff, STM32_OTGFS_DIEPINT(i));
- stm32_putreg(0xff, STM32_OTGFS_DOEPINT(i));
- }
-
- stm32_putreg(0, STM32_OTGFS_DIEPMSK);
- stm32_putreg(0, STM32_OTGFS_DOEPMSK);
- stm32_putreg(0, STM32_OTGFS_DIEPEMPMSK);
- stm32_putreg(0, STM32_OTGFS_DAINTMSK);
- stm32_putreg(0xffffffff, STM32_OTGFS_DAINT);
-
- /* Flush the FIFOs */
-
- stm32_txfifo_flush(OTGFS_GRSTCTL_TXFNUM_DALL);
- stm32_rxfifo_flush();
-
- /* TODO: Turn off USB power and clocking */
-
- priv->devstate = DEVSTATE_DEFAULT;
- irqrestore(flags);
-}
-
-/*******************************************************************************
- * Name: usbdev_register
- *
- * Description:
- * Register a USB device class driver. The class driver's bind() method will be
- * called to bind it to a USB device driver.
- *
- *******************************************************************************/
-
-int usbdev_register(struct usbdevclass_driver_s *driver)
-{
- /* At present, there is only a single OTG FS device support. Hence it is
- * pre-allocated as g_otgfsdev. However, in most code, the private data
- * structure will be referenced using the 'priv' pointer (rather than the
- * global data) in order to simplify any future support for multiple devices.
- */
-
- FAR struct stm32_usbdev_s *priv = &g_otgfsdev;
- int ret;
-
- usbtrace(TRACE_DEVREGISTER, 0);
-
-#ifdef CONFIG_DEBUG
- if (!driver || !driver->ops->bind || !driver->ops->unbind ||
- !driver->ops->disconnect || !driver->ops->setup)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_INVALIDPARMS), 0);
- return -EINVAL;
- }
-
- if (priv->driver)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_DRIVER), 0);
- return -EBUSY;
- }
-#endif
-
- /* First hook up the driver */
-
- priv->driver = driver;
-
- /* Then bind the class driver */
-
- ret = CLASS_BIND(driver, &priv->usbdev);
- if (ret)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_BINDFAILED), (uint16_t)-ret);
- priv->driver = NULL;
- }
- else
- {
- /* Enable USB controller interrupts */
-
- up_enable_irq(STM32_IRQ_OTGFS);
-
- /* FIXME: nothing seems to call DEV_CONNECT(), but we need to set
- * the RS bit to enable the controller. It kind of makes sense
- * to do this after the class has bound to us...
- * GEN: This bug is really in the class driver. It should make the
- * soft connect when it is ready to be enumerated. I have added
- * that logic to the class drivers but left this logic here.
- */
-
- stm32_pullup(&priv->usbdev, true);
- priv->usbdev.speed = USB_SPEED_FULL;
- }
-
- return ret;
-}
-
-/*******************************************************************************
- * Name: usbdev_unregister
- *
- * Description:
- * Un-register usbdev class driver.If the USB device is connected to a USB host,
- * it will first disconnect(). The driver is also requested to unbind() and clean
- * up any device state, before this procedure finally returns.
- *
- *******************************************************************************/
-
-int usbdev_unregister(struct usbdevclass_driver_s *driver)
-{
- /* At present, there is only a single OTG FS device support. Hence it is
- * pre-allocated as g_otgfsdev. However, in most code, the private data
- * structure will be referenced using the 'priv' pointer (rather than the
- * global data) in order to simplify any future support for multiple devices.
- */
-
- FAR struct stm32_usbdev_s *priv = &g_otgfsdev;
- irqstate_t flags;
-
- usbtrace(TRACE_DEVUNREGISTER, 0);
-
-#ifdef CONFIG_DEBUG
- if (driver != priv->driver)
- {
- usbtrace(TRACE_DEVERROR(STM32_TRACEERR_INVALIDPARMS), 0);
- return -EINVAL;
- }
-#endif
-
- /* Reset the hardware and cancel all requests. All requests must be
- * canceled while the class driver is still bound.
- */
-
- flags = irqsave();
- stm32_usbreset(priv);
-
- /* Unbind the class driver */
-
- CLASS_UNBIND(driver, &priv->usbdev);
-
- /* Disable USB controller interrupts */
-
- up_disable_irq(STM32_IRQ_OTGFS);
-
- /* Disconnect device */
-
- stm32_pullup(&priv->usbdev, false);
-
- /* Unhook the driver */
-
- priv->driver = NULL;
- irqrestore(flags);
-
- return OK;
-}
-
-#endif /* CONFIG_USBDEV && CONFIG_STM32_OTGFSDEV */