summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-08-11 17:11:32 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-08-11 17:11:32 -0600
commit861253baf26635b4bc6f8092bbddaaebbabc09dd (patch)
tree969b6f71c51570630ce385df30d5989adb284093
parent90d17e48b58e3fbffbe8b4d6b2476ba8bf23797d (diff)
downloadnuttx-861253baf26635b4bc6f8092bbddaaebbabc09dd.tar.gz
nuttx-861253baf26635b4bc6f8092bbddaaebbabc09dd.tar.bz2
nuttx-861253baf26635b4bc6f8092bbddaaebbabc09dd.zip
Add untested OHCI driver for the SAMA5; structure naming and header files for USB host initialization prototypes
-rw-r--r--nuttx/ChangeLog12
-rw-r--r--nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.h106
-rw-r--r--nuttx/arch/arm/src/sama5/Kconfig49
-rw-r--r--nuttx/arch/arm/src/sama5/Make.defs9
-rw-r--r--nuttx/arch/arm/src/sama5/chip/sam_ohci.h107
-rw-r--r--nuttx/arch/arm/src/sama5/sam_clockconfig.c33
-rw-r--r--nuttx/arch/arm/src/sama5/sam_ohci.c2596
-rw-r--r--nuttx/arch/arm/src/sama5/sam_ohci.h112
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_otgfs.h38
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_otgfshost.c4
-rw-r--r--nuttx/arch/mips/src/pic32mx/pic32mx-internal.h21
-rw-r--r--nuttx/configs/cloudctrl/src/up_usb.c5
-rw-r--r--nuttx/configs/mikroe-stm32f4/src/up_usb.c3
-rw-r--r--nuttx/configs/olimex-lpc1766stk/src/up_nsh.c1
-rw-r--r--nuttx/configs/open1788/src/lpc17_nsh.c1
-rw-r--r--nuttx/configs/sama5d3x-ek/README.txt61
-rw-r--r--nuttx/configs/sama5d3x-ek/include/board.h34
-rw-r--r--nuttx/configs/shenzhou/src/up_usb.c5
-rw-r--r--nuttx/configs/stm3220g-eval/src/up_usb.c5
-rw-r--r--nuttx/configs/stm3240g-eval/src/up_usb.c5
-rw-r--r--nuttx/configs/stm32f4discovery/src/up_usb.c5
-rw-r--r--nuttx/drivers/usbhost/usbhost_hidkbd.c55
-rw-r--r--nuttx/drivers/usbhost/usbhost_storage.c52
-rw-r--r--nuttx/include/nuttx/usb/usbhost.h27
24 files changed, 3227 insertions, 119 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index ad37d615b..45262a4d4 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -5352,3 +5352,15 @@
(2013-8-10).
* arch/arm/src/stm32/Kconfig and stm32_serial.c: Added option to
disable serial port reordering. From Lorenz Meier (2013-8-10).
+ * arch/arm/src/sama5/Kconfig, sam_ohci.c, and
+ arch/arm/src/sama5/sam_clockconfig.c: Add a OHCI driver for the SAMA5.
+ Untested on initial check-in (2013-8-11).
+ * include/nuttx/usb/usbhost.h, arch/arm/src/stm32, arch/arm/src/lpc17xx,
+ and include/nuttx/usb/usbhost.h, and nuttx/configs/<stm32-boards>:
+ Move prototype of usbhost_initialize() of usbhost.h and into
+ architecture specific files. This is necessasrybecause some chips
+ (like the SAMA5) have multiple, different USB host interfaces
+ (2013-8-11).
+ * drivers/usbhost/usbhost_hidkbd.c and usbhost_storage.c: Correct some
+ compilation errors when pre-allocated class structures are used. Also
+ eliminate some warnings about uninitialized variables (2013-8-11).
diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.h b/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.h
new file mode 100644
index 000000000..d473db9a6
--- /dev/null
+++ b/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.h
@@ -0,0 +1,106 @@
+/************************************************************************************
+ * arch/arm/src/lpc17xx/lpc17_usbhost.h
+ *
+ * Copyright (C) 2013 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ************************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_LPC17XX_LPC17_USBHOST_H
+#define __ARCH_ARM_SRC_LPC17XX_LPC17_USBHOST_H
+
+/************************************************************************************
+ * Included Files
+ ************************************************************************************/
+
+#include <nuttx/config.h>
+
+/************************************************************************************
+ * Pre-processor Definitions
+ ************************************************************************************/
+
+/************************************************************************************
+ * Public Types
+ ************************************************************************************/
+
+/************************************************************************************
+ * Public Data
+ ************************************************************************************/
+
+/************************************************************************************
+ * Public Functions
+ ************************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/*******************************************************************************
+ * Name: usbhost_initialize
+ *
+ * Description:
+ * Initialize USB host device controller hardware.
+ *
+ * Input Parameters:
+ * controller -- If the device supports more than USB host controller, then
+ * this identifies which controller is being intialized. Normally, this
+ * is just zero.
+ *
+ * Returned Value:
+ * And instance of the USB host interface. The controlling task should
+ * use this interface to (1) call the wait() method to wait for a device
+ * to be connected, and (2) call the enumerate() method to bind the device
+ * to a class driver.
+ *
+ * Assumptions:
+ * - This function should called in the initialization sequence in order
+ * to initialize the USB device functionality.
+ * - Class drivers should be initialized prior to calling this function.
+ * Otherwise, there is a race condition if the device is already connected.
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_USBHOST
+struct usbhost_driver_s;
+FAR struct usbhost_driver_s *usbhost_initialize(int controller);
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ARCH_ARM_SRC_LPC17XX_LPC17_USBHOST_H */
diff --git a/nuttx/arch/arm/src/sama5/Kconfig b/nuttx/arch/arm/src/sama5/Kconfig
index b4dd69bcf..10bf8b69d 100644
--- a/nuttx/arch/arm/src/sama5/Kconfig
+++ b/nuttx/arch/arm/src/sama5/Kconfig
@@ -259,7 +259,7 @@ config SAMA5_SPI_DMATHRESHOLD
---help---
When SPI DMA is enabled, small DMA transfers will still be performed
by polling logic. But we need a threshold value to determine what
- is small. That value is provided by CONFIG_SAMA5_SPI_DMATHRESHOLD.
+ is small. That value is provided by SAMA5_SPI_DMATHRESHOLD.
config SAMA5_SPI_DMADEBUG
bool "SPI DMA transfer debug"
@@ -335,6 +335,53 @@ config SAMA5_HSMCI_REGDEBUG
endmenu # HSMCI device driver options
endif # SAMA5_HSMCI0 || SAMA5_HSMCI1 || SAMA5_HSMCI2
+if SAMA5_UHPHS
+menu "USB High Speed Host device driver options"
+
+config SAMA5_OHCI
+ bool "Full speed OHCI support"
+ default n
+ ---help---
+ Build support for the SAMA5 USB full speed Open Host Controller
+ Interface (OHCI).
+
+if SAMA5_OHCI
+config SAMA5_OHCI_NEDS
+ int "Number of endpoint descriptors"
+ default 2
+
+config SAMA5_OHCI_NTDS
+ int "Number of transfer descriptors"
+ default 3
+
+config SAMA5_OHCI_TDBUFFERS
+ int "Number of transfer descriptor buffers"
+ default 2
+
+config SAMA5_OHCI_TDBUFSIZE
+ int "Size of one transfer descriptor buffer"
+ default 128
+ ---help---
+ The size of one transfer descriptor (TD) buffer in bytes. The TD
+ buffer size must be an even number of 32-bit words
+
+config SAMA5_OHCI_REGDEBUG
+ bool "Enable low-level OHCI register debug"
+ default n
+ depends on DEBUG
+
+endif # OHCI
+
+config SAMA5_EHCI
+ bool "High speed EHCI support"
+ default n
+ ---help---
+ Build support for the SAMA5 USB high speed Enhanced Host Controller
+ Interface (OHCI).
+
+endmenu # USB High Speed Host driver option
+endif # SAMA5_UHPHS
+
menu "External Memory Configuration"
config SAMA5_DDRCS
diff --git a/nuttx/arch/arm/src/sama5/Make.defs b/nuttx/arch/arm/src/sama5/Make.defs
index 3b9762beb..13649932a 100644
--- a/nuttx/arch/arm/src/sama5/Make.defs
+++ b/nuttx/arch/arm/src/sama5/Make.defs
@@ -115,6 +115,15 @@ else
endif
endif
+ifeq ($(CONFIG_SAMA5_UHPHS),y)
+ifeq ($(CONFIG_SAMA5_OHCI),y)
+CHIP_CSRCS += sam_ohci.c
+endif
+ifeq ($(CONFIG_SAMA5_EHCI),y)
+CHIP_CSRCS += sam_ehci.c
+endif
+endif
+
ifeq ($(CONFIG_SAMA5_HSMCI0),y)
CHIP_CSRCS += sam_hsmci.c
else
diff --git a/nuttx/arch/arm/src/sama5/chip/sam_ohci.h b/nuttx/arch/arm/src/sama5/chip/sam_ohci.h
new file mode 100644
index 000000000..f784b929d
--- /dev/null
+++ b/nuttx/arch/arm/src/sama5/chip/sam_ohci.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+ * arch/arm/src/sama5/chip/sam_ohci.h
+ *
+ * Copyright (C) 2013 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_SAMA5_CHIP_SAM_USB_H
+#define __ARCH_ARM_SRC_SAMA5_CHIP_SAM_USB_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/usb/ohci.h>
+
+#include "chip.h"
+#include "chip/sam_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register offsets *********************************************************/
+/* See nuttx/usb/ohci.h */
+
+/* Register addresses *******************************************************/
+
+#define SAM_USBHOST_HCIREV (SAM_UHPOHCI_VSECTION+OHCI_HCIREV_OFFSET)
+#define SAM_USBHOST_CTRL (SAM_UHPOHCI_VSECTION+OHCI_CTRL_OFFSET)
+#define SAM_USBHOST_CMDST (SAM_UHPOHCI_VSECTION+OHCI_CMDST_OFFSET)
+#define SAM_USBHOST_INTST (SAM_UHPOHCI_VSECTION+OHCI_INTST_OFFSET)
+#define SAM_USBHOST_INTEN (SAM_UHPOHCI_VSECTION+OHCI_INTEN_OFFSET)
+#define SAM_USBHOST_INTDIS (SAM_UHPOHCI_VSECTION+OHCI_INTDIS_OFFSET)
+
+/* Memory pointers (section 7.2) */
+
+#define SAM_USBHOST_HCCA (SAM_UHPOHCI_VSECTION+OHCI_HCCA_OFFSET)
+#define SAM_USBHOST_PERED (SAM_UHPOHCI_VSECTION+OHCI_PERED_OFFSET)
+#define SAM_USBHOST_CTRLHEADED (SAM_UHPOHCI_VSECTION+OHCI_CTRLHEADED_OFFSET)
+#define SAM_USBHOST_CTRLED (SAM_UHPOHCI_VSECTION+OHCI_CTRLED_OFFSET)
+#define SAM_USBHOST_BULKHEADED (SAM_UHPOHCI_VSECTION+OHCI_BULKHEADED_OFFSET)
+#define SAM_USBHOST_BULKED (SAM_UHPOHCI_VSECTION+OHCI_BULKED_OFFSET)
+#define SAM_USBHOST_DONEHEAD (SAM_UHPOHCI_VSECTION+OHCI_DONEHEAD_OFFSET)
+
+/* Frame counters (section 7.3) */
+
+#define SAM_USBHOST_FMINT (SAM_UHPOHCI_VSECTION+OHCI_FMINT_OFFSET)
+#define SAM_USBHOST_FMREM (SAM_UHPOHCI_VSECTION+OHCI_FMREM_OFFSET)
+#define SAM_USBHOST_FMNO (SAM_UHPOHCI_VSECTION+OHCI_FMNO_OFFSET)
+#define SAM_USBHOST_PERSTART (SAM_UHPOHCI_VSECTION+OHCI_PERSTART_OFFSET)
+
+/* Root hub ports (section 7.4) */
+
+#define SAM_USBHOST_LSTHRES (SAM_UHPOHCI_VSECTION+OHCI_LSTHRES_OFFSET)
+#define SAM_USBHOST_RHDESCA (SAM_UHPOHCI_VSECTION+OHCI_RHDESCA_OFFSET)
+#define SAM_USBHOST_RHDESCB (SAM_UHPOHCI_VSECTION+OHCI_RHDESCB_OFFSET)
+#define SAM_USBHOST_RHSTATUS (SAM_UHPOHCI_VSECTION+OHCI_RHSTATUS_OFFSET)
+#define SAM_USBHOST_RHPORTST1 (SAM_UHPOHCI_VSECTION+OHCI_RHPORTST1_OFFSET)
+#define SAM_USBHOST_RHPORTST2 (SAM_UHPOHCI_VSECTION+OHCI_RHPORTST2_OFFSET)
+#define SAM_USBHOST_MODID (SAM_UHPOHCI_VSECTION+SAM_USBHOST_MODID_OFFSET)
+
+/* Register bit definitions *************************************************/
+/* See include/nuttx/usb/ohci.h */
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+#endif /* __ARCH_ARM_SRC_SAMA5_CHIP_SAM_USB_H */
diff --git a/nuttx/arch/arm/src/sama5/sam_clockconfig.c b/nuttx/arch/arm/src/sama5/sam_clockconfig.c
index 67ba75210..859550a6f 100644
--- a/nuttx/arch/arm/src/sama5/sam_clockconfig.c
+++ b/nuttx/arch/arm/src/sama5/sam_clockconfig.c
@@ -321,16 +321,37 @@ static inline void sam_selectplla(void)
}
/****************************************************************************
- * Name: sam_upllsetup
+ * Name: sam_usbclockconfig
*
* Description:
- * Select the PLLA output as the input clock for PCK and MCK.
+ * Configure clocking for USB.
*
****************************************************************************/
-static inline void sam_upllsetup(void)
+static inline void sam_usbclockconfig(void)
{
-#ifdef CONFIG_USBDEV
+#ifdef CONFIG_SAMA5_OHCI
+ /* For OHCI Full-speed operations only, the user has to perform the
+ * following:
+ *
+ * 1) Enable UHP peripheral clock, bit (1 << AT91C_ID_UHPHS) in PMC_PCER
+ * register.
+ * 2) Select PLLACK as Input clock of OHCI part, USBS bit in PMC_USB
+ * register.
+ * 3) Program the OHCI clocks (UHP48M and UHP12M) with USBDIV field in
+ * PMC_USB register. USBDIV value is calculated regarding the PLLACK
+ * value and USB Full-speed accuracy.
+ * 4) Enable the OHCI clocks, UHP bit in PMC_SCER register.
+ *
+ * Steps 2 and 3 are done here. 1 and 2 are performed with the USB device
+ * driver is opened.
+ */
+
+ putreg32(BOARD_OHCI_INPUT | BOARD_OHCI_DIVIDER << PMC_USB_USBDIV_SHIFT,
+ SAM_PMC_USB);
+#endif
+
+#if 0 // #ifdef CONFIG_USBDEV
uint32_t regval;
/* Setup UTMI for USB and wait for LOCKU */
@@ -512,9 +533,9 @@ void sam_clockconfig(void)
sam_selectplla();
- /* Setup UTMI for USB */
+ /* Setup USB clocking */
- sam_upllsetup();
+ sam_usbclockconfig();
}
#endif /* CONFIG_SAMA5_BOOT_ISRAM || CONFIG_SAMA5_BOOT_CS0FLASH */
}
diff --git a/nuttx/arch/arm/src/sama5/sam_ohci.c b/nuttx/arch/arm/src/sama5/sam_ohci.c
new file mode 100644
index 000000000..040163a9c
--- /dev/null
+++ b/nuttx/arch/arm/src/sama5/sam_ohci.c
@@ -0,0 +1,2596 @@
+/*******************************************************************************
+ * arch/arm/src/sama5/sam_usbhost.c
+ *
+ * Copyright (C) 2013 Gregory Nutt. All rights reserved.
+ * Authors: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Included Files
+ *******************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <semaphore.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/usb/usb.h>
+#include <nuttx/usb/ohci.h>
+#include <nuttx/usb/usbhost.h>
+
+#include <arch/irq.h>
+
+#include <arch/board/board.h> /* May redefine PIO settings */
+
+#include "up_arch.h"
+#include "up_internal.h"
+
+#include "chip.h"
+#include "sam_periphclks.h"
+#include "sam_ohci.h"
+#include "chip/sam_pmc.h"
+#include "chip/sam_sfr.h"
+#include "chip/sam_ohci.h"
+
+/*******************************************************************************
+ * Definitions
+ *******************************************************************************/
+/* Configuration ***************************************************************/
+
+/* Fixed endpoint descriptor size. The actual size required by the hardware is only
+ * 16 bytes, however, we set aside an additional 16 bytes for for internal use by
+ * the OHCI host driver. 16-bytes is set aside because the EDs must still be
+ * aligned to 16-byte boundaries.
+ */
+
+#define SAM_ED_SIZE 32
+
+/* Configurable number of user endpoint descriptors (EDs). This number excludes
+ * the control endpoint that is always allocated.
+ */
+
+#ifndef CONFIG_SAMA5_OHCI_NEDS
+# define CONFIG_SAMA5_OHCI_NEDS 2
+#endif
+
+/* Fixed transfer descriptor size. The actual size required by the hardware is
+ * only 16 bytes, however, we set aside an additional 16 bytes for for internal
+ * use by the OHCI host driver. 16-bytes is set aside because the TDs must still
+ * be aligned to 16-byte boundaries.
+ */
+
+#define SAM_TD_SIZE 32
+
+/* Configurable number of user transfer descriptors (TDs). */
+
+#ifndef CONFIG_SAMA5_OHCI_NTDS
+# define CONFIG_SAMA5_OHCI_NTDS 3
+#endif
+
+#if CONFIG_SAMA5_OHCI_NTDS < 2
+# error Insufficent number of transfer descriptors (CONFIG_SAMA5_OHCI_NTDS < 2)
+#endif
+
+/* Configurable number of request/descriptor buffers (TDBUFFER) */
+
+#ifndef CONFIG_SAMA5_OHCI_TDBUFFERS
+# define CONFIG_SAMA5_OHCI_TDBUFFERS 2
+#endif
+
+#if CONFIG_SAMA5_OHCI_TDBUFFERS < 2
+# error At least two TD buffers are required (CONFIG_SAMA5_OHCI_TDBUFFERS < 2)
+#endif
+
+/* Configurable size of one TD buffer */
+
+#if CONFIG_SAMA5_OHCI_TDBUFFERS > 0 && !defined(CONFIG_SAMA5_OHCI_TDBUFSIZE)
+# define CONFIG_SAMA5_OHCI_TDBUFSIZE 128
+#endif
+
+#if (CONFIG_SAMA5_OHCI_TDBUFSIZE & 3) != 0
+# error "TD buffer size must be an even number of 32-bit words"
+#endif
+
+/* Total buffer size */
+
+#define SAM_BUFALLOC (CONFIG_SAMA5_OHCI_TDBUFFERS * CONFIG_SAMA5_OHCI_TDBUFSIZE)
+
+/* Debug */
+
+#ifndef CONFIG_DEBUG
+# undef CONFIG_SAMA5_OHCI_REGDEBUG
+#endif
+
+/* OHCI Setup ******************************************************************/
+/* Frame Interval / Periodic Start */
+
+#define BITS_PER_FRAME 12000
+#define FI (BITS_PER_FRAME-1)
+#define FSMPS ((6 * (FI - 210)) / 7)
+#define DEFAULT_FMINTERVAL ((FSMPS << OHCI_FMINT_FSMPS_SHIFT) | FI)
+#define DEFAULT_PERSTART (((9 * BITS_PER_FRAME) / 10) - 1)
+
+/* CLKCTRL enable bits */
+
+#define SAM_CLKCTRL_ENABLES (USBOTG_CLK_HOSTCLK|USBOTG_CLK_PORTSELCLK|USBOTG_CLK_AHBCLK)
+
+/* Interrupt enable bits */
+
+#ifdef CONFIG_DEBUG_USB
+# define SAM_DEBUG_INTS (OHCI_INT_SO|OHCI_INT_RD|OHCI_INT_UE|OHCI_INT_OC)
+#else
+# define SAM_DEBUG_INTS 0
+#endif
+
+#define SAM_NORMAL_INTS (OHCI_INT_WDH|OHCI_INT_RHSC)
+#define SAM_ALL_INTS (SAM_NORMAL_INTS|SAM_DEBUG_INTS)
+
+/* Periodic Intervals **********************************************************/
+/* Periodic intervals 2, 4, 8, 16,and 32 supported */
+
+#define MIN_PERINTERVAL 2
+#define MAX_PERINTERVAL 32
+
+/* Descriptors *****************************************************************/
+
+/* TD delay interrupt value */
+
+#define TD_DELAY(n) (uint32_t)((n) << GTD_STATUS_DI_SHIFT)
+
+/*******************************************************************************
+ * Private Types
+ *******************************************************************************/
+
+/* This structure retains the state of the USB host controller */
+
+struct sam_ohci_s
+{
+ /* Common device fields. This must be the first thing defined in the
+ * structure so that it is possible to simply cast from struct usbhost_s
+ * to structsam_usbhost_s.
+ */
+
+ struct usbhost_driver_s drvr;
+
+ /* The bound device class driver */
+
+ struct usbhost_class_s *class;
+
+ /* Driver status */
+
+ volatile bool connected; /* Connected to device */
+ volatile bool lowspeed; /* Low speed device attached. */
+ volatile bool rhswait; /* TRUE: Thread is waiting for Root Hub Status change */
+#ifndef CONFIG_USBHOST_INT_DISABLE
+ uint8_t ininterval; /* Minimum periodic IN EP polling interval: 2, 4, 6, 16, or 32 */
+ uint8_t outinterval; /* Minimum periodic IN EP polling interval: 2, 4, 6, 16, or 32 */
+#endif
+ sem_t exclsem; /* Support mutually exclusive access */
+ sem_t rhssem; /* Semaphore to wait Writeback Done Head event */
+
+ /* Debug stuff */
+
+#ifdef CONFIG_SAMA5_SPI_REGDEBUG
+ bool wrlast; /* Last was a write */
+ uint32_t addresslast; /* Last address */
+ uint32_t valuelast; /* Last value */
+ int ntimes; /* Number of times */
+#endif
+};
+
+/* The OCHI expects the size of an endpoint descriptor to be 16 bytes.
+ * However, the size allocated for an endpoint descriptor is 32 bytes in
+ * sam_ohciram.h. This extra 16-bytes is used by the OHCI host driver in
+ * order to maintain additional endpoint-specific data.
+ */
+
+struct sam_ed_s
+{
+ /* Hardware specific fields */
+
+ struct ohci_ed_s hw;
+
+ /* Software specific fields */
+
+ uint8_t xfrtype; /* Transfer type. See SB_EP_ATTR_XFER_* in usb.h */
+ uint8_t interval; /* Periodic EP polling interval: 2, 4, 6, 16, or 32 */
+ volatile uint8_t tdstatus; /* TD control status bits from last Writeback Done Head event */
+ volatile bool wdhwait; /* TRUE: Thread is waiting for WDH interrupt */
+ sem_t wdhsem; /* Semaphore used to wait for Writeback Done Head event */
+ /* Unused bytes follow, depending on the size of sem_t */
+};
+
+/* The OCHI expects the size of an transfer descriptor to be 16 bytes.
+ * However, the size allocated for an endpoint descriptor is 32 bytes in
+ * RAM. This extra 16-bytes is used by the OHCI host driver in order to
+ * maintain additional endpoint-specific data.
+ */
+
+struct sam_gtd_s
+{
+ /* Hardware specific fields */
+
+ struct ohci_gtd_s hw;
+
+ /* Software specific fields */
+
+ struct sam_ed_s *ed; /* Pointer to parent ED */
+ uint8_t pad[12];
+};
+
+/* The following is used to manage lists of free EDs, TDs, and TD buffers */
+
+struct sam_list_s
+{
+ struct sam_list_s *flink; /* Link to next buffer in the list */
+ /* Variable length buffer data follows */
+};
+
+/*******************************************************************************
+ * Private Function Prototypes
+ *******************************************************************************/
+
+/* Register operations ********************************************************/
+
+#ifdef CONFIG_SAMA5_OHCI_REGDEBUG
+static void sam_printreg(uint32_t addr, uint32_t val, bool iswrite);
+static void sam_checkreg(uint32_t addr, uint32_t val, bool iswrite);
+static uint32_t sam_getreg(uint32_t addr);
+static void sam_putreg(uint32_t val, uint32_t addr);
+#else
+# define sam_getreg(addr) getreg32(addr)
+# define sam_putreg(val,addr) putreg32(val,addr)
+#endif
+
+/* Semaphores ******************************************************************/
+
+static void sam_takesem(sem_t *sem);
+#define sam_givesem(s) sem_post(s);
+
+/* Byte stream access helper functions *****************************************/
+
+static inline uint16_t sam_getle16(const uint8_t *val);
+#if 0 /* Not used */
+static void sam_putle16(uint8_t *dest, uint16_t val);
+#endif
+
+/* OHCI memory pool helper functions *******************************************/
+
+static inline void sam_edfree(struct sam_ed_s *ed);
+static struct sam_gtd_s *sam_tdalloc(void);
+static void sam_tdfree(struct sam_gtd_s *buffer);
+static uint8_t *sam_tballoc(void);
+static void sam_tbfree(uint8_t *buffer);
+
+/* ED list helper functions ****************************************************/
+
+static inline int sam_addbulked(struct sam_ohci_s *priv,
+ struct sam_ed_s *ed);
+static inline int sam_rembulked(struct sam_ohci_s *priv,
+ struct sam_ed_s *ed);
+
+#if !defined(CONFIG_USBHOST_INT_DISABLE) || !defined(CONFIG_USBHOST_ISOC_DISABLE)
+static unsigned int sam_getinterval(uint8_t interval);
+static void sam_setinttab(uint32_t value, unsigned int interval, unsigned int offset);
+#endif
+
+static inline int sam_addinted(struct sam_ohci_s *priv,
+ const FAR struct usbhost_epdesc_s *epdesc,
+ struct sam_ed_s *ed);
+static inline int sam_reminted(struct sam_ohci_s *priv,
+ struct sam_ed_s *ed);
+
+static inline int sam_addisoced(struct sam_ohci_s *priv,
+ const FAR struct usbhost_epdesc_s *epdesc,
+ struct sam_ed_s *ed);
+static inline int sam_remisoced(struct sam_ohci_s *priv,
+ struct sam_ed_s *ed);
+
+/* Descriptor helper functions *************************************************/
+
+static int sam_enqueuetd(struct sam_ohci_s *priv,
+ struct sam_ed_s *ed, uint32_t dirpid,
+ uint32_t toggle, volatile uint8_t *buffer,
+ size_t buflen);
+static int sam_ctrltd(struct sam_ohci_s *priv, uint32_t dirpid,
+ uint8_t *buffer, size_t buflen);
+
+/* Interrupt handling **********************************************************/
+
+static int sam_usbinterrupt(int irq, FAR void *context);
+
+/* USB host controller operations **********************************************/
+
+static int sam_wait(FAR struct usbhost_driver_s *drvr, bool connected);
+static int sam_enumerate(FAR struct usbhost_driver_s *drvr);
+static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
+ uint16_t maxpacketsize);
+static int sam_epalloc(FAR struct usbhost_driver_s *drvr,
+ const FAR struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep);
+static int sam_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep);
+static int sam_alloc(FAR struct usbhost_driver_s *drvr,
+ FAR uint8_t **buffer, FAR size_t *maxlen);
+static int sam_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer);
+static int sam_ioalloc(FAR struct usbhost_driver_s *drvr,
+ FAR uint8_t **buffer, size_t buflen);
+static int sam_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer);
+static int sam_ctrlin(FAR struct usbhost_driver_s *drvr,
+ FAR const struct usb_ctrlreq_s *req,
+ FAR uint8_t *buffer);
+static int sam_ctrlout(FAR struct usbhost_driver_s *drvr,
+ FAR const struct usb_ctrlreq_s *req,
+ FAR const uint8_t *buffer);
+static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
+ FAR uint8_t *buffer, size_t buflen);
+static void sam_disconnect(FAR struct usbhost_driver_s *drvr);
+
+/* Initialization **************************************************************/
+
+static inline void sam_ep0init(struct sam_ohci_s *priv);
+
+/*******************************************************************************
+ * Private Data
+ *******************************************************************************/
+
+/* In this driver implementation, support is provided for only a single a single
+ * USB device. All status information can be simply retained in a single global
+ * instance.
+ */
+
+static struct sam_ohci_s g_usbhost =
+{
+ .drvr =
+ {
+ .wait = sam_wait,
+ .enumerate = sam_enumerate,
+ .ep0configure = sam_ep0configure,
+ .epalloc = sam_epalloc,
+ .epfree = sam_epfree,
+ .alloc = sam_alloc,
+ .free = sam_free,
+ .ioalloc = sam_ioalloc,
+ .iofree = sam_iofree,
+ .ctrlin = sam_ctrlin,
+ .ctrlout = sam_ctrlout,
+ .transfer = sam_transfer,
+ .disconnect = sam_disconnect,
+ },
+ .class = NULL,
+};
+
+/* This is a free list of EDs and TD buffers */
+
+static struct sam_list_s *g_edfree; /* List of unused EDs */
+static struct sam_list_s *g_tdfree; /* List of unused TDs */
+static struct sam_list_s *g_tbfree; /* List of unused transfer buffers */
+
+/* Allocated descriptor memory. These must all be properly aligned
+ * and must be positioned in a DMA-able memory region.
+ */
+
+/* This must be aligned to a 256-byte boundary */
+
+static struct ohci_hcca_s g_hcca __attribute__ ((aligned (256)));
+
+/* These must be aligned to 8-byte boundaries (we do 16-byte alignment). */
+
+static struct sam_gtd_s g_tdtail __attribute__ ((aligned (16)));
+static struct sam_ed_s g_edctrl __attribute__ ((aligned (16)));
+
+/* Pools of free descriptors and buffers. These will all be linked
+ * into the free lists declared above.
+ */
+
+static struct sam_ed_s g_edalloc[CONFIG_SAMA5_OHCI_NEDS]
+ __attribute__ ((aligned (16)));
+static struct sam_gtd_s g_tdalloc[CONFIG_SAMA5_OHCI_NTDS]
+ __attribute__ ((aligned (16)));
+static uint8_t g_bufalloc[SAM_BUFALLOC]
+ __attribute__ ((aligned (16)));
+
+/*******************************************************************************
+ * Public Data
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Private Functions
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Name: sam_printreg
+ *
+ * Description:
+ * Print the contents of an SAMA5 OHCI register operation
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_SAMA5_OHCI_REGDEBUG
+static void sam_printreg(uint32_t addr, uint32_t val, bool iswrite)
+{
+ lldbg("%08x%s%08x\n", addr, iswrite ? "<-" : "->", val);
+}
+#endif
+
+/*******************************************************************************
+ * Name: sam_checkreg
+ *
+ * Description:
+ * Get the contents of an SAMA5 OHCI register
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_SAMA5_OHCI_REGDEBUG
+static void sam_checkreg(uint32_t addr, uint32_t val, bool iswrite)
+{
+ static uint32_t prevaddr = 0;
+ static uint32_t preval = 0;
+ static uint32_t count = 0;
+ static bool prevwrite = false;
+
+ /* Is this the same value that we read from/wrote to the same register last time?
+ * Are we polling the register? If so, suppress the output.
+ */
+
+ if (addr == prevaddr && val == preval && prevwrite == iswrite)
+ {
+ /* Yes.. Just increment the count */
+
+ count++;
+ }
+ else
+ {
+ /* No this is a new address or value or operation. Were there any
+ * duplicate accesses before this one?
+ */
+
+ if (count > 0)
+ {
+ /* Yes.. Just one? */
+
+ if (count == 1)
+ {
+ /* Yes.. Just one */
+
+ sam_printreg(prevaddr, preval, prevwrite);
+ }
+ else
+ {
+ /* No.. More than one. */
+
+ lldbg("[repeats %d more times]\n", count);
+ }
+ }
+
+ /* Save the new address, value, count, and operation for next time */
+
+ prevaddr = addr;
+ preval = val;
+ count = 0;
+ prevwrite = iswrite;
+
+ /* Show the new regisgter access */
+
+ sam_printreg(addr, val, iswrite);
+ }
+}
+#endif
+
+/*******************************************************************************
+ * Name: sam_getreg
+ *
+ * Description:
+ * Get the contents of an SAMA5 register
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_SAMA5_OHCI_REGDEBUG
+static uint32_t sam_getreg(uint32_t addr)
+{
+ /* Read the value from the register */
+
+ uint32_t val = getreg32(addr);
+
+ /* Check if we need to print this value */
+
+ sam_checkreg(addr, val, false);
+ return val;
+}
+#endif
+
+/*******************************************************************************
+ * Name: sam_putreg
+ *
+ * Description:
+ * Set the contents of an SAMA5 register to a value
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_SAMA5_OHCI_REGDEBUG
+static void sam_putreg(uint32_t val, uint32_t addr)
+{
+ /* Check if we need to print this value */
+
+ sam_checkreg(addr, val, true);
+
+ /* Write the value */
+
+ putreg32(val, addr);
+}
+#endif
+
+/****************************************************************************
+ * Name: sam_takesem
+ *
+ * Description:
+ * This is just a wrapper to handle the annoying behavior of semaphore
+ * waits that return due to the receipt of a signal.
+ *
+ *******************************************************************************/
+
+static void sam_takesem(sem_t *sem)
+{
+ /* Take the semaphore (perhaps waiting) */
+
+ while (sem_wait(sem) != 0)
+ {
+ /* The only case that an error should occr here is if the wait was
+ * awakened by a signal.
+ */
+
+ ASSERT(errno == EINTR);
+ }
+}
+
+/****************************************************************************
+ * Name: sam_getle16
+ *
+ * Description:
+ * Get a (possibly unaligned) 16-bit little endian value.
+ *
+ *******************************************************************************/
+
+static inline uint16_t sam_getle16(const uint8_t *val)
+{
+ return (uint16_t)val[1] << 8 | (uint16_t)val[0];
+}
+
+/****************************************************************************
+ * Name: sam_putle16
+ *
+ * Description:
+ * Put a (possibly unaligned) 16-bit little endian value.
+ *
+ *******************************************************************************/
+
+#if 0 /* Not used */
+static void sam_putle16(uint8_t *dest, uint16_t val)
+{
+ dest[0] = val & 0xff; /* Little endian means LS byte first in byte stream */
+ dest[1] = val >> 8;
+}
+#endif
+
+/*******************************************************************************
+ * Name: sam_edfree
+ *
+ * Description:
+ * Return an endpoint descriptor to the free list
+ *
+ *******************************************************************************/
+
+static inline void sam_edfree(struct sam_ed_s *ed)
+{
+ struct sam_list_s *entry = (struct sam_list_s *)ed;
+
+ /* Put the ED back into the free list */
+
+ entry->flink = g_edfree;
+ g_edfree = entry;
+}
+
+/*******************************************************************************
+ * Name: sam_tdalloc
+ *
+ * Description:
+ * Allocate an transfer descriptor from the free list
+ *
+ * Assumptions:
+ * - Never called from an interrupt handler.
+ * - Protected from conconcurrent access to the TD pool by the interrupt
+ * handler
+ * - Protection from re-entrance must be assured by the caller
+ *
+ *******************************************************************************/
+
+static struct sam_gtd_s *sam_tdalloc(void)
+{
+ struct sam_gtd_s *ret;
+ irqstate_t flags;
+
+ /* Disable interrupts momentarily so that sam_tdfree is not called from the
+ * interrupt handler.
+ */
+
+ flags = irqsave();
+ ret = (struct sam_gtd_s *)g_tdfree;
+ if (ret)
+ {
+ g_tdfree = ((struct sam_list_s*)ret)->flink;
+ }
+
+ irqrestore(flags);
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: sam_tdfree
+ *
+ * Description:
+ * Return an transfer descriptor to the free list
+ *
+ * Assumptions:
+ * - Only called from the WDH interrupt handler (and during initialization).
+ * - Interrupts are disabled in any case.
+ *
+ *******************************************************************************/
+
+static void sam_tdfree(struct sam_gtd_s *td)
+{
+ struct sam_list_s *tdfree = (struct sam_list_s *)td;
+
+ /* This should not happen but just to be safe, don't free the common, pre-
+ * allocated tail TD.
+ */
+
+ if (tdfree != NULL && td != &g_tdtail)
+ {
+ tdfree->flink = g_tdfree;
+ g_tdfree = tdfree;
+ }
+}
+
+/*******************************************************************************
+ * Name: sam_tballoc
+ *
+ * Description:
+ * Allocate an request/descriptor transfer buffer from the free list
+ *
+ * Assumptions:
+ * - Never called from an interrupt handler.
+ * - Protection from re-entrance must be assured by the caller
+ *
+ *******************************************************************************/
+
+static uint8_t *sam_tballoc(void)
+{
+ uint8_t *ret = (uint8_t *)g_tbfree;
+ if (ret)
+ {
+ g_tbfree = ((struct sam_list_s*)ret)->flink;
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: sam_tbfree
+ *
+ * Description:
+ * Return an request/descriptor transfer buffer to the free list
+ *
+ *******************************************************************************/
+
+static void sam_tbfree(uint8_t *buffer)
+{
+ struct sam_list_s *tbfree = (struct sam_list_s *)buffer;
+
+ if (tbfree)
+ {
+ tbfree->flink = g_tbfree;
+ g_tbfree = tbfree;
+ }
+}
+
+/*******************************************************************************
+ * Name: sam_addbulked
+ *
+ * Description:
+ * Helper function to add an ED to the bulk list.
+ *
+ *******************************************************************************/
+
+static inline int sam_addbulked(struct sam_ohci_s *priv,
+ struct sam_ed_s *ed)
+{
+#ifndef CONFIG_USBHOST_BULK_DISABLE
+ uint32_t regval;
+
+ /* Add the new bulk ED to the head of the bulk list */
+
+ ed->hw.nexted = sam_getreg(SAM_USBHOST_BULKHEADED);
+ sam_putreg((uint32_t)ed, SAM_USBHOST_BULKHEADED);
+
+ /* BulkListEnable. This bit is set to enable the processing of the
+ * Bulk list. Note: once enabled, it remains. We really should
+ * never modify the bulk list while BLE is set.
+ */
+
+ regval = sam_getreg(SAM_USBHOST_CTRL);
+ regval |= OHCI_CTRL_BLE;
+ sam_putreg(regval, SAM_USBHOST_CTRL);
+ return OK;
+#else
+ return -ENOSYS;
+#endif
+}
+
+/*******************************************************************************
+ * Name: sam_rembulked
+ *
+ * Description:
+ * Helper function remove an ED from the bulk list.
+ *
+ *******************************************************************************/
+
+static inline int sam_rembulked(struct sam_ohci_s *priv,
+ struct sam_ed_s *ed)
+{
+#ifndef CONFIG_USBHOST_BULK_DISABLE
+ struct sam_ed_s *curr;
+ struct sam_ed_s *prev;
+ uint32_t regval;
+
+ /* Find the ED in the bulk list. NOTE: We really should never be mucking
+ * with the bulk list while BLE is set.
+ */
+
+ for (curr = (struct sam_ed_s *)sam_getreg(SAM_USBHOST_BULKHEADED),
+ prev = NULL;
+ curr && curr != ed;
+ prev = curr, curr = (struct sam_ed_s *)curr->hw.nexted);
+
+ /* Hmmm.. It would be a bug if we do not find the ED in the bulk list. */
+
+ DEBUGASSERT(curr != NULL);
+
+ /* Remove the ED from the bulk list */
+
+ if (curr != NULL)
+ {
+ /* Is this ED the first on in the bulk list? */
+
+ if (prev == NULL)
+ {
+ /* Yes... set the head of the bulk list to skip over this ED */
+
+ sam_putreg(ed->hw.nexted, SAM_USBHOST_BULKHEADED);
+
+ /* If the bulk list is now empty, then disable it */
+
+ regval = sam_getreg(SAM_USBHOST_CTRL);
+ regval &= ~OHCI_CTRL_BLE;
+ sam_putreg(regval, SAM_USBHOST_CTRL);
+ }
+ else
+ {
+ /* No.. set the forward link of the previous ED in the list
+ * skip over this ED.
+ */
+
+ prev->hw.nexted = ed->hw.nexted;
+ }
+ }
+
+ return OK;
+#else
+ return -ENOSYS;
+#endif
+}
+
+/*******************************************************************************
+ * Name: sam_getinterval
+ *
+ * Description:
+ * Convert the endpoint polling interval into a HCCA table increment
+ *
+ *******************************************************************************/
+
+#if !defined(CONFIG_USBHOST_INT_DISABLE) || !defined(CONFIG_USBHOST_ISOC_DISABLE)
+static unsigned int sam_getinterval(uint8_t interval)
+{
+ /* The bInterval field of the endpoint descriptor contains the polling interval
+ * for interrupt and isochronous endpoints. For other types of endpoint, this
+ * value should be ignored. bInterval is provided in units of 1MS frames.
+ */
+
+ if (interval < 3)
+ {
+ return 2;
+ }
+ else if (interval < 7)
+ {
+ return 4;
+ }
+ else if (interval < 15)
+ {
+ return 8;
+ }
+ else if (interval < 31)
+ {
+ return 16;
+ }
+ else
+ {
+ return 32;
+ }
+}
+#endif
+
+/*******************************************************************************
+ * Name: sam_setinttab
+ *
+ * Description:
+ * Set the interrupt table to the selected value using the provided interval
+ * and offset.
+ *
+ *******************************************************************************/
+
+#if !defined(CONFIG_USBHOST_INT_DISABLE) || !defined(CONFIG_USBHOST_ISOC_DISABLE)
+static void sam_setinttab(uint32_t value, unsigned int interval, unsigned int offset)
+{
+ unsigned int i;
+ for (i = offset; i < HCCA_INTTBL_WSIZE; i += interval)
+ {
+ g_hcca.inttbl[i] = value;
+ }
+}
+#endif
+
+/*******************************************************************************
+ * Name: sam_addinted
+ *
+ * Description:
+ * Helper function to add an ED to the HCCA interrupt table.
+ *
+ * To avoid reshuffling the table so much and to keep life simple in general,
+ * the following rules are applied:
+ *
+ * 1. IN EDs get the even entries, OUT EDs get the odd entries.
+ * 2. Add IN/OUT EDs are scheduled together at the minimum interval of all
+ * IN/OUT EDs.
+ *
+ * This has the following consequences:
+ *
+ * 1. The minimum support polling rate is 2MS, and
+ * 2. Some devices may get polled at a much higher rate than they request.
+ *
+ *******************************************************************************/
+
+static inline int sam_addinted(struct sam_ohci_s *priv,
+ const FAR struct usbhost_epdesc_s *epdesc,
+ struct sam_ed_s *ed)
+{
+#ifndef CONFIG_USBHOST_INT_DISABLE
+ unsigned int interval;
+ unsigned int offset;
+ uint32_t head;
+ uint32_t regval;
+
+ /* Disable periodic list processing. Does this take effect immediately? Or
+ * at the next SOF... need to check.
+ */
+
+ regval = sam_getreg(SAM_USBHOST_CTRL);
+ regval &= ~OHCI_CTRL_PLE;
+ sam_putreg(regval, SAM_USBHOST_CTRL);
+
+ /* Get the quanitized interval value associated with this ED and save it
+ * in the ED.
+ */
+
+ interval = sam_getinterval(epdesc->interval);
+ ed->interval = interval;
+ uvdbg("interval: %d->%d\n", epdesc->interval, interval);
+
+ /* Get the offset associated with the ED direction. IN EDs get the even
+ * entries, OUT EDs get the odd entries.
+ *
+ * Get the new, minimum interval. Add IN/OUT EDs are scheduled together
+ * at the minimum interval of all IN/OUT EDs.
+ */
+
+ if (epdesc->in)
+ {
+ offset = 0;
+ if (priv->ininterval > interval)
+ {
+ priv->ininterval = interval;
+ }
+ else
+ {
+ interval = priv->ininterval;
+ }
+ }
+ else
+ {
+ offset = 1;
+ if (priv->outinterval > interval)
+ {
+ priv->outinterval = interval;
+ }
+ else
+ {
+ interval = priv->outinterval;
+ }
+ }
+ uvdbg("min interval: %d offset: %d\n", interval, offset);
+
+ /* Get the head of the first of the duplicated entries. The first offset
+ * entry is always guaranteed to contain the common ED list head.
+ */
+
+ head = g_hcca.inttbl[offset];
+
+ /* Clear all current entries in the interrupt table for this direction */
+
+ sam_setinttab(0, 2, offset);
+
+ /* Add the new ED before the old head of the periodic ED list and set the
+ * new ED as the head ED in all of the appropriate entries of the HCCA
+ * interrupt table.
+ */
+
+ ed->hw.nexted = head;
+ sam_setinttab((uint32_t)ed, interval, offset);
+ uvdbg("head: %08x next: %08x\n", ed, head);
+
+ /* Re-enabled periodic list processing */
+
+ regval = sam_getreg(SAM_USBHOST_CTRL);
+ regval |= OHCI_CTRL_PLE;
+ sam_putreg(regval, SAM_USBHOST_CTRL);
+ return OK;
+#else
+ return -ENOSYS;
+#endif
+}
+
+/*******************************************************************************
+ * Name: sam_reminted
+ *
+ * Description:
+ * Helper function to remove an ED from the HCCA interrupt table.
+ *
+ * To avoid reshuffling the table so much and to keep life simple in general,
+ * the following rules are applied:
+ *
+ * 1. IN EDs get the even entries, OUT EDs get the odd entries.
+ * 2. Add IN/OUT EDs are scheduled together at the minimum interval of all
+ * IN/OUT EDs.
+ *
+ * This has the following consequences:
+ *
+ * 1. The minimum support polling rate is 2MS, and
+ * 2. Some devices may get polled at a much higher rate than they request.
+ *
+ *******************************************************************************/
+
+static inline int sam_reminted(struct sam_ohci_s *priv,
+ struct sam_ed_s *ed)
+{
+#ifndef CONFIG_USBHOST_INT_DISABLE
+ struct sam_ed_s *head;
+ struct sam_ed_s *curr;
+ struct sam_ed_s *prev;
+ unsigned int interval;
+ unsigned int offset;
+ uint32_t regval;
+
+ /* Disable periodic list processing. Does this take effect immediately? Or
+ * at the next SOF... need to check.
+ */
+
+ regval = sam_getreg(SAM_USBHOST_CTRL);
+ regval &= ~OHCI_CTRL_PLE;
+ sam_putreg(regval, SAM_USBHOST_CTRL);
+
+ /* Get the offset associated with the ED direction. IN EDs get the even
+ * entries, OUT EDs get the odd entries.
+ */
+
+ if ((ed->hw.ctrl & ED_CONTROL_D_MASK) == ED_CONTROL_D_IN)
+ {
+ offset = 0;
+ }
+ else
+ {
+ offset = 1;
+ }
+
+ /* Get the head of the first of the duplicated entries. The first offset
+ * entry is always guaranteed to contain the common ED list head.
+ */
+
+ head = (struct sam_ed_s *)g_hcca.inttbl[offset];
+ uvdbg("ed: %08x head: %08x next: %08x offset: %d\n",
+ ed, head, head ? head->hw.nexted : 0, offset);
+
+ /* Find the ED to be removed in the ED list */
+
+ for (curr = head, prev = NULL;
+ curr && curr != ed;
+ prev = curr, curr = (struct sam_ed_s *)curr->hw.nexted);
+
+ /* Hmmm.. It would be a bug if we do not find the ED in the bulk list. */
+
+ DEBUGASSERT(curr != NULL);
+ if (curr != NULL)
+ {
+ /* Clear all current entries in the interrupt table for this direction */
+
+ sam_setinttab(0, 2, offset);
+
+ /* Remove the ED from the list.. Is this ED the first on in the list? */
+
+ if (prev == NULL)
+ {
+ /* Yes... set the head of the bulk list to skip over this ED */
+
+ head = (struct sam_ed_s *)ed->hw.nexted;
+ }
+ else
+ {
+ /* No.. set the forward link of the previous ED in the list
+ * skip over this ED.
+ */
+
+ prev->hw.nexted = ed->hw.nexted;
+ }
+ uvdbg("ed: %08x head: %08x next: %08x\n",
+ ed, head, head ? head->hw.nexted : 0);
+
+ /* Calculate the new minimum interval for this list */
+
+ interval = MAX_PERINTERVAL;
+ for (curr = head; curr; curr = (struct sam_ed_s *)curr->hw.nexted)
+ {
+ if (curr->interval < interval)
+ {
+ interval = curr->interval;
+ }
+ }
+ uvdbg("min interval: %d offset: %d\n", interval, offset);
+
+ /* Save the new minimum interval */
+
+ if ((ed->hw.ctrl && ED_CONTROL_D_MASK) == ED_CONTROL_D_IN)
+ {
+ priv->ininterval = interval;
+ }
+ else
+ {
+ priv->outinterval = interval;
+ }
+
+ /* Set the head ED in all of the appropriate entries of the HCCA interrupt
+ * table (head might be NULL).
+ */
+
+ sam_setinttab((uint32_t)head, interval, offset);
+ }
+
+ /* Re-enabled periodic list processing */
+
+ if (head != NULL)
+ {
+ regval = sam_getreg(SAM_USBHOST_CTRL);
+ regval |= OHCI_CTRL_PLE;
+ sam_putreg(regval, SAM_USBHOST_CTRL);
+ }
+
+ return OK;
+#else
+ return -ENOSYS;
+#endif
+}
+
+/*******************************************************************************
+ * Name: sam_addisoced
+ *
+ * Description:
+ * Helper functions to add an ED to the periodic table.
+ *
+ *******************************************************************************/
+
+static inline int sam_addisoced(struct sam_ohci_s *priv,
+ const FAR struct usbhost_epdesc_s *epdesc,
+ struct sam_ed_s *ed)
+{
+#ifndef CONFIG_USBHOST_ISOC_DISABLE
+# warning "Isochronous endpoints not yet supported"
+#endif
+ return -ENOSYS;
+
+}
+
+/*******************************************************************************
+ * Name: sam_remisoced
+ *
+ * Description:
+ * Helper functions to remove an ED from the periodic table.
+ *
+ *******************************************************************************/
+
+static inline int sam_remisoced(struct sam_ohci_s *priv,
+ struct sam_ed_s *ed)
+{
+#ifndef CONFIG_USBHOST_ISOC_DISABLE
+# warning "Isochronous endpoints not yet supported"
+#endif
+ return -ENOSYS;
+}
+
+/*******************************************************************************
+ * Name: sam_enqueuetd
+ *
+ * Description:
+ * Enqueue a transfer descriptor. Notice that this function only supports
+ * queue on TD per ED.
+ *
+ *******************************************************************************/
+
+static int sam_enqueuetd(struct sam_ohci_s *priv,
+ struct sam_ed_s *ed, uint32_t dirpid,
+ uint32_t toggle, volatile uint8_t *buffer, size_t buflen)
+{
+ struct sam_gtd_s *td;
+ int ret = -ENOMEM;
+
+ /* Allocate a TD from the free list */
+
+ td = sam_tdalloc();
+ if (td != NULL)
+ {
+ /* Initialize the allocated TD and link it before the common tail TD. */
+
+ td->hw.ctrl = (GTD_STATUS_R | dirpid | TD_DELAY(0) | toggle | GTD_STATUS_CC_MASK);
+ g_tdtail.hw.ctrl = 0;
+ td->hw.cbp = (uint32_t)buffer;
+ g_tdtail.hw.cbp = 0;
+ td->hw.nexttd = (uint32_t)&g_tdtail;
+ g_tdtail.hw.nexttd = 0;
+ td->hw.be = (uint32_t)(buffer + (buflen - 1));
+ g_tdtail.hw.be = 0;
+
+ /* Configure driver-only fields in the extended TD structure */
+
+ td->ed = ed;
+
+ /* Link the td to the head of the ED's TD list */
+
+ ed->hw.headp = (uint32_t)td | ((ed->hw.headp) & ED_HEADP_C);
+ ed->hw.tailp = (uint32_t)&g_tdtail;
+
+ ret = OK;
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: sam_wdhwait
+ *
+ * Description:
+ * Set the request for the Writeback Done Head event well BEFORE enabling the
+ * transfer (as soon as we are absolutely committed to the to avoid transfer).
+ * We do this to minimize race conditions. This logic would have to be expanded
+ * if we want to have more than one packet in flight at a time!
+ *
+ *******************************************************************************/
+
+static int sam_wdhwait(struct sam_ohci_s *priv, struct sam_ed_s *ed)
+{
+ irqstate_t flags = irqsave();
+ int ret = -ENODEV;
+
+ /* Is the device still connected? */
+
+ if (priv->connected)
+ {
+ /* Yes.. then set wdhwait to indicate that we expect to be informed when
+ * either (1) the device is disconnected, or (2) the transfer completed.
+ */
+
+ ed->wdhwait = true;
+ ret = OK;
+ }
+
+ irqrestore(flags);
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: sam_ctrltd
+ *
+ * Description:
+ * Process a IN or OUT request on the control endpoint. This function
+ * will enqueue the request and wait for it to complete. Only one transfer
+ * may be queued; Neither these methods nor the transfer() method can be
+ * called again until the control transfer functions returns.
+ *
+ * These are blocking methods; these functions will not return until the
+ * control transfer has completed.
+ *
+ *******************************************************************************/
+
+static int sam_ctrltd(struct sam_ohci_s *priv, uint32_t dirpid, uint8_t *buffer,
+ size_t buflen)
+{
+ uint32_t toggle;
+ uint32_t regval;
+ int ret;
+
+ /* Set the request for the Writeback Done Head event well BEFORE enabling the
+ * transfer.
+ */
+
+ ret = sam_wdhwait(priv, &g_edctrl);
+ if (ret != OK)
+ {
+ udbg("ERROR: Device disconnected\n");
+ return ret;
+ }
+
+ /* Configure the toggle field in the TD */
+
+ if (dirpid == GTD_STATUS_DP_SETUP)
+ {
+ toggle = GTD_STATUS_T_DATA0;
+ }
+ else
+ {
+ toggle = GTD_STATUS_T_DATA1;
+ }
+
+ /* Then enqueue the transfer */
+
+ g_edctrl.tdstatus = TD_CC_NOERROR;
+ ret = sam_enqueuetd(priv, &g_edctrl, dirpid, toggle, buffer, buflen);
+ if (ret == OK)
+ {
+ /* Set ControlListFilled. This bit is used to indicate whether there are
+ * TDs on the Control list.
+ */
+
+ regval = sam_getreg(SAM_USBHOST_CMDST);
+ regval |= OHCI_CMDST_CLF;
+ sam_putreg(regval, SAM_USBHOST_CMDST);
+
+ /* Wait for the Writeback Done Head interrupt */
+
+ sam_takesem(&g_edctrl.wdhsem);
+
+ /* Check the TD completion status bits */
+
+ if (g_edctrl.tdstatus == TD_CC_NOERROR)
+ {
+ ret = OK;
+ }
+ else
+ {
+ uvdbg("Bad TD completion status: %d\n", g_edctrl.tdstatus);
+ ret = -EIO;
+ }
+ }
+
+ /* Make sure that there is no outstanding request on this endpoint */
+
+ g_edctrl.wdhwait = false;
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: sam_usbinterrupt
+ *
+ * Description:
+ * USB interrupt handler
+ *
+ *******************************************************************************/
+
+static int sam_usbinterrupt(int irq, FAR void *context)
+{
+ struct sam_ohci_s *priv = &g_usbhost;
+ uint32_t intst;
+ uint32_t pending;
+ uint32_t regval;
+
+ /* Read Interrupt Status and mask out interrupts that are not enabled. */
+
+ intst = sam_getreg(SAM_USBHOST_INTST);
+ regval = sam_getreg(SAM_USBHOST_INTEN);
+ ullvdbg("INST: %08x INTEN: %08x\n", intst, regval);
+
+ pending = intst & regval;
+ if (pending != 0)
+ {
+ /* Root hub status change interrupt */
+
+ if ((pending & OHCI_INT_RHSC) != 0)
+ {
+ uint32_t rhportst1 = sam_getreg(SAM_USBHOST_RHPORTST1);
+ ullvdbg("Root Hub Status Change, RHPORTST1: %08x\n", rhportst1);
+
+ if ((rhportst1 & OHCI_RHPORTST_CSC) != 0)
+ {
+ uint32_t rhstatus = sam_getreg(SAM_USBHOST_RHSTATUS);
+ ullvdbg("Connect Status Change, RHSTATUS: %08x\n", rhstatus);
+
+ /* If DRWE is set, Connect Status Change indicates a remote wake-up event */
+
+ if (rhstatus & OHCI_RHSTATUS_DRWE)
+ {
+ ullvdbg("DRWE: Remote wake-up\n");
+ }
+
+ /* Otherwise... Not a remote wake-up event */
+
+ else
+ {
+ /* Check current connect status */
+
+ if ((rhportst1 & OHCI_RHPORTST_CCS) != 0)
+ {
+ /* Connected ... Did we just become connected? */
+
+ if (!priv->connected)
+ {
+ /* Yes.. connected. */
+
+ ullvdbg("Connected\n");
+ priv->connected = true;
+
+ /* Notify any waiters */
+
+ if (priv->rhswait)
+ {
+ sam_givesem(&priv->rhssem);
+ priv->rhswait = false;
+ }
+ }
+ else
+ {
+ ulldbg("Spurious status change (connected)\n");
+ }
+
+ /* The LSDA (Low speed device attached) bit is valid
+ * when CCS == 1.
+ */
+
+ priv->lowspeed = (rhportst1 & OHCI_RHPORTST_LSDA) != 0;
+ ullvdbg("Speed:%s\n", priv->lowspeed ? "LOW" : "FULL");
+ }
+
+ /* Check if we are now disconnected */
+
+ else if (priv->connected)
+ {
+ /* Yes.. disconnect the device */
+
+ ullvdbg("Disconnected\n");
+ priv->connected = false;
+ priv->lowspeed = false;
+
+ /* Are we bound to a class instance? */
+
+ if (priv->class)
+ {
+ /* Yes.. Disconnect the class */
+
+ CLASS_DISCONNECTED(priv->class);
+ priv->class = NULL;
+ }
+
+ /* Notify any waiters for the Root Hub Status change event */
+
+ if (priv->rhswait)
+ {
+ sam_givesem(&priv->rhssem);
+ priv->rhswait = false;
+ }
+ }
+ else
+ {
+ ulldbg("Spurious status change (disconnected)\n");
+ }
+ }
+
+ /* Clear the status change interrupt */
+
+ sam_putreg(OHCI_RHPORTST_CSC, SAM_USBHOST_RHPORTST1);
+ }
+
+ /* Check for port reset status change */
+
+ if ((rhportst1 & OHCI_RHPORTST_PRSC) != 0)
+ {
+ /* Release the RH port from reset */
+
+ sam_putreg(OHCI_RHPORTST_PRSC, SAM_USBHOST_RHPORTST1);
+ }
+ }
+
+ /* Writeback Done Head interrupt */
+
+ if ((pending & OHCI_INT_WDH) != 0)
+ {
+ struct sam_gtd_s *td;
+ struct sam_gtd_s *next;
+
+ /* The host controller just wrote the list of finished TDs into the HCCA
+ * done head. This may include multiple packets that were transferred
+ * in the preceding frame.
+ *
+ * Remove the TD(s) from the Writeback Done Head in the HCCA and return
+ * them to the free list. Note that this is safe because the hardware
+ * will not modify the writeback done head again until the WDH bit is
+ * cleared in the interrupt status register.
+ */
+
+ td = (struct sam_gtd_s *)g_hcca.donehead;
+ g_hcca.donehead = 0;
+
+ /* Process each TD in the write done list */
+
+ for (; td; td = next)
+ {
+ /* Get the ED in which this TD was enqueued */
+
+ struct sam_ed_s *ed = td->ed;
+ DEBUGASSERT(ed != NULL);
+
+ /* Save the condition code from the (single) TD status/control
+ * word.
+ */
+
+ ed->tdstatus = (td->hw.ctrl & GTD_STATUS_CC_MASK) >> GTD_STATUS_CC_SHIFT;
+
+#ifdef CONFIG_DEBUG_USB
+ if (ed->tdstatus != TD_CC_NOERROR)
+ {
+ /* The transfer failed for some reason... dump some diagnostic info. */
+
+ ulldbg("ERROR: ED xfrtype:%d TD CTRL:%08x/CC:%d RHPORTST1:%08x\n",
+ ed->xfrtype, td->hw.ctrl, ed->tdstatus,
+ sam_getreg(SAM_USBHOST_RHPORTST1));
+ }
+#endif
+
+ /* Return the TD to the free list */
+
+ next = (struct sam_gtd_s *)td->hw.nexttd;
+ sam_tdfree(td);
+
+ /* And wake up the thread waiting for the WDH event */
+
+ if (ed->wdhwait)
+ {
+ sam_givesem(&ed->wdhsem);
+ ed->wdhwait = false;
+ }
+ }
+ }
+
+#ifdef CONFIG_DEBUG_USB
+ if ((pending & SAM_DEBUG_INTS) != 0)
+ {
+ ulldbg("ERROR: Unhandled interrupts INTST:%08x\n", intst);
+ }
+#endif
+
+ /* Clear interrupt status register */
+
+ sam_putreg(intst, SAM_USBHOST_INTST);
+ }
+
+ return OK;
+}
+
+/*******************************************************************************
+ * USB Host Controller Operations
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Name: sam_wait
+ *
+ * Description:
+ * Wait for a device to be connected or disconneced.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call
+ * to the class create() method.
+ * connected - TRUE: Wait for device to be connected; FALSE: wait for device
+ * to be disconnected
+ *
+ * Returned Values:
+ * Zero (OK) is returned when a device in connected. This function will not
+ * return until either (1) a device is connected or (2) some failure occurs.
+ * On a failure, a negated errno value is returned indicating the nature of
+ * the failure
+ *
+ * Assumptions:
+ * - Called from a single thread so no mutual exclusion is required.
+ * - Never called from an interrupt handler.
+ *
+ *******************************************************************************/
+
+static int sam_wait(FAR struct usbhost_driver_s *drvr, bool connected)
+{
+ struct sam_ohci_s *priv = (struct sam_ohci_s *)drvr;
+ irqstate_t flags;
+
+ /* Are we already connected? */
+
+ flags = irqsave();
+ while (priv->connected == connected)
+ {
+ /* No... wait for the connection/disconnection */
+
+ priv->rhswait = true;
+ sam_takesem(&priv->rhssem);
+ }
+ irqrestore(flags);
+
+ udbg("Connected:%s\n", priv->connected ? "YES" : "NO");
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: sam_enumerate
+ *
+ * Description:
+ * Enumerate the connected device. As part of this enumeration process,
+ * the driver will (1) get the device's configuration descriptor, (2)
+ * extract the class ID info from the configuration descriptor, (3) call
+ * usbhost_findclass() to find the class that supports this device, (4)
+ * call the create() method on the struct usbhost_registry_s interface
+ * to get a class instance, and finally (5) call the configdesc() method
+ * of the struct usbhost_class_s interface. After that, the class is in
+ * charge of the sequence of operations.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * - Only a single class bound to a single device is supported.
+ * - Called from a single thread so no mutual exclusion is required.
+ * - Never called from an interrupt handler.
+ *
+ *******************************************************************************/
+
+static int sam_enumerate(FAR struct usbhost_driver_s *drvr)
+{
+ struct sam_ohci_s *priv = (struct sam_ohci_s *)drvr;
+
+ /* Are we connected to a device? The caller should have called the wait()
+ * method first to be assured that a device is connected.
+ */
+
+ while (!priv->connected)
+ {
+ /* No, return an error */
+
+ udbg("Not connected\n");
+ return -ENODEV;
+ }
+
+ /* USB 2.0 spec says at least 50ms delay before port reset */
+
+ up_mdelay(100);
+
+ /* Put RH port 1 in reset (the LPC176x supports only a single downstream port) */
+
+ sam_putreg(OHCI_RHPORTST_PRS, SAM_USBHOST_RHPORTST1);
+
+ /* Wait for the port reset to complete */
+
+ while ((sam_getreg(SAM_USBHOST_RHPORTST1) & OHCI_RHPORTST_PRS) != 0);
+
+ /* Release RH port 1 from reset and wait a bit */
+
+ sam_putreg(OHCI_RHPORTST_PRSC, SAM_USBHOST_RHPORTST1);
+ up_mdelay(200);
+
+ /* Let the common usbhost_enumerate do all of the real work. Note that the
+ * FunctionAddress (USB address) is hardcoded to one.
+ */
+
+ uvdbg("Enumerate the device\n");
+ return usbhost_enumerate(drvr, 1, &priv->class);
+}
+
+/************************************************************************************
+ * Name: sam_ep0configure
+ *
+ * Description:
+ * Configure endpoint 0. This method is normally used internally by the
+ * enumerate() method but is made available at the interface to support
+ * an external implementation of the enumeration logic.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * funcaddr - The USB address of the function containing the endpoint that EP0
+ * controls
+ * maxpacketsize - The maximum number of bytes that can be sent to or
+ * received from the endpoint in a single data packet
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * This function will *not* be called from an interrupt handler.
+ *
+ ************************************************************************************/
+
+static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
+ uint16_t maxpacketsize)
+{
+ struct sam_ohci_s *priv = (struct sam_ohci_s *)drvr;
+
+ DEBUGASSERT(drvr && funcaddr < 128 && maxpacketsize < 2048);
+
+ /* We must have exclusive access to EP0 and the control list */
+
+ sam_takesem(&priv->exclsem);
+
+ /* Set the EP0 ED control word */
+
+ g_edctrl.hw.ctrl = (uint32_t)funcaddr << ED_CONTROL_FA_SHIFT |
+ (uint32_t)maxpacketsize << ED_CONTROL_MPS_SHIFT;
+
+ if (priv->lowspeed)
+ {
+ g_edctrl.hw.ctrl |= ED_CONTROL_S;
+ }
+
+ /* Set the transfer type to control */
+
+ g_edctrl.xfrtype = USB_EP_ATTR_XFER_CONTROL;
+ sam_givesem(&priv->exclsem);
+
+ uvdbg("EP0 CTRL:%08x\n", g_edctrl.hw.ctrl);
+ return OK;
+}
+
+/************************************************************************************
+ * Name: sam_epalloc
+ *
+ * Description:
+ * Allocate and configure one endpoint.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * epdesc - Describes the endpoint to be allocated.
+ * ep - A memory location provided by the caller in which to receive the
+ * allocated endpoint desciptor.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * This function will *not* be called from an interrupt handler.
+ *
+ ************************************************************************************/
+
+static int sam_epalloc(FAR struct usbhost_driver_s *drvr,
+ const FAR struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep)
+{
+ struct sam_ohci_s *priv = (struct sam_ohci_s *)drvr;
+ struct sam_ed_s *ed;
+ int ret = -ENOMEM;
+
+ /* Sanity check. NOTE that this method should only be called if a device is
+ * connected (because we need a valid low speed indication).
+ */
+
+ DEBUGASSERT(priv && epdesc && ep && priv->connected);
+
+ /* We must have exclusive access to the ED pool, the bulk list, the periodic list
+ * and the interrupt table.
+ */
+
+ sam_takesem(&priv->exclsem);
+
+ /* Take the next ED from the beginning of the free list (if the list is
+ * non-empty.
+ */
+
+ if (g_edfree)
+ {
+ /* Remove the ED from the freelist */
+
+ ed = (struct sam_ed_s *)g_edfree;
+ g_edfree = ((struct sam_list_s*)ed)->flink;
+
+ /* Configure the endpoint descriptor. */
+
+ memset((void*)ed, 0, sizeof(struct sam_ed_s));
+ ed->hw.ctrl = (uint32_t)(epdesc->funcaddr) << ED_CONTROL_FA_SHIFT |
+ (uint32_t)(epdesc->addr) << ED_CONTROL_EN_SHIFT |
+ (uint32_t)(epdesc->mxpacketsize) << ED_CONTROL_MPS_SHIFT;
+
+ /* Get the direction of the endpoint */
+
+ if (epdesc->in)
+ {
+ ed->hw.ctrl |= ED_CONTROL_D_IN;
+ }
+ else
+ {
+ ed->hw.ctrl |= ED_CONTROL_D_OUT;
+ }
+
+ /* Check for a low-speed device */
+
+ if (priv->lowspeed)
+ {
+ ed->hw.ctrl |= ED_CONTROL_S;
+ }
+
+ /* Set the transfer type */
+
+ ed->xfrtype = epdesc->xfrtype;
+
+ /* Special Case isochronous transfer types */
+
+#if 0 /* Isochronous transfers not yet supported */
+ if (ed->xfrtype == USB_EP_ATTR_XFER_ISOC)
+ {
+ ed->hw.ctrl |= ED_CONTROL_F;
+ }
+#endif
+ uvdbg("EP%d CTRL:%08x\n", epdesc->addr, ed->hw.ctrl);
+
+ /* Initialize the semaphore that is used to wait for the endpoint
+ * WDH event.
+ */
+
+ sem_init(&ed->wdhsem, 0, 0);
+
+ /* Link the common tail TD to the ED's TD list */
+
+ ed->hw.headp = (uint32_t)&g_tdtail;
+ ed->hw.tailp = (uint32_t)&g_tdtail;
+
+ /* Now add the endpoint descriptor to the appropriate list */
+
+ switch (ed->xfrtype)
+ {
+ case USB_EP_ATTR_XFER_BULK:
+ ret = sam_addbulked(priv, ed);
+ break;
+
+ case USB_EP_ATTR_XFER_INT:
+ ret = sam_addinted(priv, epdesc, ed);
+ break;
+
+ case USB_EP_ATTR_XFER_ISOC:
+ ret = sam_addisoced(priv, epdesc, ed);
+ break;
+
+ case USB_EP_ATTR_XFER_CONTROL:
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ /* Was the ED successfully added? */
+
+ if (ret != OK)
+ {
+ /* No.. destroy it and report the error */
+
+ udbg("ERROR: Failed to queue ED for transfer type: %d\n", ed->xfrtype);
+ sem_destroy(&ed->wdhsem);
+ sam_edfree(ed);
+ }
+ else
+ {
+ /* Yes.. return an opaque reference to the ED */
+
+ *ep = (usbhost_ep_t)ed;
+ }
+ }
+
+ sam_givesem(&priv->exclsem);
+ return ret;
+}
+
+/************************************************************************************
+ * Name: sam_epfree
+ *
+ * Description:
+ * Free and endpoint previously allocated by DRVR_EPALLOC.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * ep - The endpint to be freed.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * This function will *not* be called from an interrupt handler.
+ *
+ ************************************************************************************/
+
+static int sam_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep)
+{
+ struct sam_ohci_s *priv = (struct sam_ohci_s *)drvr;
+ struct sam_ed_s *ed = (struct sam_ed_s *)ep;
+ int ret;
+
+ /* There should not be any pending, real TDs linked to this ED */
+
+ DEBUGASSERT(ed && (ed->hw.headp & ED_HEADP_ADDR_MASK) == (uint32_t)&g_tdtail);
+
+ /* We must have exclusive access to the ED pool, the bulk list, the periodic list
+ * and the interrupt table.
+ */
+
+ sam_takesem(&priv->exclsem);
+
+ /* Remove the ED to the correct list depending on the trasfer type */
+
+ switch (ed->xfrtype)
+ {
+ case USB_EP_ATTR_XFER_BULK:
+ ret = sam_rembulked(priv, ed);
+ break;
+
+ case USB_EP_ATTR_XFER_INT:
+ ret = sam_reminted(priv, ed);
+ break;
+
+ case USB_EP_ATTR_XFER_ISOC:
+ ret = sam_remisoced(priv, ed);
+ break;
+
+ case USB_EP_ATTR_XFER_CONTROL:
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ /* Destroy the semaphore */
+
+ sem_destroy(&ed->wdhsem);
+
+ /* Put the ED back into the free list */
+
+ sam_edfree(ed);
+ sam_givesem(&priv->exclsem);
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: sam_alloc
+ *
+ * Description:
+ * Some hardware supports special memory in which request and descriptor data can
+ * be accessed more efficiently. This method provides a mechanism to allocate
+ * the request/descriptor memory. If the underlying hardware does not support
+ * such "special" memory, this functions may simply map to kmalloc.
+ *
+ * This interface was optimized under a particular assumption. It was assumed
+ * that the driver maintains a pool of small, pre-allocated buffers for descriptor
+ * traffic. NOTE that size is not an input, but an output: The size of the
+ * pre-allocated buffer is returned.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * buffer - The address of a memory location provided by the caller in which to
+ * return the allocated buffer memory address.
+ * maxlen - The address of a memory location provided by the caller in which to
+ * return the maximum size of the allocated buffer memory.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * - Called from a single thread so no mutual exclusion is required.
+ * - Never called from an interrupt handler.
+ *
+ *******************************************************************************/
+
+static int sam_alloc(FAR struct usbhost_driver_s *drvr,
+ FAR uint8_t **buffer, FAR size_t *maxlen)
+{
+ struct sam_ohci_s *priv = (struct sam_ohci_s *)drvr;
+ DEBUGASSERT(priv && buffer && maxlen);
+ int ret = -ENOMEM;
+
+ /* We must have exclusive access to the transfer buffer pool */
+
+ sam_takesem(&priv->exclsem);
+
+ *buffer = sam_tballoc();
+ if (*buffer)
+ {
+ *maxlen = CONFIG_SAMA5_OHCI_TDBUFSIZE;
+ ret = OK;
+ }
+
+ sam_givesem(&priv->exclsem);
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: sam_free
+ *
+ * Description:
+ * Some hardware supports special memory in which request and descriptor data
+ * can be accessed more efficiently. This method provides a mechanism to
+ * free that request/descriptor memory. If the underlying hardware does not
+ * support such "special" memory, this functions may simply map to kfree().
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call
+ * to the class create() method.
+ * buffer - The address of the allocated buffer memory to be freed.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * - Never called from an interrupt handler.
+ *
+ *******************************************************************************/
+
+static int sam_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer)
+{
+ struct sam_ohci_s *priv = (struct sam_ohci_s *)drvr;
+ DEBUGASSERT(buffer);
+
+ /* We must have exclusive access to the transfer buffer pool */
+
+ sam_takesem(&priv->exclsem);
+ sam_tbfree(buffer);
+ sam_givesem(&priv->exclsem);
+ return OK;
+}
+
+/************************************************************************************
+ * Name: sam_ioalloc
+ *
+ * Description:
+ * Some hardware supports special memory in which larger IO buffers can
+ * be accessed more efficiently. This method provides a mechanism to allocate
+ * the request/descriptor memory. If the underlying hardware does not support
+ * such "special" memory, this functions may simply map to kmalloc.
+ *
+ * This interface differs from DRVR_ALLOC in that the buffers are variable-sized.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * buffer - The address of a memory location provided by the caller in which to
+ * return the allocated buffer memory address.
+ * buflen - The size of the buffer required.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * This function will *not* be called from an interrupt handler.
+ *
+ ************************************************************************************/
+
+static int sam_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer,
+ size_t buflen)
+{
+ DEBUGASSERT(drvr && buffer);
+
+ /* kumalloc() should return user accessible, DMA-able memory */
+
+ *buffer = kumalloc(buflen);
+ return *buffer ? OK : -ENOMEM;
+}
+
+/************************************************************************************
+ * Name: sam_iofree
+ *
+ * Description:
+ * Some hardware supports special memory in which IO data can be accessed more
+ * efficiently. This method provides a mechanism to free that IO buffer
+ * memory. If the underlying hardware does not support such "special" memory,
+ * this functions may simply map to kfree().
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * buffer - The address of the allocated buffer memory to be freed.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * This function will *not* be called from an interrupt handler.
+ *
+ ************************************************************************************/
+
+static int sam_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer)
+{
+ DEBUGASSERT(drvr && buffer);
+
+ /* kufree is all that is required */
+
+ kufree(buffer);
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: sam_ctrlin and sam_ctrlout
+ *
+ * Description:
+ * Process a IN or OUT request on the control endpoint. These methods
+ * will enqueue the request and wait for it to complete. Only one transfer may
+ * be queued; Neither these methods nor the transfer() method can be called
+ * again until the control transfer functions returns.
+ *
+ * These are blocking methods; these functions will not return until the
+ * control transfer has completed.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * req - Describes the request to be sent. This request must lie in memory
+ * created by DRVR_ALLOC.
+ * buffer - A buffer used for sending the request and for returning any
+ * responses. This buffer must be large enough to hold the length value
+ * in the request description. buffer must have been allocated using DRVR_ALLOC
+ *
+ * NOTE: On an IN transaction, req and buffer may refer to the same allocated
+ * memory.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * - Only a single class bound to a single device is supported.
+ * - Called from a single thread so no mutual exclusion is required.
+ * - Never called from an interrupt handler.
+ *
+ *******************************************************************************/
+
+static int sam_ctrlin(FAR struct usbhost_driver_s *drvr,
+ FAR const struct usb_ctrlreq_s *req,
+ FAR uint8_t *buffer)
+{
+ struct sam_ohci_s *priv = (struct sam_ohci_s *)drvr;
+ uint16_t len;
+ int ret;
+
+ DEBUGASSERT(drvr && req);
+ uvdbg("type:%02x req:%02x value:%02x%02x index:%02x%02x len:%02x%02x\n",
+ req->type, req->req, req->value[1], req->value[0],
+ req->index[1], req->index[0], req->len[1], req->len[0]);
+
+ /* We must have exclusive access to EP0 and the control list */
+
+ sam_takesem(&priv->exclsem);
+
+ len = sam_getle16(req->len);
+ ret = sam_ctrltd(priv, GTD_STATUS_DP_SETUP, (uint8_t*)req, USB_SIZEOF_CTRLREQ);
+ if (ret == OK)
+ {
+ if (len)
+ {
+ ret = sam_ctrltd(priv, GTD_STATUS_DP_IN, buffer, len);
+ }
+
+ if (ret == OK)
+ {
+ ret = sam_ctrltd(priv, GTD_STATUS_DP_OUT, NULL, 0);
+ }
+ }
+
+ sam_givesem(&priv->exclsem);
+ return ret;
+}
+
+static int sam_ctrlout(FAR struct usbhost_driver_s *drvr,
+ FAR const struct usb_ctrlreq_s *req,
+ FAR const uint8_t *buffer)
+{
+ struct sam_ohci_s *priv = (struct sam_ohci_s *)drvr;
+ uint16_t len;
+ int ret;
+
+ DEBUGASSERT(drvr && req);
+ uvdbg("type:%02x req:%02x value:%02x%02x index:%02x%02x len:%02x%02x\n",
+ req->type, req->req, req->value[1], req->value[0],
+ req->index[1], req->index[0], req->len[1], req->len[0]);
+
+ /* We must have exclusive access to EP0 and the control list */
+
+ sam_takesem(&priv->exclsem);
+
+ len = sam_getle16(req->len);
+ ret = sam_ctrltd(priv, GTD_STATUS_DP_SETUP, (uint8_t*)req, USB_SIZEOF_CTRLREQ);
+ if (ret == OK)
+ {
+ if (len)
+ {
+ ret = sam_ctrltd(priv, GTD_STATUS_DP_OUT, (uint8_t*)buffer, len);
+ }
+
+ if (ret == OK)
+ {
+ ret = sam_ctrltd(priv, GTD_STATUS_DP_IN, NULL, 0);
+ }
+ }
+
+ sam_givesem(&priv->exclsem);
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: sam_transfer
+ *
+ * Description:
+ * Process a request to handle a transfer descriptor. This method will
+ * enqueue the transfer request and return immediately. Only one transfer may be
+ * queued; Neither this method nor the ctrlin or ctrlout methods can be called
+ * again until this function returns.
+ *
+ * This is a blocking method; this functions will not return until the
+ * transfer has completed.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * ep - The IN or OUT endpoint descriptor for the device endpoint on which to
+ * perform the transfer.
+ * buffer - A buffer containing the data to be sent (OUT endpoint) or received
+ * (IN endpoint). buffer must have been allocated using DRVR_ALLOC
+ * buflen - The length of the data to be sent or received.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure:
+ *
+ * EAGAIN - If devices NAKs the transfer (or NYET or other error where
+ * it may be appropriate to restart the entire transaction).
+ * EPERM - If the endpoint stalls
+ * EIO - On a TX or data toggle error
+ * EPIPE - Overrun errors
+ *
+ * Assumptions:
+ * - Only a single class bound to a single device is supported.
+ * - Called from a single thread so no mutual exclusion is required.
+ * - Never called from an interrupt handler.
+ *
+ *******************************************************************************/
+
+static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
+ FAR uint8_t *buffer, size_t buflen)
+{
+ struct sam_ohci_s *priv = (struct sam_ohci_s *)drvr;
+ struct sam_ed_s *ed = (struct sam_ed_s *)ep;
+ uint32_t dirpid;
+ uint32_t regval;
+#if SAM_IOBUFFERS > 0
+ uint8_t *origbuf = NULL;
+#endif
+ bool in;
+ int ret;
+
+ DEBUGASSERT(priv && ed && buffer && buflen > 0);
+
+ in = (ed->hw.ctrl & ED_CONTROL_D_MASK) == ED_CONTROL_D_IN;
+ uvdbg("EP%d %s toggle:%d maxpacket:%d buflen:%d\n",
+ (ed->hw.ctrl & ED_CONTROL_EN_MASK) >> ED_CONTROL_EN_SHIFT,
+ in ? "IN" : "OUT",
+ (ed->hw.headp & ED_HEADP_C) != 0 ? 1 : 0,
+ (ed->hw.ctrl & ED_CONTROL_MPS_MASK) >> ED_CONTROL_MPS_SHIFT,
+ buflen);
+
+ /* We must have exclusive access to the endpoint, the TD pool, the I/O buffer
+ * pool, the bulk and interrupt lists, and the HCCA interrupt table.
+ */
+
+ sam_takesem(&priv->exclsem);
+
+ /* Set the request for the Writeback Done Head event well BEFORE enabling the
+ * transfer.
+ */
+
+ ret = sam_wdhwait(priv, ed);
+ if (ret != OK)
+ {
+ udbg("ERROR: Device disconnected\n");
+ goto errout;
+ }
+
+ /* Get the direction of the endpoint */
+
+ if (in)
+ {
+ dirpid = GTD_STATUS_DP_IN;
+ }
+ else
+ {
+ dirpid = GTD_STATUS_DP_OUT;
+ }
+
+ /* Then enqueue the transfer */
+
+ ed->tdstatus = TD_CC_NOERROR;
+ ret = sam_enqueuetd(priv, ed, dirpid, GTD_STATUS_T_TOGGLE, buffer, buflen);
+ if (ret == OK)
+ {
+ /* BulkListFilled. This bit is used to indicate whether there are any
+ * TDs on the Bulk list.
+ */
+
+ regval = sam_getreg(SAM_USBHOST_CMDST);
+ regval |= OHCI_CMDST_BLF;
+ sam_putreg(regval, SAM_USBHOST_CMDST);
+
+ /* Wait for the Writeback Done Head interrupt */
+
+ sam_takesem(&ed->wdhsem);
+
+ /* Check the TD completion status bits */
+
+ if (ed->tdstatus == TD_CC_NOERROR)
+ {
+ ret = OK;
+ }
+ else
+ {
+ uvdbg("Bad TD completion status: %d\n", ed->tdstatus);
+ ret = -EIO;
+ }
+ }
+
+errout:
+ /* Make sure that there is no outstanding request on this endpoint */
+
+ ed->wdhwait = false;
+ sam_givesem(&priv->exclsem);
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: sam_disconnect
+ *
+ * Description:
+ * Called by the class when an error occurs and driver has been disconnected.
+ * The USB host driver should discard the handle to the class instance (it is
+ * stale) and not attempt any further interaction with the class driver instance
+ * (until a new instance is received from the create() method). The driver
+ * should not called the class' disconnected() method.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ *
+ * Returned Values:
+ * None
+ *
+ * Assumptions:
+ * - Only a single class bound to a single device is supported.
+ * - Never called from an interrupt handler.
+ *
+ *******************************************************************************/
+
+static void sam_disconnect(FAR struct usbhost_driver_s *drvr)
+{
+ struct sam_ohci_s *priv = (struct sam_ohci_s *)drvr;
+ priv->class = NULL;
+}
+
+/*******************************************************************************
+ * Initialization
+ *******************************************************************************/
+/*******************************************************************************
+ * Name: sam_ep0init
+ *
+ * Description:
+ * Initialize ED for EP0, add it to the control ED list, and enable control
+ * transfers.
+ *
+ * Input Parameters:
+ * priv - private driver state instance.
+ *
+ * Returned Values:
+ * None
+ *
+ *******************************************************************************/
+
+static inline void sam_ep0init(struct sam_ohci_s *priv)
+{
+ uint32_t regval;
+
+ /* Set up some default values */
+
+ (void)sam_ep0configure(&priv->drvr, 1, 8);
+
+ /* Initialize the common tail TD. */
+
+ memset(&g_tdtail, 0, sizeof(struct sam_gtd_s));
+ g_tdtail.ed = &g_edctrl;
+
+ /* Link the common tail TD to the ED's TD list */
+
+ memset(&g_edctrl, 0, sizeof(struct sam_ed_s));
+ g_edctrl.hw.headp = (uint32_t)&g_tdtail;
+ g_edctrl.hw.tailp = (uint32_t)&g_tdtail;
+
+ /* Set the head of the control list to the EP0 ED (this would have to
+ * change if we want more than on control EP queued at a time).
+ */
+
+ sam_putreg((uint32_t)&g_edctrl, SAM_USBHOST_CTRLHEADED);
+
+ /* ControlListEnable. This bit is set to enable the processing of the
+ * Control list. Note: once enabled, it remains enabled and we may even
+ * complete list processing before we get the bit set. We really
+ * should never modify the control list while CLE is set.
+ */
+
+ regval = sam_getreg(SAM_USBHOST_CTRL);
+ regval |= OHCI_CTRL_CLE;
+ sam_putreg(regval, SAM_USBHOST_CTRL);
+}
+
+/*******************************************************************************
+ * Public Functions
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Name: sam_ohci_initialize
+ *
+ * Description:
+ * Initialize USB OHCI host controller hardware.
+ *
+ * Input Parameters:
+ * controller -- If the device supports more than USB host controller, then
+ * this identifies which controller is being intialized. Normally, this
+ * is just zero.
+ *
+ * Returned Value:
+ * And instance of the USB host interface. The controlling task should
+ * use this interface to (1) call the wait() method to wait for a device
+ * to be connected, and (2) call the enumerate() method to bind the device
+ * to a class driver.
+ *
+ * Assumptions:
+ * - This function should called in the initialization sequence in order
+ * to initialize the USB device functionality.
+ * - Class drivers should be initialized prior to calling this function.
+ * Otherwise, there is a race condition if the device is already connected.
+ *
+ *******************************************************************************/
+
+FAR struct usbhost_driver_s *sam_ohci_initialize(int controller)
+{
+ struct sam_ohci_s *priv = &g_usbhost;
+ uint32_t regval;
+ uint8_t *buffer;
+ irqstate_t flags;
+ int i;
+
+ /* Sanity checks. NOTE: If certain OS features are enabled, it may be
+ * necessary to increase the size of SAM_ED/TD_SIZE in sam_ohciram.h
+ */
+
+ DEBUGASSERT(controller == 0);
+ DEBUGASSERT(sizeof(struct sam_ed_s) <= SAM_ED_SIZE);
+ DEBUGASSERT(sizeof(struct sam_gtd_s) <= SAM_TD_SIZE);
+
+ /* Initialize the state data structure */
+
+ sem_init(&priv->rhssem, 0, 0);
+ sem_init(&priv->exclsem, 0, 1);
+
+#ifndef CONFIG_USBHOST_INT_DISABLE
+ priv->ininterval = MAX_PERINTERVAL;
+ priv->outinterval = MAX_PERINTERVAL;
+#endif
+
+ /* For OHCI Full-speed operations only, the user has to perform the
+ * following:
+ *
+ * 1) Enable UHP peripheral clock, bit (1 << AT91C_ID_UHPHS) in PMC_PCER
+ * register.
+ * 2) Select PLLACK as Input clock of OHCI part, USBS bit in PMC_USB
+ * register.
+ * 3) Program the OHCI clocks (UHP48M and UHP12M) with USBDIV field in
+ * PMC_USB register. USBDIV value is calculated regarding the PLLACK
+ * value and USB Full-speed accuracy.
+ * 4) Enable the OHCI clocks, UHP bit in PMC_SCER register.
+ *
+ * Steps 1 and 4 are done here. 2 and 3 are already performed by
+ * sam_clockconfig().
+ */
+
+ /* Enable UHP peripheral clocking */
+
+ flags = irqsave();
+ sam_uhphs_enableclk();
+
+ /* Enable OHCI clocks */
+
+ regval = getreg32(SAM_PMC_SCER);
+ regval |= PMC_UHP;
+ putreg32(regval, SAM_PMC_SCER);
+ irqrestore(flags);
+
+ /* Note that no pin pinconfiguration is required. All USB HS pins have
+ * dedicated function
+ */
+
+ udbg("Initializing Host Stack\n");
+
+ /* Initialize all the TDs, EDs and HCCA to 0 */
+
+ memset((void*)&g_hcca, 0, sizeof(struct ohci_hcca_s));
+ memset((void*)&g_tdtail, 0, sizeof(struct ohci_gtd_s));
+ memset((void*)&g_edctrl, 0, sizeof(struct sam_ed_s));
+ sem_init(&g_edctrl.wdhsem, 0, 0);
+
+ /* Initialize user-configurable EDs */
+
+ for (i = 0; i < CONFIG_SAMA5_OHCI_NEDS; i++)
+ {
+ /* Put the ED in a free list */
+
+ sam_edfree(&g_edalloc[i]);
+ }
+
+ /* Initialize user-configurable TDs */
+
+ for (i = 0; i < CONFIG_SAMA5_OHCI_NTDS; i++)
+ {
+ /* Put the TD in a free list */
+
+ sam_tdfree(&g_tdalloc[i]);
+ }
+
+ /* Initialize user-configurable request/descriptor transfer buffers */
+
+ buffer = g_bufalloc;
+ for (i = 0; i < CONFIG_SAMA5_OHCI_TDBUFFERS; i++)
+ {
+ /* Put the TD buffer in a free list */
+
+ sam_tbfree(buffer);
+ buffer += CONFIG_SAMA5_OHCI_TDBUFSIZE;
+ }
+
+ /* Wait 50MS then perform hardware reset */
+
+ up_mdelay(50);
+
+ sam_putreg(0, SAM_USBHOST_CTRL); /* Hardware reset */
+ sam_putreg(0, SAM_USBHOST_CTRLHEADED); /* Initialize control list head to Zero */
+ sam_putreg(0, SAM_USBHOST_BULKHEADED); /* Initialize bulk list head to Zero */
+
+ /* Software reset */
+
+ sam_putreg(OHCI_CMDST_HCR, SAM_USBHOST_CMDST);
+
+ /* Write Fm interval (FI), largest data packet counter (FSMPS), and
+ * periodic start.
+ */
+
+ sam_putreg(DEFAULT_FMINTERVAL, SAM_USBHOST_FMINT);
+ sam_putreg(DEFAULT_PERSTART, SAM_USBHOST_PERSTART);
+
+ /* Put HC in operational state */
+
+ regval = sam_getreg(SAM_USBHOST_CTRL);
+ regval &= ~OHCI_CTRL_HCFS_MASK;
+ regval |= OHCI_CTRL_HCFS_OPER;
+ sam_putreg(regval, SAM_USBHOST_CTRL);
+
+ /* Set global power in HcRhStatus */
+
+ sam_putreg(OHCI_RHSTATUS_SGP, SAM_USBHOST_RHSTATUS);
+
+ /* Set HCCA base address */
+
+ sam_putreg((uint32_t)&g_hcca, SAM_USBHOST_HCCA);
+
+ /* Set up EP0 */
+
+ sam_ep0init(priv);
+
+ /* Clear pending interrupts */
+
+ regval = sam_getreg(SAM_USBHOST_INTST);
+ sam_putreg(regval, SAM_USBHOST_INTST);
+
+ /* Enable OHCI interrupts */
+
+ sam_putreg((SAM_ALL_INTS|OHCI_INT_MIE), SAM_USBHOST_INTEN);
+
+ /* Attach USB host controller interrupt handler */
+
+ if (irq_attach(SAM_IRQ_UHPHS, sam_usbinterrupt) != 0)
+ {
+ udbg("Failed to attach IRQ\n");
+ return NULL;
+ }
+
+ /* If there is a USB device in the slot at power up, then we will not
+ * get the status change interrupt to signal us that the device is
+ * connected. We need to set the initial connected state accordingly.
+ */
+
+ regval = sam_getreg(SAM_USBHOST_RHPORTST1);
+ priv->connected = ((regval & OHCI_RHPORTST_CCS) != 0);
+
+ /* Enable interrupts at the interrupt controller */
+
+ up_enable_irq(SAM_IRQ_UHPHS); /* enable USB interrupt */
+ udbg("USB host Initialized, Device connected:%s\n",
+ priv->connected ? "YES" : "NO");
+
+ return &priv->drvr;
+}
diff --git a/nuttx/arch/arm/src/sama5/sam_ohci.h b/nuttx/arch/arm/src/sama5/sam_ohci.h
new file mode 100644
index 000000000..fc7713576
--- /dev/null
+++ b/nuttx/arch/arm/src/sama5/sam_ohci.h
@@ -0,0 +1,112 @@
+/************************************************************************************
+ * arch/arm/src/lpc17xx/lpc17_usbhost.h
+ *
+ * Copyright (C) 2013 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ************************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_LPC17XX_LPC17_USBHOST_H
+#define __ARCH_ARM_SRC_LPC17XX_LPC17_USBHOST_H
+
+/************************************************************************************
+ * Included Files
+ ************************************************************************************/
+
+#include <nuttx/config.h>
+
+/************************************************************************************
+ * Pre-processor Definitions
+ ************************************************************************************/
+
+/************************************************************************************
+ * Public Types
+ ************************************************************************************/
+
+/************************************************************************************
+ * Public Data
+ ************************************************************************************/
+
+/************************************************************************************
+ * Public Data
+ ************************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/************************************************************************************
+ * Public Functions
+ ************************************************************************************/
+
+/*******************************************************************************
+ * Name: sam_ohci_initialize
+ *
+ * Description:
+ * Initialize USB OHCI host controller hardware.
+ *
+ * Input Parameters:
+ * controller -- If the device supports more than USB host controller, then
+ * this identifies which controller is being intialized. Normally, this
+ * is just zero.
+ *
+ * Returned Value:
+ * And instance of the USB host interface. The controlling task should
+ * use this interface to (1) call the wait() method to wait for a device
+ * to be connected, and (2) call the enumerate() method to bind the device
+ * to a class driver.
+ *
+ * Assumptions:
+ * - This function should called in the initialization sequence in order
+ * to initialize the USB device functionality.
+ * - Class drivers should be initialized prior to calling this function.
+ * Otherwise, there is a race condition if the device is already connected.
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_USBHOST
+struct usbhost_driver_s;
+FAR struct usbhost_driver_s *sam_ohci_initialize(int controller);
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ARCH_ARM_SRC_LPC17XX_LPC17_USBHOST_H */
diff --git a/nuttx/arch/arm/src/stm32/stm32_otgfs.h b/nuttx/arch/arm/src/stm32/stm32_otgfs.h
index 7e0e61482..8215256fd 100644
--- a/nuttx/arch/arm/src/stm32/stm32_otgfs.h
+++ b/nuttx/arch/arm/src/stm32/stm32_otgfs.h
@@ -1,7 +1,7 @@
/************************************************************************************
* arch/arm/src/stm32/stm32_otgfs.h
*
- * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2012-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -47,6 +47,8 @@
#include "stm32.h"
#include "chip/stm32_otgfs.h"
+#ifdef CONFIG_STM32_OTGFS
+
/************************************************************************************
* Pre-processor Definitions
************************************************************************************/
@@ -65,11 +67,42 @@
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
-extern "C" {
+extern "C"
+{
#else
#define EXTERN extern
#endif
+/*******************************************************************************
+ * Name: stm32_otgfshost_initialize
+ *
+ * Description:
+ * Initialize USB host device controller hardware.
+ *
+ * Input Parameters:
+ * controller -- If the device supports more than USB host controller, then
+ * this identifies which controller is being intialized. Normally, this
+ * is just zero.
+ *
+ * Returned Value:
+ * And instance of the USB host interface. The controlling task should
+ * use this interface to (1) call the wait() method to wait for a device
+ * to be connected, and (2) call the enumerate() method to bind the device
+ * to a class driver.
+ *
+ * Assumptions:
+ * - This function should called in the initialization sequence in order
+ * to initialize the USB device functionality.
+ * - Class drivers should be initialized prior to calling this function.
+ * Otherwise, there is a race condition if the device is already connected.
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_USBHOST
+struct usbhost_driver_s;
+FAR struct usbhost_driver_s *stm32_otgfshost_initialize(int controller);
+#endif
+
/************************************************************************************
* Name: stm32_usbsuspend
*
@@ -89,5 +122,6 @@ void stm32_usbsuspend(FAR struct usbdev_s *dev, bool resume);
#endif
#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_STM32_OTGFS */
#endif /* __ARCH_ARM_SRC_STM32_STM32_OTGFS_H */
diff --git a/nuttx/arch/arm/src/stm32/stm32_otgfshost.c b/nuttx/arch/arm/src/stm32/stm32_otgfshost.c
index 4b9eeb6c2..831bde5bc 100644
--- a/nuttx/arch/arm/src/stm32/stm32_otgfshost.c
+++ b/nuttx/arch/arm/src/stm32/stm32_otgfshost.c
@@ -4193,7 +4193,7 @@ static inline int stm32_hw_initialize(FAR struct stm32_usbhost_s *priv)
*******************************************************************************/
/*******************************************************************************
- * Name: usbhost_initialize
+ * Name: stm32_otgfshost_initialize
*
* Description:
* Initialize USB host device controller hardware.
@@ -4217,7 +4217,7 @@ static inline int stm32_hw_initialize(FAR struct stm32_usbhost_s *priv)
*
*******************************************************************************/
-FAR struct usbhost_driver_s *usbhost_initialize(int controller)
+FAR struct usbhost_driver_s *stm32_otgfshost_initialize(int controller)
{
/* At present, there is only support for a single OTG FS host. Hence it is
* pre-allocated as g_usbhost. However, in most code, the private data
diff --git a/nuttx/arch/mips/src/pic32mx/pic32mx-internal.h b/nuttx/arch/mips/src/pic32mx/pic32mx-internal.h
index fca5d5cac..3ea43ff6b 100644
--- a/nuttx/arch/mips/src/pic32mx/pic32mx-internal.h
+++ b/nuttx/arch/mips/src/pic32mx/pic32mx-internal.h
@@ -453,7 +453,6 @@ EXTERN int pic32mx_spi3cmddata(FAR struct spi_dev_s *dev, enum spi_dev_e devid,
#endif
/************************************************************************************
-
* Name: pic32mx_dmainitialize
*
* Description:
@@ -464,13 +463,11 @@ EXTERN int pic32mx_spi3cmddata(FAR struct spi_dev_s *dev, enum spi_dev_e devid,
*
************************************************************************************/
-
#ifdef CONFIG_PIC32MX_DMA
EXTERN void pic32mx_dmainitilaize(void);
#endif
/************************************************************************************
-
* Name: pic32mx_dmachannel
*
* Description:
@@ -484,13 +481,11 @@ EXTERN void pic32mx_dmainitilaize(void);
*
************************************************************************************/
-
#ifdef CONFIG_PIC32MX_DMA
EXTERN DMA_HANDLE pic32mx_dmachannel(void);
#endif
/************************************************************************************
-
* Name: pic32mx_dmafree
*
* Description:
@@ -502,13 +497,11 @@ EXTERN DMA_HANDLE pic32mx_dmachannel(void);
*
************************************************************************************/
-
#ifdef CONFIG_PIC32MX_DMA
EXTERN void pic32mx_dmafree(DMA_HANDLE handle);
#endif
/************************************************************************************
-
* Name: pic32mx_dmasetup
*
* Description:
@@ -516,7 +509,6 @@ EXTERN void pic32mx_dmafree(DMA_HANDLE handle);
*
************************************************************************************/
-
#ifdef CONFIG_PIC32MX_DMA
EXTERN int pic32mx_dmarxsetup(DMA_HANDLE handle,
uint32_t control, uint32_t config,
@@ -525,7 +517,6 @@ EXTERN int pic32mx_dmarxsetup(DMA_HANDLE handle,
#endif
/************************************************************************************
-
* Name: pic32mx_dmastart
*
* Description:
@@ -533,13 +524,11 @@ EXTERN int pic32mx_dmarxsetup(DMA_HANDLE handle,
*
************************************************************************************/
-
#ifdef CONFIG_PIC32MX_DMA
EXTERN int pic32mx_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg);
#endif
/************************************************************************************
-
* Name: pic32mx_dmastop
*
* Description:
@@ -549,13 +538,11 @@ EXTERN int pic32mx_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *ar
*
************************************************************************************/
-
#ifdef CONFIG_PIC32MX_DMA
EXTERN void pic32mx_dmastop(DMA_HANDLE handle);
#endif
/************************************************************************************
-
* Name: pic32mx_dmasample
*
* Description:
@@ -563,7 +550,6 @@ EXTERN void pic32mx_dmastop(DMA_HANDLE handle);
*
************************************************************************************/
-
#ifdef CONFIG_PIC32MX_DMA
#ifdef CONFIG_DEBUG_DMA
EXTERN void pic32mx_dmasample(DMA_HANDLE handle, struct pic32mx_dmaregs_s *regs);
@@ -573,7 +559,6 @@ EXTERN void pic32mx_dmasample(DMA_HANDLE handle, struct pic32mx_dmaregs_s *regs)
#endif
/************************************************************************************
-
* Name: pic32mx_dmadump
*
* Description:
@@ -581,7 +566,6 @@ EXTERN void pic32mx_dmasample(DMA_HANDLE handle, struct pic32mx_dmaregs_s *regs)
*
************************************************************************************/
-
#ifdef CONFIG_PIC32MX_DMA
#ifdef CONFIG_DEBUG_DMA
EXTERN void pic32mx_dmadump(DMA_HANDLE handle, const struct pic32mx_dmaregs_s *regs,
@@ -592,7 +576,6 @@ EXTERN void pic32mx_dmadump(DMA_HANDLE handle, const struct pic32mx_dmaregs_s *r
#endif
/************************************************************************************
-
* Name: pic32mx_usbpullup
*
* Description:
@@ -604,14 +587,12 @@ EXTERN void pic32mx_dmadump(DMA_HANDLE handle, const struct pic32mx_dmaregs_s *r
*
************************************************************************************/
-
#ifdef CONFIG_PIC32MX_USBDEV
struct usbdev_s;
EXTERN int pic32mx_usbpullup(FAR struct usbdev_s *dev, bool enable);
#endif
/************************************************************************************
-
* Name: pic32mx_usbsuspend
*
* Description:
@@ -622,7 +603,6 @@ EXTERN int pic32mx_usbpullup(FAR struct usbdev_s *dev, bool enable);
*
************************************************************************************/
-
#ifdef CONFIG_PIC32MX_USBDEV
EXTERN void pic32mx_usbsuspend(FAR struct usbdev_s *dev, bool resume);
#endif
@@ -637,7 +617,6 @@ EXTERN void pic32mx_usbsuspend(FAR struct usbdev_s *dev, bool resume);
*
************************************************************************************/
-
#ifdef CONFIG_PIC32MX_USBDEV
EXTERN void pic32mx_usbattach(void);
EXTERN void pic32mx_usbdetach(void);
diff --git a/nuttx/configs/cloudctrl/src/up_usb.c b/nuttx/configs/cloudctrl/src/up_usb.c
index 51167bcb2..98f015dee 100644
--- a/nuttx/configs/cloudctrl/src/up_usb.c
+++ b/nuttx/configs/cloudctrl/src/up_usb.c
@@ -2,7 +2,7 @@
* configs/cloudctrl/src/up_usbdev.c
* arch/arm/src/board/up_boot.c
*
- * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2012-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
* Darcy Gong <darcy.gong@gmail.com>
*
@@ -54,6 +54,7 @@
#include "up_arch.h"
#include "stm32.h"
+#include "stm32_otgfs.h"
#include "cloudctrl-internal.h"
#ifdef CONFIG_STM32_OTGFS
@@ -186,7 +187,7 @@ int stm32_usbhost_initialize(void)
/* Then get an instance of the USB host interface */
uvdbg("Initialize USB host\n");
- g_drvr = usbhost_initialize(0);
+ g_drvr = stm32_otgfshost_initialize(0);
if (g_drvr)
{
/* Start a thread to handle device connection. */
diff --git a/nuttx/configs/mikroe-stm32f4/src/up_usb.c b/nuttx/configs/mikroe-stm32f4/src/up_usb.c
index d19711fcf..f8debe5ab 100644
--- a/nuttx/configs/mikroe-stm32f4/src/up_usb.c
+++ b/nuttx/configs/mikroe-stm32f4/src/up_usb.c
@@ -53,6 +53,7 @@
#include "up_arch.h"
#include "stm32.h"
+#include "stm32_otgfs.h"
#include "mikroe-stm32f4-internal.h"
#ifdef CONFIG_STM32_OTGFS
@@ -185,7 +186,7 @@ int stm32_usbhost_initialize(void)
/* Then get an instance of the USB host interface */
uvdbg("Initialize USB host\n");
- g_drvr = usbhost_initialize(0);
+ g_drvr = stm32_otgfshost_initialize(0);
if (g_drvr)
{
/* Start a thread to handle device connection. */
diff --git a/nuttx/configs/olimex-lpc1766stk/src/up_nsh.c b/nuttx/configs/olimex-lpc1766stk/src/up_nsh.c
index 07fe78204..4ca474c65 100644
--- a/nuttx/configs/olimex-lpc1766stk/src/up_nsh.c
+++ b/nuttx/configs/olimex-lpc1766stk/src/up_nsh.c
@@ -51,6 +51,7 @@
#include "lpc17_ssp.h"
#include "lpc17_gpio.h"
+#include "lpc17_usbhost.h"
#include "lpc1766stk_internal.h"
/****************************************************************************
diff --git a/nuttx/configs/open1788/src/lpc17_nsh.c b/nuttx/configs/open1788/src/lpc17_nsh.c
index 559909a42..3dca28b2f 100644
--- a/nuttx/configs/open1788/src/lpc17_nsh.c
+++ b/nuttx/configs/open1788/src/lpc17_nsh.c
@@ -52,6 +52,7 @@
#include "lpc17_gpio.h"
#include "lpc17_sdcard.h"
+#include "lpc17_usbhost.h"
#include "open1788.h"
/****************************************************************************
diff --git a/nuttx/configs/sama5d3x-ek/README.txt b/nuttx/configs/sama5d3x-ek/README.txt
index abf0d29eb..5998bcc04 100644
--- a/nuttx/configs/sama5d3x-ek/README.txt
+++ b/nuttx/configs/sama5d3x-ek/README.txt
@@ -694,18 +694,18 @@ SAMA5D3x-EK Configuration Options
Some subsystems can be configured to operate in different ways. The drivers
need to know how to configure the subsystem.
- CONFIG_SAMA5_PIOA_IRQ - Support PIOA interrupts
- CONFIG_SAMA5_PIOB_IRQ - Support PIOB interrupts
- CONFIG_SAMA5_PIOC_IRQ - Support PIOD interrupts
- CONFIG_SAMA5_PIOD_IRQ - Support PIOD interrupts
- CONFIG_SAMA5_PIOE_IRQ - Support PIOE interrupts
+ CONFIG_SAMA5_PIOA_IRQ - Support PIOA interrupts
+ CONFIG_SAMA5_PIOB_IRQ - Support PIOB interrupts
+ CONFIG_SAMA5_PIOC_IRQ - Support PIOD interrupts
+ CONFIG_SAMA5_PIOD_IRQ - Support PIOD interrupts
+ CONFIG_SAMA5_PIOE_IRQ - Support PIOE interrupts
CONFIG_USART0_ISUART - USART0 is configured as a UART
CONFIG_USART1_ISUART - USART1 is configured as a UART
CONFIG_USART2_ISUART - USART2 is configured as a UART
CONFIG_USART3_ISUART - USART3 is configured as a UART
- ST91SAM4S specific device driver settings
+ ST91SAMA5 specific device driver settings
CONFIG_U[S]ARTn_SERIAL_CONSOLE - selects the USARTn (n=0,1,2,3) or UART
m (m=4,5) for the console and ttys0 (default is the USART1).
@@ -718,6 +718,34 @@ SAMA5D3x-EK Configuration Options
CONFIG_U[S]ARTn_PARTIY - 0=no parity, 1=odd parity, 2=even parity
CONFIG_U[S]ARTn_2STOP - Two stop bits
+ AT91SAMA5 USB Host Configuration
+ Pre-requisites
+
+ CONFIG_USBDEV - Enable USB device support
+ CONFIG_USBHOST - Enable USB host support
+ CONFIG_SAMA5_UHPHS - Needed
+ CONFIG_SAMA5_OHCI - Enable the STM32 USB OTG FS block
+ CONFIG_SCHED_WORKQUEUE - Worker thread support is required
+
+ Options:
+
+ CONFIG_SAMA5_OHCI_NEDS
+ Number of endpoint descriptors
+ CONFIG_SAMA5_OHCI_NTDS
+ Number of transfer descriptors
+ CONFIG_SAMA5_OHCI_TDBUFFERS
+ Number of transfer descriptor buffers
+ CONFIG_SAMA5_OHCI_TDBUFSIZE
+ Size of one transfer descriptor buffer
+ CONFIG_USBHOST_INT_DISABLE
+ Disable interrupt endpoint support
+ CONFIG_USBHOST_ISOC_DISABLE
+ Disable isochronous endpoint support
+ CONFIG_USBHOST_BULK_DISABLE
+ Disable bulk endpoint support
+
+config SAMA5_OHCI_REGDEBUG
+
Configurations
==============
@@ -1084,6 +1112,25 @@ Configurations
volume when it is removed. But those callbacks are not used in
this configuration.
+ 10) Support the USB full-speed OHCI host driver can be enabled by change
+ the NuttX configuration file as follows:
+
+ System Type -> ATSAMA5 Peripheral Support
+ CONFIG_SAMA5_UHPHS=y : USB Host High Speed
+
+ System Type -> USB High Speed Host driver options
+ CONFIG_SAMA5_OHCI=y : Full-speed OHCI support
+ : Defaults for values probably OK
+ Device Drivers
+ CONFIG_USBHOST=y : Enable USB host support
+
+ Device Drivers -> USB Host Driver Support
+ CONFIG_USBHOST_ISOC_DISABLE=y : Isochronous endpoints not used
+ CONFIG_USBHOST_MSC=y : Enable the mass storage class driver
+
+ Library Routines
+ CONFIG_SCHED_WORKQUEUE : Worker thread support is required
+
STATUS:
2013-7-19: This configuration (as do the others) run at 396MHz.
The SAMA5D3 can run at 536MHz. I still need to figure out the
@@ -1132,6 +1179,8 @@ Configurations
debug output is suppressed and card insertial and removal works as
expected (at least on the HSMCI1 microSD slot).
+ 2013-8-11: Added OHCI configuration. Untested!
+
ostest:
This configuration directory, performs a simple OS test using
examples/ostest.
diff --git a/nuttx/configs/sama5d3x-ek/include/board.h b/nuttx/configs/sama5d3x-ek/include/board.h
index ce5d89d57..3e2824102 100644
--- a/nuttx/configs/sama5d3x-ek/include/board.h
+++ b/nuttx/configs/sama5d3x-ek/include/board.h
@@ -96,9 +96,43 @@
#define BOARD_PMC_MCKR_PLLADIV PMC_MCKR_PLLADIV2
#define BOARD_PMC_MCKR_MDIV PMC_MCKR_MDIV_PCKDIV3
+#ifdef CONFIG_SAMA5_OHCI
+/* For OHCI Full-speed operations, the user has to perform the following:
+ *
+ * 1) Enable UHP peripheral clock, bit (1 << AT91C_ID_UHPHS) in PMC_PCER
+ * register.
+ * 2) Select PLLACK as Input clock of OHCI part, USBS bit in PMC_USB
+ * register.
+ * 3) Program the OHCI clocks (UHP48M and UHP12M) with USBDIV field in
+ * PMC_USB register. USBDIV value is calculated regarding the PLLACK
+ * value and USB Full-speed accuracy.
+ * 4) Enable the OHCI clocks, UHP bit in PMC_SCER register.
+ *
+ * "The USB Host controller requires 48 MHz and 12 MHz clocks for OHCI
+ * full-speed operations. These clocks must be generated by a PLL with a
+ * correct accuracy of ± 0.25% thanks to USBDIV field.
+ *
+ * "Thus the USB Host peripheral receives three clocks from the Power
+ * Management Controller (PMC): the Peripheral Clock (MCK domain), the
+ * UHP48M and the UHP12M (built-in UHP48M divided by four) used by the
+ * OHCI to interface with the bus USB signals (Recovered 12 MHz domain)
+ * in Full-speed operations"
+ *
+ * USB Clock = PLLACK / (USBDIV + 1) = 48MHz
+ * USBDIV = PLLACK / 48MHz - 1
+ * = 16.5
+ * REVISIT: USBDIV = 16 gives a clock of 46.59MHz which is an error of 3%
+ */
+
+# define BOARD_OHCI_INPUT PMC_USB_USBS_PLLA
+# define BOARD_OHCI_DIVIDER (16)
+#endif
+
+#if 0
/* USB UTMI PLL start-up time */
#define BOARD_CKGR_UCKR_UPLLCOUNT (3 << PMC_CKGR_UCKR_UPLLCOUNT_SHIFT)
+#endif
/* Resulting frequencies */
diff --git a/nuttx/configs/shenzhou/src/up_usb.c b/nuttx/configs/shenzhou/src/up_usb.c
index 86af406cf..0ae1d8c52 100644
--- a/nuttx/configs/shenzhou/src/up_usb.c
+++ b/nuttx/configs/shenzhou/src/up_usb.c
@@ -2,7 +2,7 @@
* configs/shenzhou/src/up_usbdev.c
* arch/arm/src/board/up_boot.c
*
- * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2012-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -53,6 +53,7 @@
#include "up_arch.h"
#include "stm32.h"
+#include "stm32_otgfs.h"
#include "shenshou-internal.h"
#ifdef CONFIG_STM32_OTGFS
@@ -185,7 +186,7 @@ int stm32_usbhost_initialize(void)
/* Then get an instance of the USB host interface */
uvdbg("Initialize USB host\n");
- g_drvr = usbhost_initialize(0);
+ g_drvr = stm32_otgfshost_initialize(0);
if (g_drvr)
{
/* Start a thread to handle device connection. */
diff --git a/nuttx/configs/stm3220g-eval/src/up_usb.c b/nuttx/configs/stm3220g-eval/src/up_usb.c
index 7ac062fb5..b16bdb6aa 100644
--- a/nuttx/configs/stm3220g-eval/src/up_usb.c
+++ b/nuttx/configs/stm3220g-eval/src/up_usb.c
@@ -2,7 +2,7 @@
* configs/stm3220g-eval/src/up_usb.c
* arch/arm/src/board/up_usb.c
*
- * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2012-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -53,6 +53,7 @@
#include "up_arch.h"
#include "stm32.h"
+#include "stm32_otgfs.h"
#include "stm3220g-internal.h"
#ifdef CONFIG_STM32_OTGFS
@@ -185,7 +186,7 @@ int stm32_usbhost_initialize(void)
/* Then get an instance of the USB host interface */
uvdbg("Initialize USB host\n");
- g_drvr = usbhost_initialize(0);
+ g_drvr = stm32_otgfshost_initialize(0);
if (g_drvr)
{
/* Start a thread to handle device connection. */
diff --git a/nuttx/configs/stm3240g-eval/src/up_usb.c b/nuttx/configs/stm3240g-eval/src/up_usb.c
index 776d71a38..b9082cbe7 100644
--- a/nuttx/configs/stm3240g-eval/src/up_usb.c
+++ b/nuttx/configs/stm3240g-eval/src/up_usb.c
@@ -2,7 +2,7 @@
* configs/stm3240g-eval/src/up_usbdev.c
* arch/arm/src/board/up_boot.c
*
- * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2012-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -53,6 +53,7 @@
#include "up_arch.h"
#include "stm32.h"
+#include "stm32_otgfs.h"
#include "stm3240g-internal.h"
#ifdef CONFIG_STM32_OTGFS
@@ -185,7 +186,7 @@ int stm32_usbhost_initialize(void)
/* Then get an instance of the USB host interface */
uvdbg("Initialize USB host\n");
- g_drvr = usbhost_initialize(0);
+ g_drvr = stm32_otgfshost_initialize(0);
if (g_drvr)
{
/* Start a thread to handle device connection. */
diff --git a/nuttx/configs/stm32f4discovery/src/up_usb.c b/nuttx/configs/stm32f4discovery/src/up_usb.c
index b06f587f3..4a5268155 100644
--- a/nuttx/configs/stm32f4discovery/src/up_usb.c
+++ b/nuttx/configs/stm32f4discovery/src/up_usb.c
@@ -2,7 +2,7 @@
* configs/stm32f4discovery/src/up_usbdev.c
* arch/arm/src/board/up_boot.c
*
- * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2012-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -53,6 +53,7 @@
#include "up_arch.h"
#include "stm32.h"
+#include "stm32_otgfs.h"
#include "stm32f4discovery-internal.h"
#ifdef CONFIG_STM32_OTGFS
@@ -185,7 +186,7 @@ int stm32_usbhost_initialize(void)
/* Then get an instance of the USB host interface */
uvdbg("Initialize USB host\n");
- g_drvr = usbhost_initialize(0);
+ g_drvr = stm32_otgfshost_initialize(0);
if (g_drvr)
{
/* Start a thread to handle device connection. */
diff --git a/nuttx/drivers/usbhost/usbhost_hidkbd.c b/nuttx/drivers/usbhost/usbhost_hidkbd.c
index 403befd49..1710a2bb8 100644
--- a/nuttx/drivers/usbhost/usbhost_hidkbd.c
+++ b/nuttx/drivers/usbhost/usbhost_hidkbd.c
@@ -1,7 +1,7 @@
/****************************************************************************
* drivers/usbhost/usbhost_hidkbd.c
*
- * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2011-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -120,7 +120,7 @@
/* The default is to support scancode mapping for the standard 104 key
* keyboard. Setting CONFIG_HIDKBD_RAWSCANCODES will disable all scancode
* mapping; Setting CONFIG_HIDKBD_ALLSCANCODES will enable mapping of all
- * scancodes;
+ * scancodes;
*/
#ifndef CONFIG_HIDKBD_RAWSCANCODES
@@ -201,7 +201,7 @@ struct usbhost_state_s
struct usbhost_driver_s *drvr;
/* The remainder of the fields are provide o the keyboard class driver */
-
+
char devchar; /* Character identifying the /dev/kbd[n] device */
volatile bool disconnected; /* TRUE: Device has been disconnected */
volatile bool polling; /* TRUE: Poll thread is running */
@@ -321,7 +321,7 @@ static inline int usbhost_tdalloc(FAR struct usbhost_state_s *priv);
static inline int usbhost_tdfree(FAR struct usbhost_state_s *priv);
/* struct usbhost_registry_s methods */
-
+
static struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr,
FAR const struct usbhost_id_s *id);
@@ -349,7 +349,7 @@ static int usbhost_poll(FAR struct file *filep, FAR struct pollfd *fds,
* Private Data
****************************************************************************/
-/* This structure provides the registry entry ID informatino that will be
+/* This structure provides the registry entry ID informatino that will be
* used to associate the USB host keyboard class driver to a connected USB
* device.
*/
@@ -763,7 +763,7 @@ static void usbhost_destroy(FAR void *arg)
DEBUGASSERT(priv != NULL);
uvdbg("crefs: %d\n", priv->crefs);
-
+
/* Unregister the driver */
uvdbg("Unregister driver\n");
@@ -1026,12 +1026,12 @@ static int usbhost_kbdpoll(int argc, char *argv[])
priv = g_priv;
DEBUGASSERT(priv != NULL);
-
+
priv->polling = true;
priv->crefs++;
usbhost_givesem(&g_syncsem);
sleep(1);
-
+
/* Loop here until the device is disconnected */
uvdbg("Entering poll loop\n");
@@ -1149,7 +1149,7 @@ static int usbhost_kbdpoll(int argc, char *argv[])
{
keycode &= 0x1f;
}
-
+
/* Copy the next keyboard character into the user
* buffer.
*/
@@ -1242,13 +1242,13 @@ static int usbhost_kbdpoll(int argc, char *argv[])
* we can destroy it now. Otherwise, we have to wait until the all
* of the file descriptors are closed.
*/
-
+
udbg("Keyboard removed, polling halted\n");
priv->polling = false;
if (--priv->crefs < 2)
{
/* Destroy the instance (while we hold the semaphore!) */
-
+
usbhost_destroy(priv);
}
else
@@ -1299,10 +1299,15 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
bool done = false;
int ret;
- DEBUGASSERT(priv != NULL &&
+ DEBUGASSERT(priv != NULL &&
configdesc != NULL &&
desclen >= sizeof(struct usb_cfgdesc_s));
-
+
+ /* Keep the compiler from complaining about uninitialized variables */
+
+ memset(&epindesc, 0, sizeof(struct usbhost_epdesc_s));
+ memset(&epoutdesc, 0, sizeof(struct usbhost_epdesc_s));
+
/* Verify that we were passed a configuration descriptor */
cfgdesc = (FAR struct usb_cfgdesc_s *)configdesc;
@@ -1338,7 +1343,7 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
case USB_DESC_TYPE_INTERFACE:
{
FAR struct usb_ifdesc_s *ifdesc = (FAR struct usb_ifdesc_s *)configdesc;
-
+
uvdbg("Interface descriptor\n");
DEBUGASSERT(remaining >= USB_SIZEOF_IFDESC);
@@ -1429,7 +1434,7 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
found |= USBHOST_EPINFOUND;
/* Save the interrupt IN endpoint information */
-
+
epindesc.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK;
epindesc.in = 1;
epindesc.funcaddr = funcaddr;
@@ -1460,13 +1465,13 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
}
/* Increment the address of the next descriptor */
-
+
configdesc += desc->len;
remaining -= desc->len;
}
/* Sanity checking... did we find all of things that we need? */
-
+
if ((found & USBHOST_RQDFOUND) != USBHOST_RQDFOUND)
{
ulldbg("ERROR: Found IF:%s EPIN:%s\n",
@@ -1752,7 +1757,7 @@ static inline int usbhost_tdfree(FAR struct usbhost_state_s *priv)
* Name: usbhost_create
*
* Description:
- * This function implements the create() method of struct usbhost_registry_s.
+ * This function implements the create() method of struct usbhost_registry_s.
* The create() method is a callback into the class implementation. It is
* used to (1) create a new instance of the USB host class state and to (2)
* bind a USB host driver "session" to the class instance. Use of this
@@ -1812,7 +1817,7 @@ static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *d
priv->drvr = drvr;
/* Return the instance of the USB keyboard class driver */
-
+
return &priv->class;
}
}
@@ -1867,7 +1872,7 @@ static int usbhost_connect(FAR struct usbhost_class_s *class,
FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)class;
int ret;
- DEBUGASSERT(priv != NULL &&
+ DEBUGASSERT(priv != NULL &&
configdesc != NULL &&
desclen >= sizeof(struct usb_cfgdesc_s));
@@ -1888,7 +1893,7 @@ static int usbhost_connect(FAR struct usbhost_class_s *class,
udbg("usbhost_devinit() failed: %d\n", ret);
}
}
-
+
/* ERROR handling: Do nothing. If we return and error during connection,
* the driver is required to call the DISCONNECT method. Possibilities:
*
@@ -1958,7 +1963,7 @@ static int usbhost_disconnected(struct usbhost_class_s *class)
if (priv->polling)
{
- /* The polling task is still alive. Signal the keyboard polling task.
+ /* The polling task is still alive. Signal the keyboard polling task.
* When that task wakes up, it will decrement the reference count and,
* perhaps, destroy the class instance. Then it will exit.
*/
@@ -2064,7 +2069,7 @@ static int usbhost_close(FAR struct file *filep)
/* Is this the last reference (other than the one held by the USB host
* controller driver)
*/
-
+
if (priv->crefs <= 1)
{
irqstate_t flags;
@@ -2098,7 +2103,7 @@ static int usbhost_close(FAR struct file *filep)
}
irqrestore(flags);
}
-
+
usbhost_givesem(&priv->exclsem);
return OK;
}
@@ -2177,7 +2182,7 @@ static ssize_t usbhost_read(FAR struct file *filep, FAR char *buffer, size_t len
}
/* Read data from our internal buffer of received characters */
-
+
for (tail = priv->tailndx, nbytes = 0;
tail != priv->headndx && nbytes < len;
nbytes++)
diff --git a/nuttx/drivers/usbhost/usbhost_storage.c b/nuttx/drivers/usbhost/usbhost_storage.c
index cb6af46b8..89ec6238f 100644
--- a/nuttx/drivers/usbhost/usbhost_storage.c
+++ b/nuttx/drivers/usbhost/usbhost_storage.c
@@ -1,7 +1,7 @@
/****************************************************************************
* drivers/usbhost/usbhost_storage.c
*
- * Copyright (C) 2010-2012 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2010-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -139,6 +139,13 @@ struct usbhost_state_s
usbhost_ep_t bulkout; /* Bulk OUT endpoint */
};
+/* This is how struct usbhost_state_s looks to the free list logic */
+
+struct usbhost_freestate_s
+{
+ FAR struct usbhost_freestate_s *flink;
+};
+
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
@@ -300,7 +307,7 @@ static struct usbhost_state_s g_prealloc[CONFIG_USBHOST_NPREALLOC];
/* This is a list of free, pre-allocated USB host storage class instances */
#if CONFIG_USBHOST_NPREALLOC > 0
-static struct usbhost_state_s *g_freelist;
+static FAR struct usbhost_freestate_s *g_freelist;
#endif
/* This is a bitmap that is used to allocate device names /dev/sda-z. */
@@ -356,7 +363,7 @@ static void usbhost_takesem(sem_t *sem)
#if CONFIG_USBHOST_NPREALLOC > 0
static inline FAR struct usbhost_state_s *usbhost_allocclass(void)
{
- struct usbhost_state_s *priv;
+ FAR struct usbhost_freestate_s *entry;
irqstate_t flags;
/* We may be executing from an interrupt handler so we need to take one of
@@ -364,15 +371,15 @@ static inline FAR struct usbhost_state_s *usbhost_allocclass(void)
*/
flags = irqsave();
- priv = g_freelist;
- if (priv)
+ entry = g_freelist;
+ if (entry)
{
- g_freelist = priv->class.flink;
- priv->class.flink = NULL;
+ g_freelist = entry->flink;
}
+
irqrestore(flags);
- ullvdbg("Allocated: %p\n", priv);;
- return priv;
+ ullvdbg("Allocated: %p\n", entry);;
+ return (FAR struct usbhost_state_s *)entry;
}
#else
static inline FAR struct usbhost_state_s *usbhost_allocclass(void)
@@ -407,16 +414,17 @@ static inline FAR struct usbhost_state_s *usbhost_allocclass(void)
#if CONFIG_USBHOST_NPREALLOC > 0
static inline void usbhost_freeclass(FAR struct usbhost_state_s *class)
{
+ FAR struct usbhost_freestate_s *entry = (FAR struct usbhost_freestate_s *)class;
irqstate_t flags;
- DEBUGASSERT(class != NULL);
+ DEBUGASSERT(entry != NULL);
- ullvdbg("Freeing: %p\n", class);;
+ ullvdbg("Freeing: %p\n", entry);
/* Just put the pre-allocated class structure back on the freelist */
flags = irqsave();
- class->class.flink = g_freelist;
- g_freelist = class;
+ entry->flink = g_freelist;
+ g_freelist = entry;
irqrestore(flags);
}
#else
@@ -821,7 +829,6 @@ static inline int usbhost_readcapacity(FAR struct usbhost_state_s *priv)
static inline int usbhost_inquiry(FAR struct usbhost_state_s *priv)
{
FAR struct usbmsc_cbw_s *cbw;
- FAR struct scsiresp_inquiry_s *resp;
int result;
/* Initialize a CBW (re-using the allocated transfer buffer) */
@@ -846,9 +853,12 @@ static inline int usbhost_inquiry(FAR struct usbhost_state_s *priv)
priv->tbuffer, SCSIRESP_INQUIRY_SIZEOF);
if (result == OK)
{
- /* TODO: If USB debug is enabled, dump the response data here */
+#if 0
+ FAR struct scsiresp_inquiry_s *resp;
+ /* TODO: If USB debug is enabled, dump the response data here */
resp = (FAR struct scsiresp_inquiry_s *)priv->tbuffer;
+#endif
/* Receive the CSW */
@@ -971,6 +981,11 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
configdesc != NULL &&
desclen >= sizeof(struct usb_cfgdesc_s));
+ /* Keep the compiler from complaining about uninitialized variables */
+
+ memset(&bindesc, 0, sizeof(struct usbhost_epdesc_s));
+ memset(&boutdesc, 0, sizeof(struct usbhost_epdesc_s));
+
/* Verify that we were passed a configuration descriptor */
cfgdesc = (FAR struct usb_cfgdesc_s *)configdesc;
@@ -2225,14 +2240,15 @@ int usbhost_storageinit(void)
*/
#if CONFIG_USBHOST_NPREALLOC > 0
+ FAR struct usbhost_freestate_s *entry;
int i;
g_freelist = NULL;
for (i = 0; i < CONFIG_USBHOST_NPREALLOC; i++)
{
- struct usbhost_state_s *class = &g_prealloc[i];
- class->class.flink = g_freelist;
- g_freelist = class;
+ entry = (FAR struct usbhost_freestate_s *)&g_prealloc[i];
+ entry->flink = g_freelist;
+ g_freelist = entry;
}
#endif
diff --git a/nuttx/include/nuttx/usb/usbhost.h b/nuttx/include/nuttx/usb/usbhost.h
index acfe9a829..e8a5a9636 100644
--- a/nuttx/include/nuttx/usb/usbhost.h
+++ b/nuttx/include/nuttx/usb/usbhost.h
@@ -800,33 +800,6 @@ EXTERN int usbhost_kbdinit(void);
EXTERN int usbhost_wlaninit(void);
/*******************************************************************************
- * Name: usbhost_initialize
- *
- * Description:
- * Initialize USB host device controller hardware.
- *
- * Input Parameters:
- * controller -- If the device supports more than USB host controller, then
- * this identifies which controller is being intialized. Normally, this
- * is just zero.
- *
- * Returned Value:
- * And instance of the USB host interface. The controlling task should
- * use this interface to (1) call the wait() method to wait for a device
- * to be connected, and (2) call the enumerate() method to bind the device
- * to a class driver.
- *
- * Assumptions:
- * - This function should called in the initialization sequence in order
- * to initialize the USB device functionality.
- * - Class drivers should be initialized prior to calling this function.
- * Otherwise, there is a race condition if the device is already connected.
- *
- *******************************************************************************/
-
-EXTERN FAR struct usbhost_driver_s *usbhost_initialize(int controller);
-
-/*******************************************************************************
* Name: usbhost_enumerate
*
* Description: