This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 560ba3adcd1a80555cbab4d0ebbd49789e5052fe
Author: Nicholas Chin <[email protected]>
AuthorDate: Wed May 27 15:32:29 2020 -0400

    usbhost: adds a driver for the FTDI FT232R USB to serial converter
---
 drivers/usbhost/Kconfig          |   92 ++
 drivers/usbhost/Make.defs        |    4 +
 drivers/usbhost/usbhost_ft232r.c | 2798 ++++++++++++++++++++++++++++++++++++++
 include/nuttx/usb/usbhost.h      |   93 +-
 4 files changed, 2952 insertions(+), 35 deletions(-)

diff --git a/drivers/usbhost/Kconfig b/drivers/usbhost/Kconfig
index ae98c2e..0c389b3 100644
--- a/drivers/usbhost/Kconfig
+++ b/drivers/usbhost/Kconfig
@@ -600,4 +600,96 @@ config USBHOST_TRACE_VERBOSE
 
 endif
 
+config USBHOST_FT232R
+       bool "FTDI FT232R support"
+       default n
+       depends on !USBHOST_BULK_DISABLE && !USBHOST_INT_DISABLE
+       select SERIAL_REMOVABLE
+       ---help---
+               Select this option to build in host support for FTDI FT232R
+               serial devices.
+
+if USBHOST_FT232R
+
+config USBHOST_FT232R_RXDELAY
+       int "RX poll delay (MSec)"
+       default 200
+       ---help---
+               When the CDC/ACM device is inactive, the host must poll it at 
this
+               rate in order to discover if it has serial data to send to us.
+
+config USBHOST_FT232R_TXDELAY
+       int "TX poll delay (MSec)"
+       default 200
+       ---help---
+               When the appellation is inactive, the host must poll it at this
+               rate in order to discover if it has serial data to send to the
+               device.
+
+config USBHOST_FT232R_NPREALLOC
+       int "Preallocated state"
+       default 0
+       ---help---
+               If this setting is zero, the FT232R driver will allocate
+               memory as needed for FT232R device state.  If this value is non-
+               zero, then it provides a number of preallocated FT232R state
+               structures.  This increases the static size of the code image, 
but
+               eliminates all, direct, run-time allocations by the driver.
+
+config USBHOST_FT232R_BAUD
+       int "Initialize FT232R BAUD"
+       default 115200
+
+config USBHOST_FT232R_PARITY
+       int "Initialize FT232R parity"
+       default 0
+       range 0 2
+       ---help---
+               Initialize FT232R parity.  0=None, 1=Odd, 2=Even.  Default: None
+
+config USBHOST_FT232R_BITS
+       int "Initialize FT232R transfer size"
+       default 8
+       range 7 8
+       ---help---
+               Initialize FT232R number of bits.  Default: 8
+
+config USBHOST_FT232R_2STOP
+       bool "FT232R use two stop bits"
+       default n
+       ---help---
+               False = 1 stop bit, True = Two stop bits.  Default: 1 stop bit
+
+config USBHOST_FT232R_HWFLOWCTRL
+       bool "Use FT232R RTS/CTS"
+       default n
+       ---help---
+               Enables the FT232R to use its flow control signals
+
+config USBHOST_FT232R_RXBUFSIZE
+       int "Serial RX buffer size"
+       default 128
+       ---help---
+               This is the size of the serial buffer that will be used to hold
+               received data.
+
+config USBHOST_FT232R_TXBUFSIZE
+       int "Serial TX buffer size"
+       default 128
+       ---help---
+               This is the size of the serial buffer that will be used to hold
+               data waiting for transmission.
+
+config USBHOST_FT232R_LATENCY
+       int "Latency Timer"
+       default 16
+       range 0 255
+       ---help---
+               A timeout for UART to USB packet reception. The FT232R will
+               release its buffer for sending to the USB host once this timeout
+               occurs or the buffer is full. Measured in ms.
+
+endif # USBHOST_FT232R
+
+
 endif # USBHOST
diff --git a/drivers/usbhost/Make.defs b/drivers/usbhost/Make.defs
index cf058a1..332e83c 100644
--- a/drivers/usbhost/Make.defs
+++ b/drivers/usbhost/Make.defs
@@ -74,6 +74,10 @@ ifeq ($(CONFIG_USBHOST_MAX3421E),y)
 CSRCS += usbhost_max3421e.c
 endif
 
+ifeq ($(CONFIG_USBHOST_FT232R),y)
+CSRCS += usbhost_ft232r.c
+endif
+
 # HCD debug/trace logic
 
 ifeq ($(CONFIG_USBHOST_TRACE),y)
diff --git a/drivers/usbhost/usbhost_ft232r.c b/drivers/usbhost/usbhost_ft232r.c
new file mode 100644
index 0000000..d85bfb8
--- /dev/null
+++ b/drivers/usbhost/usbhost_ft232r.c
@@ -0,0 +1,2798 @@
+/****************************************************************************
+ * drivers/usbhost/usbhost_ft232r.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/arch.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/clock.h>
+#include <nuttx/fs/ioctl.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/serial/serial.h>
+
+#include <nuttx/usb/usb.h>
+#include <nuttx/usb/usbhost.h>
+#include <nuttx/usb/usbhost_devaddr.h>
+
+#ifdef CONFIG_USBHOST_FT232R
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+#ifndef CONFIG_USBHOST
+#  warning USB host support not enabled (CONFIG_USBHOST)
+#endif
+
+#ifdef CONFIG_USBHOST_BULK_DISABLE
+#  warning USB bulk endpoint support is disabled (CONFIG_USBHOST_BULK_DISABLE)
+#endif
+
+#ifdef CONFIG_USBHOST_INT_DISABLE
+#  warning USB interrupt endpoint support is disabled 
(CONFIG_USBHOST_INT_DISABLE)
+#endif
+
+#if !defined(CONFIG_SCHED_WORKQUEUE)
+#  warning Worker thread support is required (CONFIG_SCHED_WORKQUEUE)
+#else
+#  ifndef CONFIG_SCHED_HPWORK
+#    warning High priority work thread support is required 
(CONFIG_SCHED_HPWORK)
+#  endif
+#  ifndef CONFIG_SCHED_LPWORK
+#    warning Low priority work thread support is required (CONFIG_SCHED_LPWORK)
+#  endif
+#  if CONFIG_SCHED_LPNTHREADS < 2
+#    warning Multiple low priority work threads recommended for performance 
(CONFIG_SCHED_LPNTHREADS > 1)
+#  endif
+#endif
+
+#ifndef CONFIG_SERIAL_REMOVABLE
+#  warning Removable serial device support is required 
(CONFIG_SERIAL_REMOVABLE)
+#endif
+
+#ifdef CONFIG_USBHOST_FT232R_RXDELAY
+#  define USBHOST_FT232R_RXDELAY MSEC2TICK(CONFIG_USBHOST_FT232R_RXDELAY)
+#else
+#  define USBHOST_FT232R_RXDELAY MSEC2TICK(200)
+#endif
+
+#ifdef CONFIG_USBHOST_FT232R_TXDELAY
+#  define USBHOST_FT232R_TXDELAY MSEC2TICK(CONFIG_USBHOST_FT232R_TXDELAY)
+#else
+#  define USBHOST_FT232R_TXDELAY MSEC2TICK(200)
+#endif
+
+/* If the create() method is called by the USB host device driver from an
+ * interrupt handler, then it will be unable to call kmm_malloc() in order to
+ * allocate a new class instance.  If the create() method is called from the
+ * interrupt level, then class instances must be pre-allocated.
+ */
+
+#ifndef CONFIG_USBHOST_FT232R_NPREALLOC
+#  define CONFIG_USBHOST_FT232R_NPREALLOC 0
+#endif
+
+#if CONFIG_USBHOST_FT232R_NPREALLOC > 32
+#  error Currently limited to 32 devices /dev/ttyUSB[n]
+#endif
+
+#ifndef CONFIG_USBHOST_FT232R_RXBUFSIZE
+#  define CONFIG_USBHOST_FT232R_RXBUFSIZE 128
+#endif
+
+#ifndef CONFIG_USBHOST_FT232R_TXBUFSIZE
+#  define CONFIG_USBHOST_FT232R_TXBUFSIZE 128
+#endif
+
+/* Initial line coding */
+
+#ifndef CONFIG_USBHOST_FT232R_BAUD
+#  define CONFIG_USBHOST_FT232R_BAUD 115200
+#endif
+
+#ifndef CONFIG_USBHOST_FT232R_PARITY
+#  define CONFIG_USBHOST_FT232R_PARITY 0
+#endif
+
+#ifndef CONFIG_USBHOST_FT232R_BITS
+#  define CONFIG_USBHOST_FT232R_BITS 8
+#endif
+
+#ifndef CONFIG_USBHOST_FT232R_2STOP
+#  define CONFIG_USBHOST_FT232R_2STOP 0
+#endif
+
+#ifndef CONFIG_USBHOST_FT232R_LATENCY
+#  define CONFIG_USBHOST_FT232R_LATENCY 16
+#endif
+
+/* Driver support ***********************************************************/
+
+/* This format is used to construct the /dev/sd[n] device driver path.  It
+ * defined here so that it will be used consistently in all places.
+ */
+
+#define DEV_FORMAT             "/dev/ttyUSB%d"
+#define DEV_NAMELEN            16
+
+#define MAX_NOTIFICATION       32
+
+/* Used in usbhost_connect() */
+
+#define USBHOST_DATAIF_FOUND   0x01      /* Data interface found */
+#define USBHOST_BULKIN_FOUND   0x02      /* Bulk IN interface found */
+#define USBHOST_BULKOUT_FOUND  0x04      /* Bulk OUT interface found */
+
+#define USBHOST_ALLFOUND     0x07     /* All configuration things */
+
+#define USBHOST_MAX_CREFS      INT16_MAX /* Max cref count before signed 
overflow */
+
+/* Configuration options */
+
+/* Special case baud rates */
+
+#define USBHOST_FT232R_BAUD_2MHZ 2000000
+#define USBHOST_FT232R_BAUD_3MHZ 3000000
+#define USBHOST_FT232R_MAX_BAUD USBHOST_FT232R_BAUD_3MHZ
+
+/* FT232R Control Transfer Request Types */
+
+#define USBHOST_FT232R_CTRLREQ_RESET        0x0
+#define USBHOST_FT232R_CTRLREQ_MODEMCTRL    0x1
+#define USBHOST_FT232R_CTRLREQ_SETFLOWCTRL  0x2
+#define USBHOST_FT232R_CTRLREQ_SETBAUD      0x3
+#define USBHOST_FT232R_CTRLREQ_SETDATA      0x4
+#define USBHOST_FT232R_CTRLREQ_GETMODEMSTAT 0x5
+#define USBHOST_FT232R_CTRLREQ_SETLATTIMER  0x9
+#define USBHOST_FT232R_CTRLREQ_GETLATTIMER  0xA
+
+#define USBHOST_FT232R_MODEMCTRL_VAL_DTR 0x1
+#define USBHOST_FT232R_MODEMCTRL_VAL_RTS 0x2
+#define USBHOST_FT232R_MODEMCTRL_VAL_DTR_EN 0x100
+#define USBHOST_FT232R_MODEMCTRL_VAL_RTS_EN 0x200
+
+#define USBHOST_FT232R_SETDATA_NBIT_MASK    0xFF
+#define USBHOST_FT232R_SETDATA_PARITY_MASK  0x7
+#define USBHOST_FT232R_SETDATA_PARITY_SHIFT 8
+#define USBHOST_FT232R_SETDATA_2STOP        0x1000
+#define USBHOST_FT232R_SETDATA_BREAK        0x4000
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This structure contains the internal, private state of the USB host ftdi.
+ */
+
+struct usbhost_ft232r_s
+{
+  /* This is the externally visible portion of the state.  The usbclass must
+   * the first element of the structure.  It is then cast compatible with
+   * struct usbhost_ft232r_s.
+   */
+
+  struct usbhost_class_s usbclass;
+
+  /* This is the standard of the lower-half serial interface.  It is not
+   * the first element of the structure, but includes a pointer back to the
+   * the beginning of this structure.
+   */
+
+  struct uart_dev_s uartdev;
+
+  /* The remainder of the fields are provide to the FTDI class */
+
+  volatile bool  disconnected;   /* TRUE: Device has been disconnected */
+  bool           stop2;          /* True: 2 stop bits (for line coding) */
+  bool           txena;          /* True: TX "interrupts" enabled */
+  bool           rxena;          /* True: RX "interrupts" enabled */
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+  bool           iflow;          /* True: Input flow control (RTS) enabled */
+  bool           rts;            /* True: Input flow control is in effect */
+#endif
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+  bool           oflow;          /* True: Output flow control (CTS) enabled */
+#endif
+#ifdef CONFIG_USBHOST_FT232R_HWFLOWCTRL
+  bool           cts;            /* True: Clear to send to FTDI chip */
+#endif
+  uint8_t        minor;          /* Minor number identifying the 
/dev/ttyUSB[n] device */
+  uint8_t        dataif;         /* Data interface number */
+  uint8_t        nbits;          /* Number of bits (for line encoding) */
+  uint8_t        parity;         /* Parity (for line encoding) */
+  uint16_t       pktsize;        /* Allocated size of transfer buffers */
+  uint16_t       nrxbytes;       /* Number of bytes in the RX packet buffer */
+  uint16_t       rxndx;          /* Index to the next byte in the RX packet 
buffer */
+  int16_t        crefs;          /* Reference count on the driver instance */
+  int16_t        nbytes;         /* The number of bytes actually transferred */
+  sem_t          exclsem;        /* Used to maintain mutual exclusive access */
+  struct work_s  ntwork;         /* For asynchronous notification work */
+  struct work_s  rxwork;         /* For RX packet work */
+  struct work_s  txwork;         /* For TX packet work */
+  FAR uint8_t   *ctrlreq;        /* Allocated ctrl request structure */
+  FAR uint8_t   *inbuf;          /* Allocated RX buffer for the Bulk IN 
endpoint */
+  FAR uint8_t   *outbuf;         /* Allocated TX buffer for the Bulk OUT 
endpoint */
+  uint32_t       baud;           /* Current baud for line coding */
+  usbhost_ep_t   bulkin;         /* Bulk IN endpoint */
+  usbhost_ep_t   bulkout;        /* Bulk OUT endpoint */
+
+  /* This is the serial data buffer */
+
+  char           rxbuffer[CONFIG_USBHOST_FT232R_RXBUFSIZE];
+  char           txbuffer[CONFIG_USBHOST_FT232R_TXBUFSIZE];
+};
+
+/* This is how struct usbhost_ft232r_s looks to the free list logic */
+
+struct usbhost_freestate_s
+{
+  FAR struct usbhost_freestate_s *flink;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Semaphores */
+
+static int usbhost_takesem(FAR sem_t *sem);
+static void usbhost_forcetake(FAR sem_t *sem);
+#define usbhost_givesem(s) nxsem_post(s);
+
+/* Memory allocation services */
+
+static FAR struct usbhost_ft232r_s *usbhost_allocclass(void);
+static void usbhost_freeclass(FAR struct usbhost_ft232r_s *usbclass);
+
+/* Device name management */
+
+static int  usbhost_devno_alloc(FAR struct usbhost_ft232r_s *priv);
+static void usbhost_devno_free(FAR struct usbhost_ft232r_s *priv);
+static inline void usbhost_mkdevname(FAR struct usbhost_ft232r_s *priv,
+              FAR char *devname);
+
+/* UART buffer data transfer */
+
+static void usbhost_txdata_work(FAR void *arg);
+static void usbhost_rxdata_work(FAR void *arg);
+
+/* Worker thread actions */
+
+static void usbhost_destroy(FAR void *arg);
+
+/* Helpers for usbhost_connect() */
+
+static int  usbhost_cfgdesc(FAR struct usbhost_ft232r_s *priv,
+              FAR const uint8_t *configdesc, int desclen);
+
+/* (Little Endian) Data helpers */
+
+static inline uint16_t usbhost_getle16(FAR const uint8_t *val);
+static inline uint16_t usbhost_getbe16(FAR const uint8_t *val);
+static inline void usbhost_putle16(FAR uint8_t *dest, uint16_t val);
+
+/* Transfer descriptor memory management */
+
+static int  usbhost_alloc_buffers(FAR struct usbhost_ft232r_s *priv);
+static void usbhost_free_buffers(FAR struct usbhost_ft232r_s *priv);
+
+/* struct usbhost_registry_s methods */
+
+static struct usbhost_class_s *usbhost_create(
+              FAR struct usbhost_hubport_s *hport,
+              FAR const struct usbhost_id_s *id);
+
+/* struct usbhost_class_s methods */
+
+static int  usbhost_connect(FAR struct usbhost_class_s *usbclass,
+              FAR const uint8_t *configdesc, int desclen);
+static int  usbhost_disconnected(FAR struct usbhost_class_s *usbclass);
+
+/* Serial driver lower-half interfaces */
+
+static int  usbhost_setup(FAR struct uart_dev_s *uartdev);
+static void usbhost_shutdown(FAR struct uart_dev_s *uartdev);
+static int  usbhost_attach(FAR struct uart_dev_s *uartdev);
+static void usbhost_detach(FAR struct uart_dev_s *uartdev);
+static int  usbhost_ioctl(FAR struct file *filep, int cmd,
+              unsigned long arg);
+static void usbhost_rxint(FAR struct uart_dev_s *uartdev, bool enable);
+static bool usbhost_rxavailable(FAR struct uart_dev_s *uartdev);
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+static bool usbhost_rxflowcontrol(FAR struct uart_dev_s *uartdev,
+              unsigned int nbuffered, bool upper);
+#endif
+static void usbhost_txint(FAR struct uart_dev_s *uartdev, bool enable);
+static bool usbhost_txready(FAR struct uart_dev_s *uartdev);
+static bool usbhost_txempty(FAR struct uart_dev_s *uartdev);
+
+/* FTDI control transfer helpers */
+
+static int ft232r_ctrlxfer(FAR struct usbhost_ft232r_s *priv, uint8_t req,
+                          uint16_t value, uint16_t index);
+static int ft232r_reset(FAR struct usbhost_ft232r_s *priv, bool purgerxtx);
+static int ft232r_modemctrl(FAR struct usbhost_ft232r_s *priv);
+static int ft232r_setflowctrl(FAR struct usbhost_ft232r_s *priv);
+static int ft232r_setdivisor(uint32_t *divisor, uint32_t baud);
+static int ft232r_setbaud(FAR struct usbhost_ft232r_s *priv);
+static int ft232r_setdata(FAR struct usbhost_ft232r_s *priv);
+static int ft232r_setlat(FAR struct usbhost_ft232r_s *priv);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* This structure provides the registry entry ID information that will  be
+ * used to associate the USB host FTDI class to a connected USB
+ * device.
+ */
+
+static const struct usbhost_id_s g_id[4] =
+{
+  {
+    USB_CLASS_VENDOR_SPEC,  /* base     */
+    0xff,                   /* subclass */
+    0xff,                   /* proto    */
+    0x0403,                 /* vid      */
+    0x6001                  /* pid      */
+  },
+  {
+    USB_CLASS_VENDOR_SPEC,  /* base     */
+    0xff,                   /* subclass */
+    0xff,                   /* proto    */
+    0x0403,                 /* vid      */
+    0x6015                  /* pid      */
+  }
+};
+
+/* This is the USB host FTDI class's registry entry */
+
+static struct usbhost_registry_s g_ft232r =
+{
+  NULL,                   /* flink    */
+  usbhost_create,         /* create   */
+  2,                      /* nids     */
+  &g_id[0]                /* id[]     */
+};
+
+/* Serial driver lower half interface */
+
+static const struct uart_ops_s g_uart_ops =
+{
+  usbhost_setup,         /* setup */
+  usbhost_shutdown,      /* shutdown */
+  usbhost_attach,        /* attach */
+  usbhost_detach,        /* detach */
+  usbhost_ioctl,         /* ioctl */
+  NULL           ,       /* receive */
+  usbhost_rxint,         /* rxinit */
+  usbhost_rxavailable,   /* rxavailable */
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+  usbhost_rxflowcontrol, /* rxflowcontrol */
+#endif
+  NULL,                  /* send */
+  usbhost_txint,         /* txinit */
+  usbhost_txready,       /* txready */
+  usbhost_txempty        /* txempty */
+};
+
+/* This is an array of pre-allocated USB host FTDI class instances */
+
+#if CONFIG_USBHOST_FT232R_NPREALLOC > 0
+static struct usbhost_ft232r_s g_prealloc[CONFIG_USBHOST_FT232R_NPREALLOC];
+#endif
+
+/* This is a list of free, pre-allocated USB host FTDI class instances */
+
+#if CONFIG_USBHOST_FT232R_NPREALLOC > 0
+static FAR struct usbhost_freestate_s *g_freelist;
+#endif
+
+/* This is a bitmap that is used to allocate device
+ * minor numbers /dev/ttyUSB[n].
+ */
+
+static uint32_t g_devinuse;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: usbhost_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 int usbhost_takesem(FAR sem_t *sem)
+{
+  return nxsem_wait_uninterruptible(sem);
+}
+
+/****************************************************************************
+ * Name: usbhost_forcetake
+ *
+ * Description:
+ *   This is just another wrapper but this one continues even if the thread
+ *   is canceled.  This must be done in certain conditions where were must
+ *   continue in order to clean-up resources.
+ *
+ ****************************************************************************/
+
+static void usbhost_forcetake(FAR sem_t *sem)
+{
+  int ret;
+
+  do
+    {
+      ret = nxsem_wait_uninterruptible(sem);
+
+      /* The only expected error would -ECANCELED meaning that the
+       * parent thread has been canceled.  We have to continue and
+       * terminate the poll in this case.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -ECANCELED);
+    }
+  while (ret < 0);
+}
+
+/****************************************************************************
+ * Name: usbhost_allocclass
+ *
+ * Description:
+ *   This is really part of the logic that implements the create() method
+ *   of struct usbhost_registry_s.  This function allocates memory for one
+ *   new class instance.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   On success, this function will return a non-NULL instance of struct
+ *   usbhost_class_s.  NULL is returned on failure; this function will
+ *   will fail only if there are insufficient resources to create another
+ *   USB host class instance.
+ *
+ ****************************************************************************/
+
+#if CONFIG_USBHOST_FT232R_NPREALLOC > 0
+static FAR struct usbhost_ft232r_s *usbhost_allocclass(void)
+{
+  FAR struct usbhost_freestate_s *entry;
+  irqstate_t flags;
+
+  /* We may be executing from an interrupt handler so we need to take one of
+   * our pre-allocated class instances from the free list.
+   */
+
+  flags = enter_critical_section();
+  entry = g_freelist;
+  if (entry)
+    {
+      g_freelist = entry->flink;
+    }
+
+  leave_critical_section(flags);
+  uinfo("Allocated: %p\n", entry);
+  return (FAR struct usbhost_ft232r_s *)entry;
+}
+#else
+static FAR struct usbhost_ft232r_s *usbhost_allocclass(void)
+{
+  FAR struct usbhost_ft232r_s *priv;
+
+  /* We are not executing from an interrupt handler so we can just call
+   * kmm_malloc() to get memory for the class instance.
+   */
+
+  DEBUGASSERT(!up_interrupt_context());
+  priv = (FAR struct usbhost_ft232r_s *)
+    kmm_malloc(sizeof(struct usbhost_ft232r_s));
+
+  uinfo("Allocated: %p\n", priv);
+  return priv;
+}
+#endif
+
+/****************************************************************************
+ * Name: usbhost_freeclass
+ *
+ * Description:
+ *   Free a class instance previously allocated by usbhost_allocclass().
+ *
+ * Input Parameters:
+ *   usbclass - A reference to the class instance to be freed.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#if CONFIG_USBHOST_FT232R_NPREALLOC > 0
+static void usbhost_freeclass(FAR struct usbhost_ft232r_s *usbclass)
+{
+  FAR struct usbhost_freestate_s *entry =
+    (FAR struct usbhost_freestate_s *)usbclass;
+  irqstate_t flags;
+  DEBUGASSERT(entry != NULL);
+
+  uinfo("Freeing: %p\n", entry);
+
+  /* Just put the pre-allocated class structure back on the freelist */
+
+  flags = enter_critical_section();
+  entry->flink = g_freelist;
+  g_freelist = entry;
+  leave_critical_section(flags);
+}
+#else
+static void usbhost_freeclass(FAR struct usbhost_ft232r_s *usbclass)
+{
+  DEBUGASSERT(usbclass != NULL);
+
+  /* Free the class instance (calling kmm_free() in case we are executing
+   * from an interrupt handler.
+   */
+
+  uinfo("Freeing: %p\n", usbclass);
+  kmm_free(usbclass);
+}
+#endif
+
+/****************************************************************************
+ * Name: usbhost_devno_alloc
+ *
+ * Description:
+ *   Allocate a unique /dev/ttyACM[n] minor number in the range 0-31.
+ *
+ ****************************************************************************/
+
+static int usbhost_devno_alloc(FAR struct usbhost_ft232r_s *priv)
+{
+  irqstate_t flags;
+  int devno;
+
+  flags = enter_critical_section();
+  for (devno = 0; devno < 32; devno++)
+    {
+      uint32_t bitno = 1 << devno;
+      if ((g_devinuse & bitno) == 0)
+        {
+          g_devinuse |= bitno;
+          priv->minor = devno;
+          leave_critical_section(flags);
+          return OK;
+        }
+    }
+
+  leave_critical_section(flags);
+  return -EMFILE;
+}
+
+/****************************************************************************
+ * Name: usbhost_devno_free
+ *
+ * Description:
+ *   Free a /dev/ttyACM[n] minor number so that it can be used.
+ *
+ ****************************************************************************/
+
+static void usbhost_devno_free(FAR struct usbhost_ft232r_s *priv)
+{
+  int devno = priv->minor;
+
+  if (devno >= 0 && devno < 32)
+    {
+      irqstate_t flags = enter_critical_section();
+      g_devinuse &= ~(1 << devno);
+      leave_critical_section(flags);
+    }
+}
+
+/****************************************************************************
+ * Name: usbhost_mkdevname
+ *
+ * Description:
+ *   Format a /dev/ttyACM[n] device name given a minor number.
+ *
+ ****************************************************************************/
+
+static inline void usbhost_mkdevname(FAR struct usbhost_ft232r_s *priv,
+                                     FAR char *devname)
+{
+  snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->minor);
+}
+
+/****************************************************************************
+ * Name: ft232r_ctrlxfer
+ *
+ * Description:
+ *   Free a class instance previously allocated by usbhost_allocclass().
+ *
+ * Input Parameters:
+ *   priv  - A reference to the USB host class instance.
+ *   req   - FTDI control transfer type.
+ *   value - Value for control transfer.
+ *   index - Index for control transfer.
+ *
+ * Returned Value:
+ *   0 on success. Negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int ft232r_ctrlxfer(FAR struct usbhost_ft232r_s *priv, uint8_t req,
+                          uint16_t value, uint16_t index)
+{
+  FAR struct usbhost_hubport_s *hport;
+  FAR struct usb_ctrlreq_s *ctrlreq;
+  int ret;
+
+  hport = priv->usbclass.hport;
+  DEBUGASSERT(hport);
+
+  /* Initialize the control request */
+
+  ctrlreq          = (FAR struct usb_ctrlreq_s *)priv->ctrlreq;
+  ctrlreq->type    = USB_DIR_OUT | USB_REQ_TYPE_VENDOR |
+                    USB_REQ_RECIPIENT_DEVICE;
+  ctrlreq->req     = req;
+
+  usbhost_putle16(ctrlreq->value, value);
+  usbhost_putle16(ctrlreq->index, index);
+  usbhost_putle16(ctrlreq->len,   0);
+
+  /* And send the request */
+
+  ret = DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL);
+  if (ret < 0)
+    {
+      uerr("ERROR: DRVR_CTRLOUT failed: %d\n", ret);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: ft232r_reset
+ *
+ * Description:
+ *   Resets the FT232.
+ *
+ * Input Parameters:
+ *   priv  - A reference to the USB host class instance.
+ *   purgerxtx - True if the RX and TX buffers of the FTDI chip
+ *               should be flushed.
+ *
+ * Returned Value:
+ *   0 on success. Negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int ft232r_reset(FAR struct usbhost_ft232r_s *priv, bool purgerxtx)
+{
+  int ret = ft232r_ctrlxfer(priv, USBHOST_FT232R_CTRLREQ_RESET,
+                              purgerxtx, 0);
+  if (ret < 0)
+    {
+      uerr("ERROR: ft232r_ctrlxfer failed: %d\n", ret);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: ft232r_modemctrl
+ *
+ * Description:
+ *   Sets RTS and DTR.
+ *
+ * Input Parameters:
+ *   priv  - A reference to the USB host class instance.
+ *
+ * Returned Value:
+ *   0 on success. Negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int ft232r_modemctrl(FAR struct usbhost_ft232r_s *priv)
+{
+  uint16_t value =  USBHOST_FT232R_MODEMCTRL_VAL_RTS |
+                    USBHOST_FT232R_MODEMCTRL_VAL_DTR |
+                    USBHOST_FT232R_MODEMCTRL_VAL_RTS_EN |
+                    USBHOST_FT232R_MODEMCTRL_VAL_DTR_EN;
+
+  int ret = ft232r_ctrlxfer(priv, USBHOST_FT232R_CTRLREQ_MODEMCTRL,
+                              value, 0);
+  if (ret < 0)
+    {
+      uerr("ERROR: ft232r_ctrlxfer failed: %d\n", ret);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: ft232r_setflowctrl
+ *
+ * Description:
+ *   Enables/ disables hardware flow control.
+ *
+ * Input Parameters:
+ *   priv  - A reference to the USB host class instance.
+ *
+ * Returned Value:
+ *   0 on success. Negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int ft232r_setflowctrl(FAR struct usbhost_ft232r_s *priv)
+{
+  /* upper byte XOFF char, lower byte XON char */
+
+  uint16_t value = 0;
+
+  /* Upper byte: flow control settings.
+   *    0th bit: RTS/CTS flow control.
+   *    1st bit: DTR/DSR flow control.
+   *    2nd bit: XON/XOFF flow control.
+   * Lower byte: 0
+   */
+
+  uint16_t index = 0;
+
+#ifdef CONFIG_USBHOST_FT232R_HWFLOWCTRL
+  index = 0x100;
+#endif
+
+  int ret = ft232r_ctrlxfer(priv, USBHOST_FT232R_CTRLREQ_SETFLOWCTRL,
+                            value, index);
+  if (ret < 0)
+    {
+      uerr("ERROR: ft232r_ctrlxfer failed: %d\n", ret);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: ft232r_setdivisor
+ *
+ * Description:
+ *   Converts a baud rate to the corresponding FT232R divisor. Returns an
+ *   error if the requested baud rate is not possible.
+ *
+ * Input Parameters:
+ *   divisor - Where the calculated divisor will be written to.
+ *   baud    - The requested baud rate.
+ * Returned Value:
+ *   0 on success. Negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int ft232r_setdivisor(uint32_t *divisor, uint32_t baud)
+{
+  int ret = 0;
+
+  /* Deal with special case baud rates: 3MHz and 2MHz */
+
+  if (baud == USBHOST_FT232R_BAUD_3MHZ)
+    {
+      *divisor = 0;
+    }
+  else if (baud == USBHOST_FT232R_BAUD_2MHZ)
+    {
+      *divisor = 1;
+    }
+  else if (baud > USBHOST_FT232R_BAUD_3MHZ / 2)
+    {
+      /* FT232 doesn't support fractional divisors between 0 and 2. */
+
+      ret = -EINVAL;
+    }
+  else
+    {
+      int divfrac[9] = {0,
+                        500,
+                        250,
+                        125,
+                        375,
+                        625,
+                        750,
+                        875,
+                        1000
+                       };
+
+      double frac = (double)USBHOST_FT232R_MAX_BAUD / (double)baud;
+
+      *divisor = (uint32_t)frac;
+      int rem = (frac - *divisor) * 1000.0;
+
+      if (rem > 0)
+        {
+          int i;
+          int j = 0;
+          int closest = rem;
+
+          for (i = 1; i < 9; i++)
+            {
+              if (rem == divfrac[i])
+                {
+                  j = i;
+                  break;
+                }
+
+              if ((rem > divfrac[i] && (rem - divfrac[i]) < closest))
+                {
+                  j = i;
+                  closest = rem - divfrac[i];
+                }
+              else if (rem < divfrac[i] && (divfrac[i] - rem) < closest)
+                {
+                  j = i;
+                  closest = divfrac[i] - rem;
+                }
+            }
+
+          /* Make sure the calculated baud is within 3% of the
+           * requested baud rate.
+           */
+
+          double err = (frac -
+                      (double)(*divisor + (double)divfrac[j] / 1000.0))
+                      / frac;
+          if (err < -0.03 || err > 0.03)
+            {
+              ret = -ENOTSUP;
+            }
+
+          if (j == 9)
+            {
+              *divisor += 1;
+            }
+          else
+            {
+              *divisor |= (j & 0x7) << 14;
+            }
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: ft232r_setbaud
+ *
+ * Description:
+ *   Sets the FT232 baud rate.
+ *
+ * Input Parameters:
+ *   priv  - A reference to the USB host class instance.
+ *
+ * Returned Value:
+ *   0 on success. Negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int ft232r_setbaud(FAR struct usbhost_ft232r_s *priv)
+{
+  /* Convert baud to FT232 divisor */
+
+  uint32_t divisor;
+  int ret = ft232r_setdivisor(&divisor, priv->baud);
+  if (ret < 0)
+    {
+      uerr("ERROR: ft232r_setdivisor failed: %d\n", ret);
+    }
+  else
+    {
+      ret = ft232r_ctrlxfer(priv, USBHOST_FT232R_CTRLREQ_SETBAUD,
+              divisor & 0xffff, divisor && 0x10000);
+      if (ret < 0)
+        {
+          uerr("ERROR: ft232r_ctrlxfer failed: %d\n", ret);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: ft232r_setdata
+ *
+ * Description:
+ *   Sets the packet characteristics for the UART side of the FT232.
+ *
+ * Input Parameters:
+ *   priv  - A reference to the USB host class instance.
+ *
+ * Returned Value:
+ *   0 on success. Negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int ft232r_setdata(FAR struct usbhost_ft232r_s *priv)
+{
+  /* Build up line coding */
+
+  uint16_t linecoding = (priv->nbits & USBHOST_FT232R_SETDATA_NBIT_MASK) |
+      ((priv->parity & USBHOST_FT232R_SETDATA_PARITY_MASK)
+      << USBHOST_FT232R_SETDATA_PARITY_SHIFT);
+  if (priv->stop2)
+    {
+      linecoding |= CONFIG_USBHOST_FT232R_2STOP;
+    }
+
+  int ret = ft232r_ctrlxfer(priv, USBHOST_FT232R_CTRLREQ_SETDATA,
+                            linecoding, 0);
+  if (ret < 0)
+    {
+      uerr("ERROR: ft232r_ctrlxfer failed: %d\n", ret);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: ft232r_setlat
+ *
+ * Description:
+ *   Sets the UART latency of the FT232.
+ *
+ * Input Parameters:
+ *   priv  - A reference to the USB host class instance.
+ *
+ * Returned Value:
+ *   0 on success. Negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int ft232r_setlat(FAR struct usbhost_ft232r_s *priv)
+{
+  int ret = ft232r_ctrlxfer(priv, USBHOST_FT232R_CTRLREQ_SETLATTIMER,
+                            CONFIG_USBHOST_FT232R_LATENCY, 0);
+  if (ret < 0)
+    {
+      uerr("ERROR: ft232r_ctrlxfer failed: %d\n", ret);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * UART buffer data transfer
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: usbhost_txdata_work
+ *
+ * Description:
+ *   Send more OUT data to the attached FTDI device.
+ *
+ * Input Parameters:
+ *   arg - A reference to the FTDI class private data
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void usbhost_txdata_work(FAR void *arg)
+{
+  FAR struct usbhost_ft232r_s *priv;
+  FAR struct usbhost_hubport_s *hport;
+  FAR struct uart_dev_s *uartdev;
+  FAR struct uart_buffer_s *txbuf;
+  ssize_t nwritten;
+  int txndx;
+  int txtail;
+  int ret;
+
+  priv = (FAR struct usbhost_ft232r_s *)arg;
+  DEBUGASSERT(priv);
+
+  hport = priv->usbclass.hport;
+  DEBUGASSERT(hport);
+
+  uartdev = &priv->uartdev;
+  txbuf   = &uartdev->xmit;
+
+  /* Do nothing if TX transmission is disabled */
+
+  if (!priv->txena)
+    {
+      /* Terminate the work now *without* rescheduling */
+
+      return;
+    }
+
+  /* Loop until The UART TX buffer is empty (or we become disconnected) */
+
+  txtail = txbuf->tail;
+  txndx  = 0;
+
+#ifdef CONFIG_USBHOST_FT232R_HWFLOWCTRL
+  while (txtail != txbuf->head && priv->txena &&
+          !priv->disconnected && priv->cts)
+#else
+  while (txtail != txbuf->head && priv->txena && !priv->disconnected)
+#endif
+    {
+      /* Copy data from the UART TX buffer until either 1) the UART TX
+       * buffer has been emptied, or 2) the Bulk OUT buffer is full.
+       */
+
+      txndx = 0;
+      while (txtail != txbuf->head && txndx < priv->pktsize)
+        {
+          /* Copy the next byte */
+
+          priv->outbuf[txndx] = txbuf->buffer[txtail];
+
+          /* Increment counters and indices */
+
+          txndx++;
+          if (++txtail >= txbuf->size)
+            {
+             txtail = 0;
+            }
+        }
+
+      /* Save the updated tail pointer so that it cannot be sent again */
+
+      txbuf->tail = txtail;
+
+      /* Bytes were removed from the TX buffer.  Inform any waiters that
+       * there is space available in the TX buffer.
+       */
+
+      uart_datasent(uartdev);
+
+      /* Send the filled TX buffer to the FTDI device */
+
+      nwritten = DRVR_TRANSFER(hport->drvr, priv->bulkout,
+                               priv->outbuf, txndx);
+      if (nwritten < 0)
+        {
+          /* The most likely reason for a failure is that FTDI device
+           * NAK'ed our packet OR that the device has been disconnected.
+           *
+           * Just break out of the loop, rescheduling the work (unless
+           * the device is disconnected).
+           */
+
+          uerr("ERROR: DRVR_TRANSFER for packet failed: %d\n",
+               (int)nwritten);
+          break;
+        }
+    }
+
+  /* We get here because: 1) the UART TX buffer is empty and there is
+   * nothing more to send, 2) the FTDI device was not ready to accept our
+   * data, or the device is no longer available.
+   *
+   * If the last packet sent was and even multiple of the packet size, then
+   * we need to send a zero length packet (ZLP).
+   */
+
+  if (txndx == priv->pktsize && !priv->disconnected)
+    {
+      /* Send the ZLP to the FTDI device */
+
+      nwritten = DRVR_TRANSFER(hport->drvr, priv->bulkout,
+                               priv->outbuf, 0);
+      if (nwritten < 0)
+        {
+          /* The most likely reason for a failure is that FTDI device
+           * NAK'ed our packet.
+           */
+
+          uerr("ERROR: DRVR_TRANSFER for ZLP failed: %d\n", (int)nwritten);
+        }
+    }
+
+  /* Check again if TX reception is enabled and that the device is still
+   * connected.  These states could have changed since we started the
+   * transfer.
+   */
+
+  if (priv->txena && !priv->disconnected)
+    {
+      /* Schedule TX data work to occur after a delay. */
+
+      ret = work_queue(LPWORK, &priv->txwork, usbhost_txdata_work, priv,
+                       USBHOST_FT232R_TXDELAY);
+      DEBUGASSERT(ret >= 0);
+      UNUSED(ret);
+    }
+}
+
+/****************************************************************************
+ * Name: usbhost_rxdata_work
+ *
+ * Description:
+ *   Get more IN data from the attached FTDI device.
+ *
+ * Input Parameters:
+ *   arg - A reference to the FTDI class private data
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void usbhost_rxdata_work(FAR void *arg)
+{
+  FAR struct usbhost_ft232r_s *priv;
+  FAR struct usbhost_hubport_s *hport;
+  FAR struct uart_dev_s *uartdev;
+  FAR struct uart_buffer_s *rxbuf;
+  ssize_t nread;
+  int nxfrd;
+  int nexthead;
+  int rxndx;
+  int ret;
+
+  priv    = (FAR struct usbhost_ft232r_s *)arg;
+  DEBUGASSERT(priv);
+
+  hport   = priv->usbclass.hport;
+  DEBUGASSERT(hport);
+
+  uartdev = &priv->uartdev;
+  rxbuf   = &uartdev->recv;
+
+  /* Get the index in the RX packet buffer where we will take the first
+   * byte of data.
+   */
+
+  rxndx    = priv->rxndx;
+  nxfrd    = 0;
+
+  /* Get the index to the value of the UART RX buffer head AFTER the
+   * first character has been stored.  We need to know this in order
+   * to test if the UART RX buffer is full.
+   */
+
+  nexthead = rxbuf->head + 1;
+  if (nexthead >= rxbuf->size)
+    {
+      nexthead = 0;
+    }
+
+  /* Loop until either:
+   *
+   * 1. The UART RX buffer is full
+   * 2. There is no more data available from the FTDI device
+   * 3. RX rec
+   */
+
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+  while (priv->rxena && priv->rts && !priv->disconnected)
+#else
+  while (priv->rxena && !priv->disconnected)
+#endif
+    {
+      /* Stop now if there is no room for another
+       * character in the RX buffer.
+       */
+
+      if (nexthead == rxbuf->tail)
+        {
+          /* Break out of the loop, rescheduling the work */
+
+          break;
+        }
+
+      /* Do we have any buffer RX data to transfer? */
+
+      if (priv->nrxbytes < 1)
+        {
+          /* No.. Read more data from the FTDI device */
+
+          nread = DRVR_TRANSFER(hport->drvr, priv->bulkin,
+                                priv->inbuf, priv->pktsize);
+          if (nread < 0)
+            {
+              /* The most likely reason for a failure is that the has no
+               * data available now and NAK'ed the IN token OR that the
+               * transfer was cancelled because the device was disconnected.
+               *
+               * Just break out of the loop, rescheduling the work (if the
+               * device was not disconnected.
+               */
+
+              uerr("ERROR: DRVR_TRANSFER for packet failed: %d\n",
+                   (int)nread);
+              break;
+            }
+
+          /* Save the number of bytes read.  This might be zero if
+           * a Zero Length Packet (ZLP) is received.  The ZLP is
+           * part of the bulk transfer protocol, but otherwise of
+           * no interest to us. Alternatively it can be 2 bytes of
+           * only FTDI status information.
+           */
+
+          priv->nrxbytes = (uint16_t)nread - 2;
+          rxndx          = 0;
+
+          /* When Hardware flow control is used, CTS is reported in the
+           * first byte of RX payload.
+           */
+
+#ifdef CONFIG_USBHOST_FT232R_HWFLOWCTRL
+          if (nread >= 2)
+            {
+              priv->cts = priv->inbuf[0] & 0x10;
+            }
+#endif
+
+          /* Ignore ZLPs and RX of only FTDI status */
+
+          if (nread < 3)
+            {
+              continue;
+            }
+        }
+
+      /* Transfer one byte from the RX packet buffer into UART RX buffer */
+
+      rxbuf->buffer[rxbuf->head] = priv->inbuf[rxndx + 2]; /* +2 to account 
for the two status byes */
+      nxfrd++;
+
+      /* Save the updated indices */
+
+      rxbuf->head = nexthead;
+      priv->rxndx = rxndx;
+
+      /* Update the head point for for the next pass through the loop
+       * handling. If nexthead incremented to rxbuf->tail, then the
+       * RX buffer will and we will exit the loop at the top.
+       */
+
+      if (++nexthead >= rxbuf->size)
+        {
+           nexthead = 0;
+        }
+
+      /* Increment the index in the USB IN packet buffer.  If the
+       * index becomes equal to the number of bytes in the buffer, then
+       * we have consumed all of the RX data.
+       */
+
+      if (++rxndx >= priv->nrxbytes)
+        {
+          /* In that case set the number of bytes in the buffer to zero.
+           * This will force re-reading on the next time through the loop.
+           */
+
+          priv->nrxbytes = 0;
+          priv->rxndx    = 0;
+
+          /* Inform any waiters there there is new incoming data available. */
+
+          uart_datareceived(uartdev);
+          nxfrd = 0;
+        }
+    }
+
+  /* We break out to here:  1) the UART RX buffer is full, 2) the FTDI
+   * device is not ready to provide us with more serial data, or 3) the
+   * device has been disconnected.
+   *
+   * Check if the device is still available:  RX enabled, no RX flow
+   * control in effect, and that the device is not disconnected. These
+   * states could have changed since we started the transfer.
+   */
+
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+  if (priv->rxena && priv->rts && work_available(&priv->rxwork) &&
+      !priv->disconnected)
+#else
+  if (priv->rxena && work_available(&priv->rxwork) && !priv->disconnected)
+#endif
+    {
+      /* Schedule RX data reception work to occur after a delay.  This will
+       * affect our responsive in certain cases.  The delayed work, however,
+       * will be cancelled and replaced with immediate work when the upper
+       * layer demands more data.
+       */
+
+      ret = work_queue(LPWORK, &priv->rxwork, usbhost_rxdata_work, priv,
+                       USBHOST_FT232R_RXDELAY);
+      DEBUGASSERT(ret >= 0);
+      UNUSED(ret);
+    }
+
+  /* If any bytes were added to the buffer, inform any waiters there there
+   * is new incoming data available.
+   */
+
+  if (nxfrd)
+    {
+      uart_datareceived(uartdev);
+    }
+}
+
+/****************************************************************************
+ * Name: usbhost_destroy
+ *
+ * Description:
+ *   The USB FTDI device has been disconnected and the reference count
+ *   on the USB host class instance has gone to 1.. Time to destroy the USB
+ *   host class instance.
+ *
+ * Input Parameters:
+ *   arg - A reference to the class instance to be destroyed.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void usbhost_destroy(FAR void *arg)
+{
+  FAR struct usbhost_ft232r_s *priv = (FAR struct usbhost_ft232r_s *)arg;
+  FAR struct usbhost_hubport_s *hport;
+  char devname[DEV_NAMELEN];
+
+  DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL);
+  hport = priv->usbclass.hport;
+
+  uinfo("crefs: %d\n", priv->crefs);
+
+  /* Unregister the serial lower half driver */
+
+  usbhost_mkdevname(priv, devname);
+  unregister_driver(devname);
+
+  /* Release the device name used by this connection */
+
+  usbhost_devno_free(priv);
+
+  /* Free the allocated endpoints */
+
+  if (priv->bulkout)
+    {
+      DRVR_EPFREE(hport->drvr, priv->bulkout);
+    }
+
+  if (priv->bulkin)
+    {
+      DRVR_EPFREE(hport->drvr, priv->bulkin);
+    }
+
+  /* Free any transfer buffers */
+
+  usbhost_free_buffers(priv);
+
+  /* Destroy the semaphores */
+
+  nxsem_destroy(&priv->exclsem);
+
+  /* Disconnect the USB host device */
+
+  DRVR_DISCONNECT(hport->drvr, hport);
+
+  /* Free the function address assigned to this device */
+
+  usbhost_devaddr_destroy(hport, hport->funcaddr);
+  hport->funcaddr = 0;
+
+  /* And free the class instance.  */
+
+  usbhost_freeclass(priv);
+}
+
+/****************************************************************************
+ * Name: usbhost_cfgdesc
+ *
+ * Description:
+ *   This function implements the connect() method of struct
+ *   usbhost_class_s.  This method is a callback into the class
+ *   implementation.  It is used to provide the device's configuration
+ *   descriptor to the class so that the class may initialize properly
+ *
+ * Input Parameters:
+ *   priv - The USB host class instance.
+ *   configdesc - A pointer to a uint8_t buffer container the configuration
+ *     descriptor.
+ *   desclen - The length in bytes of the configuration descriptor.
+ *
+ * Returned Value:
+ *   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 usbhost_cfgdesc(FAR struct usbhost_ft232r_s *priv,
+                           FAR const uint8_t *configdesc, int desclen)
+{
+  FAR struct usbhost_hubport_s *hport;
+  FAR struct usb_cfgdesc_s *cfgdesc;
+  FAR struct usb_desc_s *desc;
+  struct usbhost_epdesc_s bindesc;
+  struct usbhost_epdesc_s boutdesc;
+  struct usbhost_epdesc_s iindesc;
+  int remaining;
+  uint8_t found  = 0;
+  uint8_t currif = 0;
+  int ret;
+
+  DEBUGASSERT(priv != NULL && priv->usbclass.hport &&
+              configdesc != NULL && desclen >= sizeof(struct usb_cfgdesc_s));
+  hport = priv->usbclass.hport;
+
+  /* Keep the compiler from complaining about uninitialized variables */
+
+  memset(&bindesc, 0, sizeof(struct usbhost_epdesc_s));
+  memset(&boutdesc, 0, sizeof(struct usbhost_epdesc_s));
+  memset(&iindesc, 0, sizeof(struct usbhost_epdesc_s));
+
+  /* Verify that we were passed a configuration descriptor */
+
+  cfgdesc = (FAR struct usb_cfgdesc_s *)configdesc;
+  if (cfgdesc->type != USB_DESC_TYPE_CONFIG)
+    {
+      return -EINVAL;
+    }
+
+  /* Get the total length of the configuration descriptor (little endian).
+   * It might be a good check to get the number of interfaces here too.
+   */
+
+  remaining = (int)usbhost_getle16(cfgdesc->totallen);
+
+  /* Skip to the next entry descriptor */
+
+  configdesc += cfgdesc->len;
+  remaining  -= cfgdesc->len;
+
+  /* Loop where there are more descriptors to examine */
+
+  while (remaining >= sizeof(struct usb_desc_s))
+    {
+      /* What is the next descriptor? */
+
+      desc = (FAR struct usb_desc_s *)configdesc;
+      switch (desc->type)
+        {
+        /* Interface descriptor. The FTDI device may include two
+         * interfaces:
+         *
+         * 1) A data interface which consists of two endpoints (bulk in +
+         *    bulk out) and
+         * 2) A control interface which consists of one interrupt in
+         *    endpoint.
+         */
+
+        case USB_DESC_TYPE_INTERFACE:
+          {
+            FAR struct usb_ifdesc_s *ifdesc =
+              (FAR struct usb_ifdesc_s *)configdesc;
+
+            uinfo("Interface descriptor: class: %d subclass: %d proto: %d\n",
+                  ifdesc->classid, ifdesc->subclass, ifdesc->protocol);
+            DEBUGASSERT(remaining >= USB_SIZEOF_IFDESC);
+
+            /* Check for the FTDI data interface */
+
+            if (ifdesc->classid == USB_CLASS_VENDOR_SPEC &&
+                (found & USBHOST_DATAIF_FOUND) == 0)
+              {
+                /* Save the data interface number and mark that the data
+                 * interface found has been found.
+                 */
+
+                priv->dataif  = ifdesc->ifno;
+                found        |= USBHOST_DATAIF_FOUND;
+                currif        = USBHOST_DATAIF_FOUND;
+              }
+            else
+              {
+                /* Its something else */
+
+                currif        = 0;
+              }
+          }
+          break;
+
+        /* Endpoint descriptor.  We expect two bulk endpoints, an IN and an
+         * OUT.
+         */
+
+        case USB_DESC_TYPE_ENDPOINT:
+          {
+            FAR struct usb_epdesc_s *epdesc =
+              (FAR struct usb_epdesc_s *)configdesc;
+
+            uinfo("Endpoint descriptor: currif: %02x attr: %02x\n",
+                  currif, epdesc->attr);
+            DEBUGASSERT(remaining >= USB_SIZEOF_EPDESC);
+
+            /* Check for a bulk endpoint. */
+
+            if (currif == USBHOST_DATAIF_FOUND &&
+                (epdesc->attr & USB_EP_ATTR_XFERTYPE_MASK) ==
+                USB_EP_ATTR_XFER_BULK)
+              {
+                /* Yes.. it is a bulk endpoint.  IN or OUT? */
+
+                if (USB_ISEPOUT(epdesc->addr))
+                  {
+                    /* It is an OUT bulk endpoint.  There should be only one
+                     * bulk OUT endpoint.
+                     */
+
+                    if ((found & USBHOST_BULKOUT_FOUND) != 0)
+                      {
+                        /* Oops.. more than one endpoint.  We don't know
+                         * what to do with this.
+                         */
+
+                        return -EINVAL;
+                      }
+
+                    found |= USBHOST_BULKOUT_FOUND;
+
+                    /* Save the bulk OUT endpoint information */
+
+                    boutdesc.hport        = hport;
+                    boutdesc.addr         = epdesc->addr &
+                                            USB_EP_ADDR_NUMBER_MASK;
+                    boutdesc.in           = false;
+                    boutdesc.xfrtype      = USB_EP_ATTR_XFER_BULK;
+                    boutdesc.interval     = epdesc->interval;
+                    boutdesc.mxpacketsize =
+                      usbhost_getle16(epdesc->mxpacketsize);
+
+                    uinfo("Bulk OUT EP addr:%d mxpacketsize:%d\n",
+                          boutdesc.addr, boutdesc.mxpacketsize);
+                  }
+                else
+                  {
+                    /* It is an IN bulk endpoint.  There should be only one
+                     * bulk IN endpoint.
+                     */
+
+                    if ((found & USBHOST_BULKIN_FOUND) != 0)
+                      {
+                        /* Oops.. more than one endpoint.  We don't know
+                         * what to do with this.
+                         */
+
+                        return -EINVAL;
+                      }
+
+                    found |= USBHOST_BULKIN_FOUND;
+
+                    /* Save the bulk IN endpoint information */
+
+                    bindesc.hport        = hport;
+                    bindesc.addr         = epdesc->addr &
+                                           USB_EP_ADDR_NUMBER_MASK;
+                    bindesc.in           = 1;
+                    bindesc.xfrtype      = USB_EP_ATTR_XFER_BULK;
+                    bindesc.interval     = epdesc->interval;
+                    bindesc.mxpacketsize =
+                      usbhost_getle16(epdesc->mxpacketsize);
+
+                    uinfo("Bulk IN EP addr:%d mxpacketsize:%d\n",
+                          bindesc.addr, bindesc.mxpacketsize);
+                  }
+              }
+          }
+          break;
+
+        /* Other descriptors are just ignored for now */
+
+        default:
+          break;
+        }
+
+      /* If we found everything we need with this interface, then break out
+       * of the loop early.
+       */
+
+      if (found == USBHOST_ALLFOUND)
+        {
+          break;
+        }
+
+      /* Increment the address of the next descriptor */
+
+      configdesc += desc->len;
+      remaining  -= desc->len;
+    }
+
+  /* Sanity checking... did we find all of things that we needed for the
+   * FT232R interface?
+   */
+
+  if (found != USBHOST_ALLFOUND)
+    {
+      uerr("ERROR: Found DATA IF:%s BULK IN:%s BULK OUT:%s\n",
+           (found & USBHOST_DATAIF_FOUND)  != 0  ? "YES" : "NO",
+           (found & USBHOST_BULKIN_FOUND)  != 0 ? "YES" : "NO",
+           (found & USBHOST_BULKOUT_FOUND) != 0 ? "YES" : "NO");
+      return -EINVAL;
+    }
+
+  /* We are good... Allocate the endpoints */
+
+  ret = DRVR_EPALLOC(hport->drvr, &boutdesc, &priv->bulkout);
+  if (ret < 0)
+    {
+      uerr("ERROR: Failed to allocate Bulk OUT endpoint\n");
+      return ret;
+    }
+
+  ret = DRVR_EPALLOC(hport->drvr, &bindesc, &priv->bulkin);
+  if (ret < 0)
+    {
+      uerr("ERROR: Failed to allocate Bulk IN endpoint\n");
+      DRVR_EPFREE(hport->drvr, priv->bulkout);
+      return ret;
+    }
+
+  uinfo("Endpoints allocated\n");
+  return OK;
+}
+
+/****************************************************************************
+ * Name: usbhost_getle16
+ *
+ * Description:
+ *   Get a (possibly unaligned) 16-bit little endian value.
+ *
+ * Input Parameters:
+ *   val - A pointer to the first byte of the little endian value.
+ *
+ * Returned Value:
+ *   A uint16_t representing the whole 16-bit integer value
+ *
+ ****************************************************************************/
+
+static inline uint16_t usbhost_getle16(FAR const uint8_t *val)
+{
+  return (uint16_t)val[1] << 8 | (uint16_t)val[0];
+}
+
+/****************************************************************************
+ * Name: usbhost_getbe16
+ *
+ * Description:
+ *   Get a (possibly unaligned) 16-bit big endian value.
+ *
+ * Input Parameters:
+ *   val - A pointer to the first byte of the big endian value.
+ *
+ * Returned Value:
+ *   A uint16_t representing the whole 16-bit integer value
+ *
+ ****************************************************************************/
+
+static inline uint16_t usbhost_getbe16(FAR const uint8_t *val)
+{
+  return (uint16_t)val[0] << 8 | (uint16_t)val[1];
+}
+
+/****************************************************************************
+ * Name: usbhost_putle16
+ *
+ * Description:
+ *   Put a (possibly unaligned) 16-bit little endian value.
+ *
+ * Input Parameters:
+ *   dest - A pointer to the first byte to save the little endian value.
+ *   val - The 16-bit value to be saved.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void usbhost_putle16(FAR uint8_t *dest, uint16_t val)
+{
+  dest[0] = val & 0xff; /* Little endian means LS byte first in byte stream */
+  dest[1] = val >> 8;
+}
+
+/****************************************************************************
+ * Name: usbhost_alloc_buffers
+ *
+ * Description:
+ *   Allocate transfer buffer memory.
+ *
+ * Input Parameters:
+ *   priv - A reference to the class instance.
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned.  On failure, an negated errno value
+ *   is returned to indicate the nature of the failure.
+ *
+ ****************************************************************************/
+
+static int usbhost_alloc_buffers(FAR struct usbhost_ft232r_s *priv)
+{
+  FAR struct usbhost_hubport_s *hport;
+  size_t maxlen;
+  int ret;
+
+  DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL);
+  hport = priv->usbclass.hport;
+
+  /* Allocate memory for control requests */
+
+  ret = DRVR_ALLOC(hport->drvr, (FAR uint8_t **)&priv->ctrlreq, &maxlen);
+  if (ret < 0)
+    {
+      uerr("ERROR: DRVR_ALLOC of ctrlreq failed: %d\n", ret);
+      goto errout;
+    }
+
+  DEBUGASSERT(maxlen >= sizeof(struct usb_ctrlreq_s));
+
+  /* Set the size of Bulk IN and OUT buffers to the max packet size */
+
+  priv->pktsize = (hport->speed == USB_SPEED_HIGH) ? 512 : 64;
+
+  /* Allocate a RX buffer for Bulk IN transfers */
+
+  ret = DRVR_IOALLOC(hport->drvr, &priv->inbuf, priv->pktsize);
+  if (ret < 0)
+    {
+      uerr("ERROR: DRVR_IOALLOC of Bulk IN buffer failed: %d (%d bytes)\n",
+           ret, priv->pktsize);
+      goto errout;
+    }
+
+  /* Allocate a TX buffer for Bulk IN transfers */
+
+  ret = DRVR_IOALLOC(hport->drvr, &priv->outbuf, priv->pktsize);
+  if (ret < 0)
+    {
+      uerr("ERROR: DRVR_IOALLOC of Bulk OUT buffer failed: %d (%d bytes)\n",
+           ret, priv->pktsize);
+      goto errout;
+    }
+
+  return OK;
+
+errout:
+  usbhost_free_buffers(priv);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: usbhost_free_buffers
+ *
+ * Description:
+ *   Free transfer buffer memory.
+ *
+ * Input Parameters:
+ *   priv - A reference to the class instance.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void usbhost_free_buffers(FAR struct usbhost_ft232r_s *priv)
+{
+  FAR struct usbhost_hubport_s *hport;
+
+  DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL);
+  hport = priv->usbclass.hport;
+
+  if (priv->ctrlreq)
+    {
+      DRVR_FREE(hport->drvr, priv->ctrlreq);
+    }
+
+  if (priv->inbuf)
+    {
+      DRVR_IOFREE(hport->drvr, priv->inbuf);
+    }
+
+  if (priv->outbuf)
+    {
+      DRVR_IOFREE(hport->drvr, priv->outbuf);
+    }
+
+  priv->pktsize      = 0;
+  priv->ctrlreq      = NULL;
+  priv->inbuf        = NULL;
+  priv->outbuf       = NULL;
+}
+
+/****************************************************************************
+ * struct usbhost_registry_s methods
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: usbhost_create
+ *
+ * Description:
+ *   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 create() method will support environments
+ *   where there may be multiple USB ports and multiple USB devices
+ *   simultaneously connected.
+ *
+ * Input Parameters:
+ *   hport - The hub port that manages the new class instance.
+ *   id - In the case where the device supports multiple base classes,
+ *     subclasses, or protocols, this specifies which to configure for.
+ *
+ * Returned Value:
+ *   On success, this function will return a non-NULL instance of struct
+ *   usbhost_class_s that can be used by the USB host driver to communicate
+ *   with the USB host class.  NULL is returned on failure; this function
+ *   will fail only if the hport input parameter is NULL or if there are
+ *   insufficient resources to create another USB host class instance.
+ *
+ ****************************************************************************/
+
+static FAR struct usbhost_class_s *
+usbhost_create(FAR struct usbhost_hubport_s *hport,
+               FAR const struct usbhost_id_s *id)
+{
+  FAR struct usbhost_ft232r_s *priv;
+  FAR struct uart_dev_s *uartdev;
+
+  /* Allocate a USB host FTDI class instance */
+
+  priv = usbhost_allocclass();
+  if (priv)
+    {
+      /* Initialize the allocated FTDI class instance */
+
+      memset(priv, 0, sizeof(struct usbhost_ft232r_s));
+
+      /* Assign a device number to this class instance */
+
+      if (usbhost_devno_alloc(priv) == OK)
+        {
+          /* Initialize class method function pointers */
+
+          priv->usbclass.hport        = hport;
+          priv->usbclass.connect      = usbhost_connect;
+          priv->usbclass.disconnected = usbhost_disconnected;
+
+          /* The initial reference count is 1...
+           * One reference is held by the driver
+           */
+
+          priv->crefs = 1;
+
+          /* Initialize semaphores
+           * (this works okay in the interrupt context)
+           */
+
+          nxsem_init(&priv->exclsem, 0, 1);
+
+          /* Set up the serial lower-half interface */
+
+          uartdev              = &priv->uartdev;
+          uartdev->recv.size   = CONFIG_USBHOST_FT232R_RXBUFSIZE;
+          uartdev->recv.buffer = priv->rxbuffer;
+          uartdev->xmit.size   = CONFIG_USBHOST_FT232R_TXBUFSIZE;
+          uartdev->xmit.buffer = priv->txbuffer;
+          uartdev->ops         = &g_uart_ops;
+          uartdev->priv        = priv;
+
+          /* Set up the initial line status */
+
+          priv->baud           = CONFIG_USBHOST_FT232R_BAUD;
+          priv->nbits          = CONFIG_USBHOST_FT232R_BITS;
+          priv->parity         = CONFIG_USBHOST_FT232R_PARITY;
+          priv->stop2          = CONFIG_USBHOST_FT232R_2STOP;
+
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+          priv->rts            = true;
+#endif
+
+          /* Return the instance of the USB FTDI class */
+
+          return &priv->usbclass;
+        }
+    }
+
+  /* An error occurred. Free the allocation and return NULL on all failures */
+
+  if (priv)
+    {
+      usbhost_freeclass(priv);
+    }
+
+  return NULL;
+}
+
+/****************************************************************************
+ * struct usbhost_class_s methods
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: usbhost_connect
+ *
+ * Description:
+ *   This function implements the connect() method of struct
+ *   usbhost_class_s.  This method is a callback into the class
+ *   implementation.  It is used to provide the device's configuration
+ *   descriptor to the class so that the class may initialize properly
+ *
+ * Input Parameters:
+ *   usbclass - The USB host class entry previously obtained from a call to
+ *     create().
+ *   configdesc - A pointer to a uint8_t buffer container the configuration
+ *     descriptor.
+ *   desclen - The length in bytes of the configuration descriptor.
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned. On a failure, a negated errno value
+ *   is returned indicating the nature of the failure
+ *
+ *   NOTE that the class instance remains valid upon return with a failure.
+ *   It is the responsibility of the higher level enumeration logic to call
+ *   CLASS_DISCONNECTED to free up the class driver resources.
+ *
+ * Assumptions:
+ *   - This function will *not* be called from an interrupt handler.
+ *   - If this function returns an error, the USB host controller driver
+ *     must call to DISCONNECTED method to recover from the error
+ *
+ ****************************************************************************/
+
+static int usbhost_connect(FAR struct usbhost_class_s *usbclass,
+                           FAR const uint8_t *configdesc, int desclen)
+{
+  FAR struct usbhost_ft232r_s *priv =
+                  (FAR struct usbhost_ft232r_s *)usbclass;
+  char devname[DEV_NAMELEN];
+  int ret;
+
+  DEBUGASSERT(priv != NULL &&
+              configdesc != NULL &&
+              desclen >= sizeof(struct usb_cfgdesc_s));
+
+  /* Get exclusive access to the device structure */
+
+  ret = usbhost_takesem(&priv->exclsem);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Increment the reference count.  This will prevent usbhost_destroy() from
+   * being called asynchronously if the device is removed.
+   */
+
+  priv->crefs++;
+  DEBUGASSERT(priv->crefs == 2);
+
+  /* Parse the configuration descriptor to get the bulk I/O endpoints */
+
+  ret = usbhost_cfgdesc(priv, configdesc, desclen);
+  if (ret < 0)
+    {
+      uerr("ERROR: usbhost_cfgdesc() failed: %d\n", ret);
+      goto errout;
+    }
+
+  /* Set aside a transfer buffer for exclusive use by the FTDI driver */
+
+  ret = usbhost_alloc_buffers(priv);
+  if (ret < 0)
+    {
+      uerr("ERROR: Failed to allocate transfer buffer\n");
+      goto errout;
+    }
+
+  /* Send the initial line encoding */
+
+  ret = ft232r_reset(priv, true);
+  if (ret < 0)
+    {
+      uerr("ERROR: ft232r_reset() failed: %d\n", ret);
+    }
+
+  ret = ft232r_setflowctrl(priv);
+  if (ret < 0)
+    {
+      uerr("ERROR: ft232r_setflowctrl() failed: %d\n", ret);
+    }
+
+  ret = ft232r_modemctrl(priv);
+  if (ret < 0)
+    {
+      uerr("ERROR: ft232r_modemctrl() failed: %d\n", ret);
+    }
+
+  ret = ft232r_setbaud(priv);
+  if (ret < 0)
+    {
+      uerr("ERROR: ft232r_setbaud() failed: %d\n", ret);
+    }
+
+  ret = ft232r_setdata(priv);
+  if (ret < 0)
+    {
+      uerr("ERROR: ft232r_setdata() failed: %d\n", ret);
+    }
+
+  ret = ft232r_setlat(priv);
+  if (ret < 0)
+    {
+      uerr("ERROR: ft232r_setlat() failed: %d\n", ret);
+    }
+
+  /* Register the lower half serial instance with the upper half serial
+   * driver.
+   */
+
+  usbhost_mkdevname(priv, devname);
+  uinfo("Register device: %s\n", devname);
+
+  ret = uart_register(devname, &priv->uartdev);
+  if (ret < 0)
+    {
+      uerr("ERROR: uart_register() failed: %d\n", ret);
+      goto errout;
+    }
+
+errout:
+  /* Decrement the reference count.  We incremented the reference count
+   * above so that usbhost_destroy() could not be called.  We now have to
+   * be concerned about asynchronous modification of crefs because the
+   * serial driver has been registered.
+   */
+
+  DEBUGASSERT(priv->crefs >= 2);
+  priv->crefs--;
+
+  /* Release the semaphore... there is a race condition here.
+   * Decrementing the reference count and releasing the semaphore
+   * allows usbhost_destroy() to execute (on the worker thread);
+   * the class driver instance could get destroyed before we are
+   * ready to handle it!
+   */
+
+  usbhost_givesem(&priv->exclsem);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: usbhost_disconnected
+ *
+ * Description:
+ *   This function implements the disconnected() method of struct
+ *   usbhost_class_s.  This method is a callback into the class
+ *   implementation.  It is used to inform the class that the USB device has
+ *   been disconnected.
+ *
+ * Input Parameters:
+ *   usbclass - The USB host class entry previously obtained from a call to
+ *     create().
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned. On a failure, a negated errno value
+ *   is returned indicating the nature of the failure
+ *
+ * Assumptions:
+ *   This function may be called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static int usbhost_disconnected(FAR struct usbhost_class_s *usbclass)
+{
+  FAR struct usbhost_ft232r_s *priv =
+    (FAR struct usbhost_ft232r_s *)usbclass;
+  irqstate_t flags;
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set an indication to any users of the FTDI device that the device
+   * is no longer available.
+   */
+
+  flags              = enter_critical_section();
+  priv->disconnected = true;
+
+  /* Let the upper half driver know that serial device is no longer
+   * connected.
+   */
+
+  uart_connected(&priv->uartdev, false);
+
+  /* Now check the number of references on the class instance.  If it is one,
+   * then we can free the class instance now.  Otherwise, we will have to
+   * wait until the holders of the references free them by closing the
+   * serial driver.
+   */
+
+  uinfo("crefs: %d\n", priv->crefs);
+  if (priv->crefs == 1)
+    {
+      /* Destroy the class instance.  If we are executing from an interrupt
+       * handler, then defer the destruction to the worker thread.
+       * Otherwise, destroy the instance now.
+       */
+
+      if (up_interrupt_context())
+        {
+          /* Destroy the instance on the worker thread. */
+
+          uinfo("Queuing destruction: worker %p->%p\n",
+                priv->ntwork.worker, usbhost_destroy);
+
+          DEBUGASSERT(work_available(&priv->ntwork));
+          work_queue(HPWORK, &priv->ntwork, usbhost_destroy, priv, 0);
+        }
+      else
+        {
+          /* Do the work now */
+
+          usbhost_destroy(priv);
+        }
+    }
+
+  leave_critical_section(flags);
+  return OK;
+}
+
+/****************************************************************************
+ * Serial Lower-Half Interfaces
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: usbhost_setup
+ *
+ * Description:
+ *   Configure the USART baud, bits, parity, etc. This method is called the
+ *   first time that the serial port is opened.
+ *
+ ****************************************************************************/
+
+static int usbhost_setup(FAR struct uart_dev_s *uartdev)
+{
+  FAR struct usbhost_ft232r_s *priv;
+  irqstate_t flags;
+  int ret;
+
+  uinfo("Entry\n");
+  DEBUGASSERT(uartdev && uartdev->priv);
+  priv = (FAR struct usbhost_ft232r_s *)uartdev->priv;
+
+  /* Make sure that we have exclusive access to the private data structure */
+
+  DEBUGASSERT(priv->crefs > 0 && priv->crefs < USBHOST_MAX_CREFS);
+  ret = usbhost_takesem(&priv->exclsem);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Check if the FTDI device is still connected.  We need to disable
+   * interrupts momentarily to assure that there are no asynchronous
+   * isconnect events.
+   */
+
+  flags = enter_critical_section();
+  if (priv->disconnected)
+    {
+      /* No... the block driver is no longer bound to the class.  That means
+       * that the USB FTDI device is no longer connected.  Refuse any
+       * further attempts to open the driver.
+       */
+
+      ret = -ENODEV;
+    }
+  else
+    {
+      /* Otherwise, just increment the reference count on the driver */
+
+      priv->crefs++;
+      ret = OK;
+    }
+
+  leave_critical_section(flags);
+  usbhost_givesem(&priv->exclsem);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: usbhost_shutdown
+ *
+ * Description:
+ *   Disable the USART.  This method is called when the serial
+ *   port is closed
+ *
+ ****************************************************************************/
+
+static void usbhost_shutdown(FAR struct uart_dev_s *uartdev)
+{
+  FAR struct usbhost_ft232r_s *priv;
+  irqstate_t flags;
+
+  uinfo("Entry\n");
+  DEBUGASSERT(uartdev && uartdev->priv);
+  priv = (FAR struct usbhost_ft232r_s *)uartdev->priv;
+
+  /* Decrement the reference count on the block driver */
+
+  DEBUGASSERT(priv->crefs > 1);
+  usbhost_forcetake(&priv->exclsem);
+  priv->crefs--;
+
+  /* Release the semaphore.  The following operations when crefs == 1 are
+   * safe because we know that there is no outstanding open references to
+   * the block driver.
+   */
+
+  usbhost_givesem(&priv->exclsem);
+
+  /* We need to disable interrupts momentarily to assure that there are
+   * no asynchronous disconnect events.
+   */
+
+  flags = enter_critical_section();
+
+  /* Check if the USB FTDI device is still connected.  If the
+   * FTDI device is not connected and the reference count just
+   * decremented to one, then unregister the block driver and free
+   * the class instance.
+   */
+
+  if (priv->crefs <= 1 && priv->disconnected)
+    {
+      /* Destroy the class instance */
+
+      DEBUGASSERT(priv->crefs == 1);
+      usbhost_destroy(priv);
+    }
+
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: usbhost_attach
+ *
+ * Description:
+ *   Configure the USART to operation in interrupt driven mode.  This method
+ *   is called when the serial port is opened.  Normally, this is just after
+ *   the setup() method is called, however, the serial console may operate in
+ *   a non-interrupt driven mode during the boot phase.
+ *
+ *   RX and TX interrupts are not enabled when by the attach method (unless
+ *   the hardware supports multiple levels of interrupt enabling).  The RX
+ *   and TX interrupts are not enabled until the txint() and rxint() methods
+ *   are called.
+ *
+ ****************************************************************************/
+
+static int usbhost_attach(FAR struct uart_dev_s *uartdev)
+{
+  return OK;
+}
+
+/****************************************************************************
+ * Name: usbhost_detach
+ *
+ * Description:
+ *   Detach USART interrupts.  This method is called when the serial port is
+ *   closed normally just before the shutdown method is called.  The
+ *   exception is the serial console which is never shutdown.
+ *
+ ****************************************************************************/
+
+static void usbhost_detach(FAR struct uart_dev_s *uartdev)
+{
+}
+
+/****************************************************************************
+ * Name: usbhost_ioctl
+ *
+ * Description:
+ *   All ioctl calls will be routed through this method
+ *
+ ****************************************************************************/
+
+static int usbhost_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
+{
+  FAR struct inode *inode;
+  FAR struct usbhost_ft232r_s *priv;
+  FAR struct uart_dev_s *uartdev;
+  int ret = 0;
+
+  uinfo("Entry\n");
+  DEBUGASSERT(filep && filep->f_inode);
+  inode = filep->f_inode;
+
+  DEBUGASSERT(inode && inode->i_private);
+  uartdev = (FAR struct uart_dev_s *)inode->i_private;
+
+  DEBUGASSERT(uartdev && uartdev->priv);
+  priv  = (FAR struct usbhost_ft232r_s *)uartdev->priv;
+
+  /* Check if the FTDI device is still connected */
+
+  if (priv->disconnected)
+    {
+      /* No... the serial device has been disconnecgted.  Refuse to process
+       * any ioctl commands.
+       */
+
+      ret = -ENODEV;
+    }
+  else
+    {
+      /* Process the IOCTL by command */
+
+      ret = usbhost_takesem(&priv->exclsem);
+      if (ret < 0)
+        {
+          return ret;
+        }
+
+      switch (cmd)
+        {
+#ifdef CONFIG_SERIAL_TIOCSERGSTRUCT
+        case TIOCSERGSTRUCT:
+          {
+            FAR struct usbhost_ft232r_s *user =
+              (FAR struct usbhost_ft232r_s *)arg;
+            if (!user)
+              {
+                ret = -EINVAL;
+              }
+            else
+              {
+                memcpy(user, uartdev, sizeof(struct usbhost_ft232r_s));
+              }
+          }
+          break;
+#endif
+
+#ifdef CONFIG_SERIAL_TERMIOS
+        case TCGETS:
+          {
+            FAR struct termios *termiosp = (FAR struct termios *)arg;
+
+            if (!termiosp)
+              {
+                ret = -EINVAL;
+                break;
+              }
+
+            cfsetispeed(termiosp, priv->baud);
+
+            termiosp->c_cflag =
+              ((priv->parity != 0) ? PARENB : 0) |
+              ((priv->parity == 1) ? PARODD : 0) |
+              ((priv->stop2) ? CSTOPB : 0)
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+              | ((priv->oflow) ? CCTS_OFLOW : 0)
+#endif
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+              | ((priv->iflow) ? CRTS_IFLOW : 0)
+#endif
+              ;
+
+            switch (priv->nbits)
+              {
+              case 7:
+                termiosp->c_cflag |= CS7;
+                break;
+
+              default:
+              case 8:
+                termiosp->c_cflag |= CS8;
+                break;
+              }
+          }
+          break;
+
+        case TCSETS:
+          {
+            FAR struct termios *termiosp = (FAR struct termios *)arg;
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+            bool iflow;
+#endif
+
+            if (!termiosp)
+              {
+                ret = -EINVAL;
+                break;
+              }
+
+            if (termiosp->c_cflag & PARENB)
+              {
+                priv->parity = (termiosp->c_cflag & PARODD) ? 1 : 2;
+              }
+            else
+               {
+                priv->parity = 0;
+              }
+
+            priv->stop2 = (termiosp->c_cflag & CSTOPB) != 0;
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+            priv->oflow = (termiosp->c_cflag & CCTS_OFLOW) != 0;
+#endif
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+            iflow       = priv->iflow;
+            priv->iflow = (termiosp->c_cflag & CRTS_IFLOW) != 0;
+#endif
+
+            switch (termiosp->c_cflag & CSIZE)
+              {
+              case CS7:
+                priv->nbits = 7;
+                break;
+
+              default:
+              case CS8:
+                priv->nbits = 8;
+                break;
+              }
+
+            /* Note that only cfgetispeed is used because we have knowledge
+             * that only one speed is supported.
+             */
+
+            priv->baud = cfgetispeed(termiosp);
+
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+            /* Set RTS if input flow control changed */
+
+            if (iflow != !priv->iflow)
+              {
+                 priv->rts = true;
+              }
+#endif
+
+            ret = ft232r_setbaud(priv);
+            if (ret < 0)
+              {
+                uerr("ERROR: ft232r_setbaud failed: %d\n", ret);
+              }
+
+            ret = ft232r_setdata(priv);
+            if (ret < 0)
+              {
+                uerr("ERROR: ft232r_setdata failed: %d\n", ret);
+              }
+
+            ret = ft232r_setflowctrl(priv);
+            if (ret < 0)
+              {
+                uerr("ERROR: ft232r_setflowctrl failed: %d\n", ret);
+              }
+          }
+
+          break;
+
+#endif /* CONFIG_SERIAL_TERMIOS */
+
+        default:
+          ret = -ENOTTY;
+          break;
+        }
+
+      usbhost_givesem(&priv->exclsem);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: usbhost_rxint
+ *
+ * Description:
+ *   Call to enable or disable RX interrupts
+ *
+ ****************************************************************************/
+
+static void usbhost_rxint(FAR struct uart_dev_s *uartdev, bool enable)
+{
+  FAR struct usbhost_ft232r_s *priv;
+  int ret;
+
+  DEBUGASSERT(uartdev && uartdev->priv);
+  priv = (FAR struct usbhost_ft232r_s *)uartdev->priv;
+
+  /* Are we enabling or disabling RX reception? */
+
+  if (enable && !priv->rxena)
+    {
+      /* Cancel any pending, delayed RX data reception work */
+
+      work_cancel(LPWORK, &priv->rxwork);
+
+      /* Restart immediate RX data reception work (unless RX flow control
+       * is in effect.
+       */
+
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+      if (priv->rts)
+#endif
+        {
+          ret = work_queue(LPWORK, &priv->rxwork,
+                           usbhost_rxdata_work, priv, 0);
+          DEBUGASSERT(ret >= 0);
+          UNUSED(ret);
+        }
+    }
+  else if (!enable && priv->rxena)
+    {
+      /* Cancel any pending RX data reception work */
+
+      work_cancel(LPWORK, &priv->rxwork);
+    }
+
+  /* Save the new RX enable state */
+
+  priv->rxena = enable;
+}
+
+/****************************************************************************
+ * Name: usbhost_rxavailable
+ *
+ * Description:
+ *   Return true if the receive buffer is not empty
+ *
+ ****************************************************************************/
+
+static bool usbhost_rxavailable(FAR struct uart_dev_s *uartdev)
+{
+  FAR struct usbhost_ft232r_s *priv;
+
+  DEBUGASSERT(uartdev && uartdev->priv);
+  priv = (FAR struct usbhost_ft232r_s *)uartdev->priv;
+  return (priv->nrxbytes > 0);
+}
+
+/****************************************************************************
+ * Name: usbhost_rxflowcontrol
+ *
+ * Description:
+ *   Called when Rx buffer is full (or exceeds configured watermark levels
+ *   if CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS is defined).
+ *   Return true if UART activated RX flow control to block more incoming
+ *   data
+ *
+ * Input Parameters:
+ *   uartdev   - UART device instance
+ *   nbuffered - the number of characters currently buffered
+ *               (if CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS is
+ *               not defined the value will be 0 for an empty buffer or the
+ *               defined buffer size for a full buffer)
+ *   upper     - true indicates the upper watermark was crossed where
+ *               false indicates the lower watermark has been crossed
+ *
+ * Returned Value:
+ *   true if RX flow control activated.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+static bool usbhost_rxflowcontrol(FAR struct uart_dev_s *uartdev,
+                                  unsigned int nbuffered, bool upper)
+{
+  FAR struct usbhost_ft232r_s *priv;
+  bool newrts;
+  int ret;
+
+  DEBUGASSERT(uartdev && uartdev->priv);
+  priv = (FAR struct usbhost_ft232r_s *)uartdev->priv
+
+  /* Is RX flow control enabled? */
+
+  if (!priv->iflow)
+    {
+      /* Now.. make sure that RTS is set */
+
+      priv->rts = true;
+      return false;
+    }
+
+  /* Are we enabling or disabling RX flow control? */
+
+  if (priv->rts && upper)
+    {
+      /* RX flow control is not in effect (RTS is true) but we have just
+       * crossed the upper threshold, meaning that we should now clear
+       * RTS.
+       */
+
+      priv->rts = false;
+
+      /* Cancel any pending RX data reception work */
+
+      work_cancel(LPWORK, &priv->rxwork);
+      return true;
+    }
+  else if (!priv->rts && !upper)
+    {
+      /* RX flow control is in effect (RTS is false) and we have just
+       * crossed the lower threshold, meaning that we should now set
+       * RTS.
+       */
+
+       priv->rts = true;
+
+      /* Restart RX data reception work flow unless RX reception is
+       * disabled.
+       */
+
+      if (priv->rxena && work_available(&priv->rxwork))
+        {
+          ret = work_queue(LPWORK, &priv->rxwork,
+                           usbhost_rxdata_work, priv, 0);
+          DEBUGASSERT(ret >= 0);
+          UNUSED(ret);
+        }
+
+      return false;
+    }
+}
+#endif
+
+/****************************************************************************
+ * Name: usbhost_txint
+ *
+ * Description:
+ *   Call to enable or disable TX interrupts
+ *
+ ****************************************************************************/
+
+static void usbhost_txint(FAR struct uart_dev_s *uartdev, bool enable)
+{
+  FAR struct usbhost_ft232r_s *priv;
+  int ret;
+
+  DEBUGASSERT(uartdev && uartdev->priv);
+  priv = (FAR struct usbhost_ft232r_s *)uartdev->priv;
+
+  /* Are we enabling or disabling TX transmission? */
+
+  if (enable && !priv->txena)
+    {
+      /* Cancel any pending, delayed TX data transmission work */
+
+      work_cancel(LPWORK, &priv->txwork);
+
+      /* Restart immediate TX data transmission work */
+
+      ret = work_queue(LPWORK, &priv->txwork,
+                       usbhost_txdata_work, priv, 0);
+      DEBUGASSERT(ret >= 0);
+      UNUSED(ret);
+    }
+  else if (!enable && priv->txena)
+    {
+      /* Cancel any pending TX data transmission work */
+
+      work_cancel(LPWORK, &priv->txwork);
+    }
+
+  /* Save the new TX enable state */
+
+  priv->txena = enable;
+}
+
+/****************************************************************************
+ * Name: usbhost_txready
+ *
+ * Description:
+ *   Return true if the transmit data register is not full.
+ *
+ ****************************************************************************/
+
+static bool usbhost_txready(FAR struct uart_dev_s *uartdev)
+{
+  return true;
+}
+
+/****************************************************************************
+ * Name: usbhost_txempty
+ *
+ * Description:
+ *   Return true if the transmit data buffer is empty
+ *
+ ****************************************************************************/
+
+static bool usbhost_txempty(FAR struct uart_dev_s *uartdev)
+{
+  return true;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: usbhost_ft232r_initialize
+ *
+ * Description:
+ *   Initialize the USB host FTDI. This function should be called
+ *   by platform-specific code in order to initialize and register support
+ *   for the FT232.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   On success this function will return zero (OK);  A negated errno value
+ *   will be returned on failure.
+ *
+ ****************************************************************************/
+
+int usbhost_ft232r_initialize(void)
+{
+  /* If we have been configured to use pre-allocated FTDI class instances,
+   * then place all of the pre-allocated USB host FTDI class instances
+   * into a free list.
+   */
+
+#if CONFIG_USBHOST_FT232R_NPREALLOC > 0
+  FAR struct usbhost_freestate_s *entry;
+  int i;
+
+  g_freelist = NULL;
+  for (i = 0; i < CONFIG_USBHOST_FT232R_NPREALLOC; i++)
+    {
+      entry        = (FAR struct usbhost_freestate_s *)&g_prealloc[i];
+      entry->flink = g_freelist;
+      g_freelist   = entry;
+    }
+#endif
+
+  /* Advertise our availability to support (certain) FTDI devices */
+
+  return usbhost_registerclass(&g_ft232r);
+}
+
+#endif /* CONFIG_USBHOST_FT232R */
diff --git a/include/nuttx/usb/usbhost.h b/include/nuttx/usb/usbhost.h
index 7baf5d2..b1f06fd 100644
--- a/include/nuttx/usb/usbhost.h
+++ b/include/nuttx/usb/usbhost.h
@@ -77,12 +77,12 @@
  * Name: CLASS_CREATE
  *
  * Description:
- *   This macro will call 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 create() method will support
- *   environments where there may be multiple USB ports and multiple USB 
devices
- *   simultaneously connected.
+ *   This macro will call 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 create() 
method
+ *   will support environments where there may be multiple USB ports and 
multiple
+ *   USB devices simultaneously connected.
  *
  * Input Parameters:
  *   reg - The USB host class registry entry previously obtained from a call to
@@ -112,14 +112,16 @@
  *
  * Description:
  *   This macro will call the connect() method of struct usbhost_class_s.  This
- *   method is a callback into the devclass implementation.  It is used to 
provide the
- *   device's configuration descriptor to the devclass so that the devclass 
may initialize
- *   properly
+ *   method is a callback into the devclass implementation.  It is used to 
provide
+ *   the device's configuration descriptor to the devclass so that the 
devclass may
+ *   initialize properly.
  *
  * Input Parameters:
- *   devclass - The USB host class entry previously obtained from a call to 
create().
- *   configdesc - A pointer to a uint8_t buffer container the configuration 
descriptor.
- *   desclen - The length in bytes of the configuration descriptor.
+ *   devclass   - The USB host class entry previously obtained from a call
+ *                to create().
+ *   configdesc - A pointer to a uint8_t buffer containing the configuration
+ *                descriptor.
+ *   desclen    - The length in bytes of the configuration descriptor.
  *
  * Returned Value:
  *   On success, zero (OK) is returned. On a failure, a negated errno value is
@@ -163,7 +165,7 @@
 
 #define CLASS_DISCONNECTED(devclass) ((devclass)->disconnected(devclass))
 
-/****************************************************************************
+/************************************************************************************
  * Name: CONN_WAIT
  *
  * Description:
@@ -186,7 +188,7 @@
  *   - Called from a single thread so no mutual exclusion is required.
  *   - Never called from an interrupt handler.
  *
- ****************************************************************************/
+ 
************************************************************************************/
 
 #define CONN_WAIT(conn,hport) ((conn)->wait(conn,hport))
 
@@ -644,8 +646,8 @@ struct usbhost_id_s
  * connected to the USB port.
  */
 
-struct usbhost_hubport_s;    /* Forward reference to the hub state structure */
-struct usbhost_class_s;  /* Forward reference to the class state structure */
+struct usbhost_hubport_s;   /* Forward reference to the hub state structure */
+struct usbhost_class_s;     /* Forward reference to the class state structure 
*/
 struct usbhost_registry_s
 {
   /* This field is used to implement a singly-link registry structure.  
Because of
@@ -730,9 +732,9 @@ struct usbhost_roothubport_s
 
 struct usbhost_class_s
 {
- /* Class instances are associated with devices connected on one port on a
-  * hub and are represented by this structure.
-  */
+  /* Class instances are associated with devices connected on one port on a
+   * hub and are represented by this structure.
+   */
 
   FAR struct usbhost_hubport_s *hport;  /* The port used by this class 
instance */
 
@@ -985,7 +987,7 @@ const struct usbhost_registry_s *
   usbhost_findclass(FAR const struct usbhost_id_s *id);
 
 #ifdef CONFIG_USBHOST_HUB
- /****************************************************************************
+ 
/***********************************************************************************
  * Name: usbhost_hub_initialize
  *
  * Description:
@@ -1000,13 +1002,13 @@ const struct usbhost_registry_s *
  *   On success this function will return zero (OK);  A negated errno value
  *   will be returned on failure.
  *
- ****************************************************************************/
+ 
************************************************************************************/
 
 int usbhost_hub_initialize(void);
 #endif
 
 #ifdef CONFIG_USBHOST_MSC
-/****************************************************************************
+/************************************************************************************
  * Name: usbhost_msc_initialize
  *
  * Description:
@@ -1021,13 +1023,13 @@ int usbhost_hub_initialize(void);
  *   On success this function will return zero (OK);  A negated errno value
  *   will be returned on failure.
  *
- ****************************************************************************/
+ 
************************************************************************************/
 
 int usbhost_msc_initialize(void);
 #endif
 
 #ifdef CONFIG_USBHOST_CDCACM
-/****************************************************************************
+/************************************************************************************
  * Name: usbhost_cdcacm_initialize
  *
  * Description:
@@ -1042,13 +1044,34 @@ int usbhost_msc_initialize(void);
  *   On success this function will return zero (OK);  A negated errno value
  *   will be returned on failure.
  *
- ****************************************************************************/
+ 
************************************************************************************/
 
 int usbhost_cdcacm_initialize(void);
 #endif
 
+#ifdef CONFIG_USBHOST_FT232R
+/************************************************************************************
+ * Name: usbhost_ft232r_initialize
+ *
+ * Description:
+ *   Initialize the USB FT232R driver.  This function should be called
+ *   be platform-specific code in order to initialize and register support
+ *   for the FT232R.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   On success this function will return zero (OK);  A negated errno value
+ *   will be returned on failure.
+ *
+ 
************************************************************************************/
+
+int usbhost_ft232r_initialize(void);
+#endif
+
 #ifdef CONFIG_USBHOST_HIDKBD
-/****************************************************************************
+/************************************************************************************
  * Name: usbhost_kbdinit
  *
  * Description:
@@ -1063,13 +1086,13 @@ int usbhost_cdcacm_initialize(void);
  *   On success this function will return zero (OK);  A negated errno value
  *   will be returned on failure.
  *
- ****************************************************************************/
+ 
************************************************************************************/
 
 int usbhost_kbdinit(void);
 #endif
 
 #ifdef CONFIG_USBHOST_HIDMOUSE
-/****************************************************************************
+/************************************************************************************
  * Name: usbhost_mouse_init
  *
  * Description:
@@ -1084,13 +1107,13 @@ int usbhost_kbdinit(void);
  *   On success this function will return zero (OK);  A negated errno value
  *   will be returned on failure.
  *
- ****************************************************************************/
+ 
************************************************************************************/
 
 int usbhost_mouse_init(void);
 #endif
 
 #ifdef CONFIG_USBHOST_XBOXCONTROLLER
-/****************************************************************************
+/************************************************************************************
  * Name: usbhost_xboxcontroller_init
  *
  * Description:
@@ -1105,12 +1128,12 @@ int usbhost_mouse_init(void);
  *   On success this function will return zero (OK);  A negated errno value
  *   will be returned on failure.
  *
- ****************************************************************************/
+ 
************************************************************************************/
 
 int usbhost_xboxcontroller_init(void);
 #endif
 
-/****************************************************************************
+/************************************************************************************
  * Name: usbhost_wlaninit
  *
  * Description:
@@ -1125,11 +1148,11 @@ int usbhost_xboxcontroller_init(void);
  *   On success this function will return zero (OK);  A negated errno value
  *   will be returned on failure.
  *
- ****************************************************************************/
+ 
************************************************************************************/
 
 int usbhost_wlaninit(void);
 
-/****************************************************************************
+/************************************************************************************
  * Name: usbhost_enumerate
  *
  * Description:
@@ -1161,7 +1184,7 @@ int usbhost_wlaninit(void);
  *   - Called from a single thread so no mutual exclusion is required.
  *   - Never called from an interrupt handler.
  *
- ****************************************************************************/
+ 
************************************************************************************/
 
 int usbhost_enumerate(FAR struct usbhost_hubport_s *hub,
                       FAR struct usbhost_class_s **devclass);

Reply via email to