pkarashchenko commented on code in PR #9525: URL: https://github.com/apache/nuttx/pull/9525#discussion_r1228737265
########## arch/xtensa/src/esp32s3/esp32s3_otg_device.c: ########## @@ -0,0 +1,5847 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s3/esp32s3_otg_device.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/param.h> +#include <sys/types.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/arch.h> +#include <nuttx/kmalloc.h> +#include <nuttx/usb/usb.h> +#include <nuttx/usb/usbdev.h> +#include <nuttx/usb/usbdev_trace.h> + +#include <nuttx/irq.h> +#include <arch/board/board.h> + +#include "xtensa.h" +#include "hardware/esp32s3_otg.h" +#include "hardware/esp32s3_system.h" +#include "hardware/esp32s3_gpio_sigmap.h" +#include "hardware/esp32s3_usb_wrap.h" +#include "hardware/esp32s3_rtccntl.h" +#include "hardware/esp32s3_pinmap.h" +#include "esp32s3_gpio.h" +#include "esp32s3_irq.h" +#include "esp32s3_otg.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* USB hardware definition */ + +#define ESP32S3_FIFO_SIZE (1280) +#define ESP32S3_FIFO_WORDS (ESP32S3_FIFO_SIZE >> 2) + +/* EP0 + additional EP */ + +#define ESP32S3_ENDPOINT_NUM (CONFIG_ESP32S3_OTG_ENDPOINT_NUM + 1) + +/* 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. + */ + +#define ESP32S3_TXFIFO_SIZE \ + (ESP32S3_FIFO_SIZE / 2 / ESP32S3_ENDPOINT_NUM * ESP32S3_ENDPOINT_NUM) + +#define ESP32S3_EP_TXFIFO_SIZE \ + (ESP32S3_TXFIFO_SIZE / ESP32S3_ENDPOINT_NUM) + +/* EP0 must exist */ + +#ifdef CONFIG_USBDEV_EP0_TXFIFO_SIZE +# define ESP32S3_EP0_TXFIFO_SIZE CONFIG_USBDEV_EP0_TXFIFO_SIZE +#else +# define ESP32S3_EP0_TXFIFO_SIZE ESP32S3_EP_TXFIFO_SIZE +#endif + +#if ESP32S3_ENDPOINT_NUM > 1 +# ifdef CONFIG_USBDEV_EP1_TXFIFO_SIZE +# define ESP32S3_EP1_TXFIFO_SIZE CONFIG_USBDEV_EP1_TXFIFO_SIZE +# else +# define ESP32S3_EP1_TXFIFO_SIZE ESP32S3_EP_TXFIFO_SIZE +# endif +#else +# define ESP32S3_EP1_TXFIFO_SIZE 0 +#endif + +#if ESP32S3_ENDPOINT_NUM > 2 +# ifdef CONFIG_USBDEV_EP2_TXFIFO_SIZE +# define ESP32S3_EP2_TXFIFO_SIZE CONFIG_USBDEV_EP2_TXFIFO_SIZE +# else +# define ESP32S3_EP2_TXFIFO_SIZE ESP32S3_EP_TXFIFO_SIZE +# endif +#else +# define ESP32S3_EP2_TXFIFO_SIZE 0 +#endif + +#if ESP32S3_ENDPOINT_NUM > 3 +# ifdef CONFIG_USBDEV_EP3_TXFIFO_SIZE +# define ESP32S3_EP3_TXFIFO_SIZE CONFIG_USBDEV_EP3_TXFIFO_SIZE +# else +# define ESP32S3_EP3_TXFIFO_SIZE ESP32S3_EP_TXFIFO_SIZE +# endif +#else +# define ESP32S3_EP3_TXFIFO_SIZE 0 +#endif + +#if ESP32S3_ENDPOINT_NUM > 4 +# ifdef CONFIG_USBDEV_EP4_TXFIFO_SIZE +# define ESP32S3_EP4_TXFIFO_SIZE CONFIG_USBDEV_EP4_TXFIFO_SIZE +# else +# define ESP32S3_EP4_TXFIFO_SIZE ESP32S3_EP_TXFIFO_SIZE +# endif +#else +# define ESP32S3_EP4_TXFIFO_SIZE 0 +#endif + +#if ESP32S3_ENDPOINT_NUM > 5 +# ifdef CONFIG_USBDEV_EP5_TXFIFO_SIZE +# define ESP32S3_EP5_TXFIFO_SIZE CONFIG_USBDEV_EP5_TXFIFO_SIZE +# else +# define ESP32S3_EP5_TXFIFO_SIZE ESP32S3_EP_TXFIFO_SIZE +# endif +#else +# define ESP32S3_EP5_TXFIFO_SIZE 0 +#endif + +#if ESP32S3_ENDPOINT_NUM > 6 +# ifdef CONFIG_USBDEV_EP6_TXFIFO_SIZE +# define ESP32S3_EP6_TXFIFO_SIZE CONFIG_USBDEV_EP6_TXFIFO_SIZE +# else +# define ESP32S3_EP6_TXFIFO_SIZE ESP32S3_EP_TXFIFO_SIZE +# endif +#else +# define ESP32S3_EP6_TXFIFO_SIZE 0 +#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 ALIGN(v, a) (((v) + (a - 1)) & (~(a - 1))) + +#define ESP32S3_EP0_TXFIFO_WORDS (ALIGN(ESP32S3_EP0_TXFIFO_SIZE, 4) >> 2) +#define ESP32S3_EP1_TXFIFO_WORDS (ALIGN(ESP32S3_EP1_TXFIFO_SIZE, 4) >> 2) +#define ESP32S3_EP2_TXFIFO_WORDS (ALIGN(ESP32S3_EP2_TXFIFO_SIZE, 4) >> 2) +#define ESP32S3_EP3_TXFIFO_WORDS (ALIGN(ESP32S3_EP3_TXFIFO_SIZE, 4) >> 2) +#define ESP32S3_EP4_TXFIFO_WORDS (ALIGN(ESP32S3_EP4_TXFIFO_SIZE, 4) >> 2) +#define ESP32S3_EP5_TXFIFO_WORDS (ALIGN(ESP32S3_EP5_TXFIFO_SIZE, 4) >> 2) +#define ESP32S3_EP6_TXFIFO_WORDS (ALIGN(ESP32S3_EP6_TXFIFO_SIZE, 4) >> 2) + +#define ESP32S3_RXFIFO_WORDS \ + (ESP32S3_FIFO_WORDS - \ + ESP32S3_EP0_TXFIFO_WORDS - \ + ESP32S3_EP1_TXFIFO_WORDS - \ + ESP32S3_EP2_TXFIFO_WORDS - \ + ESP32S3_EP3_TXFIFO_WORDS - \ + ESP32S3_EP4_TXFIFO_WORDS - \ + ESP32S3_EP5_TXFIFO_WORDS - \ + ESP32S3_EP6_TXFIFO_WORDS) + +#if (ESP32S3_RXFIFO_WORDS * 4) < 64 +# error "ESP32-S3 OTG device RX FIFO size should >= 64" +#endif + +/* EP0 max packet size */ + +#define ESP32S3_CDCACM_EP0MAXPACKET CONFIG_CDCACM_EP0MAXPACKET + +#define OTG_GINT_RESERVED_FS (OTG_GINT_RES89 | \ + OTG_GINT_RES1617 | \ + OTG_GINT_RES22) + +#define OTG_GINT_RC_W1_FS (OTG_GINT_MMIS | \ + OTG_GINT_SOF | \ + OTG_GINT_ESUSP | \ + OTG_GINT_USBSUSP | \ + OTG_GINT_USBRST | \ + OTG_GINT_ENUMDNE | \ + OTG_GINT_ISOODRP | \ + OTG_GINT_EOPF | \ + OTG_GINT_IISOIXFR | \ + OTG_GINT_IISOOXFR | \ + OTG_GINT_RSTDET | \ + OTG_GINT_LPMINT | \ + OTG_GINT_CIDSCHG | \ + OTG_GINT_DISC | \ + OTG_GINT_SRQ | \ + OTG_GINT_WKUP) + +#define OTG_GINT_RESERVED OTG_GINT_RESERVED_FS +#define OTG_GINT_RC_W1 OTG_GINT_RC_W1_FS + +/* Debug ********************************************************************/ + +/* Trace error codes */ + +#define ESP32S3_TRACEERR_ALLOCFAIL 0x01 +#define ESP32S3_TRACEERR_BADCLEARFEATURE 0x02 +#define ESP32S3_TRACEERR_BADDEVGETSTATUS 0x03 +#define ESP32S3_TRACEERR_BADEPNO 0x04 +#define ESP32S3_TRACEERR_BADEPGETSTATUS 0x05 +#define ESP32S3_TRACEERR_BADGETCONFIG 0x06 +#define ESP32S3_TRACEERR_BADGETSETDESC 0x07 +#define ESP32S3_TRACEERR_BADGETSTATUS 0x08 +#define ESP32S3_TRACEERR_BADSETADDRESS 0x09 +#define ESP32S3_TRACEERR_BADSETCONFIG 0x0a +#define ESP32S3_TRACEERR_BADSETFEATURE 0x0b +#define ESP32S3_TRACEERR_BADTESTMODE 0x0c +#define ESP32S3_TRACEERR_BINDFAILED 0x0d +#define ESP32S3_TRACEERR_DISPATCHSTALL 0x0e +#define ESP32S3_TRACEERR_DRIVER 0x0f +#define ESP32S3_TRACEERR_DRIVERREGISTERED 0x10 +#define ESP32S3_TRACEERR_EP0NOSETUP 0x11 +#define ESP32S3_TRACEERR_EP0SETUPSTALLED 0x12 +#define ESP32S3_TRACEERR_EPINNULLPACKET 0x13 +#define ESP32S3_TRACEERR_EPINUNEXPECTED 0x14 +#define ESP32S3_TRACEERR_EPOUTNULLPACKET 0x15 +#define ESP32S3_TRACEERR_EPOUTUNEXPECTED 0x16 +#define ESP32S3_TRACEERR_INVALIDCTRLREQ 0x17 +#define ESP32S3_TRACEERR_INVALIDPARMS 0x18 +#define ESP32S3_TRACEERR_IRQREGISTRATION 0x19 +#define ESP32S3_TRACEERR_NOEP 0x1a +#define ESP32S3_TRACEERR_NOTCONFIGURED 0x1b +#define ESP32S3_TRACEERR_EPOUTQEMPTY 0x1c +#define ESP32S3_TRACEERR_EPINREQEMPTY 0x1d +#define ESP32S3_TRACEERR_NOOUTSETUP 0x1e +#define ESP32S3_TRACEERR_POLLTIMEOUT 0x1f + +/* Trace interrupt codes */ + +#define ESP32S3_TRACEINTID_USB 1 /* USB Interrupt entry/exit */ +#define ESP32S3_TRACEINTID_INTPENDING 2 /* On each pass through the loop */ + +#define ESP32S3_TRACEINTID_EPOUT (10 + 0) /* First level interrupt decode */ +#define ESP32S3_TRACEINTID_EPIN (10 + 1) +#define ESP32S3_TRACEINTID_MISMATCH (10 + 2) +#define ESP32S3_TRACEINTID_WAKEUP (10 + 3) +#define ESP32S3_TRACEINTID_SUSPEND (10 + 4) +#define ESP32S3_TRACEINTID_SOF (10 + 5) +#define ESP32S3_TRACEINTID_RXFIFO (10 + 6) +#define ESP32S3_TRACEINTID_DEVRESET (10 + 7) +#define ESP32S3_TRACEINTID_ENUMDNE (10 + 8) +#define ESP32S3_TRACEINTID_IISOIXFR (10 + 9) +#define ESP32S3_TRACEINTID_IISOOXFR (10 + 10) +#define ESP32S3_TRACEINTID_SRQ (10 + 11) +#define ESP32S3_TRACEINTID_OTG (10 + 12) + +#define ESP32S3_TRACEINTID_EPOUT_XFRC (40 + 0) /* EPOUT second level decode */ +#define ESP32S3_TRACEINTID_EPOUT_EPDISD (40 + 1) +#define ESP32S3_TRACEINTID_EPOUT_SETUP (40 + 2) +#define ESP32S3_TRACEINTID_DISPATCH (40 + 3) + +#define ESP32S3_TRACEINTID_GETSTATUS (50 + 0) /* EPOUT third level decode */ +#define ESP32S3_TRACEINTID_EPGETSTATUS (50 + 1) +#define ESP32S3_TRACEINTID_DEVGETSTATUS (50 + 2) +#define ESP32S3_TRACEINTID_IFGETSTATUS (50 + 3) +#define ESP32S3_TRACEINTID_CLEARFEATURE (50 + 4) +#define ESP32S3_TRACEINTID_SETFEATURE (50 + 5) +#define ESP32S3_TRACEINTID_SETADDRESS (50 + 6) +#define ESP32S3_TRACEINTID_GETSETDESC (50 + 7) +#define ESP32S3_TRACEINTID_GETCONFIG (50 + 8) +#define ESP32S3_TRACEINTID_SETCONFIG (50 + 9) +#define ESP32S3_TRACEINTID_GETSETIF (50 + 10) +#define ESP32S3_TRACEINTID_SYNCHFRAME (50 + 11) + +#define ESP32S3_TRACEINTID_EPIN_XFRC (70 + 0) /* EPIN second level decode */ +#define ESP32S3_TRACEINTID_EPIN_TOC (70 + 1) +#define ESP32S3_TRACEINTID_EPIN_ITTXFE (70 + 2) +#define ESP32S3_TRACEINTID_EPIN_EPDISD (70 + 3) +#define ESP32S3_TRACEINTID_EPIN_TXFE (70 + 4) + +#define ESP32S3_TRACEINTID_EPIN_EMPWAIT (80 + 0) /* EPIN second level decode */ + +#define ESP32S3_TRACEINTID_OUTNAK (90 + 0) /* RXFLVL second level decode */ +#define ESP32S3_TRACEINTID_OUTRECVD (90 + 1) +#define ESP32S3_TRACEINTID_OUTDONE (90 + 2) +#define ESP32S3_TRACEINTID_SETUPDONE (90 + 3) +#define ESP32S3_TRACEINTID_SETUPRECVD (90 + 4) + +/* Endpoints ****************************************************************/ + +/* Odd physical endpoint numbers are IN; even are OUT */ + +#define ESP32S3_EPPHYIN2LOG(epphy) ((uint8_t)(epphy) | USB_DIR_IN) +#define ESP32S3_EPPHYOUT2LOG(epphy) ((uint8_t)(epphy) | USB_DIR_OUT) + +/* Endpoint 0 */ + +#define EP0 (0) + +/* The set of all endpoints available to the class implementation (1-3) */ + +#define ESP32S3_EP_AVAILABLE (0xfe) /* All available endpoints */ + +/* Delays *******************************************************************/ + +#define ESP32S3_READY_DELAY 200000 +#define ESP32S3_FLUSH_DELAY 200000 + +/* Request queue operations *************************************************/ + +#define esp32s3_rqempty(ep) ((ep)->head == NULL) +#define esp32s3_rqpeek(ep) ((ep)->head) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Overall device state */ + +enum esp32s3_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 esp32s3_ep0state_e +{ + EP0STATE_IDLE = 0, /* Idle State, leave on receiving a SETUP + * packet or epsubmit: SET: In esp32s3_epin() and + * esp32s3_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 + * esp32s3_rxinterrupt() when SETUP OUT packet is + * received. TESTED: In esp32s3_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) + * esp32s3_ep0out_receive() when the OUT SETUP + * data phase completes, or (2) + * esp32s3_rxinterrupt() when an IN SETUP is + * packet received. TESTED: Tested in + * esp32s3_epout_interrupt() when SETUP phase is + * done to see if the SETUP command is ready to + * be processed. Also tested in + * esp32s3_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 + * esp32s3_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 esp32s3_ep0in_setupresponse() TESTED: Never */ + EP0STATE_DATA_IN, /* Waiting for data out stage (with a USB + * request): SET: In esp32s3_epin_request() when + * a write request is processed on EP0. + * TESTED: In esp32s3_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 esp32s3_epout_request() + * when a read request is processed on EP0. + * TESTED: In esp32s3_epout() to see if we should + * revert to SETUP processing */ +}; + +/* Parsed control request */ + +struct esp32s3_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 esp32s3_req_s +{ + struct usbdev_req_s req; /* Standard USB request */ + struct esp32s3_req_s *flink; /* Supports a singly linked list */ +}; + +/* This is the internal representation of an endpoint */ + +struct esp32s3_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 esp32s3_ep_s. + */ + + struct usbdev_ep_s ep; /* Standard endpoint structure */ + + /* ESP32-S3-specific fields */ + + struct esp32s3_usbdev_s *dev; /* Reference to private driver data */ + struct esp32s3_req_s *head; /* Request list for this endpoint */ + struct esp32s3_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 esp32s3_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 esp32s3_usbdev_s. + */ + + struct usbdev_s usbdev; + + /* The bound device class driver */ + + struct usbdevclass_driver_s *driver; + + /* ESP32-S3-specific fields */ + + int cpu; /* CPU ID */ + int cpuint; /* OTG interrupt ID */ + + 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 esp32s3_devstate_e */ + uint8_t ep0state:4; /* See enum esp32s3_ep0state_e */ + uint8_t testmode:4; /* Selected test mode */ + uint8_t epavail[2]; /* Bitset of available OUT/IN 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 occur AFTER the SETUP + * control request is processed. In that case, ep0data[] may be used + * as the response buffer. + * + * ep0datlen: + * Length of OUT DATA received in ep0data[] (Not used with OUT data) + */ + + struct usb_ctrlreq_s ctrlreq; + uint8_t ep0data[ESP32S3_CDCACM_EP0MAXPACKET]; + uint16_t ep0datlen; + + /* The endpoint lists */ + + struct esp32s3_ep_s epin[ESP32S3_ENDPOINT_NUM]; + struct esp32s3_ep_s epout[ESP32S3_ENDPOINT_NUM]; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Register operations ******************************************************/ + +#ifdef CONFIG_ESP32S3_OTG_DEBUG_REGISTER +static uint32_t esp32s3_getreg(uint32_t addr); +static void esp32s3_putreg(uint32_t val, uint32_t addr); +#else +# define esp32s3_getreg(addr) getreg32(addr) +# define esp32s3_putreg(val,addr) putreg32(val,addr) +#endif + +/* Request queue operations *************************************************/ + +static struct esp32s3_req_s *esp32s3_req_remfirst(struct esp32s3_ep_s + *privep); +static bool esp32s3_req_addlast(struct esp32s3_ep_s *privep, + struct esp32s3_req_s *req); + +/* Low level data transfers and request operations **************************/ + +/* Special endpoint 0 data transfer logic */ + +static void esp32s3_ep0in_setupresponse(struct esp32s3_usbdev_s *priv, + uint8_t * data, uint32_t nbytes); +static inline void esp32s3_ep0in_transmitzlp(struct esp32s3_usbdev_s *priv); +static void esp32s3_ep0in_activate(void); + +static void esp32s3_ep0out_ctrlsetup(struct esp32s3_usbdev_s *priv); + +/* IN request and TxFIFO handling */ + +static void esp32s3_txfifo_write(struct esp32s3_ep_s *privep, + uint8_t * buf, int nbytes); +static void esp32s3_epin_transfer(struct esp32s3_ep_s *privep, + uint8_t * buf, int nbytes); +static void esp32s3_epin_request(struct esp32s3_usbdev_s *priv, + struct esp32s3_ep_s *privep); + +/* OUT request and RxFIFO handling */ + +static void esp32s3_rxfifo_read(struct esp32s3_ep_s *privep, + uint8_t * dest, uint16_t len); +static void esp32s3_rxfifo_discard(struct esp32s3_ep_s *privep, int len); +static void esp32s3_epout_complete(struct esp32s3_usbdev_s *priv, + struct esp32s3_ep_s *privep); +static inline void esp32s3_ep0out_receive(struct esp32s3_ep_s *privep, + int bcnt); +static inline void esp32s3_epout_receive(struct esp32s3_ep_s *privep, + int bcnt); +static void esp32s3_epout_request(struct esp32s3_usbdev_s *priv, + struct esp32s3_ep_s *privep); + +/* General request handling */ + +static void esp32s3_ep_flush(struct esp32s3_ep_s *privep); +static void esp32s3_req_complete(struct esp32s3_ep_s *privep, + int16_t result); +static void esp32s3_req_cancel(struct esp32s3_ep_s *privep, int16_t status); + +/* Interrupt handling *******************************************************/ + +static struct esp32s3_ep_s *esp32s3_ep_findbyaddr( + struct esp32s3_usbdev_s *priv, + uint16_t eplog); +static int esp32s3_req_dispatch(struct esp32s3_usbdev_s *priv, + const struct usb_ctrlreq_s *ctrl); +static void esp32s3_usbreset(struct esp32s3_usbdev_s *priv); + +/* Second level OUT endpoint interrupt processing */ + +static inline void esp32s3_ep0out_testmode(struct esp32s3_usbdev_s *priv, + uint16_t index); +static inline void esp32s3_ep0out_stdrequest( + struct esp32s3_usbdev_s *priv, + struct esp32s3_ctrlreq_s *ctrlreq); +static inline void esp32s3_ep0out_setup(struct esp32s3_usbdev_s *priv); +static inline void esp32s3_epout(struct esp32s3_usbdev_s *priv, + uint8_t epno); +static inline void esp32s3_epout_interrupt(struct esp32s3_usbdev_s *priv); + +/* Second level IN endpoint interrupt processing */ + +static inline void esp32s3_epin_runtestmode(struct esp32s3_usbdev_s *priv); +static inline void esp32s3_epin(struct esp32s3_usbdev_s *priv, uint8_t epno); +static inline void esp32s3_epin_txfifoempty(struct esp32s3_usbdev_s *priv, + int epno); +static inline void esp32s3_epin_interrupt(struct esp32s3_usbdev_s *priv); + +/* Other second level interrupt processing */ + +static inline void esp32s3_resumeinterrupt(struct esp32s3_usbdev_s *priv); +static inline void esp32s3_suspendinterrupt(struct esp32s3_usbdev_s *priv); +static inline void esp32s3_rxinterrupt(struct esp32s3_usbdev_s *priv); +static inline void esp32s3_enuminterrupt(struct esp32s3_usbdev_s *priv); +#ifdef CONFIG_USBDEV_ISOCHRONOUS +static inline void esp32s3_isocininterrupt(struct esp32s3_usbdev_s *priv); +static inline void esp32s3_isocoutinterrupt(struct esp32s3_usbdev_s *priv); +#endif +#ifdef CONFIG_USBDEV_VBUSSENSING +static inline void esp32s3_sessioninterrupt(struct esp32s3_usbdev_s *priv); +static inline void esp32s3_otginterrupt(struct esp32s3_usbdev_s *priv); +#endif + +/* First level interrupt processing */ + +static int esp32s3_usbinterrupt(int irq, void *context, void *arg); + +/* Endpoint operations ******************************************************/ + +/* Global OUT NAK controls */ + +static void esp32s3_enablegonak(struct esp32s3_ep_s *privep); +static void esp32s3_disablegonak(struct esp32s3_ep_s *privep); + +/* Endpoint configuration */ + +static int esp32s3_epout_configure(struct esp32s3_ep_s *privep, + uint8_t eptype, uint16_t maxpacket); +static int esp32s3_epin_configure(struct esp32s3_ep_s *privep, + uint8_t eptype, uint16_t maxpacket); +static int esp32s3_ep_configure(struct usbdev_ep_s *ep, + const struct usb_epdesc_s *desc, + bool last); +static void esp32s3_ep0_configure(struct esp32s3_usbdev_s *priv); + +/* Endpoint disable */ + +static void esp32s3_epout_disable(struct esp32s3_ep_s *privep); +static void esp32s3_epin_disable(struct esp32s3_ep_s *privep); +static int esp32s3_ep_disable(struct usbdev_ep_s *ep); + +/* Endpoint request management */ + +static struct usbdev_req_s *esp32s3_ep_allocreq( + struct usbdev_ep_s *ep); +static void esp32s3_ep_freereq(struct usbdev_ep_s *ep, + struct usbdev_req_s *); + +/* Endpoint buffer management */ + +#ifdef CONFIG_USBDEV_DMA +static void *esp32s3_ep_allocbuffer(struct usbdev_ep_s *ep, + uint16_t bytes); +static void esp32s3_ep_freebuffer(struct usbdev_ep_s *ep, void *buf); +#endif + +/* Endpoint request submission */ + +static int esp32s3_ep_submit(struct usbdev_ep_s *ep, + struct usbdev_req_s *req); + +/* Endpoint request cancellation */ + +static int esp32s3_ep_cancel(struct usbdev_ep_s *ep, + struct usbdev_req_s *req); + +/* Stall handling */ + +static int esp32s3_epout_setstall(struct esp32s3_ep_s *privep); +static int esp32s3_epin_setstall(struct esp32s3_ep_s *privep); +static int esp32s3_ep_setstall(struct esp32s3_ep_s *privep); +static int esp32s3_ep_clrstall(struct esp32s3_ep_s *privep); +static int esp32s3_ep_stall(struct usbdev_ep_s *ep, bool resume); +static void esp32s3_ep0_stall(struct esp32s3_usbdev_s *priv); + +/* Endpoint allocation */ + +static struct usbdev_ep_s *esp32s3_ep_alloc(struct usbdev_s *dev, + uint8_t epno, bool in, + uint8_t eptype); +static void esp32s3_ep_free(struct usbdev_s *dev, + struct usbdev_ep_s *ep); + +/* USB device controller operations *****************************************/ + +static int esp32s3_getframe(struct usbdev_s *dev); +static int esp32s3_wakeup(struct usbdev_s *dev); +static int esp32s3_selfpowered(struct usbdev_s *dev, bool selfpowered); +static int esp32s3_pullup(struct usbdev_s *dev, bool enable); +static void esp32s3_setaddress(struct esp32s3_usbdev_s *priv, + uint16_t address); +static int esp32s3_txfifo_flush(uint32_t txfnum); +static int esp32s3_rxfifo_flush(void); + +/* Initialization ***********************************************************/ + +static void esp32s3_swinitialize(struct esp32s3_usbdev_s *priv); +static void esp32s3_hwinitialize(struct esp32s3_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 esp32s3_usbdev_s g_otghsdev; + +static const struct usbdev_epops_s g_epops = +{ + .configure = esp32s3_ep_configure, + .disable = esp32s3_ep_disable, + .allocreq = esp32s3_ep_allocreq, + .freereq = esp32s3_ep_freereq, +#ifdef CONFIG_USBDEV_DMA + .allocbuffer = esp32s3_ep_allocbuffer, + .freebuffer = esp32s3_ep_freebuffer, +#endif + .submit = esp32s3_ep_submit, + .cancel = esp32s3_ep_cancel, + .stall = esp32s3_ep_stall, +}; + +static const struct usbdev_ops_s g_devops = +{ + .allocep = esp32s3_ep_alloc, + .freeep = esp32s3_ep_free, + .getframe = esp32s3_getframe, + .wakeup = esp32s3_wakeup, + .selfpowered = esp32s3_selfpowered, + .pullup = esp32s3_pullup, +}; + +/* Device error strings that may be enabled for more descriptive USB trace + * output. + */ + +#ifdef CONFIG_USBDEV_TRACE_STRINGS +const struct trace_msg_t g_usb_trace_strings_deverror[] = +{ + TRACE_STR(ESP32S3_TRACEERR_ALLOCFAIL), + TRACE_STR(ESP32S3_TRACEERR_BADCLEARFEATURE), + TRACE_STR(ESP32S3_TRACEERR_BADDEVGETSTATUS), + TRACE_STR(ESP32S3_TRACEERR_BADEPNO), + TRACE_STR(ESP32S3_TRACEERR_BADEPGETSTATUS), + TRACE_STR(ESP32S3_TRACEERR_BADGETCONFIG), + TRACE_STR(ESP32S3_TRACEERR_BADGETSETDESC), + TRACE_STR(ESP32S3_TRACEERR_BADGETSTATUS), + TRACE_STR(ESP32S3_TRACEERR_BADSETADDRESS), + TRACE_STR(ESP32S3_TRACEERR_BADSETCONFIG), + TRACE_STR(ESP32S3_TRACEERR_BADSETFEATURE), + TRACE_STR(ESP32S3_TRACEERR_BADTESTMODE), + TRACE_STR(ESP32S3_TRACEERR_BINDFAILED), + TRACE_STR(ESP32S3_TRACEERR_DISPATCHSTALL), + TRACE_STR(ESP32S3_TRACEERR_DRIVER), + TRACE_STR(ESP32S3_TRACEERR_DRIVERREGISTERED), + TRACE_STR(ESP32S3_TRACEERR_EP0NOSETUP), + TRACE_STR(ESP32S3_TRACEERR_EP0SETUPSTALLED), + TRACE_STR(ESP32S3_TRACEERR_EPINNULLPACKET), + TRACE_STR(ESP32S3_TRACEERR_EPINUNEXPECTED), + TRACE_STR(ESP32S3_TRACEERR_EPOUTNULLPACKET), + TRACE_STR(ESP32S3_TRACEERR_EPOUTUNEXPECTED), + TRACE_STR(ESP32S3_TRACEERR_INVALIDCTRLREQ), + TRACE_STR(ESP32S3_TRACEERR_INVALIDPARMS), + TRACE_STR(ESP32S3_TRACEERR_IRQREGISTRATION), + TRACE_STR(ESP32S3_TRACEERR_NOEP), + TRACE_STR(ESP32S3_TRACEERR_NOTCONFIGURED), + TRACE_STR(ESP32S3_TRACEERR_EPOUTQEMPTY), + TRACE_STR(ESP32S3_TRACEERR_EPINREQEMPTY), + TRACE_STR(ESP32S3_TRACEERR_NOOUTSETUP), + TRACE_STR(ESP32S3_TRACEERR_POLLTIMEOUT), + TRACE_STR_END +}; +#endif + +/* Interrupt event strings that may be enabled for more descriptive USB trace + * output. + */ + +#ifdef CONFIG_USBDEV_TRACE_STRINGS +const struct trace_msg_t g_usb_trace_strings_intdecode[] = +{ + TRACE_STR(ESP32S3_TRACEINTID_USB), + TRACE_STR(ESP32S3_TRACEINTID_INTPENDING), + TRACE_STR(ESP32S3_TRACEINTID_EPOUT), + TRACE_STR(ESP32S3_TRACEINTID_EPIN), + TRACE_STR(ESP32S3_TRACEINTID_MISMATCH), + TRACE_STR(ESP32S3_TRACEINTID_WAKEUP), + TRACE_STR(ESP32S3_TRACEINTID_SUSPEND), + TRACE_STR(ESP32S3_TRACEINTID_SOF), + TRACE_STR(ESP32S3_TRACEINTID_RXFIFO), + TRACE_STR(ESP32S3_TRACEINTID_DEVRESET), + TRACE_STR(ESP32S3_TRACEINTID_ENUMDNE), + TRACE_STR(ESP32S3_TRACEINTID_IISOIXFR), + TRACE_STR(ESP32S3_TRACEINTID_IISOOXFR), + TRACE_STR(ESP32S3_TRACEINTID_SRQ), + TRACE_STR(ESP32S3_TRACEINTID_OTG), + TRACE_STR(ESP32S3_TRACEINTID_EPOUT_XFRC), + TRACE_STR(ESP32S3_TRACEINTID_EPOUT_EPDISD), + TRACE_STR(ESP32S3_TRACEINTID_EPOUT_SETUP), + TRACE_STR(ESP32S3_TRACEINTID_DISPATCH), + TRACE_STR(ESP32S3_TRACEINTID_GETSTATUS), + TRACE_STR(ESP32S3_TRACEINTID_EPGETSTATUS), + TRACE_STR(ESP32S3_TRACEINTID_DEVGETSTATUS), + TRACE_STR(ESP32S3_TRACEINTID_IFGETSTATUS), + TRACE_STR(ESP32S3_TRACEINTID_CLEARFEATURE), + TRACE_STR(ESP32S3_TRACEINTID_SETFEATURE), + TRACE_STR(ESP32S3_TRACEINTID_SETADDRESS), + TRACE_STR(ESP32S3_TRACEINTID_GETSETDESC), + TRACE_STR(ESP32S3_TRACEINTID_GETCONFIG), + TRACE_STR(ESP32S3_TRACEINTID_SETCONFIG), + TRACE_STR(ESP32S3_TRACEINTID_GETSETIF), + TRACE_STR(ESP32S3_TRACEINTID_SYNCHFRAME), + TRACE_STR(ESP32S3_TRACEINTID_EPIN_XFRC), + TRACE_STR(ESP32S3_TRACEINTID_EPIN_TOC), + TRACE_STR(ESP32S3_TRACEINTID_EPIN_ITTXFE), + TRACE_STR(ESP32S3_TRACEINTID_EPIN_EPDISD), + TRACE_STR(ESP32S3_TRACEINTID_EPIN_TXFE), + TRACE_STR(ESP32S3_TRACEINTID_EPIN_EMPWAIT), + TRACE_STR(ESP32S3_TRACEINTID_OUTNAK), + TRACE_STR(ESP32S3_TRACEINTID_OUTRECVD), + TRACE_STR(ESP32S3_TRACEINTID_OUTDONE), + TRACE_STR(ESP32S3_TRACEINTID_SETUPDONE), + TRACE_STR(ESP32S3_TRACEINTID_SETUPRECVD), + TRACE_STR_END +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32s3_getreg + * + * Description: + * Get the contents of an ESP32-S3 register + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_OTG_DEBUG_REGISTER +static uint32_t esp32s3_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 register 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) + { + uinfo("...\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 */ + + uinfo("[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 */ + + uinfo("%08x->%08x\n", addr, val); + return val; +} +#endif + +/**************************************************************************** + * Name: esp32s3_putreg + * + * Description: + * Set the contents of an ESP32-S3 register to a value + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_OTG_DEBUG_REGISTER +static void esp32s3_putreg(uint32_t val, uint32_t addr) +{ + /* Show the register value being written */ + + uinfo("%08x<-%08x\n", addr, val); + + /* Write the value */ + + putreg32(val, addr); +} +#endif + +/**************************************************************************** + * Name: esp32s3_req_remfirst + * + * Description: + * Remove a request from the head of an endpoint request queue + * + ****************************************************************************/ + +static struct esp32s3_req_s *esp32s3_req_remfirst( + struct esp32s3_ep_s *privep) +{ + struct esp32s3_req_s *ret = privep->head; + + if (ret) + { + privep->head = ret->flink; + if (!privep->head) + { + privep->tail = NULL; + } + + ret->flink = NULL; + } + + return ret; +} + +/**************************************************************************** + * Name: esp32s3_req_addlast + * + * Description: + * Add a request to the end of an endpoint request queue + * + ****************************************************************************/ + +static bool esp32s3_req_addlast(struct esp32s3_ep_s *privep, + struct esp32s3_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: esp32s3_ep0in_setupresponse + * + * Description: + * Schedule a short transfer on Endpoint 0 (IN or OUT) + * + ****************************************************************************/ + +static void esp32s3_ep0in_setupresponse(struct esp32s3_usbdev_s *priv, + uint8_t *buf, + uint32_t nbytes) +{ + esp32s3_epin_transfer(&priv->epin[EP0], buf, nbytes); + priv->ep0state = EP0STATE_SETUPRESPONSE; + esp32s3_ep0out_ctrlsetup(priv); +} + +/**************************************************************************** + * Name: esp32s3_ep0in_transmitzlp + * + * Description: + * Send a zero length packet (ZLP) on endpoint 0 IN + * + ****************************************************************************/ + +static inline void esp32s3_ep0in_transmitzlp(struct esp32s3_usbdev_s *priv) +{ + esp32s3_ep0in_setupresponse(priv, NULL, 0); +} + +/**************************************************************************** + * Name: esp32s3_ep0in_activate + * + * Description: + * Activate the endpoint 0 IN endpoint. + * + ****************************************************************************/ + +static void esp32s3_ep0in_activate(void) +{ + uint32_t regval; + + /* Set the max packet size of the IN EP. */ + + regval = esp32s3_getreg(ESP32S3_OTG_DIEPCTL(0)); + regval &= ~OTG_DIEPCTL0_MPSIZ_MASK; + +#if ESP32S3_CDCACM_EP0MAXPACKET == 8 + regval |= OTG_DIEPCTL0_MPSIZ_8; +#elif ESP32S3_CDCACM_EP0MAXPACKET == 16 + regval |= OTG_DIEPCTL0_MPSIZ_16; +#elif ESP32S3_CDCACM_EP0MAXPACKET == 32 + regval |= OTG_DIEPCTL0_MPSIZ_32; +#elif ESP32S3_CDCACM_EP0MAXPACKET == 64 + regval |= OTG_DIEPCTL0_MPSIZ_64; +#else +# error "Unsupported value of ESP32S3_CDCACM_EP0MAXPACKET" +#endif + + esp32s3_putreg(regval, ESP32S3_OTG_DIEPCTL(0)); + + /* Clear global IN NAK */ + + regval = esp32s3_getreg(ESP32S3_OTG_DCTL); + regval |= OTG_DCTL_CGINAK; + esp32s3_putreg(regval, ESP32S3_OTG_DCTL); +} + +/**************************************************************************** + * Name: esp32s3_ep0out_ctrlsetup + * + * Description: + * Setup to receive a SETUP packet. + * + ****************************************************************************/ + +static void esp32s3_ep0out_ctrlsetup(struct esp32s3_usbdev_s *priv) +{ + uint32_t regval; + + /* Setup the hardware to perform the SETUP transfer */ + + regval = ((USB_SIZEOF_CTRLREQ * 3) << OTG_DOEPTSIZ0_XFRSIZ_SHIFT) | + (OTG_DOEPTSIZ0_PKTCNT) | + (3 << OTG_DOEPTSIZ0_STUPCNT_SHIFT); + esp32s3_putreg(regval, ESP32S3_OTG_DOEPTSIZ(0)); + + /* Then clear NAKing and enable the transfer */ + + regval = esp32s3_getreg(ESP32S3_OTG_DOEPCTL(0)); + regval |= (OTG_DOEPCTL0_CNAK | OTG_DOEPCTL0_EPENA); + esp32s3_putreg(regval, ESP32S3_OTG_DOEPCTL(0)); +} + +/**************************************************************************** + * Name: esp32s3_txfifo_write + * + * Description: + * Send data to the endpoint's TxFIFO. + * + ****************************************************************************/ + +static void esp32s3_txfifo_write(struct esp32s3_ep_s *privep, + 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 = ESP32S3_OTG_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; Review Comment: ```suggestion regval = (uint32_t)*buf++; regval |= ((uint32_t)*buf++) << 8; regval |= ((uint32_t)*buf++) << 16; regval |= ((uint32_t)*buf++) << 24; ``` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
