summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2010-06-13 15:42:11 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2010-06-13 15:42:11 +0000
commit0798efef0c881858173d0001682526195e5a6b85 (patch)
treee2b97434559900a1a4589b7506e5e9a64a143ebf
parent4223c35adc0674a935a028b603cbe42c54b1a244 (diff)
downloadnuttx-0798efef0c881858173d0001682526195e5a6b85.tar.gz
nuttx-0798efef0c881858173d0001682526195e5a6b85.tar.bz2
nuttx-0798efef0c881858173d0001682526195e5a6b85.zip
Add USB device driver
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2743 42af7a65-404d-4744-a932-0658087f49c3
-rwxr-xr-xnuttx/arch/arm/src/lpc17xx/Make.defs6
-rwxr-xr-xnuttx/arch/arm/src/lpc17xx/lpc17_usb.h177
-rwxr-xr-xnuttx/arch/arm/src/lpc17xx/lpc17_usbdev.c3319
-rwxr-xr-xnuttx/configs/nucleus2g/src/up_leds.c18
4 files changed, 3505 insertions, 15 deletions
diff --git a/nuttx/arch/arm/src/lpc17xx/Make.defs b/nuttx/arch/arm/src/lpc17xx/Make.defs
index 5b5c04f61..21d7b4703 100755
--- a/nuttx/arch/arm/src/lpc17xx/Make.defs
+++ b/nuttx/arch/arm/src/lpc17xx/Make.defs
@@ -65,6 +65,10 @@ ifeq ($(CONFIG_DEBUG),y)
CHIP_CSRCS += lpc17_gpiodbg.c
endif
+ifeq ($(CONFIG_USBDEV),y)
+CHIP_CSRCS += lpc17_usbdev.c
+endif
+
ifeq ($(CONFIG_LPC17_DMA),y)
-CHIP_CSRCS += lpc17_dmac.c
+CHIP_CSRCS += lpc17_gpdma.c
endif
diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_usb.h b/nuttx/arch/arm/src/lpc17xx/lpc17_usb.h
index f50acbe00..f9d9752e5 100755
--- a/nuttx/arch/arm/src/lpc17xx/lpc17_usb.h
+++ b/nuttx/arch/arm/src/lpc17xx/lpc17_usb.h
@@ -359,7 +359,6 @@
#define USBDEV_CMDDATA_SHIFT (0) /* Bits 0-7: Command read data */
#define USBDEV_CMDDATA_MASK (0xff << USBDEV_CMDDATA_SHIFT)
/* Bits 8-31: Reserved */
-
/* USB transfer registers:
*
* USB Receive Data (Bits 0-31: Received data)
@@ -369,7 +368,7 @@
#define USBDEV_RXPLEN_SHIFT (0) /* Bits 0-9: Bytes remaining to be read */
#define USBDEV_RXPLEN_MASK (0x3ff << USBDEV_RXPLEN_SHIFT)
-#define USBDEV_RXPLEN_DV (1 << 10) /* Bit 10: DV Data valid*/
+#define USBDEV_RXPLEN_DV (1 << 10) /* Bit 10: DV Data valid */
#define USBDEV_RXPLEN_PKTRDY (1 << 11) /* Bit 11: Packet ready for reading */
/* Bits 12-31: Reserved */
/* USB Transmit Data (Bits 0-31: Transmit data) */
@@ -383,8 +382,8 @@
#define USBDEV_CTRL_RDEN (1 << 0) /* Bit 0: Read mode control */
#define USBDEV_CTRL_WREN (1 << 1) /* Bit 1: Write mode control */
-#define USBDEV_CTRL_LOGENDPOINT_SHIFT (2) /* Bits 2-5: Logical Endpoint number */
-#define USBDEV_CTRL_LOGENDPOINT_MASK (15 << USBDEV_CTRL_LOGENDPOINT_SHIFT)
+#define USBDEV_CTRL_LOGEP_SHIFT (2) /* Bits 2-5: Logical Endpoint number */
+#define USBDEV_CTRL_LOGEP_MASK (15 << USBDEV_CTRL_LOGEP_SHIFT)
/* Bits 6-31: Reserved */
/* Endpoint interrupt registers:
*
@@ -435,15 +434,15 @@
#define USBDEV_PHYEP(n) (1 << (n))
#define USBDEV_PHYEP0 (1 << 0)
-#define USBDEV_PHYEP0 (1 << 1)
-#define USBDEV_PHYEP0 (1 << 2)
-#define USBDEV_PHYEP0 (1 << 3)
-#define USBDEV_PHYEP0 (1 << 4)
-#define USBDEV_PHYEP0 (1 << 5)
-#define USBDEV_PHYEP0 (1 << 6)
-#define USBDEV_PHYEP0 (1 << 7)
-#define USBDEV_PHYEP0 (1 << 8)
-#define USBDEV_PHYEP0 (1 << 9)
+#define USBDEV_PHYEP1 (1 << 1)
+#define USBDEV_PHYEP2 (1 << 2)
+#define USBDEV_PHYEP3 (1 << 3)
+#define USBDEV_PHYEP4 (1 << 4)
+#define USBDEV_PHYEP5 (1 << 5)
+#define USBDEV_PHYEP6 (1 << 6)
+#define USBDEV_PHYEP7 (1 << 7)
+#define USBDEV_PHYEP8 (1 << 8)
+#define USBDEV_PHYEP9 (1 << 9)
#define USBDEV_PHYEP10 (1 << 10)
#define USBDEV_PHYEP11 (1 << 11)
#define USBDEV_PHYEP12 (1 << 12)
@@ -472,7 +471,6 @@
#define USBDEV_EPIND_SHIFT (0) /* Bits 0-4: Physical endpoint number (0-31) */
#define USBDEV_EPIND_MASK (31 << USBDEV_EPIND_SHIFT)
/* Bits 5-31: Reserved */
-
/* USB MaxPacketSize */
#define USBDEV_MAXPSIZE_SHIFT (0) /* Bits 0-9: Maximum packet size value */
@@ -579,6 +577,157 @@
#define USBDEV_CLK_AHBCLK (1 << 4) /* Bit 4: AHB clock */
/* Bits 5-31: Reserved */
+/* Endpoints *************************************************************************/
+
+#define LPC17_EP0_OUT 0
+#define LPC17_EP0_IN 1
+#define LPC17_CTRLEP_OUT LPC17_EP0_OUT
+#define LPC17_CTRLEP_IN LPC17_EP0_IN
+#define LPC17_EP1_OUT 2
+#define LPC17_EP1_IN 3
+#define LPC17_EP2_OUT 4
+#define LPC17_EP2_IN 5
+#define LPC17_EP3_OUT 6
+#define LPC17_EP3_IN 7
+#define LPC17_EP4_OUT 8
+#define LPC17_EP4_IN 9
+#define LPC17_EP5_OUT 10
+#define LPC17_EP5_IN 11
+#define LPC17_EP6_OUT 12
+#define LPC17_EP6_IN 13
+#define LPC17_EP7_OUT 14
+#define LPC17_EP7_IN 15
+#define LPC17_EP8_OUT 16
+#define LPC17_EP8_IN 17
+#define LPC17_EP9_OUT 18
+#define LPC17_EP9_IN 19
+#define LPC17_EP10_OUT 20
+#define LPC17_EP10_IN 21
+#define LPC17_EP11_OUT 22
+#define LPC17_EP11_IN 23
+#define LPC17_EP12_OUT 24
+#define LPC17_EP12_IN 25
+#define LPC17_EP13_OUT 26
+#define LPC17_EP13_IN 27
+#define LPC17_EP14_OUT 28
+#define LPC17_EP14_IN 29
+#define LPC17_EP15_OUT 30
+#define LPC17_EP15_IN 31
+#define LPC17_NUMEPS 32
+
+/* Commands *************************************************************************/
+
+/* USB Command Code Register -- Command phase values */
+
+#define CMD_USBDEV_CMDWR (0x00000500)
+#define CMD_USBDEV_DATAWR (0x00000100)
+#define CMD_USBDEV_DATARD (0x00000200)
+
+/* Device Commands */
+
+#define CMD_USBDEV_SETADDRESS (0x00d0)
+#define CMD_USBDEV_CONFIG (0x00d8)
+#define CMD_USBDEV_SETMODE (0x00f3)
+#define CMD_USBDEV_READFRAMENO (0x00f5)
+#define CMD_USBDEV_READTESTREG (0x00fd)
+#define CMD_USBDEV_SETSTATUS (0x01fe)
+#define CMD_USBDEV_GETSTATUS (0x00fe)
+#define CMD_USBDEV_GETERRORCODE (0x00ff)
+#define CMD_USBDEV_READERRORSTATUS (0x00fb)
+
+/* Endpoint Commands */
+
+#define CMD_USBDEV_EPSELECT (0x0000)
+#define CMD_USBDEV_EPSELECTCLEAR (0x0040)
+#define CMD_USBDEV_EPSETSTATUS (0x0140)
+#define CMD_USBDEV_EPCLRBUFFER (0x00f2)
+#define CMD_USBDEV_EPVALIDATEBUFFER (0x00fa)
+
+/* Command/response bit definitions ********************************************/
+/* SETADDRESS (0xd0) command definitions */
+
+#define CMD_USBDEV_SETADDRESS_MASK (0x7f) /* Bits 0-6: Device address */
+#define CMD_USBDEV_SETADDRESS_DEVEN (1 << 7) /* Bit 7: Device enable */
+
+/* SETSTATUS (0xfe) and GETSTATUS (0xfe) response: */
+
+#define CMD_STATUS_CONNECT (1 << 0) /* Bit 0: Connected */
+#define CMD_STATUS_CONNCHG (1 << 1) /* Bit 1: Connect change */
+#define CMD_STATUS_SUSPEND (1 << 2) /* Bit 2: Suspend */
+#define CMD_STATUS_SUSPCHG (1 << 3) /* Bit 3: Suspend change */
+#define CMD_STATUS_RESET (1 << 4) /* Bit 4: Bus reset bit */
+
+/* EPSELECT (0x00) endpoint status response */
+
+#define CMD_EPSELECT_FE (1 << 0) /* Bit 0: IN empty or OUT full */
+#define CMD_EPSELECT_ST (1 << 1) /* Bit 1: Endpoint is stalled */
+#define CMD_EPSELECT_STP (1 << 2) /* Bit 2: Last packet was setup */
+#define CMD_EPSELECT_PO (1 << 3) /* Bit 3: Previous packet was overwritten */
+#define CMD_EPSELECT_EPN (1 << 4) /* Bit 4: NAK sent */
+#define CMD_EPSELECT_B1FULL (1 << 5) /* Bit 5: Buffer 1 full */
+#define CMD_EPSELECT_B2FULL (1 << 6) /* Bit 6: Buffer 2 full */
+ /* Bit 7: Reserved */
+/* EPSETSTATUS (0x40) command */
+
+#define CMD_SETSTAUS_ST (1 << 0) /* Bit 0: Stalled endpoint bit */
+ /* Bits 1-4: Reserved */
+#define CMD_SETSTAUS_DA (1 << 5) /* Bit 5: Disabled endpoint bit */
+#define CMD_SETSTAUS_RFMO (1 << 6) /* Bit 6: Rate feedback mode */
+#define CMD_SETSTAUS_CNDST (1 << 7) /* Bit 7: Conditional stall bit */
+
+/* EPCLRBUFFER (0xf2) response */
+
+#define CMD_USBDEV_CLRBUFFER_PO (0x00000001)
+
+/* DMA ******************************************************************************/
+/* The DMA descriptor */
+
+#define USB_DMADESC_NEXTDDPTR 0 /* Offset 0: Next USB descriptor in RAM */
+#define USB_DMADESC_CONFIG 1 /* Offset 1: DMA configuration info. */
+#define USB_DMADESC_STARTADDR 2 /* Offset 2: DMA start address */
+#define USB_DMADESC_STATUS 3 /* Offset 3: DMA status info (read only) */
+#define USB_DMADESC_ISOCSIZEADDR 4 /* Offset 4: Isoc. packet size address */
+
+/* Bit settings for CONFIG (offset 1 )*/
+
+#define USB_DMADESC_MODE_SHIFT (0) /* Bits 0-1: DMA mode */
+#define USB_DMADESC_MODE_MASK (3 << USB_DMADESC_MODE_SHIFT)
+# define USB_DMADESC_MODENORMAL (0 << USB_DMADESC_MODE_SHIFT) /* Mode normal */
+# define USB_DMADESC_MODEATLE (1 << USB_DMADESC_MODE_SHIFT) /* ATLE normal */
+#define USB_DMADESC_NEXTDDVALID (1 << 2) /* Bit 2: Next descriptor valid */
+ /* Bit 3: Reserved */
+#define USB_DMADESC_ISCOEP (1 << 4) /* Bit 4: ISOC endpoint */
+#define USB_DMADESC_PKTSIZE_SHIFT (5) /* Bits 5-15: Max packet size */
+#define USB_DMADESC_PKTSIZE_MASK (0x7ff << USB_DMADESC_PKTSIZE_SHIFT)
+#define USB_DMADESC_BUFLEN_SHIFT (16) /* Bits 16-31: DMA buffer length */
+#define USB_DMADESC_BUFLEN_MASK (0xffff << USB_DMADESC_BUFLEN_SHIFT
+
+/* Bit settings for STATUS (offset 3). All must be initialized to zero. */
+
+#define USB_DMADESC_STATUS_SHIFT (1) /* Bits 1-4: DMA status */
+#define USB_DMADESC_STATUS_MASK (15 << USB_DMADESC_STATUS_SHIFT)
+# define USB_DMADESC_NOTSERVICED (0 << USB_DMADESC_STATUS_SHIFT)
+# define USB_DMADESC_BEINGSERVICED (1 << USB_DMADESC_STATUS_SHIFT)
+# define USB_DMADESC_NORMALCOMPLETION (2 << USB_DMADESC_STATUS_SHIFT)
+# define USB_DMADESC_DATAUNDERRUN (3 << USB_DMADESC_STATUS_SHIFT)
+# define USB_DMADESC_DATAOVERRUN (8 << USB_DMADESC_STATUS_SHIFT)
+# define USB_DMADESC_SYSTEMERROR (9 << USB_DMADESC_STATUS_SHIFT)
+#define USB_DMADESC_PKTVALID (1 << 5) /* Bit 5: Packet valid */
+#define USB_DMADESC_LSBEXTRACTED (1 << 6) /* Bit 6: LS byte extracted */
+#define USB_DMADESC_MSBEXTRACTED (1 << 7) /* Bit 7: MS byte extracted */
+#define USB_DMADESC_MSGLENPOS_SHIFT (8) /* Bits 8-13: Message length position */
+#define USB_DMADESC_MSGLENPOS_MASK (0x3f << USB_DMADESC_MSGLENPOS_SHIFT)
+#define USB_DMADESC_DMACOUNT_SHIFT (16) /* Bits 16-31: DMA count */
+#define USB_DMADESC_DMACOUNT_MASK (0xffff << USB_DMADESC_DMACOUNT_SHIFT)
+
+/* DMA packet size format */
+
+#define USB_DMAPKTSIZE_PKTLEN_SHIFT (0) /* Bits 0-15: Packet length */
+#define USB_DMAPKTSIZE_PKTLEN_MASK (0xffff << USB_DMAPKTSIZE_PKTLEN_SHIFT)
+#define USB_DMAPKTSIZE_PKTVALID (1 << 16) /* Bit 16: Packet valid */
+#define USB_DMAPKTSIZE_FRAMENO_SHIFT (17) /* Bit 17-31: Frame number */
+#define USB_DMAPKTSIZE_FRAMENO_MASK (0x7fff << USB_DMAPKTSIZE_FRAMENO_SHIFT)
+
/************************************************************************************
* Public Types
************************************************************************************/
diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_usbdev.c b/nuttx/arch/arm/src/lpc17xx/lpc17_usbdev.c
new file mode 100755
index 000000000..cf77f07a4
--- /dev/null
+++ b/nuttx/arch/arm/src/lpc17xx/lpc17_usbdev.c
@@ -0,0 +1,3319 @@
+/*******************************************************************************
+ * arch/arm/src/lpc17xx/lpc17_usbdev.c
+ *
+ * Copyright (C) 2010 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * 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.h>
+#include <nuttx/usbdev.h>
+#include <nuttx/usbdev_trace.h>
+
+#include <arch/irq.h>
+#include <arch/board/board.h>
+
+#include "chip.h"
+#include "up_arch.h"
+#include "up_internal.h"
+
+#include "lpc17_usb.h"
+#include "lpc17_syscon.h"
+
+/*******************************************************************************
+ * Definitions
+ *******************************************************************************/
+
+/* Configuration ***************************************************************/
+
+#ifndef CONFIG_USBDEV_EP0_MAXSIZE
+# define CONFIG_USBDEV_EP0_MAXSIZE 64
+#endif
+
+#ifndef CONFIG_USBDEV_MAXPOWER
+# define CONFIG_USBDEV_MAXPOWER 100 /* mA */
+#endif
+
+#define USB_SLOW_INT USBDEV_INT_EPSLOW
+#define USB_DEVSTATUS_INT USBDEV_INT_DEVSTAT
+
+#ifdef CONFIG_LPC17_USBDEV_EPFAST_INTERRUPT
+# define USB_FAST_INT USBDEV_INT_EPFAST
+#else
+# define USB_FAST_INT 0
+#endif
+
+/* Extremely detailed register debug that you would normally never want
+ * enabled.
+ */
+
+#undef CONFIG_LPC17_USBDEV_REGDEBUG
+
+/* Enable reading SOF from interrupt handler vs. simply reading on demand. Probably
+ * a bad idea... Unless there is some issue with sampling the SOF from hardware
+ * asynchronously.
+ */
+
+#ifdef CONFIG_LPC17_USBDEV_FRAME_INTERRUPT
+# define USB_FRAME_INT USBDEV_INT_FRAME
+#else
+# define USB_FRAME_INT 0
+#endif
+
+#ifdef CONFIG_DEBUG
+# define USB_ERROR_INT USBDEV_INT_EPRINT
+#else
+# define USB_ERROR_INT 0
+#endif
+
+/* Number of DMA descriptors */
+
+#ifdef CONFIG_LPC17_USBDEV_DMA
+# error DMA SUPPORT NOT YET FULLY IMPLEMENTED
+# ifndef CONFIG_LPC17_USBDEV_NDMADESCRIPTORS
+# define CONFIG_LPC17_USBDEV_NDMADESCRIPTORS 8
+# elif CONFIG_LPC17_USBDEV_NDMADESCRIPTORS > 30
+# define CONFIG_LPC17_USBDEV_NDMADESCRIPTORS 30
+# endif
+#endif
+
+/* Debug ***********************************************************************/
+
+/* Trace error codes */
+
+#define LPC17_TRACEERR_ALLOCFAIL 0x0001
+#define LPC17_TRACEERR_BADCLEARFEATURE 0x0002
+#define LPC17_TRACEERR_BADDEVGETSTATUS 0x0003
+#define LPC17_TRACEERR_BADEPNO 0x0004
+#define LPC17_TRACEERR_BADEPGETSTATUS 0x0005
+#define LPC17_TRACEERR_BADEPTYPE 0x0006
+#define LPC17_TRACEERR_BADGETCONFIG 0x0007
+#define LPC17_TRACEERR_BADGETSETDESC 0x0008
+#define LPC17_TRACEERR_BADGETSTATUS 0x0009
+#define LPC17_TRACEERR_BADSETADDRESS 0x000a
+#define LPC17_TRACEERR_BADSETCONFIG 0x000b
+#define LPC17_TRACEERR_BADSETFEATURE 0x000c
+#define LPC17_TRACEERR_BINDFAILED 0x000d
+#define LPC17_TRACEERR_DISPATCHSTALL 0x000e
+#define LPC17_TRACEERR_DMABUSY 0x000f
+#define LPC17_TRACEERR_DRIVER 0x0010
+#define LPC17_TRACEERR_DRIVERREGISTERED 0x0011
+#define LPC17_TRACEERR_EP0INSTALLED 0x0012
+#define LPC17_TRACEERR_EP0OUTSTALLED 0x0013
+#define LPC17_TRACEERR_EP0SETUPSTALLED 0x0014
+#define LPC17_TRACEERR_EPINNULLPACKET 0x0015
+#define LPC17_TRACEERR_EPOUTNULLPACKET 0x0016
+#define LPC17_TRACEERR_EPREAD 0x0017
+#define LPC17_TRACEERR_INVALIDCMD 0x0018
+#define LPC17_TRACEERR_INVALIDCTRLREQ 0x0019
+#define LPC17_TRACEERR_INVALIDPARMS 0x001a
+#define LPC17_TRACEERR_IRQREGISTRATION 0x001b
+#define LPC17_TRACEERR_NODMADESC 0x001c
+#define LPC17_TRACEERR_NOEP 0x001d
+#define LPC17_TRACEERR_NOTCONFIGURED 0x001e
+#define LPC17_TRACEERR_REQABORTED 0x001f
+
+/* Trace interrupt codes */
+
+#define LPC17_TRACEINTID_USB 0x0001
+#define LPC17_TRACEINTID_CLEARFEATURE 0x0002
+#define LPC17_TRACEINTID_CONNECTCHG 0x0003
+#define LPC17_TRACEINTID_CONNECTED 0x0004
+#define LPC17_TRACEINTID_DEVGETSTATUS 0x0005
+#define LPC17_TRACEINTID_DEVRESET 0x0006
+#define LPC17_TRACEINTID_DEVSTAT 0x0007
+#define LPC17_TRACEINTID_DISCONNECTED 0x0008
+#define LPC17_TRACEINTID_DISPATCH 0x0009
+#define LPC17_TRACEINTID_EP0IN 0x000a
+#define LPC17_TRACEINTID_EP0OUT 0x000b
+#define LPC17_TRACEINTID_EP0SETUP 0x000c
+#define LPC17_TRACEINTID_EPDMA 0x000d
+#define LPC17_TRACEINTID_EPFAST 0x000e
+#define LPC17_TRACEINTID_EPGETSTATUS 0x000f
+#define LPC17_TRACEINTID_EPIN 0x0010
+#define LPC17_TRACEINTID_EPINQEMPTY 0x0011
+#define LPC17_TRACEINTID_EP0INSETADDRESS 0x0012
+#define LPC17_TRACEINTID_EPOUT 0x0013
+#define LPC17_TRACEINTID_EPOUTQEMPTY 0x0014
+#define LPC17_TRACEINTID_EP0SETUPSETADDRESS 0x0015
+#define LPC17_TRACEINTID_EPRINT 0x0016
+#define LPC17_TRACEINTID_EPSLOW 0x0017
+#define LPC17_TRACEINTID_FRAME 0x0018
+#define LPC17_TRACEINTID_GETCONFIG 0x0019
+#define LPC17_TRACEINTID_GETSETDESC 0x001a
+#define LPC17_TRACEINTID_GETSETIF 0x001b
+#define LPC17_TRACEINTID_GETSTATUS 0x001c
+#define LPC17_TRACEINTID_IFGETSTATUS 0x001d
+#define LPC17_TRACEINTID_SETCONFIG 0x001e
+#define LPC17_TRACEINTID_SETFEATURE 0x001f
+#define LPC17_TRACEINTID_SUSPENDCHG 0x0020
+#define LPC17_TRACEINTID_SYNCHFRAME 0x0021
+
+/* Hardware interface **********************************************************/
+
+/* Macros for testing the device status response */
+
+#define DEVSTATUS_CONNECT(s) (((s)&CMD_STATUS_CONNECT)!=0)
+#define DEVSTATUS_CONNCHG(s) (((s)&CMD_STATUS_CONNCHG)!=0)
+#define DEVSTATUS_SUSPEND(s) (((s)&CMD_STATUS_SUSPEND)!=0)
+#define DEVSTATUS_SUSPCHG(s) (((s)&CMD_STATUS_SUSPCHG)!=0)
+#define DEVSTATUS_RESET(s) (((s)&CMD_STATUS_RESET)!=0)
+
+/* If this bit is set in the lpc17_epread response, it means that the
+ * recevied packet was overwritten by a later setup packet (ep0 only).
+ */
+
+#define LPC17_READOVERRUN_BIT (0x80000000)
+#define LPC17_READOVERRUN(s) (((s) & LPC17_READOVERRUN_BIT) != 0)
+
+/* USB RAM ********************************************************************
+ *
+ * UBS_UDCA is is list of 32 pointers to DMA desciptors located at the
+ * beginning of USB RAM. Each pointer points to a DMA descriptor with
+ * assocated DMA buffer.
+ */
+
+#define USB_UDCA (uint32_t*)LPC17_USBDEV_RAMBASE)
+#define USB_USCASIZE (LPC17_NPHYSENDPOINTS*sizeof(uint32_t))
+
+/* Each descriptor must be aligned to a 128 address boundary */
+
+#define USB_DDALIGNDOWN(a) ((a)&~0x7f)
+#define USB_DDALIGNUP(a) USB_DDALIGNDOWN((a)+0x7f)
+
+#define USB_DDSIZE USB_DDALIGNDOWN((LPC17_USBDEV_RAMSIZE-USB_USCASIZE)/CONFIG_LPC17_USBDEV_NDMADESCRIPTORS)
+#define USB_DDESC ((struct lpc17_dmadesc_s*)(LPC17_USBDEV_RAMBASE+USB_USCASIZE))
+
+#ifdef CONFIG_USBDEV_ISOCHRONOUS
+# define USB_DDESCSIZE (5*sizeof(uint32_t))
+#else
+# define USB_DDESCSIZE (4*sizeof(uint32_t))
+#endif
+
+/* Endpoints ******************************************************************/
+
+/* Number of endpoints */
+
+#define LPC17_NLOGENDPOINTS (16) /* ep0-15 */
+#define LPC17_NPHYSENDPOINTS (32) /* x2 for IN and OUT */
+
+/* Odd physical endpoint numbers are IN; even are out */
+
+#define LPC17_EPPHYIN(epphy) (((epphy)&1)!=0)
+#define LPC17_EPPHYOUT(epphy) (((epphy)&1)==0)
+
+#define LPC17_EPPHYIN2LOG(epphy) (((uint8_t)(epphy)>>1)|USB_DIR_IN)
+#define LPC17_EPPHYOUT2LOG(epphy) (((uint8_t)(epphy)>>1)|USB_DIR_OUT)
+
+/* Each endpoint has somewhat different characteristics */
+
+#define LPC17_EPALLSET (0xffffffff) /* All endpoints */
+#define LPC17_EPOUTSET (0x55555555) /* Even phy endpoint numbers are OUT EPs */
+#define LPC17_EPINSET (0xaaaaaaaa) /* Odd endpoint numbers are IN EPs */
+#define LPC17_EPCTRLSET (0x00000003) /* EP0 IN/OUT are control endpoints */
+#define LPC17_EPINTRSET (0x0c30c30c) /* Interrupt endpoints */
+#define LPC17_EPBULKSET (0xf0c30c30) /* Bulk endpoints */
+#define LPC17_EPISOCSET (0x030c30c0) /* Isochronous endpoints */
+#define LPC17_EPDBLBUFFER (0xf3cf3cf0) /* Double buffered endpoints */
+
+#define LPC17_EP0MAXPACKET (64) /* EP0 max packet size (1-64) */
+#define LPC17_BULKMAXPACKET (64) /* Bulk endpoint max packet (8/16/32/64) */
+#define LPC17_INTRMAXPACKET (64) /* Interrupt endpoint max packet (1 to 64) */
+#define LPC17_ISOCMAXPACKET (512) /* Acutally 1..1023 */
+
+/* EP0 status. EP0 transfers occur in a number of different contexts. A
+ * simple state machine is required to handle the various transfer complete
+ * interrupt responses. The following values are the various states:
+ */
+ /*** INTERRUPT CAUSE ***/
+#define LPC17_EP0REQUEST (0) /* Normal request handling */
+#define LPC17_EP0STATUSIN (1) /* Status sent */
+#define LPC17_EP0STATUSOUT (2) /* Status received */
+#define LPC17_EP0SHORTWRITE (3) /* Short data sent with no request */
+#define LPC17_EP0SHORTWRSENT (4) /* Short data write complete */
+#define LPC17_EP0SETADDRESS (5) /* Set address received */
+#define LPC17_EP0WRITEREQUEST (6) /* EP0 write request sent */
+
+/* Request queue operations ****************************************************/
+
+#define lpc17_rqempty(ep) ((ep)->head == NULL)
+#define lpc17_rqpeek(ep) ((ep)->head)
+
+/*******************************************************************************
+ * Private Types
+ *******************************************************************************/
+
+/* A container for a request so that the request make be retained in a list */
+
+struct lpc17_req_s
+{
+ struct usbdev_req_s req; /* Standard USB request */
+ struct lpc17_req_s *flink; /* Supports a singly linked list */
+};
+
+/* This is the internal representation of an endpoint */
+
+struct lpc17_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 lpc17_ep_s.
+ */
+
+ struct usbdev_ep_s ep; /* Standard endpoint structure */
+
+ /* LPC17xx-specific fields */
+
+ struct lpc17_usbdev_s *dev; /* Reference to private driver data */
+ struct lpc17_req_s *head; /* Request list for this endpoint */
+ struct lpc17_req_s *tail;
+ uint8_t epphy; /* Physical EP address */
+ uint8_t stalled:1; /* 1: Endpoint is stalled */
+ uint8_t halted:1; /* 1: Endpoint feature halted */
+ uint8_t txbusy:1; /* 1: TX endpoint FIFO full */
+ uint8_t txnullpkt:1; /* Null packet needed at end of transfer */
+};
+
+/* This represents a DMA descriptor */
+
+#ifdef CONFIG_LPC17_USBDEV_DMA
+struct lpc17_dmadesc_s
+{
+ uint32_t nextdesc; /* Address of the next DMA descripto in RAM */
+ uint32_t config; /* Misc. bit encoded configuration information */
+ uint32_t start; /* DMA start address */
+ uint32_t status; /* Misc. bit encoded status inforamation */
+#ifdef CONFIG_USBDEV_ISOCHRONOUS
+ uint32_t size; /* Isochronous packet size address */
+#endif
+ uint8_t buffer[USB_DDSIZE-USB_DDESCSIZE];
+};
+#endif
+
+/* This structure retains the state of the USB device controller */
+
+struct lpc17_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 structlpc17_usbdev_s.
+ */
+
+ struct usbdev_s usbdev;
+
+ /* The bound device class driver */
+
+ struct usbdevclass_driver_s *driver;
+
+ /* LPC17xx-specific fields */
+
+ uint8_t devstatus; /* Last response to device status command */
+ uint8_t ep0state; /* State of certain EP0 operations */
+ uint8_t paddr; /* Address assigned by SETADDRESS */
+ uint8_t stalled:1; /* 1: Protocol stalled */
+ uint8_t selfpowered:1; /* 1: Device is self powered */
+ uint8_t paddrset:1; /* 1: Peripheral addr has been set */
+ uint8_t attached:1; /* 1: Host attached */
+ uint8_t rxpending:1; /* 1: RX pending */
+ uint32_t softprio; /* Bitset of high priority interrupts */
+ uint32_t epavail; /* Bitset of available endpoints */
+#ifdef CONFIG_LPC17_USBDEV_FRAME_INTERRUPT
+ uint32_t sof; /* Last start-of-frame */
+#endif
+
+ /* Allocated DMA descriptor */
+
+#ifdef CONFIG_LPC17_USBDEV_DMA
+ struct lpc17_dmadesc_s *dmadesc;
+#endif
+
+ /* The endpoint list */
+
+ struct lpc17_ep_s eplist[LPC17_NPHYSENDPOINTS];
+};
+
+/*******************************************************************************
+ * Private Function Prototypes
+ *******************************************************************************/
+
+/* Register operations ********************************************************/
+
+#if defined(CONFIG_LPC17_USBDEV_REGDEBUG) && defined(CONFIG_DEBUG)
+static uint32_t lpc17_getreg(uint32_t addr);
+static void lpc17_putreg(uint32_t val, uint32_t addr);
+#else
+# define lpc17_getreg(addr) getreg32(addr)
+# define lpc17_putreg(val,addr) putreg32(val,addr)
+#endif
+
+/* Command operations **********************************************************/
+
+static uint32_t lpc17_usbcmd(uint16_t cmd, uint8_t data);
+
+/* Request queue operations ****************************************************/
+
+static FAR struct lpc17_req_s *lpc17_rqdequeue(FAR struct lpc17_ep_s *privep);
+static void lpc17_rqenqueue(FAR struct lpc17_ep_s *privep,
+ FAR struct lpc17_req_s *req);
+
+/* Low level data transfers and request operations *****************************/
+
+static void lpc17_epwrite(uint8_t epphy, const uint8_t *data, uint32_t nbytes);
+static int lpc17_epread(uint8_t epphy, uint8_t *data, uint32_t nbytes);
+static inline void lpc17_abortrequest(struct lpc17_ep_s *privep,
+ struct lpc17_req_s *privreq, int16_t result);
+static void lpc17_reqcomplete(struct lpc17_ep_s *privep, int16_t result);
+static int lpc17_wrrequest(struct lpc17_ep_s *privep);
+static int lpc17_rdrequest(struct lpc17_ep_s *privep);
+static void lpc17_cancelrequests(struct lpc17_ep_s *privep);
+
+/* Interrupt handling **********************************************************/
+
+static struct lpc17_ep_s *lpc17_epfindbyaddr(struct lpc17_usbdev_s *priv,
+ uint16_t eplog);
+static void lpc17_eprealize(struct lpc17_ep_s *privep, bool prio,
+ uint32_t packetsize);
+static uint8_t lpc17_epclrinterrupt(uint8_t epphy);
+static inline void lpc17_ep0configure(struct lpc17_usbdev_s *priv);
+#ifdef CONFIG_LPC17_USBDEV_DMA
+static inline void lpc17_dmareset(uint32_t enable);
+#endif
+static void lpc17_usbreset(struct lpc17_usbdev_s *priv);
+static void lpc17_dispatchrequest(struct lpc17_usbdev_s *priv,
+ const struct usb_ctrlreq_s *ctrl);
+static inline void lpc17_ep0setup(struct lpc17_usbdev_s *priv);
+static inline void lpc17_ep0dataoutinterrupt(struct lpc17_usbdev_s *priv);
+static inline void lpc17_ep0dataininterrupt(struct lpc17_usbdev_s *priv);
+static int lpc17_usbinterrupt(int irq, FAR void *context);
+
+#ifdef CONFIG_LPC17_USBDEV_DMA
+static int lpc17_dmasetup(struct lpc17_usbdev_s *priv, uint8_t epphy,
+ uint32_t epmaxsize, uint32_t nbytes, uint32_t *isocpacket,
+ bool isochronous);
+static void lpc17_dmarestart(uint8_t epphy, uint32_t descndx);
+static void lpc17_dmadisable(uint8_t epphy);
+#endif /* CONFIG_LPC17_USBDEV_DMA */
+
+/* Endpoint operations *********************************************************/
+
+static int lpc17_epconfigure(FAR struct usbdev_ep_s *ep,
+ const struct usb_epdesc_s *desc, bool last);
+static int lpc17_epdisable(FAR struct usbdev_ep_s *ep);
+static FAR struct usbdev_req_s *lpc17_epallocreq(FAR struct usbdev_ep_s *ep);
+static void lpc17_epfreereq(FAR struct usbdev_ep_s *ep,
+ FAR struct usbdev_req_s *);
+#ifdef CONFIG_LPC17_USBDEV_DMA
+static FAR void *lpc17_epallocbuffer(FAR struct usbdev_ep_s *ep,
+ uint16_t nbytes);
+static void lpc17_epfreebuffer(FAR struct usbdev_ep_s *ep, void *buf);
+#endif
+static int lpc17_epsubmit(FAR struct usbdev_ep_s *ep,
+ struct usbdev_req_s *req);
+static int lpc17_epcancel(FAR struct usbdev_ep_s *ep,
+ struct usbdev_req_s *req);
+static int lpc17_epstall(FAR struct usbdev_ep_s *ep, bool resume);
+
+/* USB device controller operations ********************************************/
+
+static FAR struct usbdev_ep_s *lpc17_allocep(FAR struct usbdev_s *dev,
+ uint8_t epno, bool in, uint8_t eptype);
+static void lpc17_freeep(FAR struct usbdev_s *dev, FAR struct usbdev_ep_s *ep);
+static int lpc17_getframe(struct usbdev_s *dev);
+static int lpc17_wakeup(struct usbdev_s *dev);
+static int lpc17_selfpowered(struct usbdev_s *dev, bool selfpowered);
+static int lpc17_pullup(struct usbdev_s *dev, bool enable);
+
+/*******************************************************************************
+ * 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 lpc17_usbdev_s g_usbdev;
+
+static const struct usbdev_epops_s g_epops =
+{
+ .configure = lpc17_epconfigure,
+ .disable = lpc17_epdisable,
+ .allocreq = lpc17_epallocreq,
+ .freereq = lpc17_epfreereq,
+#ifdef CONFIG_LPC17_USBDEV_DMA
+ .allocbuffer = lpc17_epallocbuffer,
+ .freebuffer = lpc17_epfreebuffer,
+#endif
+ .submit = lpc17_epsubmit,
+ .cancel = lpc17_epcancel,
+ .stall = lpc17_epstall,
+};
+
+static const struct usbdev_ops_s g_devops =
+{
+ .allocep = lpc17_allocep,
+ .freeep = lpc17_freeep,
+ .getframe = lpc17_getframe,
+ .wakeup = lpc17_wakeup,
+ .selfpowered = lpc17_selfpowered,
+ .pullup = lpc17_pullup,
+};
+
+/*******************************************************************************
+ * Public Data
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Private Functions
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Name: lpc17_getreg
+ *
+ * Description:
+ * Get the contents of an LPC17xx register
+ *
+ *******************************************************************************/
+
+#if defined(CONFIG_LPC17_USBDEV_REGDEBUG) && defined(CONFIG_DEBUG)
+static uint32_t lpc17_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: lpc17_putreg
+ *
+ * Description:
+ * Set the contents of an LPC17xx register to a value
+ *
+ *******************************************************************************/
+
+#if defined(CONFIG_LPC17_USBDEV_REGDEBUG) && defined(CONFIG_DEBUG)
+static void lpc17_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: lpc17_usbcmd
+ *
+ * Description:
+ * Transmit commands to the USB engine
+ *
+ *******************************************************************************/
+
+static uint32_t lpc17_usbcmd(uint16_t cmd, uint8_t data)
+{
+ irqstate_t flags;
+ uint32_t tmp = 0;
+
+ /* Disable interrupt and clear CDFULL and CCEMPTY interrupt status */
+
+ flags = irqsave();
+ lpc17_putreg(USBDEV_INT_CDFULL|USBDEV_INT_CCEMPTY, LPC17_USBDEV_INTCLR);
+
+ /* Load command + WR in command code register */
+
+ lpc17_putreg(((cmd & 0xff) << 16) + CMD_USBDEV_CMDWR, LPC17_USBDEV_CMDCODE);
+
+ /* Wait until the command register is empty (CCEMPTY != 0, command is accepted) */
+
+ while ((lpc17_getreg(LPC17_USBDEV_INTST) & USBDEV_INT_CCEMPTY) == 0);
+
+ /* Clear command register empty (CCEMPTY) interrupt */
+
+ lpc17_putreg(USBDEV_INT_CCEMPTY, LPC17_USBDEV_INTCLR);
+
+ /* Determine next phase of the command */
+
+ switch (cmd)
+ {
+ /* Write operations (1 byte of data) */
+
+ case CMD_USBDEV_SETADDRESS:
+ case CMD_USBDEV_CONFIG:
+ case CMD_USBDEV_SETMODE:
+ case CMD_USBDEV_SETSTATUS:
+ {
+ /* Send data + WR and wait for CCEMPTY */
+
+ lpc17_putreg((data << 16) + CMD_USBDEV_DATAWR, LPC17_USBDEV_CMDCODE);
+ while ((lpc17_getreg(LPC17_USBDEV_INTST) & USBDEV_INT_CCEMPTY) == 0);
+ }
+ break;
+
+ /* 16 bit read operations */
+
+ case CMD_USBDEV_READFRAMENO:
+ case CMD_USBDEV_READTESTREG:
+ {
+ /* Send command code + RD and wait for CDFULL */
+
+ lpc17_putreg((cmd << 16) + CMD_USBDEV_DATARD, LPC17_USBDEV_CMDCODE);
+ while ((lpc17_getreg(LPC17_USBDEV_INTST) & USBDEV_INT_CDFULL) == 0);
+
+ /* Clear CDFULL and read LS data */
+
+ lpc17_putreg(USBDEV_INT_CDFULL, LPC17_USBDEV_INTCLR);
+ tmp = lpc17_getreg(LPC17_USBDEV_CMDDATA);
+
+ /* Send command code + RD and wait for CDFULL */
+
+ lpc17_putreg((cmd << 16) + CMD_USBDEV_DATARD, LPC17_USBDEV_CMDCODE);
+ while ((lpc17_getreg(LPC17_USBDEV_INTST) & USBDEV_INT_CDFULL) == 0);
+
+ /* Read MS data */
+
+ tmp |= lpc17_getreg(LPC17_USBDEV_CMDDATA) << 8;
+ }
+ break;
+
+ /* 8-bit read operations */
+
+ case CMD_USBDEV_GETSTATUS:
+ case CMD_USBDEV_GETERRORCODE:
+ case CMD_USBDEV_READERRORSTATUS:
+ case CMD_USBDEV_EPCLRBUFFER:
+ {
+ /* Send command code + RD and wait for CDFULL */
+
+ lpc17_putreg((cmd << 16) + CMD_USBDEV_DATARD, LPC17_USBDEV_CMDCODE);
+ while ((lpc17_getreg(LPC17_USBDEV_INTST) & USBDEV_INT_CDFULL) == 0);
+
+ /* Read data */
+
+ tmp = lpc17_getreg(LPC17_USBDEV_CMDDATA);
+ }
+ break;
+
+ /* No data transfer */
+
+ case CMD_USBDEV_EPVALIDATEBUFFER:
+ break;
+
+ default:
+ switch (cmd & 0x1e0)
+ {
+ case CMD_USBDEV_EPSELECT:
+ case CMD_USBDEV_EPSELECTCLEAR:
+ {
+ /* Send command code + RD and wait for CDFULL */
+
+ lpc17_putreg((cmd << 16) + CMD_USBDEV_DATARD, LPC17_USBDEV_CMDCODE);
+ while ((lpc17_getreg(LPC17_USBDEV_INTST) & USBDEV_INT_CDFULL) == 0);
+
+ /* Read data */
+
+ tmp = lpc17_getreg(LPC17_USBDEV_CMDDATA);
+ }
+ break;
+
+ case CMD_USBDEV_EPSETSTATUS:
+ {
+ /* Send data + RD and wait for CCEMPTY */
+
+ lpc17_putreg((data << 16) + CMD_USBDEV_DATAWR, LPC17_USBDEV_CMDCODE);
+ while ((lpc17_getreg(LPC17_USBDEV_INTST) & USBDEV_INT_CCEMPTY) == 0);
+ }
+ break;
+
+ default:
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_INVALIDCMD), 0);
+ break;
+ }
+ break;
+ }
+
+ /* Restore the interrupt flags */
+
+ irqrestore(flags);
+ return tmp;
+}
+
+/*******************************************************************************
+ * Name: lpc17_rqdequeue
+ *
+ * Description:
+ * Remove a request from an endpoint request queue
+ *
+ *******************************************************************************/
+
+static FAR struct lpc17_req_s *lpc17_rqdequeue(FAR struct lpc17_ep_s *privep)
+{
+ FAR struct lpc17_req_s *ret = privep->head;
+
+ if (ret)
+ {
+ privep->head = ret->flink;
+ if (!privep->head)
+ {
+ privep->tail = NULL;
+ }
+
+ ret->flink = NULL;
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: lpc17_rqenqueue
+ *
+ * Description:
+ * Add a request from an endpoint request queue
+ *
+ *******************************************************************************/
+
+static void lpc17_rqenqueue(FAR struct lpc17_ep_s *privep,
+ FAR struct lpc17_req_s *req)
+{
+ req->flink = NULL;
+ if (!privep->head)
+ {
+ privep->head = req;
+ privep->tail = req;
+ }
+ else
+ {
+ privep->tail->flink = req;
+ privep->tail = req;
+ }
+}
+
+/*******************************************************************************
+ * Name: lpc17_epwrite
+ *
+ * Description:
+ * Endpoint write (IN)
+ *
+ *******************************************************************************/
+
+static void lpc17_epwrite(uint8_t epphy, const uint8_t *data, uint32_t nbytes)
+{
+ uint32_t value;
+ bool aligned = (((uint32_t)data & 3) == 0);
+
+ /* Set the write enable bit for this physical EP address. Bits 2-5 are
+ * the logical endpoint number (0-15)
+ */
+
+ lpc17_putreg(((epphy << 1) & USBDEV_CTRL_LOGEP_MASK) | USBDEV_CTRL_WREN,
+ LPC17_USBDEV_CTRL);
+
+ /* Set the transmit packet length (nbytes must be less than 2048) */
+
+ lpc17_putreg(nbytes, LPC17_USBDEV_TXPLEN);
+
+ /* Transfer the packet data */
+
+ do
+ {
+ /* Zero length packets are a special case */
+
+ if (nbytes)
+ {
+ if (aligned)
+ {
+ value = *(uint32_t*)data;
+ }
+ else
+ {
+ value = (uint32_t)data[0] | ((uint32_t)data[1] << 8) |
+ ((uint32_t)data[2] << 16) | ((uint32_t)data[3] << 24);
+ }
+
+ lpc17_putreg(value, LPC17_USBDEV_TXDATA);
+ data += 4;
+ }
+ else
+ {
+ /* Zero length packet */
+
+ lpc17_putreg(0, LPC17_USBDEV_TXDATA);
+ }
+ }
+ while ((lpc17_getreg(LPC17_USBDEV_CTRL) & USBDEV_CTRL_WREN) != 0);
+
+ /* Done */
+
+ lpc17_putreg(0, LPC17_USBDEV_CTRL);
+ (void)lpc17_usbcmd(CMD_USBDEV_EPSELECT | epphy, 0);
+ (void)lpc17_usbcmd(CMD_USBDEV_EPVALIDATEBUFFER, 0);
+}
+
+/*******************************************************************************
+ * Name: lpc17_epread
+ *
+ * Description:
+ * Endpoint read (OUT)
+ *
+ *******************************************************************************/
+
+static int lpc17_epread(uint8_t epphy, uint8_t *data, uint32_t nbytes)
+{
+ uint32_t pktlen;
+ uint32_t result;
+ uint32_t value;
+ uint8_t aligned = 0;
+
+ /* If data is NULL, then we are being asked to read but discard the data.
+ * For most cases, the resulting buffer will be aligned and we will be
+ * able to do faster 32-bit transfers.
+ */
+
+ if (data)
+ {
+ if (((uint32_t)data & 3) == 0)
+ {
+ aligned = 1;
+ }
+ else
+ {
+ aligned = 2;
+ }
+ }
+
+ /* Set the read enable bit for this physical EP address. Bits 2-5 are
+ * the logical endpoint number (0-15).
+ */
+
+ lpc17_putreg(((epphy << 1) & USBDEV_CTRL_LOGEP_MASK) | USBDEV_CTRL_RDEN,
+ LPC17_USBDEV_CTRL);
+
+ /* Wait for packet buffer ready for reading */
+
+ while ((lpc17_getreg(LPC17_USBDEV_RXPLEN) & USBDEV_RXPLEN_PKTRDY) == 0);
+
+ /* Get the number of bytes of data to be read */
+
+ pktlen = lpc17_getreg(LPC17_USBDEV_RXPLEN) & USBDEV_RXPLEN_MASK;
+
+ /* Read data from input buffer while read data is valid (DV) */
+
+ while ((lpc17_getreg(LPC17_USBDEV_RXPLEN) & USBDEV_RXPLEN_DV) != 0)
+ {
+ value = lpc17_getreg(LPC17_USBDEV_RXDATA);
+ if (aligned == 1)
+ {
+ *(uint32_t*)data = value;
+ data += 4;
+ }
+ else if (aligned == 2)
+ {
+ *data++ = (uint8_t)value;
+ *data++ = (uint8_t)(value >> 8);
+ *data++ = (uint8_t)(value >> 16);
+ *data++ = (uint8_t)(value >> 24);
+ }
+ }
+
+ /* Done */
+
+ lpc17_putreg(0, LPC17_USBDEV_CTRL);
+ (void)lpc17_usbcmd(CMD_USBDEV_EPSELECT | epphy, 0);
+ result = lpc17_usbcmd(CMD_USBDEV_EPCLRBUFFER, 0);
+
+ /* The packet overrun bit in the clear buffer response is applicable only
+ * on EP0 transfers. If set it means that the recevied packet was overwritten
+ * by a later setup packet.
+ */
+
+ if (epphy == LPC17_EP0_OUT && (result & CMD_USBDEV_CLRBUFFER_PO) != 0)
+ {
+ /* Pass this information in bit 31 */
+
+ pktlen |= LPC17_READOVERRUN_BIT;
+ }
+ return pktlen;
+}
+
+/*******************************************************************************
+ * Name: lpc17_abortrequest
+ *
+ * Description:
+ * Discard a request
+ *
+ *******************************************************************************/
+
+static inline void lpc17_abortrequest(struct lpc17_ep_s *privep,
+ struct lpc17_req_s *privreq,
+ int16_t result)
+{
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_REQABORTED), (uint16_t)privep->epphy);
+
+ /* Save the result in the request structure */
+
+ privreq->req.result = result;
+
+ /* Callback to the request completion handler */
+
+ privreq->req.callback(&privep->ep, &privreq->req);
+}
+
+/*******************************************************************************
+ * Name: lpc17_reqcomplete
+ *
+ * Description:
+ * Handle termination of the request at the head of the endpoint request queue.
+ *
+ *******************************************************************************/
+
+static void lpc17_reqcomplete(struct lpc17_ep_s *privep, int16_t result)
+{
+ struct lpc17_req_s *privreq;
+ int stalled = privep->stalled;
+ irqstate_t flags;
+
+ /* Remove the completed request at the head of the endpoint request list */
+
+ flags = irqsave();
+ privreq = lpc17_rqdequeue(privep);
+ irqrestore(flags);
+
+ if (privreq)
+ {
+ /* If endpoint 0, temporarily reflect the state of protocol stalled
+ * in the callback.
+ */
+
+ if (privep->epphy == LPC17_EP0_IN)
+ {
+ privep->stalled = privep->dev->stalled;
+ }
+
+ /* Save the result in the request structure */
+
+ privreq->req.result = result;
+
+ /* Callback to the request completion handler */
+
+ privreq->flink = NULL;
+ privreq->req.callback(&privep->ep, &privreq->req);
+
+ /* Restore the stalled indication */
+
+ privep->stalled = stalled;
+ }
+}
+
+/*******************************************************************************
+ * Name: lpc17_wrrequest
+ *
+ * Description:
+ * Send from the next queued write request
+ *
+ *******************************************************************************/
+
+static int lpc17_wrrequest(struct lpc17_ep_s *privep)
+{
+ struct lpc17_req_s *privreq;
+ uint8_t *buf;
+ int nbytes;
+ int bytesleft;
+
+ /* Check the request from the head of the endpoint request queue */
+
+ privreq = lpc17_rqpeek(privep);
+ if (!privreq)
+ {
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_EPINQEMPTY), 0);
+ return OK;
+ }
+
+ ullvdbg("epphy=%d req=%p: len=%d xfrd=%d nullpkt=%d\n",
+ privep->epphy, privreq, privreq->req.len, privreq->req.xfrd, privep->txnullpkt);
+
+ /* Ignore any attempt to send a zero length packet on anything but EP0IN */
+
+ if (privreq->req.len == 0)
+ {
+ if (privep->epphy == LPC17_EP0_IN)
+ {
+ lpc17_epwrite(LPC17_EP0_IN, NULL, 0);
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_EPINNULLPACKET), 0);
+ }
+
+ /* In any event, the request is complete */
+
+ lpc17_reqcomplete(privep, OK);
+ return OK;
+ }
+
+ /* Otherwise send the data in the packet (in the DMA on case, we
+ * may be resuming transfer already in progress.
+ */
+#warning REVISIT... If the EP supports double buffering, then we can do better
+
+ /* Get the number of bytes left to be sent in the packet */
+
+ bytesleft = privreq->req.len - privreq->req.xfrd;
+
+ /* Send the next packet if (1) there are more bytes to be sent, or
+ * (2) the last packet sent was exactly maxpacketsize (bytesleft == 0)
+ */
+
+ usbtrace(TRACE_WRITE(privep->epphy), privreq->req.xfrd);
+ if (bytesleft > 0 || privep->txnullpkt)
+ {
+ /* Indicate that there is data in the TX FIFO. This will be cleared
+ * when the EPIN interrupt is received
+ */
+
+ privep->txbusy = 1;
+
+ /* Try to send maxpacketsize -- unless we don't have that many
+ * bytes to send.
+ */
+
+ privep->txnullpkt = 0;
+ if (bytesleft > privep->ep.maxpacket)
+ {
+ nbytes = privep->ep.maxpacket;
+ }
+ else
+ {
+ nbytes = bytesleft;
+ if ((privreq->req.flags & USBDEV_REQFLAGS_NULLPKT) != 0)
+ {
+ privep->txnullpkt = (bytesleft == privep->ep.maxpacket);
+ }
+ }
+
+ /* Send the largest number of bytes that we can in this packet */
+
+ buf = privreq->req.buf + privreq->req.xfrd;
+ lpc17_epwrite(privep->epphy, buf, nbytes);
+
+ /* Update for the next time through the loop */
+
+ privreq->req.xfrd += nbytes;
+ }
+
+ /* 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->txnullpkt)
+ {
+ usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd);
+ privep->txnullpkt = 0;
+ lpc17_reqcomplete(privep, OK);
+ }
+
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: lpc17_rdrequest
+ *
+ * Description:
+ * Receive to the next queued read request
+ *
+ *******************************************************************************/
+
+static int lpc17_rdrequest(struct lpc17_ep_s *privep)
+{
+ struct lpc17_req_s *privreq;
+ uint8_t *buf;
+ int nbytesread;
+
+ /* Check the request from the head of the endpoint request queue */
+
+ privreq = lpc17_rqpeek(privep);
+ if (!privreq)
+ {
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_EPOUTQEMPTY), 0);
+ return OK;
+ }
+
+ ullvdbg("len=%d xfrd=%d nullpkt=%d\n",
+ privreq->req.len, privreq->req.xfrd, privep->txnullpkt);
+
+ /* Ignore any attempt to receive a zero length packet */
+
+ if (privreq->req.len == 0)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_EPOUTNULLPACKET), 0);
+ lpc17_reqcomplete(privep, OK);
+ return OK;
+ }
+
+ usbtrace(TRACE_READ(privep->epphy), privreq->req.xfrd);
+
+ /* Receive the next packet */
+
+ buf = privreq->req.buf + privreq->req.xfrd;
+ nbytesread = lpc17_epread(privep->epphy, buf, privep->ep.maxpacket);
+ if (nbytesread < 0)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_EPREAD), nbytesread);
+ return ERROR;
+ }
+
+ /* If the receive buffer is full or if the last packet was not full
+ * then we are finished with the transfer.
+ */
+
+ privreq->req.xfrd += nbytesread;
+ if (privreq->req.xfrd >= privreq->req.len || nbytesread < privep->ep.maxpacket)
+ {
+ usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd);
+ lpc17_reqcomplete(privep, OK);
+ }
+
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: lpc17_cancelrequests
+ *
+ * Description:
+ * Cancel all pending requests for an endpoint
+ *
+ *******************************************************************************/
+
+static void lpc17_cancelrequests(struct lpc17_ep_s *privep)
+{
+ while (!lpc17_rqempty(privep))
+ {
+ usbtrace(TRACE_COMPLETE(privep->epphy),
+ (lpc17_rqpeek(privep))->req.xfrd);
+ lpc17_reqcomplete(privep, -ESHUTDOWN);
+ }
+}
+
+/*******************************************************************************
+ * Name: lpc17_epfindbyaddr
+ *
+ * Description:
+ * Find the physical endpoint structure corresponding to a logic endpoint
+ * address
+ *
+ *******************************************************************************/
+
+static struct lpc17_ep_s *lpc17_epfindbyaddr(struct lpc17_usbdev_s *priv,
+ uint16_t eplog)
+{
+ struct lpc17_ep_s *privep;
+ int i;
+
+ /* Endpoint zero is a special case */
+
+ if (USB_EPNO(eplog) == 0)
+ {
+ return &priv->eplist[0];
+ }
+
+ /* Handle the remaining */
+
+ for (i = 1; i < LPC17_NPHYSENDPOINTS; i++)
+ {
+ privep = &priv->eplist[i];
+
+ /* Same logical endpoint number? (includes direction bit) */
+
+ if (eplog == privep->ep.eplog)
+ {
+ /* Return endpoint found */
+
+ return privep;
+ }
+ }
+
+ /* Return endpoint not found */
+
+ return NULL;
+}
+
+/*******************************************************************************
+ * Name: lpc17_eprealize
+ *
+ * Description:
+ * Enable or disable an endpoint
+ *
+ *******************************************************************************/
+
+static void lpc17_eprealize(struct lpc17_ep_s *privep, bool prio, uint32_t packetsize)
+{
+ struct lpc17_usbdev_s *priv = privep->dev;
+ uint32_t mask;
+ uint32_t reg;
+
+ /* Initialize endpoint software priority */
+
+ mask = 1 << privep->epphy;
+ if (prio)
+ {
+ priv->softprio = priv->softprio | mask;
+ }
+ else
+ {
+ priv->softprio = priv->softprio & ~mask;
+ }
+
+ /* Clear realize interrupt bit */
+
+ lpc17_putreg(USBDEV_INT_EPRLZED, LPC17_USBDEV_INTCLR);
+
+ /* Realize the endpoint */
+
+ reg = lpc17_getreg(LPC17_USBDEV_REEP);
+ reg |= (1 << privep->epphy);
+ lpc17_putreg(reg, LPC17_USBDEV_REEP);
+
+ /* Set endpoint maximum packet size */
+
+ lpc17_putreg(privep->epphy, LPC17_USBDEV_EPIND);
+ lpc17_putreg(packetsize, LPC17_USBDEV_MAXPSIZE);
+
+ /* Wait for Realize complete */
+
+ while ((lpc17_getreg(LPC17_USBDEV_INTST) & USBDEV_INT_EPRLZED) == 0);
+
+ /* Clear realize interrupt bit */
+
+ lpc17_putreg(USBDEV_INT_EPRLZED,LPC17_USBDEV_INTCLR);
+}
+
+/*******************************************************************************
+ * Name: lpc17_epclrinterrupt
+ *
+ * Description:
+ * Clear the EP interrupt flag and return the current EP status
+ *
+ *******************************************************************************/
+
+static uint8_t lpc17_epclrinterrupt(uint8_t epphy)
+{
+ /* Clear the endpoint interrupt */
+
+ lpc17_putreg(1 << epphy, LPC17_USBDEV_EPINTCLR);
+
+ /* Wait for data in the command data register */
+
+ while ((lpc17_getreg(LPC17_USBDEV_INTST) & USBDEV_INT_CDFULL) == 0);
+
+ /* Return the value of the command data register */
+
+ return lpc17_getreg(LPC17_USBDEV_CMDDATA);
+}
+
+/*******************************************************************************
+ * Name: lpc17_ep0configure
+ *
+ * Description:
+ * Configure endpoint 0
+ *
+ *******************************************************************************/
+
+static inline void lpc17_ep0configure(struct lpc17_usbdev_s *priv)
+{
+ uint32_t inten;
+
+ /* EndPoint 0 initialization */
+
+ lpc17_eprealize(&priv->eplist[LPC17_CTRLEP_OUT], 0, CONFIG_USBDEV_EP0_MAXSIZE);
+ lpc17_eprealize(&priv->eplist[LPC17_CTRLEP_IN], 1, CONFIG_USBDEV_EP0_MAXSIZE);
+
+ /* Enable EP0 interrupts (not DMA) */
+
+ inten = lpc17_getreg(LPC17_USBDEV_EPINTEN);
+ inten |= 3; /* EP0 Rx and Tx */
+ lpc17_putreg(inten, LPC17_USBDEV_EPINTEN);
+}
+
+/*******************************************************************************
+ * Name: lpc17_dmareset
+ *
+ * Description: Reset USB DMA
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_LPC17_USBDEV_DMA
+static inline void lpc17_dmareset(uint32_t enable)
+{
+ int i;
+
+ /* Disable All DMA interrupts */
+
+ lpc17_putreg(0, LPC17_USBDEV_DMAINTEN);
+
+ /* DMA Disable */
+
+ lpc17_putreg(0xffffffff, LPC17_USBDEV_EPDMADIS);
+
+ /* DMA Request clear */
+
+ putreq32(0xffffffff, LPC17_USBDEV_DMARCLR);
+
+ /* End of Transfer Interrupt Clear */
+
+ putreq32(0xffffffff, LPC17_USBDEV_EOTINTCLR);
+
+ /* New DD Request Interrupt Clear */
+
+ putreq32(0xffffffff, LPC17_USBDEV_NDDRINTCLR);
+
+ /* System Error Interrupt Clear */
+
+ putreq32(0xffffffff, LPC17_USBDEV_SYSERRINTCLR);
+
+ /* Nullify all pointers in the UDCA */
+
+ for (i = 0; i < LPC17_NPHYSENDPOINTS; ++i)
+ {
+ USB_UDCA[i] = NULL;
+ }
+
+ /* Set USB UDCA Head register */
+
+ lpc17_putreg((uint32_t)USB_UDCA, LPC17_USBDEV_UDCAH);
+
+ /* Invalidate all DMA descriptors */
+
+ for (i = 0; i < CONFIG_LPC17_USBDEV_NDMADESCRIPTORS; ++i)
+ {
+ memset(&USB_DDESC[i], 0, USB_DDESCSIZE);
+ }
+
+ /* Enable DMA interrupts */
+
+ lpc17_putreg(enable, LPC17_USBDEV_DMAINTEN);
+}
+#endif
+
+/*******************************************************************************
+ * Name: lpc17_usbreset
+ *
+ * Description:
+ * Reset Usb engine
+ *
+ *******************************************************************************/
+
+static void lpc17_usbreset(struct lpc17_usbdev_s *priv)
+{
+ /* Disable all endpoint interrupts */
+
+ lpc17_putreg(0, LPC17_USBDEV_EPINTEN);
+
+ /* Frame is Hp interrupt */
+
+ lpc17_putreg(1, LPC17_USBDEV_INTPRI);
+
+ /* Clear all pending interrupts */
+
+ lpc17_putreg(0xffffffff, LPC17_USBDEV_EPINTCLR);
+ lpc17_putreg(0xffffffff, LPC17_USBDEV_INTCLR);
+
+ /* Periperhal address is needed */
+
+ priv->paddrset = 0;
+
+ /* Endpoints not yet configured */
+
+ lpc17_usbcmd(CMD_USBDEV_CONFIG, 0);
+
+ /* EndPoint 0 initialization */
+
+ lpc17_ep0configure(priv);
+
+#ifdef CONFIG_LPC17_USBDEV_DMA
+ /* Enable End_of_Transfer_Interrupt and System_Error_Interrupt USB DMA
+ * interrupts
+ */
+
+ lpc17_dmareset(CONFIG_LPC17_USBDEV_DMAINT_MASK);
+
+#endif
+
+ /* Enable Device interrupts */
+
+ lpc17_putreg(USB_SLOW_INT|USB_DEVSTATUS_INT|USB_FAST_INT|USB_FRAME_INT|USB_ERROR_INT,
+ LPC17_USBDEV_INTEN);
+}
+
+/*******************************************************************************
+ * Name: lpc17_dispatchrequest
+ *
+ * Description:
+ * Provide unhandled setup actions to the class driver. This is logically part
+ * of the USB interrupt handler.
+ *
+ *******************************************************************************/
+
+static void lpc17_dispatchrequest(struct lpc17_usbdev_s *priv,
+ const struct usb_ctrlreq_s *ctrl)
+{
+ int ret;
+
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_DISPATCH), 0);
+ if (priv && priv->driver)
+ {
+ /* Forward to the control request to the class driver implementation */
+
+ ret = CLASS_SETUP(priv->driver, &priv->usbdev, ctrl);
+ if (ret < 0)
+ {
+ /* Stall on failure */
+
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_DISPATCHSTALL), 0);
+ priv->stalled = 1;
+ }
+ }
+}
+
+/*******************************************************************************
+ * Name: lpc17_ep0setup
+ *
+ * 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 lpc17_ep0setup(struct lpc17_usbdev_s *priv)
+{
+ struct lpc17_ep_s *ep0 = &priv->eplist[LPC17_EP0_OUT];
+ struct lpc17_ep_s *privep;
+ struct lpc17_req_s *privreq = lpc17_rqpeek(ep0);
+ struct usb_ctrlreq_s ctrl;
+ uint16_t value;
+ uint16_t index;
+ uint16_t len;
+ uint8_t response[2];
+ int ret;
+
+ /* Starting a control request? */
+
+ if (priv->usbdev.speed == USB_SPEED_UNKNOWN)
+ {
+ priv->usbdev.speed = USB_SPEED_FULL;
+ lpc17_usbcmd(CMD_USBDEV_CONFIG, 1);
+ }
+
+ /* Terminate any pending requests */
+
+ while (!lpc17_rqempty(ep0))
+ {
+ int16_t result = OK;
+ if (privreq->req.xfrd != privreq->req.len)
+ {
+ result = -EPROTO;
+ }
+
+ usbtrace(TRACE_COMPLETE(ep0->epphy), privreq->req.xfrd);
+ lpc17_reqcomplete(ep0, result);
+ }
+
+ /* Assume NOT stalled */
+
+ ep0->stalled = 0;
+ priv->stalled = 0;
+
+ /* Read EP0 data */
+
+ ret = lpc17_epread(LPC17_EP0_OUT, (uint8_t*)&ctrl, USB_SIZEOF_CTRLREQ);
+ if (ret <= 0)
+ {
+ return;
+ }
+
+ /* And extract the little-endian 16-bit values to host order */
+
+ value = GETUINT16(ctrl.value);
+ index = GETUINT16(ctrl.index);
+ len = GETUINT16(ctrl.len);
+
+ ullvdbg("type=%02x req=%02x value=%04x index=%04x len=%04x\n",
+ ctrl.type, ctrl.req, value, index, len);
+
+ /* Dispatch any non-standard requests */
+
+ if ((ctrl.type & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD)
+ {
+ lpc17_dispatchrequest(priv, &ctrl);
+ return;
+ }
+
+ /* Handle standard request. Pick off the things of interest to the
+ * USB device controller driver; pass what is left to the class driver
+ */
+
+ switch (ctrl.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(LPC17_TRACEINTID_GETSTATUS), 0);
+ if (!priv->paddrset || len != 2 ||
+ (ctrl.type & USB_REQ_DIR_IN) == 0 || value != 0)
+ {
+ priv->stalled = 1;
+ }
+ else
+ {
+ switch (ctrl.type & USB_REQ_RECIPIENT_MASK)
+ {
+ case USB_REQ_RECIPIENT_ENDPOINT:
+ {
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_EPGETSTATUS), 0);
+ privep = lpc17_epfindbyaddr(priv, index);
+ if (!privep)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_BADEPGETSTATUS), 0);
+ priv->stalled = 1;
+ }
+ else
+ {
+ if ((lpc17_usbcmd(CMD_USBDEV_EPSELECT|privep->epphy, 0) & CMD_EPSELECT_ST) != 0)
+ {
+ response[0] = 1; /* Stalled */
+ }
+ else
+ {
+ response[0] = 0; /* Not stalled */
+ }
+ response[1] = 0;
+ lpc17_epwrite(LPC17_EP0_IN, response, 2);
+ priv->ep0state = LPC17_EP0SHORTWRITE;
+ }
+ }
+ break;
+
+ case USB_REQ_RECIPIENT_DEVICE:
+ {
+ if (index == 0)
+ {
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_DEVGETSTATUS), 0);
+
+ /* Features: Remote Wakeup=YES; selfpowered=? */
+
+ response[0] = (priv->selfpowered << USB_FEATURE_SELFPOWERED) |
+ (1 << USB_FEATURE_REMOTEWAKEUP);
+ response[1] = 0;
+ lpc17_epwrite(LPC17_EP0_IN, response, 2);
+ priv->ep0state = LPC17_EP0SHORTWRITE;
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_BADDEVGETSTATUS), 0);
+ priv->stalled = 1;
+ }
+ }
+ break;
+
+ case USB_REQ_RECIPIENT_INTERFACE:
+ {
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_IFGETSTATUS), 0);
+ response[0] = 0;
+ response[1] = 0;
+ lpc17_epwrite(LPC17_EP0_IN, response, 2);
+ priv->ep0state = LPC17_EP0SHORTWRITE;
+ }
+ break;
+
+ default:
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_BADGETSTATUS), 0);
+ priv->stalled = 1;
+ }
+ 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(LPC17_TRACEINTID_CLEARFEATURE), 0);
+ if ((ctrl.type & USB_REQ_RECIPIENT_MASK) != USB_REQ_RECIPIENT_ENDPOINT)
+ {
+ lpc17_dispatchrequest(priv, &ctrl);
+ }
+ else if (priv->paddrset != 0 && value == USB_FEATURE_ENDPOINTHALT && len == 0 &&
+ (privep = lpc17_epfindbyaddr(priv, index)) != NULL)
+ {
+ privep->halted = 0;
+ ret = lpc17_epstall(&privep->ep, true);
+ lpc17_epwrite(LPC17_EP0_IN, NULL, 0);
+ priv->ep0state = LPC17_EP0STATUSIN;
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_BADCLEARFEATURE), 0);
+ priv->stalled = 1;
+ }
+ }
+ 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(LPC17_TRACEINTID_SETFEATURE), 0);
+ if (((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE) &&
+ value == USB_FEATURE_TESTMODE)
+ {
+ ullvdbg("test mode: %d\n", index);
+ }
+ else if ((ctrl.type & USB_REQ_RECIPIENT_MASK) != USB_REQ_RECIPIENT_ENDPOINT)
+ {
+ lpc17_dispatchrequest(priv, &ctrl);
+ }
+ else if (priv->paddrset != 0 && value == USB_FEATURE_ENDPOINTHALT && len == 0 &&
+ (privep = lpc17_epfindbyaddr(priv, index)) != NULL)
+ {
+ privep->halted = 1;
+ lpc17_epwrite(LPC17_EP0_IN, NULL, 0);
+ priv->ep0state = LPC17_EP0STATUSIN;
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_BADSETFEATURE), 0);
+ priv->stalled = 1;
+ }
+ }
+ break;
+
+ case USB_REQ_SETADDRESS:
+ {
+ /* type: host-to-device; recipient = device
+ * value: device address
+ * index: 0
+ * len: 0; data = none
+ */
+
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_EP0SETUPSETADDRESS), value);
+ if ((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE &&
+ index == 0 && len == 0 && value < 128)
+ {
+ /* Save the address. We cannot actually change to the next address until
+ * the completion of the status phase.
+ */
+
+ priv->paddr = ctrl.value[0];
+
+ /* Note that if we send the SETADDRESS command twice, that will force the
+ * address change. Otherwise, the hardware will automatically set the
+ * address at the end of the status phase.
+ */
+
+ lpc17_usbcmd(CMD_USBDEV_SETADDRESS, CMD_USBDEV_SETADDRESS_DEVEN | priv->paddr);
+
+ /* Send a NULL packet. The status phase completes when the null packet has
+ * been sent successfully.
+ */
+
+ lpc17_epwrite(LPC17_EP0_IN, NULL, 0);
+ priv->ep0state = LPC17_EP0SETADDRESS;
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_BADSETADDRESS), 0);
+ priv->stalled = 1;
+ }
+ }
+ 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(LPC17_TRACEINTID_GETSETDESC), 0);
+ if ((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE)
+ {
+ lpc17_dispatchrequest(priv, &ctrl);
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_BADGETSETDESC), 0);
+ priv->stalled = 1;
+ }
+ }
+ break;
+
+ case USB_REQ_GETCONFIGURATION:
+ /* type: device-to-host; recipient = device
+ * value: 0;
+ * index: 0;
+ * len: 1; data = configuration value
+ */
+ {
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_GETCONFIG), 0);
+ if (priv->paddrset && (ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE &&
+ value == 0 && index == 0 && len == 1)
+ {
+ lpc17_dispatchrequest(priv, &ctrl);
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_BADGETCONFIG), 0);
+ priv->stalled = 1;
+ }
+ }
+ break;
+
+ case USB_REQ_SETCONFIGURATION:
+ /* type: host-to-device; recipient = device
+ * value: configuration value
+ * index: 0;
+ * len: 0; data = none
+ */
+ {
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_SETCONFIG), 0);
+ if ((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE &&
+ index == 0 && len == 0)
+ {
+ lpc17_dispatchrequest(priv, &ctrl);
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_BADSETCONFIG), 0);
+ priv->stalled = 1;
+ }
+ }
+ 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(LPC17_TRACEINTID_GETSETIF), 0);
+ lpc17_dispatchrequest(priv, &ctrl);
+ }
+ break;
+
+ case USB_REQ_SYNCHFRAME:
+ /* type: device-to-host; recipient = endpoint
+ * value: 0
+ * index: endpoint;
+ * len: 2; data = frame number
+ */
+ {
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_SYNCHFRAME), 0);
+ }
+ break;
+
+ default:
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_INVALIDCTRLREQ), 0);
+ priv->stalled = 1;
+ }
+ break;
+ }
+
+ if (priv->stalled)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_EP0SETUPSTALLED), priv->ep0state);
+ lpc17_epstall(&ep0->ep, false);
+ lpc17_epstall(&ep0->ep, false);
+ }
+}
+
+/*******************************************************************************
+ * Name: lpc17_ep0dataoutinterrupt
+ *
+ * Description:
+ * USB Ctrl EP Data OUT Event. This is logically part of the USB interrupt
+ * handler. Each non-isochronous OUT endpoint gives an interrupt when they
+ * receive a packet without error.
+ *
+ *******************************************************************************/
+
+static inline void lpc17_ep0dataoutinterrupt(struct lpc17_usbdev_s *priv)
+{
+ struct lpc17_ep_s *ep0;
+ uint32_t pktlen;
+
+ /* Copy new setup packet into setup buffer */
+
+ switch (priv->ep0state)
+ {
+ case LPC17_EP0SHORTWRITE:
+ {
+ priv->ep0state = LPC17_EP0STATUSOUT;
+ pktlen = lpc17_epread(LPC17_EP0_OUT, NULL, CONFIG_USBDEV_EP0_MAXSIZE);
+ if (LPC17_READOVERRUN(pktlen))
+ {
+ lpc17_ep0setup(priv);
+ }
+ }
+ break;
+
+ case LPC17_EP0SHORTWRSENT:
+ {
+ priv->ep0state = LPC17_EP0REQUEST;
+ pktlen = lpc17_epread(LPC17_EP0_OUT, NULL, CONFIG_USBDEV_EP0_MAXSIZE);
+ if (LPC17_READOVERRUN(pktlen))
+ {
+ lpc17_ep0setup(priv);
+ }
+ }
+ break;
+
+ case LPC17_EP0REQUEST:
+ {
+ /* Process the next request action (if any) */
+
+ lpc17_rdrequest(&priv->eplist[LPC17_EP0_OUT]);
+ }
+ break;
+
+ default:
+ priv->stalled = 1;
+ break;
+ }
+
+ if (priv->stalled)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_EP0OUTSTALLED), priv->ep0state);
+ ep0 = &priv->eplist[LPC17_EP0_OUT];
+ lpc17_epstall(&ep0->ep, false);
+ lpc17_epstall(&ep0->ep, false);
+ }
+ return;
+}
+
+/*******************************************************************************
+ * Name: lpc17_ep0dataininterrupt
+ *
+ * Description:
+ * USB Ctrl EP Data IN Event. This is logically part of the USB interrupt
+ * handler. All non-isochronous IN endpoints give this interrupt when a
+ * packet is successfully transmitted (OR a NAK handshake is sent on the bus
+ * provided that the interrupt on NAK feature is enabled).
+ *
+ *******************************************************************************/
+
+static inline void lpc17_ep0dataininterrupt(struct lpc17_usbdev_s *priv)
+{
+ struct lpc17_ep_s *ep0;
+
+ switch (priv->ep0state)
+ {
+ case LPC17_EP0STATUSOUT:
+ case LPC17_EP0STATUSIN:
+ priv->ep0state = LPC17_EP0REQUEST;
+ break;
+
+ case LPC17_EP0SHORTWRITE:
+ priv->ep0state = LPC17_EP0SHORTWRSENT;
+ break;
+
+ case LPC17_EP0SETADDRESS:
+ {
+ /* If the address was set to a non-zero value, then thiscompletes the
+ * default phase, and begins the address phase (still not fully configured)
+ */
+
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_EP0INSETADDRESS), (uint16_t)priv->paddr);
+ lpc17_usbcmd(CMD_USBDEV_CONFIG, 0);
+ if (priv->paddr)
+ {
+ priv->paddrset = 1;
+ priv->ep0state = LPC17_EP0REQUEST;
+ }
+ }
+ break;
+
+ case LPC17_EP0REQUEST:
+ {
+ /* Process the next request action (if any) */
+
+ ep0 = &priv->eplist[LPC17_EP0_IN];
+ ep0->txbusy = 0;
+ lpc17_wrrequest(ep0);
+ }
+ break;
+
+ default:
+ priv->stalled = 1;
+ break;
+ }
+
+ if (priv->stalled)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_EP0INSTALLED), priv->ep0state);
+ ep0 = &priv->eplist[LPC17_EP0_IN];
+ lpc17_epstall(&ep0->ep, false);
+ lpc17_epstall(&ep0->ep, false);
+ }
+}
+
+/*******************************************************************************
+ * Name: lpc17_usbinterrupt
+ *
+ * Description:
+ * USB interrupt handler
+ *
+ *******************************************************************************/
+
+static int lpc17_usbinterrupt(int irq, FAR void *context)
+{
+ struct lpc17_usbdev_s *priv = &g_usbdev;
+ struct lpc17_ep_s *privep ;
+
+ uint32_t devintstatus; /* Sampled state of the device interrupt status register */
+ uint32_t epintstatus; /* Sampled state of the endpoint interrupt status register */
+#ifdef CONFIG_LPC17_USBDEV_DMA
+ uint32_t dmaintstatus; /* Sampled state of dma interrupt status register */
+#endif
+ uint32_t softprio; /* Current priority interrupt bitset */
+ uint32_t pending; /* Pending subset of priority interrupt bitset */
+ uint8_t epphy; /* Physical endpoint number being processed */
+ int i;
+
+ usbtrace(TRACE_INTENTRY(LPC17_TRACEINTID_USB), 0);
+
+ /* Read the device interrupt status register */
+
+ devintstatus = lpc17_getreg(LPC17_USBDEV_INTST);
+
+#ifdef CONFIG_LPC17_USBDEV_DMA
+ /* Check for low priority and high priority (non-DMA) interrupts */
+
+ if ((lpc17_getreg(LPC17_USBDEV_INTST) & (USBDEV_INTST_REQLP|USBDEV_INTST_REQHP)) != 0)
+ {
+#endif
+#ifdef CONFIG_LPC17_USBDEV_EPFAST_INTERRUPT
+ /* Fast EP interrupt */
+
+ if ((devintstatus & USBDEV_INT_EPFAST) != 0)
+ {
+ /* Clear Fast EP interrupt */
+
+ lpc17_putreg(USBDEV_INT_EPFAST, LPC17_USBDEV_INTCLR);
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_EPFAST), 0);
+
+ /* Do what? */
+ }
+
+#endif
+
+#if CONFIG_DEBUG
+ /* USB engine error interrupt */
+
+ if ((devintstatus & USBDEV_INT_EPRINT))
+ {
+ uint8_t errcode;
+
+ /* Clear the error interrupt */
+
+ lpc17_putreg(USBDEV_INT_EPRINT, LPC17_USBDEV_INTCLR);
+
+ /* And show what error occurred */
+
+ errcode = (uint8_t)lpc17_usbcmd(CMD_USBDEV_READERRORSTATUS, 0) & 0x0f;
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_EPRINT), (uint16_t)errcode);
+ }
+#endif
+
+#ifdef CONFIG_LPC17_USBDEV_FRAME_INTERRUPT
+ /* Frame interrupt */
+
+ if ((devintstatus & USBDEV_INT_FRAME) != 0)
+ {
+ /* Clear the frame interrupt */
+
+ lpc17_putreg(USBDEV_INT_FRAME, LPC17_USBDEV_INTCLR);
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_FRAME), 0);
+
+ /* Then read the start of frame value */
+
+ priv->sof = (uint16_t)lpc17_usbcmd(CMD_USBDEV_READFRAMENO, 0);
+ }
+#endif
+
+ /* Device Status interrupt */
+
+ if ((devintstatus & USBDEV_INT_DEVSTAT) != 0)
+ {
+ /* Clear Device status interrupt */
+
+ lpc17_putreg(USBDEV_INT_DEVSTAT, LPC17_USBDEV_INTCLR);
+
+ /* Get device status */
+
+ g_usbdev.devstatus = (uint8_t)lpc17_usbcmd(CMD_USBDEV_GETSTATUS, 0);
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_DEVSTAT), (uint16_t)g_usbdev.devstatus);
+
+ /* Device connection status */
+
+ if (DEVSTATUS_CONNCHG(g_usbdev.devstatus))
+ {
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_CONNECTCHG),
+ (uint16_t)g_usbdev.devstatus);
+ if (DEVSTATUS_CONNECT(g_usbdev.devstatus))
+ {
+ /* Host is connected */
+
+ if (!priv->attached)
+ {
+ /* We have a transition from unattached to attached */
+
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_CONNECTED),
+ (uint16_t)g_usbdev.devstatus);
+ priv->usbdev.speed = USB_SPEED_UNKNOWN;
+ lpc17_usbcmd(CMD_USBDEV_CONFIG, 0);
+ priv->attached = 1;
+ }
+ }
+
+ /* Otherwise the host is not attached */
+
+ else if (priv->attached)
+ {
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_DISCONNECTED),
+ (uint16_t)g_usbdev.devstatus);
+ priv->usbdev.speed = USB_SPEED_UNKNOWN;
+ lpc17_usbcmd(CMD_USBDEV_CONFIG, 0);
+ priv->attached = 0;
+ priv->paddrset = 0;
+ }
+ }
+
+ /* Device suspend status */
+
+ if (DEVSTATUS_SUSPCHG(g_usbdev.devstatus))
+ {
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_SUSPENDCHG),
+ (uint16_t)g_usbdev.devstatus);
+ }
+
+ /* Device reset */
+
+ if (DEVSTATUS_RESET(g_usbdev.devstatus))
+ {
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_DEVRESET),
+ (uint16_t)g_usbdev.devstatus);
+ lpc17_usbreset(priv);
+ }
+ }
+
+ /* Slow EP interrupt */
+
+ if ((devintstatus & USBDEV_INT_EPSLOW) != 0)
+ {
+ /* Clear Slow EP interrupt */
+
+ lpc17_putreg(USBDEV_INT_EPSLOW, LPC17_USBDEV_INTCLR);
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_EPSLOW), 0);
+
+ do
+ {
+ /* Read the endpoint interrupt status register */
+
+ epintstatus = lpc17_getreg(LPC17_USBDEV_EPINTST);
+
+ /* Loop twice: Process software high priority interrupts
+ * on the first pass and low priority interrupts on the
+ * second.
+ */
+
+ softprio = priv->softprio;
+ for (i = 0; i < 2; i++, softprio = ~softprio)
+ {
+ /* On the first time through the loop, pending will be
+ * the bitset of high priority pending interrupts; on the
+ * second time throught it will be the bitset of low
+ * priority interrupts.
+ */
+
+ pending = epintstatus & softprio;
+
+ /* EP0 OUT interrupt indicated by bit0 == 1 */
+
+ if ((pending & 1) != 0)
+ {
+ /* Clear the endpoint interrupt */
+
+ uint32_t result = lpc17_epclrinterrupt(LPC17_CTRLEP_OUT);
+ if (result & CMD_EPSELECT_STP)
+ {
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_EP0SETUP), (uint16_t)result);
+ lpc17_ep0setup(priv);
+ }
+ else
+ {
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_EP0OUT), priv->ep0state);
+ lpc17_ep0dataoutinterrupt(priv);
+ }
+ break;
+ }
+
+ /* EP0 IN interrupt indicated by bit1 == 1 */
+
+ if ((pending & 2) != 0)
+ {
+ /* Clear the endpoint interrupt */
+
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_EP0IN), priv->ep0state);
+ (void)lpc17_epclrinterrupt(LPC17_CTRLEP_IN);
+ lpc17_ep0dataininterrupt(priv);
+ }
+ pending >>= 2;
+
+ /* All other endpoints EP 1-31 */
+
+ for (epphy = 2; pending; epphy++, pending >>= 1)
+ {
+ /* Is the endpoint interrupt pending? */
+
+ if ((pending & 1) != 0)
+ {
+ /* Yes.. clear the endpoint interrupt */
+
+ (void)lpc17_epclrinterrupt(epphy);
+
+ /* Get the endpoint sructure corresponding to the physical
+ * endpoint number.
+ */
+
+ privep = &priv->eplist[epphy];
+
+ /* Check for complete on IN or OUT endpoint. Odd physical
+ * endpoint addresses are IN endpoints.
+ */
+
+ if ((epphy & 1) != 0)
+ {
+ /* IN: device-to-host */
+
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_EPOUT), (uint16_t)epphy);
+ if (priv->usbdev.speed == USB_SPEED_UNKNOWN)
+ {
+ priv->usbdev.speed = USB_SPEED_FULL;
+ lpc17_usbcmd(CMD_USBDEV_CONFIG, 1);
+ }
+
+ /* Write host data from the current write request (if any) */
+
+ privep->txbusy = 0;
+ lpc17_wrrequest(privep);
+ }
+ else
+ {
+ /* OUT: host-to-device */
+
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_EPIN), (uint16_t)epphy);
+
+ /* Read host data into the current read request */
+
+ if (!lpc17_rqempty(privep))
+ {
+ lpc17_rdrequest(privep);
+ }
+ else
+ {
+ ullvdbg("Pending data on OUT endpoint\n");
+ priv->rxpending = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ while (epintstatus);
+ }
+#ifdef CONFIG_LPC17_USBDEV_DMA
+ }
+
+ /* Check for DMA interrupts */
+
+ if ((lpc17_getreg(LPC17_USBDEV_INTST) & USBDEV_INTST_REQDMA) != 0)
+ {
+ /* First Software High priority and then low priority */
+
+ uint32_t tmp;
+
+ /* Collect the DMA interrupt sources */
+
+ dmaintstatus = 0;
+ tmp = lpc17_getreg(LPC17_USBDEV_EOTINTST);
+ if (lpc17_getreg(LPC17_USBDEV_DMAINTEN) & 1)
+ {
+ dmaintstatus |= tmp;
+ }
+ lpc17_putreg(tmp, LPC17_USBDEV_EOTINTCLR);
+
+ tmp = lpc17_getreg(LPC17_USBDEV_NDDRINTST);
+ if (lpc17_getreg(LPC17_USBDEV_DMAINTEN) & 2)
+ {
+ dmaintstatus |= tmp;
+ }
+ lpc17_putreg(tmp, LPC17_USBDEV_NDDRINTCLR);
+
+ tmp = lpc17_getreg(LPC17_USBDEV_SYSERRINTST);
+ if (lpc17_getreg(LPC17_USBDEV_DMAINTEN) & 4)
+ {
+ dmaintstatus |= tmp;
+ }
+ lpc17_putreg(tmp, LPC17_USBDEV_SYSERRINTCLR);
+
+ /* Loop twice: Process software high priority interrupts on the
+ * first pass and low priority interrupts on the second.
+ */
+
+ softprio = priv->softprio;
+ for (i = 0; i < 2; i++, softprio = ~softprio)
+ {
+ /* On the first time through the loop, pending will be
+ * the bitset of high priority pending interrupts; on the
+ * second time throught it will be the bitset of low
+ * priority interrupts. Note that EP0 IN and OUT are
+ * omitted.
+ */
+
+ pending = (dmaintstatus & softprio) >> 2;
+ for (epphy = 2; pending; epphy++, pending >>= 1)
+ {
+ if ((pending & 1) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(LPC17_TRACEINTID_EPDMA), (uint16_t)epphy);
+#warning DO WHAT?
+ }
+ }
+ }
+ }
+#endif
+ usbtrace(TRACE_INTEXIT(LPC17_TRACEINTID_USB), 0);
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: lpc17_dmasetup
+ *
+ * Description:
+ * Setup for DMA Transfer
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_LPC17_USBDEV_DMA
+static int lpc17_dmasetup(struct lpc17_usbdev_s *priv, uint8_t epphy,
+ uint32_t epmaxsize, uint32_t nbytes, uint32_t *isocpacket,
+ bool isochronous);
+{
+ struct lpc17_dmadesc_s *dmadesc = priv;
+ uint32_t reg;
+
+#ifdef CONFIG_DEBUG
+ if (!priv || epphy < 2)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_INVALIDPARMS), 0);
+ return -EINVAL;
+ }
+#endif
+
+ /* Check if a DMA descriptor has been assigned. If not, than that indicates
+ * that we will have to do parallel I/O
+ */
+
+ if (!dmadesc)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_NODMADESC), 0);
+ return -EBUSY;
+ }
+
+ /* Verify that the DMA descriptor is available */
+
+ if ((dmadesc->status & USB_DMADESC_STATUS_MASK) == USB_DMADESC_BEINGSERVICED)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_DMABUSY), 0);
+ return -EBUSY; /* Shouldn't happen */
+ }
+
+ /* Init DMA Descriptor */
+
+ dmadesc->nexdesc = 0;
+ dmadesc->config = USB_DMADESC_MODENORMAL |
+ ((epmaxsize << USB_DMADESC_PKTSIZE_SHIFT) & USB_DMADESC_PKTSIZE_MASK) |
+ ((nbytes << USB_DMADESC_BUFLEN_SHIFT) & USB_DMADESC_BUFLEN_MASK);
+
+#ifdef CONFIG_USBDEV_ISOCHRONOUS
+ if (isochronous)
+ {
+ dmadesc->config |= USB_DMADESC_ISCOEP;
+ }
+#endif
+
+ dmadesc->start = (uint32_t)&dmadesc->buffer;
+ dmadesc->status = 0;
+
+#ifdef CONFIG_USBDEV_ISOCHRONOUS
+ dmadesc->size = (uint32_t)packet;
+#endif
+
+ /* Enable DMA tranfer for this endpoint */
+
+ putreq32(1 << epphy, LPC17_USBDEV_EPDMAEN);
+
+ /* Check state of IN/OUT Ep buffer */
+
+ reg = lpc17_usbcmd(CMD_USBDEV_EPSELECT | epphy, 0);
+
+ if ((LPC17_EPPHYIN(epphy) && (reg & 0x60) == 0) ||
+ (LPC17_EPPHYOUT(epphy) && (reg & 0x60) == 0x60))
+ {
+ /* DMA should be "being serviced" */
+
+ if ((dmadesc->status & USB_DMADESC_STATUS_MASK) != USB_DMADESC_BEINGSERVICED))
+ {
+ /* Re-trigger the DMA Transfer */
+
+ putreq32(1 << epphy, LPC17_USBDEV_DMARCLR);
+ putreq32(1 << epphy, LPC17_USBDEV_EPDMAEN);
+ }
+ }
+ return OK;
+}
+#endif /* CONFIG_LPC17_USBDEV_DMA */
+
+/*******************************************************************************
+ * Name: lpc17_dmarestart
+ *
+ * Description:
+ * Restart DMA Transfer
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_LPC17_USBDEV_DMA
+static void lpc17_dmarestart(uint8_t epphy, uint32_t descndx)
+{
+ uint32_t reg;
+
+ /* Clear DMA descriptor status */
+
+ USB_DmaDesc[descndx].status = 0;
+
+ /* Enable DMA transfer on the endpoint */
+
+ lpc17_putreg(1 << epph, LPC17_USBDEV_EPDMAEN);
+
+ /* Check the state of IN/OUT EP buffer */
+
+ uint32_t reg = lpc17_usbcmd(CMD_USBDEV_EPSELECT | epphy, 0);
+ if ((LPC17_EPPHYIN(epphy) && (reg & 0x60) == 0) ||
+ (LPC17_EPPHYIN(epphy) && (reg & 0x60) == 0x60))
+ {
+ /* Re-trigger the DMA Transfer */
+
+ putreq32(1 << epphy, LPC17_USBDEV_DMARCLR);
+ putreq32(1 << epphy, LPC17_USBDEV_EPDMAEN);
+ }
+}
+#endif /* CONFIG_LPC17_USBDEV_DMA */
+
+/*******************************************************************************
+ * Name: lpc17_dmadisable
+ *
+ * Description:
+ * Disable DMA transfer for the EP
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_LPC17_USBDEV_DMA
+static void lpc17_dmadisable(uint8_t epphy)
+{
+ EPDMADIS = 1 << epphy;
+}
+#endif /* CONFIG_LPC17_USBDEV_DMA */
+
+/*******************************************************************************
+ * Endpoint operations
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Name: lpc17_epconfigure
+ *
+ * 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 lpc17_epconfigure(FAR struct usbdev_ep_s *ep,
+ FAR const struct usb_epdesc_s *desc,
+ bool last)
+{
+ FAR struct lpc17_ep_s *privep = (FAR struct lpc17_ep_s *)ep;
+ uint32_t inten;
+
+ usbtrace(TRACE_EPCONFIGURE, privep->epphy);
+ DEBUGASSERT(desc->addr == ep->eplog);
+
+ /* Realize the endpoint */
+
+ lpc17_eprealize(privep, 1, GETUINT16(desc->mxpacketsize));
+
+ /* Enable and reset EP -- twice */
+
+ lpc17_usbcmd(CMD_USBDEV_EPSETSTATUS | privep->epphy, 0);
+ lpc17_usbcmd(CMD_USBDEV_EPSETSTATUS | privep->epphy, 0);
+
+#ifdef CONFIG_LPC17_USBDEV_DMA
+ /* Enable DMA Ep interrupt (WO) */
+
+ lpc17_putreg(1 << privep->epphy, LPC17_USBDEV_EPDMAEN);
+#else
+ /* Enable Ep interrupt (R/W) */
+
+ inten = lpc17_getreg(LPC17_USBDEV_EPINTEN);
+ inten |= (1 << privep->epphy);
+ lpc17_putreg(inten, LPC17_USBDEV_EPINTEN);
+#endif
+
+ /* If all of the endpoints have been configured, then tell the USB controller
+ * to enabled normal activity on all realized endpoints.
+ */
+
+ if (last)
+ {
+ lpc17_usbcmd(CMD_USBDEV_CONFIG, 1);
+ }
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: lpc17_epdisable
+ *
+ * Description:
+ * The endpoint will no longer be used
+ *
+ *******************************************************************************/
+
+static int lpc17_epdisable(FAR struct usbdev_ep_s *ep)
+{
+ FAR struct lpc17_ep_s *privep = (FAR struct lpc17_ep_s *)ep;
+ irqstate_t flags;
+ uint32_t mask = (1 << privep->epphy);
+ uint32_t reg;
+
+#ifdef CONFIG_DEBUG
+ if (!ep)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_INVALIDPARMS), 0);
+ return -EINVAL;
+ }
+#endif
+ usbtrace(TRACE_EPDISABLE, privep->epphy);
+
+ /* Cancel any ongoing activity */
+
+ flags = irqsave();
+ lpc17_cancelrequests(privep);
+
+ /* Disable endpoint and interrupt */
+
+ reg = lpc17_getreg(LPC17_USBDEV_REEP);
+ reg &= ~mask;
+ lpc17_putreg(reg, LPC17_USBDEV_REEP);
+
+ lpc17_putreg(mask, LPC17_USBDEV_EPDMADIS);
+
+ reg = lpc17_getreg(LPC17_USBDEV_EPINTEN);
+ reg &= ~mask;
+ lpc17_putreg(reg, LPC17_USBDEV_EPINTEN);
+
+ irqrestore(flags);
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: lpc17_epallocreq
+ *
+ * Description:
+ * Allocate an I/O request
+ *
+ *******************************************************************************/
+
+static FAR struct usbdev_req_s *lpc17_epallocreq(FAR struct usbdev_ep_s *ep)
+{
+ FAR struct lpc17_req_s *privreq;
+
+#ifdef CONFIG_DEBUG
+ if (!ep)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_INVALIDPARMS), 0);
+ return NULL;
+ }
+#endif
+ usbtrace(TRACE_EPALLOCREQ, ((FAR struct lpc17_ep_s *)ep)->epphy);
+
+ privreq = (FAR struct lpc17_req_s *)malloc(sizeof(struct lpc17_req_s));
+ if (!privreq)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_ALLOCFAIL), 0);
+ return NULL;
+ }
+
+ memset(privreq, 0, sizeof(struct lpc17_req_s));
+ return &privreq->req;
+}
+
+/*******************************************************************************
+ * Name: lpc17_epfreereq
+ *
+ * Description:
+ * Free an I/O request
+ *
+ *******************************************************************************/
+
+static void lpc17_epfreereq(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req)
+{
+ FAR struct lpc17_req_s *privreq = (FAR struct lpc17_req_s *)req;
+
+#ifdef CONFIG_DEBUG
+ if (!ep || !req)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_INVALIDPARMS), 0);
+ return;
+ }
+#endif
+ usbtrace(TRACE_EPFREEREQ, ((FAR struct lpc17_ep_s *)ep)->epphy);
+
+ free(privreq);
+}
+
+/*******************************************************************************
+ * Name: lpc17_epallocbuffer
+ *
+ * Description:
+ * Allocate an I/O buffer
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_LPC17_USBDEV_DMA
+static FAR void *lpc17_epallocbuffer(FAR struct usbdev_ep_s *ep, uint16_t nbytes)
+{
+ FAR struct lpc17_ep_s *privep = (FAR struct lpc17_ep_s *)ep;
+ int descndx;
+
+ usbtrace(TRACE_EPALLOCBUFFER, privep->epphy);
+
+ /* Find a free DMA description */
+
+#error "LOGIC INCOMPLETE"
+
+ /* Set UDCA to the allocated DMA descriptor for this endpoint */
+
+ USB_UDCA[privep->epphy] = &USB_DDESC[descndx];
+ return &USB_DDESC[descndx]
+}
+#endif
+
+/*******************************************************************************
+ * Name: lpc17_epfreebuffer
+ *
+ * Description:
+ * Free an I/O buffer
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_LPC17_USBDEV_DMA
+static void lpc17_epfreebuffer(FAR struct usbdev_ep_s *ep, FAR void *buf)
+{
+ FAR struct lpc17_ep_s *privep = (FAR struct lpc17_ep_s *)ep;
+
+ usbtrace(TRACE_EPFREEBUFFER, privep->epphy);
+
+ /* Indicate that there is no DMA descriptor associated with this endpoint */
+
+ USB_UDCA[privep->epphy] = NULL;
+
+ /* Mark the DMA descriptor as free for re-allocation */
+
+#error "LOGIC INCOMPLETE"
+}
+#endif
+
+/*******************************************************************************
+ * Name: lpc17_epsubmit
+ *
+ * Description:
+ * Submit an I/O request to the endpoint
+ *
+ *******************************************************************************/
+
+static int lpc17_epsubmit(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req)
+{
+ FAR struct lpc17_req_s *privreq = (FAR struct lpc17_req_s *)req;
+ FAR struct lpc17_ep_s *privep = (FAR struct lpc17_ep_s *)ep;
+ FAR struct lpc17_usbdev_s *priv;
+ irqstate_t flags;
+ int ret = OK;
+
+#ifdef CONFIG_DEBUG
+ if (!req || !req->callback || !req->buf || !ep)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_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;
+
+ if (!priv->driver || priv->usbdev.speed == USB_SPEED_UNKNOWN)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_NOTCONFIGURED), priv->usbdev.speed);
+ return -ESHUTDOWN;
+ }
+
+ /* Handle the request from the class driver */
+
+ req->result = -EINPROGRESS;
+ req->xfrd = 0;
+ flags = irqsave();
+
+ /* If we are stalled, then drop all requests on the floor */
+
+ if (privep->stalled)
+ {
+ lpc17_abortrequest(privep, privreq, -EBUSY);
+ ret = -EBUSY;
+ }
+
+ /* Handle IN (device-to-host) requests */
+
+ else if (LPC17_EPPHYIN(privep->epphy))
+ {
+ /* Add the new request to the request queue for the IN endpoint */
+
+ lpc17_rqenqueue(privep, privreq);
+ usbtrace(TRACE_INREQQUEUED(privep->epphy), privreq->req.len);
+
+ /* If the IN endpoint FIFO is available, then transfer the data now */
+
+ if (privep->txbusy == 0)
+ {
+ ret = lpc17_wrrequest(privep);
+ }
+ }
+
+ /* Handle OUT (host-to-device) requests */
+
+ else
+ {
+ /* Add the new request to the request queue for the OUT endpoint */
+
+ privep->txnullpkt = 0;
+ lpc17_rqenqueue(privep, privreq);
+ usbtrace(TRACE_OUTREQQUEUED(privep->epphy), privreq->req.len);
+
+ /* This there a incoming data pending the availability of a request? */
+
+ if (priv->rxpending)
+ {
+ ret = lpc17_rdrequest(privep);
+ priv->rxpending = 0;
+ }
+ }
+
+ irqrestore(flags);
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: lpc17_epcancel
+ *
+ * Description:
+ * Cancel an I/O request previously sent to an endpoint
+ *
+ *******************************************************************************/
+
+static int lpc17_epcancel(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req)
+{
+ FAR struct lpc17_ep_s *privep = (FAR struct lpc17_ep_s *)ep;
+ FAR struct lpc17_usbdev_s *priv;
+ irqstate_t flags;
+
+#ifdef CONFIG_DEBUG
+ if (!ep || !req)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_INVALIDPARMS), 0);
+ return -EINVAL;
+ }
+#endif
+ usbtrace(TRACE_EPCANCEL, privep->epphy);
+ priv = privep->dev;
+
+ flags = irqsave();
+ lpc17_cancelrequests(privep);
+ irqrestore(flags);
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: lpc17_epstall
+ *
+ * Description:
+ * Stall or resume and endpoint
+ *
+ *******************************************************************************/
+
+static int lpc17_epstall(FAR struct usbdev_ep_s *ep, bool resume)
+{
+ FAR struct lpc17_ep_s *privep = (FAR struct lpc17_ep_s *)ep;
+ irqstate_t flags;
+
+ /* STALL or RESUME the endpoint */
+
+ flags = irqsave();
+ usbtrace(resume ? TRACE_EPRESUME : TRACE_EPSTALL, privep->epphy);
+ lpc17_usbcmd(CMD_USBDEV_EPSETSTATUS | privep->epphy, (resume ? 0 : CMD_SETSTAUS_ST));
+
+ /* If the endpoint of was resumed, then restart any queue write requests */
+
+ if (resume)
+ {
+ (void)lpc17_wrrequest(privep);
+ }
+ irqrestore(flags);
+ return OK;
+}
+
+/*******************************************************************************
+ * Device operations
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Name: lpc17_allocep
+ *
+ * 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 *lpc17_allocep(FAR struct usbdev_s *dev, uint8_t eplog,
+ bool in, uint8_t eptype)
+{
+ FAR struct lpc17_usbdev_s *priv = (FAR struct lpc17_usbdev_s *)dev;
+ uint32_t epset = LPC17_EPALLSET & ~LPC17_EPCTRLSET;
+ irqstate_t flags;
+ int epndx = 0;
+
+ usbtrace(TRACE_DEVALLOCEP, (uint16_t)eplog);
+
+ /* Ignore any direction bits in the logical address */
+
+ eplog = USB_EPNO(eplog);
+
+ /* A logical address of 0 means that any endpoint will do */
+
+ if (eplog > 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 (eplog >= LPC17_NLOGENDPOINTS)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_BADEPNO), (uint16_t)eplog);
+ return NULL;
+ }
+
+ /* Convert the logical address to a physical OUT endpoint address and
+ * remove all of the candidate endpoints from the bitset except for the
+ * the IN/OUT pair for this logical address.
+ */
+
+ epset &= 3 << (eplog << 1);
+ }
+
+ /* Get the subset matching the requested direction */
+
+ if (in)
+ {
+ epset &= LPC17_EPINSET;
+ }
+ else
+ {
+ epset &= LPC17_EPOUTSET;
+ }
+
+ /* Get the subset matching the requested type */
+
+ switch (eptype)
+ {
+ case USB_EP_ATTR_XFER_INT: /* Interrupt endpoint */
+ epset &= LPC17_EPINTRSET;
+ break;
+
+ case USB_EP_ATTR_XFER_BULK: /* Bulk endpoint */
+ epset &= LPC17_EPBULKSET;
+ break;
+
+ case USB_EP_ATTR_XFER_ISOC: /* Isochronous endpoint */
+ epset &= LPC17_EPISOCSET;
+ break;
+
+ case USB_EP_ATTR_XFER_CONTROL: /* Control endpoint -- not a valid choice */
+ default:
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_BADEPTYPE), (uint16_t)eptype);
+ return NULL;
+ }
+
+ /* Is the resulting endpoint supported by the LPC17xx? */
+
+ if (epset)
+ {
+ /* Yes.. now see if any of the request endpoints are available */
+
+ flags = irqsave();
+ epset &= priv->epavail;
+ if (epset)
+ {
+ /* Select the lowest bit in the set of matching, available endpoints */
+
+ for (epndx = 2; epndx < LPC17_NPHYSENDPOINTS; epndx++)
+ {
+ uint32_t bit = 1 << epndx;
+ if ((epset & bit) != 0)
+ {
+ /* Mark the IN/OUT endpoint no longer available */
+
+ priv->epavail &= ~(3 << (bit & ~1));
+ irqrestore(flags);
+
+ /* And return the pointer to the standard endpoint structure */
+
+ return &priv->eplist[epndx].ep;
+ }
+ }
+ /* Shouldn't get here */
+ }
+ irqrestore(flags);
+ }
+
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_NOEP), (uint16_t)eplog);
+ return NULL;
+}
+
+/*******************************************************************************
+ * Name: lpc17_freeep
+ *
+ * Description:
+ * Free the previously allocated endpoint
+ *
+ *******************************************************************************/
+
+static void lpc17_freeep(FAR struct usbdev_s *dev, FAR struct usbdev_ep_s *ep)
+{
+ FAR struct lpc17_usbdev_s *priv = (FAR struct lpc17_usbdev_s *)dev;
+ FAR struct lpc17_ep_s *privep = (FAR struct lpc17_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: lpc17_getframe
+ *
+ * Description:
+ * Returns the current frame number
+ *
+ *******************************************************************************/
+
+static int lpc17_getframe(struct usbdev_s *dev)
+{
+#ifdef CONFIG_LPC17_USBDEV_FRAME_INTERRUPT
+ FAR struct lpc17_usbdev_s *priv = (FAR struct lpc17_usbdev_s *)dev;
+
+ /* Return last valid value of SOF read by the interrupt handler */
+
+ usbtrace(TRACE_DEVGETFRAME, (uint16_t)priv->sof);
+ return priv->sof;
+#else
+ /* Return the last frame number detected by the hardware */
+
+ usbtrace(TRACE_DEVGETFRAME, 0);
+ return (int)lpc17_usbcmd(CMD_USBDEV_READFRAMENO, 0);
+#endif
+}
+
+/*******************************************************************************
+ * Name: lpc17_wakeup
+ *
+ * Description:
+ * Tries to wake up the host connected to this device
+ *
+ *******************************************************************************/
+
+static int lpc17_wakeup(struct usbdev_s *dev)
+{
+ uint8_t arg = CMD_STATUS_SUSPEND;
+ irqstate_t flags;
+
+ usbtrace(TRACE_DEVWAKEUP, (uint16_t)g_usbdev.devstatus);
+
+ flags = irqsave();
+ if (DEVSTATUS_CONNECT(g_usbdev.devstatus))
+ {
+ arg |= CMD_STATUS_CONNECT;
+ }
+
+ lpc17_usbcmd(CMD_USBDEV_SETSTATUS, arg);
+ irqrestore(flags);
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: lpc17_selfpowered
+ *
+ * Description:
+ * Sets/clears the device selfpowered feature
+ *
+ *******************************************************************************/
+
+static int lpc17_selfpowered(struct usbdev_s *dev, bool selfpowered)
+{
+ FAR struct lpc17_usbdev_s *priv = (FAR struct lpc17_usbdev_s *)dev;
+
+ usbtrace(TRACE_DEVSELFPOWERED, (uint16_t)selfpowered);
+
+#ifdef CONFIG_DEBUG
+ if (!dev)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_INVALIDPARMS), 0);
+ return -ENODEV;
+ }
+#endif
+
+ priv->selfpowered = selfpowered;
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: lpc17_pullup
+ *
+ * Description:
+ * Software-controlled connect to/disconnect from USB host
+ *
+ *******************************************************************************/
+
+static int lpc17_pullup(struct usbdev_s *dev, bool enable)
+{
+ usbtrace(TRACE_DEVPULLUP, (uint16_t)enable);
+
+ /* The CMD_STATUS_CONNECT bit in the CMD_USBDEV_SETSTATUS command
+ * controls the LPC17xx SoftConnect_N output pin that is used for SoftConnect.
+ */
+
+ lpc17_usbcmd(CMD_USBDEV_SETSTATUS, (enable ? CMD_STATUS_CONNECT : 0));
+ return OK;
+}
+
+/*******************************************************************************
+ * 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)
+{
+ struct lpc17_usbdev_s *priv = &g_usbdev;
+ uint32_t reg;
+ int i;
+
+ usbtrace(TRACE_DEVINIT, 0);
+
+ /* Disable USB interrupts */
+
+ lpc17_putreg(0, LPC17_USBDEV_INTST);
+
+ /* Initialize the device state structure */
+
+ memset(priv, 0, sizeof(struct lpc17_usbdev_s));
+ priv->usbdev.ops = &g_devops;
+ priv->usbdev.ep0 = &priv->eplist[LPC17_EP0_IN].ep;
+ priv->epavail = LPC17_EPALLSET;
+
+ /* Initialize the endpoint list */
+
+ for (i = 0; i < LPC17_NPHYSENDPOINTS; i++)
+ {
+ uint32_t bit = 1 << 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).
+ */
+ priv->eplist[i].ep.ops = &g_epops;
+ priv->eplist[i].dev = priv;
+
+ /* The index, i, is the physical endpoint address; Map this
+ * to a logical endpoint address usable by the class driver.
+ */
+
+ priv->eplist[i].epphy = i;
+ if (LPC17_EPPHYIN(i))
+ {
+ priv->eplist[i].ep.eplog = LPC17_EPPHYIN2LOG(i);
+ }
+ else
+ {
+ priv->eplist[i].ep.eplog = LPC17_EPPHYOUT2LOG(i);
+ }
+
+ /* The maximum packet size may depend on the type of endpoint */
+
+ if ((LPC17_EPCTRLSET & bit) != 0)
+ {
+ priv->eplist[i].ep.maxpacket = LPC17_EP0MAXPACKET;
+ }
+ else if ((LPC17_EPINTRSET & bit) != 0)
+ {
+ priv->eplist[i].ep.maxpacket = LPC17_INTRMAXPACKET;
+ }
+ else if ((LPC17_EPBULKSET & bit) != 0)
+ {
+ priv->eplist[i].ep.maxpacket = LPC17_BULKMAXPACKET;
+ }
+ else /* if ((LPC17_EPISOCSET & bit) != 0) */
+ {
+ priv->eplist[i].ep.maxpacket = LPC17_ISOCMAXPACKET;
+ }
+ }
+
+ /* Turn on USB power and clocking */
+
+ reg = lpc17_getreg(LPC17_PCON_PCONP);
+ reg |= LPC17_PCONP_PCUSB;
+ lpc17_putreg(reg, LPC17_PCON_PCONP);
+
+ /* Attach USB controller interrupt handler */
+
+ if (irq_attach(LPC17_IRQ_USB, lpc17_usbinterrupt) != 0)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_IRQREGISTRATION),
+ (uint16_t)LPC17_IRQ_USB);
+ goto errout;
+ }
+
+ /* Enable USB inerrupts at the controller -- but do not disable
+ * the ARM interrupt until the device is bound to the class
+ * driver
+ */
+
+ lpc17_putreg(USBDEV_INTST_ENUSBINTS, LPC17_USBDEV_INTST);
+
+ /* Disconnect device */
+
+ lpc17_pullup(&priv->usbdev, false);
+
+ /* Enable EP0 for OUT (host-to-device) */
+
+ lpc17_usbcmd(CMD_USBDEV_SETADDRESS, CMD_USBDEV_SETADDRESS_DEVEN|0);
+ lpc17_usbcmd(CMD_USBDEV_SETADDRESS, CMD_USBDEV_SETADDRESS_DEVEN|0);
+
+ /* Reset/Re-initialize the USB hardware */
+
+ lpc17_usbreset(priv);
+
+ /* Init Device state structure */
+
+ priv->devstatus = lpc17_usbcmd(CMD_USBDEV_GETSTATUS, 0);
+ return;
+
+errout:
+ up_usbuninitialize();
+}
+
+/*******************************************************************************
+ * Name: up_usbuninitialize
+ *******************************************************************************/
+
+void up_usbuninitialize(void)
+{
+ struct lpc17_usbdev_s *priv = &g_usbdev;
+ uint32_t reg;
+ irqstate_t flags;
+
+ usbtrace(TRACE_DEVUNINIT, 0);
+
+ if (priv->driver)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_DRIVERREGISTERED), 0);
+ usbdev_unregister(priv->driver);
+ }
+
+ /* Disconnect device */
+
+ flags = irqsave();
+ lpc17_pullup(&priv->usbdev, false);
+ priv->usbdev.speed = USB_SPEED_UNKNOWN;
+ lpc17_usbcmd(CMD_USBDEV_CONFIG, 0);
+
+ /* Disable and detach IRQs */
+
+ up_disable_irq(LPC17_IRQ_USB);
+ irq_detach(LPC17_IRQ_USB);
+
+ /* Turn off USB power and clocking */
+
+ reg = lpc17_getreg(LPC17_PCON_PCONP);
+ reg &= ~LPC17_PCONP_PCUSB;
+ lpc17_putreg(reg, LPC17_PCON_PCONP);
+ 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)
+{
+ 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(LPC17_TRACEERR_INVALIDPARMS), 0);
+ return -EINVAL;
+ }
+
+ if (g_usbdev.driver)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_DRIVER), 0);
+ return -EBUSY;
+ }
+#endif
+
+ /* First hook up the driver */
+
+ g_usbdev.driver = driver;
+
+ /* Then bind the class driver */
+
+ ret = CLASS_BIND(driver, &g_usbdev.usbdev);
+ if (ret)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_BINDFAILED), (uint16_t)-ret);
+ g_usbdev.driver = NULL;
+ }
+ else
+ {
+ /* Enable USB controller interrupts */
+
+ up_enable_irq(LPC17_IRQ_USB);
+ }
+ 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)
+{
+ usbtrace(TRACE_DEVUNREGISTER, 0);
+
+#ifdef CONFIG_DEBUG
+ if (driver != g_usbdev.driver)
+ {
+ usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_INVALIDPARMS), 0);
+ return -EINVAL;
+ }
+#endif
+
+ /* Unbind the class driver */
+
+ CLASS_UNBIND(driver, &g_usbdev.usbdev);
+
+ /* Disable USB controller interrupts */
+
+ up_disable_irq(LPC17_IRQ_USB);
+
+ /* Unhook the driver */
+
+ g_usbdev.driver = NULL;
+ return OK;
+}
diff --git a/nuttx/configs/nucleus2g/src/up_leds.c b/nuttx/configs/nucleus2g/src/up_leds.c
index 6ac41ff41..a3babda36 100755
--- a/nuttx/configs/nucleus2g/src/up_leds.c
+++ b/nuttx/configs/nucleus2g/src/up_leds.c
@@ -89,6 +89,24 @@
* Private Data
****************************************************************************/
+/* The Nucleus2G has 3 LEDs... two on the Babel CAN board and a "heartbeat" LED."
+ * The LEDs on the Babel CAN board are capabl of OFF/GREEN/RED/AMBER status.
+ * In normal usage, the two LEDs on the Babel CAN board would show CAN status, but if
+ * CONFIG_ARCH_LEDS is defined, these LEDs will be controlled as follows for NuttX
+ * debug functionality (where NC means "No Change").
+ *
+ * LED1 LED2 HEARTBEAT
+ * +------- ------ -----------------------
+ * LED_STARTED | OFF OFF OFF
+ * LED_HEAPALLOCATE | GREEN OFF OFF
+ * LED_IRQSENABLED | OFF GREEN OFF
+ * LED_STACKCREATED | GREEN GREEN OFF
+ * LED_INIRQ | NC NC ON
+ * LED_SIGNAL | NC RED NC
+ * LED_ASSERTION | RED NC NC
+ * LED_PANIC | RED RED NC (1Hz flashing)
+ */
+
static const uint8_t g_led1on[8] =
{
LED_OFF, LED_GREEN, LED_OFF, LED_GREEN,