diff --git a/ChangeLog b/ChangeLog
index 5c57f6aea5cf7da507b9b03ed11204cc1e026e2d..29199d4a1fb3b396dfbb7db52b0692dca6ecdf7a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -485,6 +485,9 @@
 	* Add an option to set aside a separate stack for interrupt handling (ARM only).
 	  This is useful when memory is constrained, there are multiple tasks, and
 	  the interrupt stack requirement is high (as when USB is enabled).
+	* Basic LPC214x USB device side driver basically functional (but probably still buggy)
+	* Initial USB serial class device side driver check in (not well tested at initial checkin)
+	* Add LPC214x USB serial configuration; Add examples/usbserial test (still a work in progress)
 
 
 
diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html
index b405c52df6345633eb611ac102ecb34a773b81a7..9e4b2ce0addcb3b994522bde0a583c099b9f016f 100644
--- a/Documentation/NuttX.html
+++ b/Documentation/NuttX.html
@@ -1075,6 +1075,9 @@ nuttx-0.3.16 2008-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
 	* Add an option to set aside a separate stack for interrupt handling (ARM only).
 	  This is useful when memory is constrained, there are multiple tasks, and
 	  the interrupt stack requirement is high (as when USB is enabled).
+	* Basic LPC214x USB device side driver basically functional (but probably still buggy)
+	* Initial USB serial class device side driver check in (not well tested at initial checkin)
+	* Add LPC214x USB serial configuration; Add examples/usbserial test (still a work in progress)
 
 pascal-0.1.3 2008-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
 
diff --git a/arch/arm/src/lpc214x/lpc214x_usbdev.c b/arch/arm/src/lpc214x/lpc214x_usbdev.c
index b2780c775a0522954dde6e7776da6074d6eaa6f4..4141f4a3954b01012e668ea65a020f1abe8cd83a 100644
--- a/arch/arm/src/lpc214x/lpc214x_usbdev.c
+++ b/arch/arm/src/lpc214x/lpc214x_usbdev.c
@@ -1014,11 +1014,21 @@ static int lpc214x_wrrequest(struct lpc214x_ep_s *privep)
   uvdbg("len=%d xfrd=%d nullpkt=%d\n",
         privreq->req.len, privreq->req.xfrd, privep->txnullpkt);
 
-  /* Ignore any attempt to send a zero length packet */
+  /* Ignore any attempt to send a zero length packet on anything but EP0IN */
 
   if (privreq->req.len == 0)
     {
-      usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_EPINNULLPACKET), 0);
+      if (privep->epphy == LPC214X_EP0_IN)
+        {
+          lpc214x_epwrite(LPC214X_EP0_IN, NULL, 0);
+        }
+      else
+        {
+          usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_EPINNULLPACKET), 0);
+        }
+
+      /* In any event, the request is complete */
+
       lpc214x_reqcomplete(privep, OK);
       return OK;
     }
@@ -1390,6 +1400,8 @@ static void lpc214x_dispatchrequest(struct lpc214x_usbdev_s *priv,
   usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_DISPATCH), 0);
   if (priv && priv->driver)
     {
+      /* Forward to the control request to the class driver implementation */
+
       ret = CLASS_SETUP(priv->driver, &priv->usbdev, ctrl);
       if (ret < 0)
         {
@@ -1414,7 +1426,9 @@ static inline void lpc214x_ep0setup(struct lpc214x_usbdev_s *priv)
   struct lpc214x_ep_s *ep0 = &priv->eplist[LPC214X_EP0_OUT];
   struct lpc214x_req_s *privreq = lpc214x_rqpeek(ep0);
   struct usb_ctrlreq_s ctrl;
+  uint16 value;
   uint16 index;
+  uint16 len;
   ubyte  epphy;
   ubyte  response[2];
   int    ret;
@@ -1454,9 +1468,14 @@ static inline void lpc214x_ep0setup(struct lpc214x_usbdev_s *priv)
       return;
     }
 
+  /* And extract the little-endian 16-bit values to host order */
+
+  value = GETUINT16(ctrl.value);
+  index = GETUINT16(ctrl.index);
+  len   = GETUINT16(ctrl.len);
+
   uvdbg("type=%02x req=%02x value=%04x index=%04x len=%04x\n",
-        ctrl.type, ctrl.req,
-        GETUINT16(ctrl.value), GETUINT16(ctrl.index), GETUINT16(ctrl.len));
+        ctrl.type, ctrl.req, value, index, len);
 
   /* Dispatch any non-standard requests */
 
@@ -1481,8 +1500,8 @@ static inline void lpc214x_ep0setup(struct lpc214x_usbdev_s *priv)
          */
 
         usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_GETSTATUS), 0);
-        if (!priv->paddrset || GETUINT16(ctrl.len) != 2 ||
-            (ctrl.type & USB_REQ_DIR_IN) == 0 || GETUINT16(ctrl.value) != 0)
+        if (!priv->paddrset || len != 2 ||
+            (ctrl.type & USB_REQ_DIR_IN) == 0 || value != 0)
           {
             priv->stalled = 1;
           }
@@ -1493,7 +1512,7 @@ static inline void lpc214x_ep0setup(struct lpc214x_usbdev_s *priv)
               case USB_REQ_RECIPIENT_ENDPOINT:
                 {
                   usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPGETSTATUS), 0);
-                  epphy = USB_EPNO(GETUINT16(ctrl.index)) << 1;
+                  epphy = USB_EPNO(index) << 1;
                   if (epphy < LPC214X_NPHYSENDPOINTS)
                     {
                        if ((lpc214x_usbcmd(CMD_USB_EP_SELECT|epphy, 0) & CMD_USB_EPSELECT_ST) != 0)
@@ -1518,7 +1537,6 @@ static inline void lpc214x_ep0setup(struct lpc214x_usbdev_s *priv)
 
               case USB_REQ_RECIPIENT_DEVICE:
                 {
-                  index = GETUINT16(ctrl.index);
                   if (index == 0)
                     {
                       usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_DEVGETSTATUS), 0);
@@ -1573,10 +1591,10 @@ static inline void lpc214x_ep0setup(struct lpc214x_usbdev_s *priv)
           {
             lpc214x_dispatchrequest(priv, &ctrl);
           }
-        else if (priv->paddrset && GETUINT16(ctrl.value) == USB_FEATURE_ENDPOINTHALT &&
-                 GETUINT16(ctrl.index) < LPC214X_NLOGENDPOINTS && GETUINT16(ctrl.len) == 0)
+        else if (priv->paddrset != 0 && value == USB_FEATURE_ENDPOINTHALT &&
+                 index < LPC214X_NLOGENDPOINTS && len == 0)
           {
-            ubyte epphys = LPC214X_EP_LOG2PHY(GETUINT16(ctrl.index));
+            ubyte epphys = LPC214X_EP_LOG2PHY(index);
             priv->eplist[epphys].halted = 0;
             lpc214x_epwrite(LPC214X_EP0_IN, NULL, 0);
             priv->ep0state = LPC214X_EP0STATUSIN;
@@ -1599,18 +1617,18 @@ static inline void lpc214x_ep0setup(struct lpc214x_usbdev_s *priv)
 
         usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_SETFEATURE), 0);
         if (((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE) &&
-            GETUINT16(ctrl.value) == USB_FEATURE_TESTMODE)
+            value == USB_FEATURE_TESTMODE)
           {
-            uvdbg("test mode: %d\n", GETUINT16(ctrl.index));
+            uvdbg("test mode: %d\n", index);
           }
         else if ((ctrl.type & USB_REQ_RECIPIENT_MASK) != USB_REQ_RECIPIENT_ENDPOINT)
           {
            lpc214x_dispatchrequest(priv, &ctrl);
           }
-        else if (priv->paddrset && GETUINT16(ctrl.value) == USB_FEATURE_ENDPOINTHALT &&
-                 GETUINT16(ctrl.index) < LPC214X_NLOGENDPOINTS && GETUINT16(ctrl.len) == 0)
+        else if (priv->paddrset != 0 && value == USB_FEATURE_ENDPOINTHALT &&
+                 index < LPC214X_NLOGENDPOINTS && len == 0)
           {
-            ubyte epphys = LPC214X_EP_LOG2PHY(GETUINT16(ctrl.index));
+            ubyte epphys = LPC214X_EP_LOG2PHY(index);
             priv->eplist[epphys].halted = 1;
             lpc214x_epwrite(LPC214X_EP0_IN, NULL, 0);
             priv->ep0state = LPC214X_EP0STATUSIN;
@@ -1631,10 +1649,9 @@ static inline void lpc214x_ep0setup(struct lpc214x_usbdev_s *priv)
          * len:   0; data = none
          */
 
-        usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EP0SETUPSETADDRESS), GETUINT16(ctrl.value));
+        usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EP0SETUPSETADDRESS), value);
         if ((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE &&
-            GETUINT16(ctrl.index)  == 0 && GETUINT16(ctrl.len) == 0 &&
-            GETUINT16(ctrl.value) < 128)
+            index  == 0 && len == 0 && value < 128)
           {
             /* Save the address.  We cannot actually change to the next address until
              * the completion of the status phase.
@@ -1699,8 +1716,7 @@ static inline void lpc214x_ep0setup(struct lpc214x_usbdev_s *priv)
       {
         usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_GETCONFIG), 0);
         if (priv->paddrset && (ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE &&
-            GETUINT16(ctrl.value) == 0 && GETUINT16(ctrl.index) == 0 &&
-            GETUINT16(ctrl.len) == 1)
+            value == 0 && index == 0 && len == 1)
           {
             lpc214x_dispatchrequest(priv, &ctrl);
           }
@@ -1721,7 +1737,7 @@ static inline void lpc214x_ep0setup(struct lpc214x_usbdev_s *priv)
       {
         usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_SETCONFIG), 0);
         if ((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE &&
-            GETUINT16(ctrl.index) == 0 && GETUINT16(ctrl.len) == 0)
+            index == 0 && len == 0)
           {
             lpc214x_dispatchrequest(priv, &ctrl);
           }
diff --git a/configs/mcu123-lpc214x/nsh/defconfig b/configs/mcu123-lpc214x/nsh/defconfig
index cf194adf12875e8df55c492b3706dcbc144554ec..266577649e78f4e172302154fa89629c8774584b 100644
--- a/configs/mcu123-lpc214x/nsh/defconfig
+++ b/configs/mcu123-lpc214x/nsh/defconfig
@@ -398,8 +398,8 @@ CONFIG_USBSER_EPOUT=1
 CONFIG_USBSER_EPIN=2
 CONFIG_USBSER_NWRREQS=4
 CONFIG_USBSER_NRDREQS=4
-CONFIG_USBSER_VENDORID=0x0525
-CONFIG_USBSER_PRODUCTID=0xa4a6
+CONFIG_USBSER_VENDORID=0x067b
+CONFIG_USBSER_PRODUCTID=0x2303
 CONFIG_USBSER_VENDORSTR="Nuttx"
 CONFIG_USBSER_PRODUCTSTR="USBdev Serial"
 CONFIG_USBSER_RXBUFSIZE=512
diff --git a/configs/mcu123-lpc214x/ostest/defconfig b/configs/mcu123-lpc214x/ostest/defconfig
index fdbabd3ed27f5e4023af9408556de8bcf7742d70..f0fe2f49af455fe1fe92f2ccb3b68d72bfcf056c 100644
--- a/configs/mcu123-lpc214x/ostest/defconfig
+++ b/configs/mcu123-lpc214x/ostest/defconfig
@@ -398,8 +398,8 @@ CONFIG_USBSER_EPOUT=1
 CONFIG_USBSER_EPIN=2
 CONFIG_USBSER_NWRREQS=4
 CONFIG_USBSER_NRDREQS=4
-CONFIG_USBSER_VENDORID=0x0525
-CONFIG_USBSER_PRODUCTID=0xa4a6
+CONFIG_USBSER_VENDORID=0x067b
+CONFIG_USBSER_PRODUCTID=0x2303
 CONFIG_USBSER_VENDORSTR="Nuttx"
 CONFIG_USBSER_PRODUCTSTR="USBdev Serial"
 CONFIG_USBSER_RXBUFSIZE=512
diff --git a/configs/ntosd-dm320/nettest/defconfig b/configs/ntosd-dm320/nettest/defconfig
index a176359491e417e2dcc36c64993fb57de5966bee..934b6d6d89700c516425a267078fdf5c2ed756e1 100644
--- a/configs/ntosd-dm320/nettest/defconfig
+++ b/configs/ntosd-dm320/nettest/defconfig
@@ -375,8 +375,8 @@ CONFIG_USBSER_EPOUT=1
 CONFIG_USBSER_EPIN=2
 CONFIG_USBSER_NWRREQS=4
 CONFIG_USBSER_NRDREQS=4
-CONFIG_USBSER_VENDORID=0x0525
-CONFIG_USBSER_PRODUCTID=0xa4a6
+CONFIG_USBSER_VENDORID=0x067b
+CONFIG_USBSER_PRODUCTID=0x2303
 CONFIG_USBSER_VENDORSTR="Nuttx"
 CONFIG_USBSER_PRODUCTSTR="USBdev Serial"
 CONFIG_USBSER_RXBUFSIZE=512
diff --git a/configs/ntosd-dm320/nsh/defconfig b/configs/ntosd-dm320/nsh/defconfig
index 4fb6c47bb973d5003e389813359974cd69402c9e..bfe69b341e493ecad559d89288e48b19ab930b26 100644
--- a/configs/ntosd-dm320/nsh/defconfig
+++ b/configs/ntosd-dm320/nsh/defconfig
@@ -383,8 +383,8 @@ CONFIG_USBSER_EPOUT=1
 CONFIG_USBSER_EPIN=2
 CONFIG_USBSER_NWRREQS=4
 CONFIG_USBSER_NRDREQS=4
-CONFIG_USBSER_VENDORID=0x0525
-CONFIG_USBSER_PRODUCTID=0xa4a6
+CONFIG_USBSER_VENDORID=0x067b
+CONFIG_USBSER_PRODUCTID=0x2303
 CONFIG_USBSER_VENDORSTR="Nuttx"
 CONFIG_USBSER_PRODUCTSTR="USBdev Serial"
 CONFIG_USBSER_RXBUFSIZE=512
diff --git a/configs/ntosd-dm320/ostest/defconfig b/configs/ntosd-dm320/ostest/defconfig
index a8ac562d8de14312861db2502d2ca82e3cb18149..b50367d0df9d9ba10567cea966195e95ae295232 100644
--- a/configs/ntosd-dm320/ostest/defconfig
+++ b/configs/ntosd-dm320/ostest/defconfig
@@ -375,8 +375,8 @@ CONFIG_USBSER_EPOUT=1
 CONFIG_USBSER_EPIN=2
 CONFIG_USBSER_NWRREQS=4
 CONFIG_USBSER_NRDREQS=4
-CONFIG_USBSER_VENDORID=0x0525
-CONFIG_USBSER_PRODUCTID=0xa4a6
+CONFIG_USBSER_VENDORID=0x067b
+CONFIG_USBSER_PRODUCTID=0x2303
 CONFIG_USBSER_VENDORSTR="Nuttx"
 CONFIG_USBSER_PRODUCTSTR="USBdev Serial"
 CONFIG_USBSER_RXBUFSIZE=512
diff --git a/configs/ntosd-dm320/udp/defconfig b/configs/ntosd-dm320/udp/defconfig
index d4c02d7eca2a23961edcef2ae285c40623eefe3c..d90659a4d48af1c045c5238182d2387add50517d 100644
--- a/configs/ntosd-dm320/udp/defconfig
+++ b/configs/ntosd-dm320/udp/defconfig
@@ -375,8 +375,8 @@ CONFIG_USBSER_EPOUT=1
 CONFIG_USBSER_EPIN=2
 CONFIG_USBSER_NWRREQS=4
 CONFIG_USBSER_NRDREQS=4
-CONFIG_USBSER_VENDORID=0x0525
-CONFIG_USBSER_PRODUCTID=0xa4a6
+CONFIG_USBSER_VENDORID=0x067b
+CONFIG_USBSER_PRODUCTID=0x2303
 CONFIG_USBSER_VENDORSTR="Nuttx"
 CONFIG_USBSER_PRODUCTSTR="USBdev Serial"
 CONFIG_USBSER_RXBUFSIZE=512
diff --git a/configs/ntosd-dm320/uip/defconfig b/configs/ntosd-dm320/uip/defconfig
index 9f19366e862e4b584b915e19acab8d7d78e721b6..b69b86749de4fdb6aa7231ca8ff91b8b90d905ec 100644
--- a/configs/ntosd-dm320/uip/defconfig
+++ b/configs/ntosd-dm320/uip/defconfig
@@ -375,8 +375,8 @@ CONFIG_USBSER_EPOUT=1
 CONFIG_USBSER_EPIN=2
 CONFIG_USBSER_NWRREQS=4
 CONFIG_USBSER_NRDREQS=4
-CONFIG_USBSER_VENDORID=0x0525
-CONFIG_USBSER_PRODUCTID=0xa4a6
+CONFIG_USBSER_VENDORID=0x067b
+CONFIG_USBSER_PRODUCTID=0x2303
 CONFIG_USBSER_VENDORSTR="Nuttx"
 CONFIG_USBSER_PRODUCTSTR="USBdev Serial"
 CONFIG_USBSER_RXBUFSIZE=512
diff --git a/drivers/usbdev/Make.defs b/drivers/usbdev/Make.defs
index da1af40ae88527825e7a6caca31c0260a8144508..dd2149ffa80929027249122624db422c41f820de 100644
--- a/drivers/usbdev/Make.defs
+++ b/drivers/usbdev/Make.defs
@@ -37,6 +37,6 @@ USBDEV_ASRCS  =
 USBDEV_CSRCS  =
 
 ifeq ($(CONFIG_USBDEV),y)
-USBDEV_CSRCS  += usbdev_trace.c
+USBDEV_CSRCS  += usbdev_serial.c usbdev_trace.c
 endif
 
diff --git a/drivers/usbdev/usbdev_serial.c b/drivers/usbdev/usbdev_serial.c
new file mode 100644
index 0000000000000000000000000000000000000000..1ee3d307e11b88fb2f4b805f7ff139b506a2ebdf
--- /dev/null
+++ b/drivers/usbdev/usbdev_serial.c
@@ -0,0 +1,1860 @@
+/****************************************************************************
+ * drivers/usbdev/usbdev_serial.c
+ *
+ *   Copyright (C) 2008 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * This a work-alike clone Prolific PL2303
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <semaphore.h>
+#include <string.h>
+#include <errno.h>
+#include <queue.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/serial.h>
+#include <nuttx/usb.h>
+#include <nuttx/usbdev.h>
+#include <nuttx/usbdev_trace.h>
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+/* Number of requests in the write queue */
+
+#ifndef CONFIG_USBSER_NWRREQS
+#  define CONFIG_USBSER_NWRREQS 4
+#endif
+
+/* Number of requests in the read queue */
+
+#ifndef CONFIG_USBSER_NRDREQS
+#  define CONFIG_USBSER_NRDREQS 4
+#endif
+
+/* Write buffer size */
+
+#ifndef CONFIG_USBSER_WRBUFFERSIZE
+#  define CONFIG_USBSER_WRBUFFERSIZE 1024
+#endif
+
+/* Logical endpoint numbers / max packet sizes */
+
+#ifndef CONFIG_USBSER_EPIN
+#  define CONFIG_USBSER_EPIN 2
+#endif
+
+#ifndef CONFIG_USBSER_EPOUT
+#  define CONFIG_USBSER_EPOUT 1
+#endif
+
+#ifndef CONFIG_USBSER_EP0MAXPACKET
+#  define CONFIG_USBSER_EP0MAXPACKET 64
+#endif
+
+/* Vendor and product IDs and strings */
+
+#ifndef CONFIG_USBSER_VENDORID
+#  define CONFIG_USBSER_VENDORID  0x067b
+#endif
+
+#ifndef CONFIG_USBSER_PRODUCTID
+#  define CONFIG_USBSER_PRODUCTID 0x2303
+#endif
+
+#ifndef CONFIG_USBSER_VENDORSTR
+#  warning "No Vendor string specified"
+#  define CONFIG_USBSER_VENDORSTR  "NuttX"
+#endif
+
+#ifndef CONFIG_USBSER_PRODUCTSTR
+#  warning "No Product string specified"
+#  define CONFIG_USBSER_PRODUCTSTR "USBdev Serial"
+#endif
+
+#undef CONFIG_USBSER_SERIALSTR
+#define CONFIG_USBSER_SERIALSTR "0"
+
+#undef CONFIG_USBSER_CONFIGSTR
+#define CONFIG_USBSER_CONFIGSTR "Bulk"
+
+/* USB Controller */
+
+#ifndef CONFIG_USBDEV_SELFPOWERED
+#  define SELFPOWERED USB_CONFIG_ATT_SELFPOWER
+#else
+#  define SELFPOWERED (0)
+#endif
+
+#ifndef  CONFIG_USBDEV_REMOTEWAKEUP
+#  define REMOTEWAKEUP USB_CONFIG_ATTR_WAKEUP
+#else
+#  define REMOTEWAKEUP (0)
+#endif
+
+/* These settings are not modifiable via the NuttX configuration */
+
+#define USBSER_VERSIONNO           (0x0202) /* Device version number */
+#define USBSER_CONFIGIDNONE        (0)      /* Config ID means to return to address mode */
+#define USBSER_CONFIGID            (1)      /* The only supported configuration ID */
+#define USBSER_NCONFIGS            (1)      /* Number of configurations supported */
+#define USBSER_INTERFACEID         (0)
+#define USBSER_ALTINTERFACEID      (0)
+#define USBSER_NINTERFACES         (1)      /* Number of interfaces in the configuration */
+#define USBSER_NENDPOINTS          (3)      /* Number of endpoints in the interface  */
+
+/* Endpoint configuration */
+
+#define USBSER_EPINTIN_ADDR        (USB_DIR_IN|1)
+#define USBSER_EPINTIN_ATTR        (USB_EP_ATTR_XFER_INT)
+#define USBSER_EPINTIN_MXPACKET    (10)
+#define USBSER_EPOUTBULK_ADDR      (2)
+#define USBSER_EPOUTBULK_ATTR      (USB_EP_ATTR_XFER_BULK)
+#define USBSER_EPINBULK_ADDR       (USB_DIR_IN|3)
+#define USBSER_EPINBULK_ATTR       (USB_EP_ATTR_XFER_BULK)
+
+/* Vender specific control requests */
+
+#define PL2303_CONTROL_TYPE            0x20
+#define PL2303_SETLINEREQUEST          0x20 /* OUT, Recipient interface */
+#define PL2303_GETLINEREQUEST          0x21 /* IN, Recipient interface */
+#define PL2303_SETCONTROLREQUEST       0x22 /* OUT, Recipient interface */
+#define PL2303_BREAKREQUEST            0x23 /* OUT, Recipient interface */
+
+/* Vendor read/write */
+
+#define PL2303_RWREQUEST_TYPE          0x40
+#define PL2303_RWREQUEST               0x01 /* IN/OUT, Recipient device */
+
+/* Values *********************************************************************/
+
+/* String language */
+
+#define USBSER_STR_LANGUAGE        0x0409 /* en-us */
+
+/* Descriptor strings */
+
+#define USBSER_MANUFACTURERSTRID    1
+#define USBSER_PRODUCTSTRID         2
+#define USBSER_SERIALSTRID          3
+#define USBSER_CONFIGSTRID          4
+
+/* Buffer big enough for any of our descriptors */
+
+#define USBSER_MXDESCLEN           256
+
+/* min/max macros */
+
+#ifndef min
+#  define min(a,b) ((a)<(b)?(a):(b))
+#endif
+
+#ifndef max
+#  define max(a,b) ((a)>(b)?(a):(b))
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* Container to support a list of requests */
+
+struct usbser_req_s
+{
+  struct usbser_req_s *flink; /* Implements a singly linked list */
+  struct usbdev_req_s *req;
+};
+
+/* This structure describes the internal state of the driver */
+
+struct usbser_dev_s
+{
+  struct uart_dev_s    serdev;    /* Serial device structure */
+  struct usbdev_s     *usbdev;    /* usbdev driver pointer */
+  ubyte                config;    /* Configuration number */
+  ubyte                nwralloc;  /* Number of write requests allocated */
+  ubyte                nwrq;      /* Number of queue write requests */
+  boolean              open;      /* TRUE: Driver has been opened */
+  boolean              wravail;   /* TRUE: write data is buffered */
+  ubyte                linest[7]; /* Fake line status */
+  struct usbdev_ep_s  *epintin;   /* Address of Interrupt IN endpoint */
+  struct usbdev_ep_s  *epbulkin;  /* Address of Bulk IN endpoint */
+  struct usbdev_ep_s  *epbulkout; /* Address of Bulk OUT endpoint */
+  struct usbdev_req_s *ctrlreq;   /* Control request */
+  struct sq_queue_s    reqlist;   /* List of write request containers */
+
+  /* Pre-allocated write requests (linked in reqlist) */
+
+  struct usbser_req_s wrreqs[CONFIG_USBSER_NWRREQS];
+
+  /* Serial I/O buffers */
+
+  char rxbuffer[CONFIG_USBSER_RXBUFSIZE];
+  char txbuffer[CONFIG_USBSER_TXBUFSIZE];
+};
+
+/* The internal version of the class driver */
+
+struct usbser_driver_s
+{
+  struct usbdevclass_driver_s drvr;
+  struct usbser_dev_s        *dev;
+};
+
+/* This is what is allocated */
+
+struct usbser_alloc_s
+{
+  struct usbser_dev_s    dev;
+  struct usbser_driver_s drvr;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Transfer helpers *********************************************************/
+
+static uint16  usbclass_fillpacket(FAR struct usbser_dev_s *priv,
+                 char *packet, uint16 size);
+static int     usbclass_sndpacket(FAR struct usbser_dev_s *priv);
+static int     usbclass_recvpacket(FAR struct usbser_dev_s *priv,
+                 char *packet, uint16 size);
+
+/* Request helpers *********************************************************/
+
+static struct usbdev_req_s *usbclass_allocreq(FAR struct usbdev_ep_s *ep,
+                 uint16 len);
+static void    usbclass_freereq(FAR struct usbdev_ep_s *ep,
+                 struct usbdev_req_s *req);
+
+/* Configuration ***********************************************************/
+
+static int     usbclass_mkstrdesc(ubyte id, struct usb_strdesc_s *strdesc);
+static void    usbclass_mkepdesc(ubyte addr, ubyte attr,  uint16 mxpacket,
+                                 struct usb_epdesc_s *desc);
+#ifdef CONFIG_USBDEV_DUALSPEED
+static sint16  usbclass_mkcfgdesc(ubyte *buf, ubyte speed);
+#else
+static sint16  usbclass_mkcfgdesc(ubyte *buf);
+#endif
+static void    usbclass_resetconfig(FAR struct usbser_dev_s *priv);
+static int     usbclass_setconfig(FAR struct usbser_dev_s *priv,
+                 ubyte config);
+
+/* Completion event handlers ***********************************************/
+
+static void    usbclass_setupcomplete(FAR struct usbdev_ep_s *ep,
+                 struct usbdev_req_s *req);
+static void    usbclass_rdcomplete(FAR struct usbdev_ep_s *ep,
+                 struct usbdev_req_s *req);
+static void    usbclass_wrcomplete(FAR struct usbdev_ep_s *ep,
+                 struct usbdev_req_s *req);
+
+/* USB class device ********************************************************/
+
+static int     usbclass_bind(FAR struct usbdev_s *dev,
+                 FAR struct usbdevclass_driver_s *driver);
+static void    usbclass_unbind(FAR struct usbdev_s *dev);
+static int     usbclass_setup(FAR struct usbdev_s *dev,
+                 const struct usb_ctrlreq_s *ctrl);
+static void    usbclass_disconnect(FAR struct usbdev_s *dev);
+
+/* Serial port *************************************************************/
+
+static int     usbser_setup(FAR struct uart_dev_s *dev);
+static void    usbser_shutdown(FAR struct uart_dev_s *dev);
+static int     usbser_attach(FAR struct uart_dev_s *dev);
+static void    usbser_detach(FAR struct uart_dev_s *dev);
+static void    usbser_rxint(FAR struct uart_dev_s *dev, boolean enable);
+static void    usbser_txint(FAR struct uart_dev_s *dev, boolean enable);
+static boolean usbser_txempty(FAR struct uart_dev_s *dev);
+
+/****************************************************************************
+ * Private Variables
+ ****************************************************************************/
+
+/* USB class device ********************************************************/
+
+static const struct usbdevclass_driverops_s g_driverops =
+{
+  usbclass_bind,        /* bind */
+  usbclass_unbind,      /* unbind */
+  usbclass_setup,       /* setup */
+  usbclass_disconnect,  /* disconnect */
+  NULL,                 /* suspend */
+  NULL,                 /* resume */
+};
+
+/* Serial port *************************************************************/
+
+static const struct uart_ops_s g_uartops =
+{
+  usbser_setup,         /* setup */
+  usbser_shutdown,      /* shutdown */
+  usbser_attach,        /* attach */
+  usbser_detach,        /* detach */
+  NULL,                 /* ioctl */
+  NULL,                 /* receive */
+  usbser_rxint,         /* rxinit */
+  NULL,                 /* rxavailable */
+  NULL,                 /* send */
+  usbser_txint,         /* txinit */
+  NULL,                 /* txready */
+  usbser_txempty        /* txempty */
+};
+
+/* USB descriptor templates these will be copied and modified */
+
+static const struct usb_devdesc_s g_devdesc =
+{
+  USB_SIZEOF_DEVDESC,                           /* len */
+  USB_DESC_TYPE_DEVICE,                         /* type */
+  {LSBYTE(0x0200), MSBYTE(0x0200)},             /* usb */
+  USB_CLASS_PER_INTERFACE,                      /* class */
+  0,                                            /* subclass */
+  0,                                            /* protocol */
+  CONFIG_USBSER_EP0MAXPACKET,                   /* maxpacketsize */
+  {LSBYTE(CONFIG_USBSER_VENDORID),              /* vendor */
+   MSBYTE(CONFIG_USBSER_VENDORID)},
+  {LSBYTE(CONFIG_USBSER_PRODUCTID),             /* product */
+   MSBYTE(CONFIG_USBSER_PRODUCTID)},
+  {LSBYTE(USBSER_VERSIONNO),                    /* device */
+   MSBYTE(USBSER_VERSIONNO)},
+  USBSER_MANUFACTURERSTRID,                     /* imfgr */
+  USBSER_PRODUCTSTRID,                          /* iproduct */
+  USBSER_SERIALSTRID,                           /* serno */
+  USBSER_NCONFIGS                               /* nconfigs */
+};
+
+static const struct usb_cfgdesc_s g_cfgdesc =
+{
+  USB_SIZEOF_CFGDESC,                           /* len */
+  USB_DESC_TYPE_CONFIG,                         /* type */
+  {0, 0},                                       /* totallen -- to be provided */
+  USBSER_NINTERFACES,                           /* ninterfaces */
+  USBSER_CONFIGID,                              /* cfgvalue */
+  USBSER_CONFIGSTRID,                           /* icfg */
+  USB_CONFIG_ATTR_ONE|SELFPOWERED|REMOTEWAKEUP, /* attr */
+  (CONFIG_USBDEV_MAXPOWER + 1) / 2              /* mxpower */
+};
+
+static const struct usb_ifdesc_s g_ifdesc =
+{
+  USB_SIZEOF_IFDESC,                            /* len */
+  USB_DESC_TYPE_INTERFACE,                      /* type */
+  0,                                            /* ifno */
+  0,                                            /* alt */
+  USBSER_NENDPOINTS,                            /* neps */
+  USB_CLASS_VENDOR_SPEC,                        /* class */
+  0,                                            /* subclass */
+  0,                                            /* protocol */
+  USBSER_CONFIGSTRID                            /* iif */
+};
+
+#ifdef CONFIG_USBDEV_DUALSPEED
+static const struct usb_qualdesc_s g_qualdesc =
+{
+  USB_SIZEOF_QUALDESC,                          /* len */
+  USB_DESC_TYPE_DEVICEQUALIFIER,                /* type */
+  {LSBYTE(0x0200), MSBYTE(0x0200) },            /* USB */
+  USB_CLASS_VENDOR_SPEC,                        /* class */
+  0,                                            /* subclass */
+  0,                                            /* protocol */
+  CONFIG_USBSER_EP0MAXPACKET,                   /* mxpacketsize */
+  USBSER_NCONFIGS,                              /* nconfigs */
+  0,                                            /* reserved */
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/************************************************************************************
+ * Name: usbclass_fillpacket
+ *
+ * Description:
+ *   If there is data to send, a packet is built in the given buffer.  Called either
+ *   to initiate the first write operation, or from the completion interrupt handler
+ *   service consecutive write operations.
+ *
+ * NOTE: The USB serial driver does not use the serial drivers uart_xmitchars()
+ *   API.  That logic is essentially duplicated here because unlike UART hardware,
+ *   we need to be able to handle writes not byte-by-byte, but packet-by-packet.
+ *   Unfortunately, that decision also exposes some internals of the serial driver
+ *   in the following.
+ *
+ ************************************************************************************/
+
+static uint16 usbclass_fillpacket(FAR struct usbser_dev_s *priv, char *packet, uint16 size)
+{
+  uart_dev_t *serdev = &priv->serdev;
+  struct uart_buffer_s *xmit = &serdev->xmit;
+  irqstate_t flags;
+  uint16 nbytes = 0;
+
+  /* Disable interrupts */
+
+  flags = irqsave();
+
+  /* Transfer bytes while we have bytes available and there is room in the packet */
+
+  while (xmit->head != xmit->tail && nbytes < size)
+    {
+      *packet++ = xmit->buffer[xmit->tail];
+      nbytes++;
+
+      /* Increment the tail pointer */
+
+      if (++(xmit->tail) >= xmit->size)
+        {
+          xmit->tail = 0;
+        }
+
+      /* Check if we have to wake up the serial driver */
+
+      if (serdev->xmitwaiting)
+        {
+          serdev->xmitwaiting = FALSE;
+          sem_post(&serdev->xmitsem);
+        }
+    }
+
+  /* When all of the characters have been sent from the buffer
+   * disable the "TX interrupt".
+   */
+
+  if (xmit->head == xmit->tail)
+    {
+      priv->wravail = FALSE;
+      uart_disabletxint(serdev);
+    }
+
+  irqrestore(flags);
+  return nbytes;
+}
+
+/************************************************************************************
+ * Name: usbclass_sndpacket
+ *
+ * Description:
+ *   This function obtains write requests, transfers the TX data into the packet,
+ *   and submits the packets to the USB controller.  This continues untils either
+ *   (1) there are no further packets available, or (2) thre is not further data
+ *   to send.
+ *
+ ************************************************************************************/
+
+static int usbclass_sndpacket(FAR struct usbser_dev_s *priv)
+{
+  struct usbdev_ep_s *ep;
+  struct usbdev_req_s *req;
+  struct usbser_req_s *reqcontainer;
+  irqstate_t flags;
+  int len;
+  int ret = OK;
+
+#ifdef CONFIG_DEBUG
+  if (priv == NULL)
+    {
+      return -ENODEV;
+    }
+#endif
+
+  flags = irqsave();
+
+  /* Use our IN endpoint for the transfer */
+
+  ep = priv->epbulkin;
+
+  /* Loop until either (1) we run out or write requests, or (2) usbclass_fillpacket()
+   * is unable to fill the packet with data (i.e., untilthere is no more data
+   * to be sent).
+   */
+
+  while (priv->reqlist.head)
+    {
+      /* Peek at the request in the container at the head of the list */
+
+      req = (struct usbdev_req_s *)priv->reqlist.head;
+
+      /* Fill the packet with serial TX data */
+
+      len = usbclass_fillpacket(priv, req->buf, ep->maxpacket);
+      if (len > 0)
+        {
+          /* Then submit the request to the endpoint */
+
+          req->len     = len;
+          req->private = reqcontainer;
+          ret          = EP_SUBMIT(ep, req);
+          if (ret != OK)
+            {
+              usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_SUBMITFAIL), (uint16)-ret);
+              break;
+            }
+
+          /* Remove the empty contained from the request list */
+
+          reqcontainer = (struct usbser_req_s *)sq_remfirst(&priv->reqlist);
+          priv->nwrq--;
+        }
+      else
+        {
+          break;
+        }
+    }
+
+  irqrestore(flags);
+  return ret;
+}
+
+/************************************************************************************
+ * Name: usbclass_recvpacket
+ *
+ * Description:
+ *   A normal completion event was received by the read completion handler at the
+ *   interrupt level (with interrupts disabled).  This function handles the USB packet
+ *   and provides the received data to the uart RX buffer.
+ *
+ ************************************************************************************/
+
+static int usbclass_recvpacket(FAR struct usbser_dev_s *priv, char *packet, uint16 size)
+{
+  uart_dev_t *serdev = &priv->serdev;
+  struct uart_buffer_s *recv = &serdev->recv;
+  uint16 nexthead;
+
+  /* Get the next head index */
+
+  nexthead = recv->head + 1;
+  if (nexthead >= recv->size)
+    {
+      nexthead = 0;
+    }
+
+  /* Then copy data into the RX buffer until either: (1) all of the data has been
+   * copied, or (2) the RX buffer is full.  NOTE:  If the RX buffer becomes full,
+   * then we have overrun the serial driver and data will be lost.
+   */
+
+  while (nexthead != recv->tail && size > 0)
+    {
+      /* Copy one byte to the head of the circular RX buffer */
+
+      recv->buffer[recv->head] = *packet++;
+
+      /* Update counts and indices */
+
+      recv->head = nexthead;
+      size--;
+      if (++nexthead >= recv->size)
+        {
+           nexthead = 0;
+        }
+
+      /* Wake up the serial driver if it is waiting for incoming data */
+
+      if (serdev->recvwaiting)
+        {
+          serdev->recvwaiting = FALSE;
+          sem_post(&serdev->recvsem);
+        }
+    }
+  return OK;
+}
+
+/****************************************************************************
+ * Name: usbclass_allocreq
+ *
+ * Description:
+ *   Allocate a request instance along with its buffer
+ *
+ ****************************************************************************/
+
+static struct usbdev_req_s *usbclass_allocreq(FAR struct usbdev_ep_s *ep, uint16 len)
+{
+  struct usbdev_req_s *req;
+
+  req = EP_ALLOCREQ(ep);
+  if (req != NULL)
+    {
+      req->len = len;
+      req->buf = EP_ALLOCBUFFER(ep, len);
+      if (!req->buf)
+        {
+          EP_FREEREQ(ep, req);
+          req = NULL;
+        }
+    }
+  return req;
+}
+
+/****************************************************************************
+ * Name: usbclass_freereq
+ *
+ * Description:
+ *   Free a request instance along with its buffer
+ *
+ ****************************************************************************/
+
+static void usbclass_freereq(FAR struct usbdev_ep_s *ep, struct usbdev_req_s *req)
+{
+  if (ep != NULL && req != NULL)
+    {
+      if (req->buf != NULL)
+        {
+          EP_FREEBUFFER(ep, req->buf);
+        }
+      EP_FREEREQ(ep, req);
+    }
+}
+
+/****************************************************************************
+ * Name: usbclass_mkstrdesc
+ *
+ * Description:
+ *   Construct a string descriptor
+ *
+ ****************************************************************************/
+
+static int usbclass_mkstrdesc(ubyte id, struct usb_strdesc_s *strdesc)
+{
+  const char *str;
+  int len;
+  int ndata;
+  int i;
+
+  switch (id)
+    {
+    case 0:
+      {
+        /* Descriptor 0 is the language id */
+
+        strdesc->len     = 4;
+        strdesc->type    = USB_DESC_TYPE_STRING;
+        strdesc->data[0] = LSBYTE(USBSER_STR_LANGUAGE);
+        strdesc->data[1] = MSBYTE(USBSER_STR_LANGUAGE);
+        return 4;
+      }
+
+    case USBSER_MANUFACTURERSTRID:
+      str = CONFIG_USBSER_VENDORSTR;
+      break;
+
+    case USBSER_PRODUCTSTRID:
+      str = CONFIG_USBSER_PRODUCTSTR;
+      break;
+
+    case USBSER_SERIALSTRID:
+      str = CONFIG_USBSER_SERIALSTR;
+      break;
+
+    case USBSER_CONFIGSTRID:
+      str = CONFIG_USBSER_CONFIGSTR;
+      break;
+
+    default:
+      return -EINVAL;
+    }
+
+   /* The string is utf16-le.  The poor man's utf-8 to utf16-le
+    * conversion below will only handle 7-bit en-us ascii
+    */
+
+   len = strlen(str);
+   for (i = 0, ndata = 0; i < len; i++, ndata += 2)
+     {
+       strdesc->data[ndata]   = str[i];
+       strdesc->data[ndata+1] = 0;
+     }
+
+   strdesc->len  = ndata+2;
+   strdesc->type = USB_DESC_TYPE_STRING;
+   return strdesc->len;
+}
+
+/****************************************************************************
+ * Name: usbclass_mkepdesc
+ *
+ * Description:
+ *   Construct the endpoint descriptor
+ *
+ ****************************************************************************/
+
+static void usbclass_mkepdesc(ubyte addr, ubyte attr, uint16 mxpacket,
+                              struct usb_epdesc_s *desc)
+{
+  /* Format the endpoint descriptor */
+
+  desc->len             = USB_SIZEOF_EPDESC;
+  desc->type            = USB_DESC_TYPE_ENDPOINT;
+  desc->addr            = addr;
+  desc->attr            = attr;
+  desc->mxpacketsize[0] = LSBYTE(mxpacket);
+  desc->mxpacketsize[1] = MSBYTE(mxpacket);
+  desc->interval        = 0;
+}
+
+/****************************************************************************
+ * Name: usbclass_mkcfgdesc
+ *
+ * Description:
+ *   Construct the configuration descriptor
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_USBDEV_DUALSPEED
+static sint16  usbclass_mkcfgdesc(ubyte *buf, ubyte speed)
+#else
+static sint16  usbclass_mkcfgdesc(ubyte *buf)
+#endif
+{
+  struct usb_cfgdesc_s *cfgdesc = (struct usb_cfgdesc_s*)buf;
+#ifdef CONFIG_USBDEV_DUALSPEED
+  boolean highspeed = (speed == USB_SPEED_HIGH);
+#endif
+  uint16 bulkmxpacket;
+  uint16 totallen;
+
+  /* This is the total length of the configuration (not necessarily the
+   * size that we will be sending now.
+   */
+
+  totallen = USB_SIZEOF_CFGDESC + USB_SIZEOF_IFDESC + USBSER_NENDPOINTS * USB_SIZEOF_EPDESC;
+
+  /* Configuration descriptor -- Copy the canned descriptor and fill in the
+   * type (we'll also need to update the size below
+   */
+
+  memcpy(cfgdesc, &g_cfgdesc, USB_SIZEOF_CFGDESC);
+  buf += USB_SIZEOF_CFGDESC;
+
+  /*  Copy the canned interface descriptor */
+
+  memcpy(buf, &g_ifdesc, USB_SIZEOF_IFDESC);
+  buf += USB_SIZEOF_IFDESC;
+
+  /* Make the two endpoint configurations.  First, check for switches
+   * between high and full speed
+   */
+
+#ifdef CONFIG_USBDEV_DUALSPEED
+  if (type == USB_DESC_TYPE_OTHERSPEEDCONFIG)
+    {
+      hispeed = !hispeed;
+    }
+#endif
+
+#ifdef CONFIG_USBDEV_DUALSPEED
+  if (hispeed)
+    {
+      bulkmxpacket = 512;
+    }
+  else
+#endif
+    {
+      bulkmxpacket = 64;
+    }
+
+  usbclass_mkepdesc(USBSER_EPINTIN_ADDR, USBSER_EPINTIN_ATTR,
+                    USBSER_EPINTIN_MXPACKET, (struct usb_epdesc_s*)buf);
+  buf += USB_SIZEOF_EPDESC;
+  usbclass_mkepdesc(USBSER_EPOUTBULK_ADDR, USBSER_EPOUTBULK_ATTR,
+                    bulkmxpacket, (struct usb_epdesc_s*)buf);
+  buf += USB_SIZEOF_EPDESC;
+  usbclass_mkepdesc(USBSER_EPINBULK_ADDR, USBSER_EPINBULK_ATTR,
+                    bulkmxpacket, (struct usb_epdesc_s*)buf);
+
+  /* Finally, fill in the total size of the configuration descriptor */
+
+  cfgdesc->totallen[0] = LSBYTE(totallen);
+  cfgdesc->totallen[1] = MSBYTE(totallen);
+  return totallen;
+}
+
+/****************************************************************************
+ * Name: usbclass_resetconfig
+ *
+ * Description:
+ *   Mark the device as not configured and disable all endpoints.
+ *
+ ****************************************************************************/
+
+static void usbclass_resetconfig(FAR struct usbser_dev_s *priv)
+{
+  FAR struct usbdev_s *dev = priv->usbdev;
+  struct usbser_req_s *reqcontainer;
+  irqstate_t flags;
+
+  /* Are we configured? */
+
+  if (priv->config != USBSER_CONFIGIDNONE)
+    {
+      priv->config = USBSER_CONFIGIDNONE;
+
+      /* Free write requests that are not in use */
+
+      flags = irqsave();
+      while (!sq_empty(&priv->reqlist))
+        {
+          reqcontainer = (struct usbser_req_s *)sq_remfirst(&priv->reqlist);
+          if (reqcontainer->req != NULL)
+            {
+              usbclass_freereq(priv->epbulkin, reqcontainer->req);
+
+              priv->nwralloc--; /* Number of write requests allocated */
+              priv->nwrq--;     /* Number of write requests queued */
+            }
+        }
+      irqrestore(flags);
+
+      /* Disable and free endpoints.  This should force completion of all pending
+       * transfers.
+       */
+
+      if (priv->epintin)
+        {
+          EP_DISABLE(priv->epintin);
+          DEV_FREEEP(dev, priv->epintin);
+          priv->epintin = NULL;
+        }
+
+      if (priv->epbulkin)
+        {
+          EP_DISABLE(priv->epbulkin);
+          DEV_FREEEP(dev, priv->epbulkin);
+          priv->epbulkin = NULL;
+        }
+
+      if (priv->epbulkout)
+        {
+          EP_DISABLE(priv->epbulkout);
+          DEV_FREEEP(dev, priv->epbulkout);
+          priv->epbulkout = NULL;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: usbclass_setconfig
+ *
+ * Description:
+ *   Set the device configuration by allocating and configuring endpoints and
+ *   by allocating and queue read and write requests.
+ *
+ ****************************************************************************/
+
+static int usbclass_setconfig(FAR struct usbser_dev_s *priv, ubyte config)
+{
+  struct usbdev_s *dev = priv->usbdev;
+  struct usbdev_req_s *req;
+  struct usbser_req_s *reqcontainer;
+  struct usb_epdesc_s epdesc;
+  irqstate_t flags;
+  uint16 bulkmxpacket;
+  int i;
+  int ret = 0;
+
+#if CONFIG_DEBUG
+  if (priv == NULL)
+    {
+      return -ENODEV;
+    }
+#endif
+
+  if (config == priv->config)
+    {
+      /* Already configured */
+
+      return 0;
+    }
+
+  /* Discard the previous configuration data */
+
+  usbclass_resetconfig(priv);
+
+  /* Was this a request to simply discard the current configuration? */
+
+  if (config != USBSER_CONFIGIDNONE)
+    {
+      return 0;
+    }
+
+  /* The only configuration that we accept is ourt BULK configuration */
+
+  if (config != USBSER_CONFIGID)
+    {
+      return -EINVAL;
+    }
+
+  /* Configure the IN interrupt endpoint */
+
+  priv->epintin = DEV_ALLOCEP(dev, 0, TRUE, USB_EP_ATTR_XFER_INT);
+  if (!priv->epintin)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INALLOCEPFAIL), 0);
+      ret = -ENODEV;
+      goto errout;
+    }
+
+  usbclass_mkepdesc(USBSER_EPINTIN_ADDR, USBSER_EPINTIN_ATTR,
+                    USBSER_EPINTIN_MXPACKET, &epdesc);
+
+  ret = EP_CONFIGURE(priv->epintin, &epdesc);
+  if (ret < 0)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INCONFIGEPFAIL), 0);
+      goto errout;
+    }
+
+  priv->epintin->private = priv;
+
+  /* Configure the IN bulk endpoint */
+
+  priv->epbulkin = DEV_ALLOCEP(dev, 0, TRUE, USB_EP_ATTR_XFER_BULK);
+  if (!priv->epbulkin)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INALLOCEPFAIL), 0);
+      ret = -ENODEV;
+      goto errout;
+    }
+
+#ifdef CONFIG_USBDEV_DUALSPEED
+  if (dev->speed == USB_SPEED_HIGH)
+    {
+      bulkmxpacket = 512;
+    }
+  else
+#endif
+    {
+      bulkmxpacket = 64;
+    }
+
+  usbclass_mkepdesc(USBSER_EPINBULK_ADDR, USBSER_EPINBULK_ATTR,
+                    bulkmxpacket, &epdesc);
+
+  ret = EP_CONFIGURE(priv->epbulkin, &epdesc);
+  if (ret < 0)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INCONFIGEPFAIL), 0);
+      goto errout;
+    }
+
+  priv->epbulkin->private = priv;
+
+  /* Configure the OUT bulk endpoint */
+
+  priv->epbulkout = DEV_ALLOCEP(dev, 0, FALSE, USB_EP_ATTR_XFER_BULK);
+  if (!priv->epbulkout)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_OUTALLOCEPFAIL), 0);
+      ret = -ENODEV;
+      goto errout;
+    }
+
+  usbclass_mkepdesc(USBSER_EPOUTBULK_ADDR, USBSER_EPOUTBULK_ATTR,
+                    bulkmxpacket, &epdesc);
+
+  ret = EP_CONFIGURE(priv->epbulkout, &epdesc);
+  if (ret < 0)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_OUTCONFIGEPFAIL), 0);
+      goto errout;
+    }
+
+  priv->epbulkout->private = priv;
+
+  /* Allocate and queue read requests */
+
+  for (i = 0; i < CONFIG_USBSER_NRDREQS && ret == 0; i++)
+    {
+      req = usbclass_allocreq(priv->epbulkout, priv->epbulkout->maxpacket);
+      if (ret == 0)
+        {
+          req->callback = usbclass_rdcomplete;
+          ret           = EP_SUBMIT(priv->epbulkout, req);
+          if (ret != OK)
+            {
+              usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16)-ret);
+            }
+        }
+      else
+        {
+          usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDALLOCREQ), (uint16)-ret);
+          usbclass_resetconfig(priv);
+          return -ENOMEM;
+        }
+    }
+
+  /* Allocate write request containers and put in a free list */
+
+  for (i = 0; i < CONFIG_USBSER_NWRREQS; i++)
+    {
+      reqcontainer      = &priv->wrreqs[i];
+      reqcontainer->req = usbclass_allocreq(priv->epbulkin, priv->epbulkin->maxpacket);
+      if (reqcontainer->req == NULL)
+        {
+          usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRALLOCREQ), (uint16)-ret);
+          usbclass_resetconfig(priv);
+          return -ENOMEM;
+        }
+      reqcontainer->req->private  = reqcontainer;
+      reqcontainer->req->callback = usbclass_wrcomplete;
+
+      flags = irqsave();
+      sq_addlast((sq_entry_t*)reqcontainer, &priv->reqlist);
+
+      priv->nwralloc++; /* Count of write requests allocated */
+      priv->nwrq++;     /* Count of write requests available */
+      irqrestore(flags);
+    }
+
+  priv->config = config;
+  return OK;
+
+errout:
+  usbclass_resetconfig(priv);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: usbclass_setupcomplete
+ *
+ * Description:
+ *   Handle completion of EP0 control operations
+ *
+ ****************************************************************************/
+
+static void usbclass_setupcomplete(FAR struct usbdev_ep_s *ep, struct usbdev_req_s *req)
+{
+  if (req->result || req->xfrd != req->len)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_REQRESULT), (uint16)-req->result);
+    }
+}
+
+/****************************************************************************
+ * Name: usbclass_rdcomplete
+ *
+ * Description:
+ *   Handle completion of read request
+ *
+ ****************************************************************************/
+
+static void usbclass_rdcomplete(FAR struct usbdev_ep_s *ep, struct usbdev_req_s *req)
+{
+  struct usbser_dev_s *priv = (FAR struct usbser_dev_s*)ep->private;
+  int ret;
+
+  if (priv != NULL)
+    {
+      switch (req->result)
+        {
+        case 0: /* Normal completion */
+          usbclass_recvpacket(priv, req->buf, req->xfrd);
+          break;
+
+        case -ESHUTDOWN: /* Disconnection */
+          usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSHUTDOWN), 0);
+          usbclass_freereq(ep, req);
+          return;
+
+        default:
+          usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDUNEXPECTED), (uint16)-req->result);
+          break;
+        };
+
+      /* Requeue the read request */
+
+      req->len = ep->maxpacket;
+      ret      = EP_SUBMIT(ep, req);
+      if (ret != OK)
+        {
+          usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16)-req->result);
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: usbclass_wrcomplete
+ *
+ * Description:
+ *   Handle completion of write request.  This function probably executes
+ *   in the context of an interrupt handler.
+ *
+ ****************************************************************************/
+
+static void usbclass_wrcomplete(FAR struct usbdev_ep_s *ep, struct usbdev_req_s *req)
+{
+  struct usbser_dev_s *priv = (FAR struct usbser_dev_s *)ep->private;
+  struct usbser_req_s *reqcontainer = req->private;
+  irqstate_t flags;
+
+  if (priv != NULL)
+    {
+      switch (req->result)
+        {
+        case 0: /* Normal completion */
+          break;
+
+        case -ESHUTDOWN: /* Disconnection */
+          usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRSHUTDOWN), 0);
+          usbclass_freereq(ep, req);
+          priv->nwralloc--; /* Number of write requests allocated */
+          return;
+
+        default:
+          usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRUNEXPECTED), (uint16)-req->result);
+          break;
+        }
+
+      /* Put write request back into the free list */
+
+      if (reqcontainer == NULL)
+        {
+          flags = irqsave();
+          sq_addlast((sq_entry_t*)reqcontainer, &priv->reqlist);
+          priv->nwrq++;
+          irqrestore(flags);
+
+          /* And send another packet if: TX output is enabled */
+
+          usbclass_sndpacket(priv);
+        }
+    }
+}
+
+/****************************************************************************
+ * USB Class Driver Methods
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: usbclass_bind
+ *
+ * Description:
+ *   Invoked when the driver is bound to a USB device driver
+ *
+ ****************************************************************************/
+
+static int usbclass_bind(FAR struct usbdev_s *dev, FAR struct usbdevclass_driver_s *driver)
+{
+  struct usbser_dev_s *priv = ((struct usbser_driver_s*)driver)->dev;
+
+  usbtrace(TRACE_CLASSBIND, 0);
+
+  /* Preallocate control request */
+
+  priv->ctrlreq = usbclass_allocreq(dev->ep0, USBSER_MXDESCLEN);
+  if (priv->ctrlreq == NULL)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_ALLOCCTRLREQ), 0);
+      usbclass_unbind(dev);
+      return -ENOMEM;
+    }
+  priv->ctrlreq->callback = usbclass_setupcomplete;
+
+  /* Bind the structures */
+
+  priv->usbdev      = dev;
+  dev->ep0->private = priv;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: usbclass_unbind
+ *
+ * Description:
+ *    Invoked when the driver is unbound from a USB device driver
+ *
+ ****************************************************************************/
+
+static void usbclass_unbind(FAR struct usbdev_s *dev)
+{
+  struct usbser_dev_s *priv;
+
+  usbtrace(TRACE_CLASSUNBIND, 0);
+
+#ifdef CONFIG_DEBUG
+  if (!dev || !dev->ep0)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
+      return;
+     }
+#endif
+  priv = (FAR struct usbser_dev_s *)dev->ep0->private;
+
+#ifdef CONFIG_DEBUG
+  if (!priv)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EP0NOTBOUND), 0);
+      return;
+    }
+#endif
+
+  if (priv != NULL)
+    {
+      if (priv->ctrlreq != NULL)
+        {
+          usbclass_freereq(dev->ep0, priv->ctrlreq);
+        }
+
+      /* Clear out all data in the circular buffer */
+
+      priv->serdev.xmit.head = 0;
+      priv->serdev.xmit.tail = 0;
+    }
+}
+
+/****************************************************************************
+ * Name: usbclass_setup
+ *
+ * Description:
+ *   Invoked for ep0 control requests.  This function probably executes
+ *   in the context of an interrupt handler.
+ *
+ ****************************************************************************/
+
+static int usbclass_setup(FAR struct usbdev_s *dev, const struct usb_ctrlreq_s *ctrl)
+{
+  struct usbser_dev_s *priv;
+  struct usbdev_req_s *ctrlreq;
+  uint16 value;
+  uint16 index;
+  uint16 len;
+  int ret = -EOPNOTSUPP;
+
+#ifdef CONFIG_DEBUG
+  if (!dev || !dev->ep0 || !ctrl)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
+      return -EINVAL;
+     }
+#endif
+  usbtrace(TRACE_CLASSSETUP, ctrl->req);
+  priv = (FAR struct usbser_dev_s *)dev->ep0->private;
+
+#ifdef CONFIG_DEBUG
+  if (!priv || !priv->ctrlreq)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EP0NOTBOUND), 0);
+      return -ENODEV;
+    }
+#endif
+  ctrlreq = priv->ctrlreq;
+
+  /* Extract the little-endian 16-bit values to host order */
+
+  value = GETUINT16(ctrl->value);
+  index = GETUINT16(ctrl->index);
+  len   = GETUINT16(ctrl->len);
+
+  uvdbg("type=%02x req=%02x value=%04x index=%04x len=%04x\n",
+        ctrl->type, ctrl->req, value, index, len);
+
+  switch (ctrl->type & USB_REQ_TYPE_MASK)
+    {
+    case USB_REQ_TYPE_STANDARD:
+      {
+        switch (ctrl->req)
+          {
+          case USB_REQ_GETDESCRIPTOR:
+            {
+              /* The value field specifies the descriptor type in the MS byte and the
+               * descriptor index in the LS byte (order is little endian)
+               */
+
+              switch (ctrl->value[1])
+                {
+                case USB_DESC_TYPE_DEVICE:
+                  {
+                    ret = USB_SIZEOF_DEVDESC;
+                    memcpy(ctrlreq->buf, &g_devdesc, ret);
+                  }
+                  break;
+
+#ifdef CONFIG_USBDEV_DUALSPEED
+                case USB_DESC_TYPE_DEVICEQUALIFIER:
+                  {
+                    ret = USB_SIZEOF_QUALDESC;
+                    memcpy(ctrlreq->buf, &g_qualdesc, ret);
+                  }
+                  break;
+
+                case USB_DESC_TYPE_OTHERSPEEDCONFIG:
+#endif /* CONFIG_USBDEV_DUALSPEED */
+
+                case USB_DESC_TYPE_CONFIG:
+                  {
+#ifdef CONFIG_USBDEV_DUALSPEED
+                    ret = usbclass_mkcfgdesc(ctrlreq->buf, dev->speed, len);
+#else
+                    ret = usbclass_mkcfgdesc(ctrlreq->buf);
+#endif
+                  }
+                  break;
+
+                case USB_DESC_TYPE_STRING:
+                  {
+                    /* index == language code. */
+
+                    ret = usbclass_mkstrdesc(ctrl->value[0], (struct usb_strdesc_s *)ctrlreq->buf);
+                  }
+                  break;
+
+                default:
+                  {
+                    usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_GETUNKNOWNDESC), value);
+                  }
+                  break;
+                }
+            }
+            break;
+
+          case USB_REQ_SETCONFIGURATION:
+            {
+              if (ctrl->type == 0)
+                {
+                  ret = usbclass_setconfig(priv, value);
+                }
+            }
+            break;
+
+          case USB_REQ_GETCONFIGURATION:
+            {
+              if (ctrl->type == USB_DIR_IN)
+                {
+                  *(ubyte*)ctrlreq->buf = priv->config;
+                  ret = 1;
+                }
+            }
+            break;
+
+          case USB_REQ_SETINTERFACE:
+            {
+              if (ctrl->type == USB_REQ_RECIPIENT_INTERFACE)
+                {
+                  if (priv->config == USBSER_CONFIGID &&
+                      index == USBSER_INTERFACEID &&
+                      value == USBSER_ALTINTERFACEID)
+                    {
+                      usbclass_resetconfig(priv);
+                      usbclass_setconfig(priv, priv->config);
+                      ret = 0;
+                    }
+                }
+            }
+            break;
+
+          case USB_REQ_GETINTERFACE:
+            {
+              if (ctrl->type == (USB_DIR_IN|USB_REQ_RECIPIENT_INTERFACE) &&
+                  priv->config == USBSER_CONFIGIDNONE)
+                {
+                  if (index != USBSER_INTERFACEID)
+                    {
+                      ret = -EDOM;
+                    }
+                  else
+                     {
+                      *(ubyte*) ctrlreq->buf = USBSER_ALTINTERFACEID;
+                      ret = 1;
+                    }
+                }
+             }
+             break;
+
+          default:
+            usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDSTDREQ), ctrl->req);
+            break;
+          }
+      }
+      break;
+
+    case PL2303_CONTROL_TYPE:
+      {
+        if ((ctrl->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_INTERFACE)
+          {
+            switch (ctrl->req)
+              {
+              case PL2303_SETLINEREQUEST:
+                {
+                   memcpy(priv->linest, ctrlreq->buf, min(len, 7));
+                   ret = 0;
+                }
+                break;
+
+
+              case PL2303_GETLINEREQUEST:
+                {
+                   memcpy(ctrlreq->buf, priv->linest, 7);
+                   ret = 7;
+                }
+                break;
+
+              case PL2303_SETCONTROLREQUEST:
+              case PL2303_BREAKREQUEST:
+                {
+                  ret = 0;
+                }
+                break;
+
+              default:
+                usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCTRLREQ), ctrl->type);
+                break;
+              }
+          }
+      }
+      break;
+
+    case PL2303_RWREQUEST_TYPE:
+      {
+        if ((ctrl->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE)
+          {
+            if (ctrl->req == PL2303_RWREQUEST)
+              {
+                if ((ctrl->type & USB_DIR_IN) != 0)
+                  {
+                    *(uint32*)ctrlreq->buf = 0xdeadbeef;
+                    ret = 4;
+                  }
+                else
+                  {
+                     ret = 0;
+                  }
+              }
+            else
+              {
+                usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDRWREQ), ctrl->type);
+              }
+          }
+      }
+      break;
+
+    default:
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDTYPE), ctrl->type);
+      break;
+    }
+
+  /* Respond with data transfer before status phase? */
+
+  if (ret >= 0)
+    {
+      ctrlreq->len = min(len, ret);
+      ret          = EP_SUBMIT(dev->ep0, ctrlreq);
+      if (ret < 0)
+        {
+          usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPRESPQ), (uint16)-ret);
+          ctrlreq->result = OK;
+          usbclass_setupcomplete(dev->ep0, ctrlreq);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: usbclass_disconnect
+ *
+ * Description:
+ *   Invoked after all transfers have been stopped, when the host is
+ *   disconnected.  This function is probably called from the context of an
+ *   interrupt handler.
+ *
+ ****************************************************************************/
+
+static void usbclass_disconnect(FAR struct usbdev_s *dev)
+{
+  struct usbser_dev_s *priv;
+  irqstate_t flags;
+
+  usbtrace(TRACE_CLASSDISCONNECT, 0);
+
+#ifdef CONFIG_DEBUG
+  if (!dev || !dev->ep0)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
+      return;
+     }
+#endif
+  priv = (FAR struct usbser_dev_s *)dev->ep0->private;
+
+#ifdef CONFIG_DEBUG
+  if (!priv)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EP0NOTBOUND), 0);
+      return;
+    }
+#endif
+
+  flags = irqsave();
+  usbclass_resetconfig(priv);
+
+  /* Clear out all data in the circular buffer */
+
+  priv->serdev.xmit.head = 0;
+  priv->serdev.xmit.tail = 0;
+  irqrestore(flags);
+}
+
+/****************************************************************************
+ * Serial Device Methods
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: usbser_setup
+ *
+ * Description:
+ *   This method is called the first time that the serial port is opened.
+ *
+ ****************************************************************************/
+
+static int usbser_setup(FAR struct uart_dev_s *dev)
+{
+  struct usbser_dev_s *priv = (FAR struct usbser_dev_s*)dev->priv;
+
+#if CONFIG_DEBUG
+  if (!priv)
+    {
+       return -EIO;
+    }
+
+  if (priv->config == USBSER_CONFIGIDNONE)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_SETUPNOTCONNECTED), 0);
+      return -ENODEV;
+    }
+#endif
+
+  priv->open = TRUE;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: usbser_shutdown
+ *
+ * Description:
+ *   This method is called when the serial port is closed.  This operation
+ *   is very simple for the USB serial backend because the serial driver
+ *   has already assured that the TX data has full drained -- it calls
+ *   usbser_txempty() until that function returns TRUE before calling this
+ *   function.
+ *
+ ****************************************************************************/
+
+static void usbser_shutdown(FAR struct uart_dev_s *dev)
+{
+  struct usbser_dev_s *priv = (FAR struct usbser_dev_s*)dev->priv;
+  irqstate_t flags;
+
+#if CONFIG_DEBUG
+  if (!priv)
+    {
+       usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
+       return;
+    }
+#endif
+
+  flags = irqsave();
+
+#if CONFIG_DEBUG
+  if (!priv->open)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_ALREADYCLOSED), 0);
+      goto errout;
+    }
+#endif
+
+  /* Make sure that we are disconnected from the host */
+
+  usbclass_resetconfig(priv);
+  priv->open = FALSE;
+
+errout:
+  irqrestore(flags);
+}
+
+/****************************************************************************
+ * Name: usbser_attach
+ *
+ * Description:
+ *   Does not apply to the USB serial class device
+ *
+ ****************************************************************************/
+
+static int usbser_attach(FAR struct uart_dev_s *dev)
+{
+  return OK;
+}
+
+/****************************************************************************
+ * Name: usbser_detach
+ *
+ * Description:
+*   Does not apply to the USB serial class device
+  *
+ ****************************************************************************/
+
+static void usbser_detach(FAR struct uart_dev_s *dev)
+{
+}
+
+/****************************************************************************
+ * Name: usbser_rxint
+ *
+ * Description:
+ *   Called by the serial driver to enable or disable RX interrupts.  We, of
+ *   course, have no RX interrupts but must behave consistently.  This method
+ *   is called under the conditions:
+ *
+ *   1. With enable==TRUE when the port is opened (just after usbser_setup
+ *      and usbser_attach are called called)
+ *   2. With enable==FALSE while transferring data from the RX buffer
+ *   2. With enable==TRUE while waiting for more incoming data
+ *   3. With enable==FALSE when the port is closed (just before usbser_detach
+ *      and usbser_shutdown are called).
+ *
+ ****************************************************************************/
+
+static void usbser_rxint(FAR struct uart_dev_s *dev, boolean enable)
+{
+  struct usbser_dev_s *priv = (FAR struct usbser_dev_s*)dev->priv;
+
+#if CONFIG_DEBUG
+  if (!priv)
+    {
+       return;
+    }
+#endif
+
+  /* I think we can simulate this behavior by stalling and/or resuming the
+   * OUT endpoint.
+   */
+
+  if (enable)
+    {
+      EP_RESUME(priv->epbulkout);
+    }
+  else
+    {
+      EP_STALL(priv->epbulkout);
+    }
+}
+
+/****************************************************************************
+ * Name: usbser_txint
+ *
+ * Description:
+ *   Called by the serial driver to enable or disable TX interrupts.  We, of
+ *   course, have no TX interrupts but must behave consistently.  Initially,
+ *   TX interrupts are disabled.  This method is called under the conditions:
+ *
+ *   1. With enable==FALSE while transferring data into the TX buffer
+ *   2. With enable==TRUE when data may be taken from the buffer.
+ *   3. With enable==FALSE when the TX buffer is empty
+ *
+ ****************************************************************************/
+
+static void usbser_txint(FAR struct uart_dev_s *dev, boolean enable)
+{
+  struct usbser_dev_s *priv = (FAR struct usbser_dev_s*)dev->priv;
+
+#if CONFIG_DEBUG
+  if (!priv)
+    {
+       return;
+    }
+#endif
+
+  /* Save the TX enable/disable state */
+
+  priv->wravail = enable;
+
+  /* If the new state is enabled and if there is data in the XMIT buffer,
+   * send the next packet now.
+   */
+
+  if (enable && priv->serdev.xmit.head != priv->serdev.xmit.tail)
+    {
+      usbclass_sndpacket(priv);
+    }
+}
+
+/****************************************************************************
+ * Name: usbser_txempty
+ *
+ * Description:
+ *   Return TRUE when all data has been sent.  This is called from the
+ *   serial driver when the driver is closed.  It will call this API
+ *   periodically until it reports TRUE.  NOTE that the serial driver takes all
+ *   responsibility for flushing TX data through the hardware so we can be
+ *   a bit sloppy about that.
+ *
+ ****************************************************************************/
+
+static boolean usbser_txempty(FAR struct uart_dev_s *dev)
+{
+  struct usbser_dev_s *priv = (FAR struct usbser_dev_s*)dev->priv;
+
+#if CONFIG_DEBUG
+  if (!priv)
+    {
+       return TRUE;
+    }
+#endif
+
+  /* When all of the allocated write requests have been returned to the
+   * reqlist, then there is no longer any TX data in flight.
+   */
+
+  return priv->nwrq >= priv->nwralloc;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: usbdev_serialinitialize
+ *
+ * Description:
+ *   Register USB serial port (and USB serial console if so configured).
+ *
+ ****************************************************************************/
+
+int usbdev_serialinitialize(int minor)
+{
+  FAR struct usbser_alloc_s *alloc;
+  FAR struct usbser_dev_s *priv;
+  FAR struct usbser_driver_s *drvr;
+  char devname[16];
+  int ret;
+
+  /* Allocate the structures needed */
+
+  alloc = (FAR struct usbser_alloc_s*)malloc(sizeof(struct usbser_alloc_s));
+  if (!alloc)
+    {
+      return -ENOMEM;
+    }
+
+  /* Convenience pointers into the allocated blob */
+
+  priv = &alloc->dev;
+  drvr = &alloc->drvr;
+
+  /* Initialize the USB serial driver structure */
+
+  memset(priv, 0, sizeof(struct usbser_dev_s));
+  sq_init(&priv->reqlist);
+
+  /* Fake line status */
+
+  priv->linest[0] = (115200) & 0xff;       /* Baud=115200 */
+  priv->linest[1] = (115200 >> 8) & 0xff;
+  priv->linest[2] = (115200 >> 16) & 0xff;
+  priv->linest[3] = (115200 >> 24) & 0xff;
+  priv->linest[4] = 0;                     /* One stop bit */
+  priv->linest[5] = 0;                     /* No parity */
+  priv->linest[6] = 8;                     /*8 data bits */
+
+  /* Initialize the serial driver sub-structure */
+
+  priv->serdev.recv.size   = CONFIG_USBSER_RXBUFSIZE;
+  priv->serdev.recv.buffer = priv->rxbuffer;
+  priv->serdev.xmit.size   = CONFIG_USBSER_RXBUFSIZE;
+  priv->serdev.xmit.buffer = priv->rxbuffer;
+  priv->serdev.ops         = &g_uartops;
+
+  /* Initialize the USB class driver structure */
+
+#ifdef CONFIG_USBDEV_DUALSPEED
+  drvr->drvr.speed         = USB_SPEED_HIGH;
+#else
+  drvr->drvr.speed         = USB_SPEED_FULL;
+#endif
+  drvr->drvr.ops           = &g_driverops;
+  drvr->dev                = priv;
+
+  /* Register the USB serial class driver */
+
+  ret = usbdev_register(&drvr->drvr);
+  if (ret)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_DEVREGISTER), (uint16)-ret);
+      goto errout_with_alloc;
+    }
+
+  /* Register the USB serial console */
+
+#ifdef CONFIG_USBSER_CONSOLE
+  g_usbserialport.isconsole = TRUE;
+  ret = uart_register("/dev/console", &pri->serdev);
+  if (ret < 0)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_CONSOLEREGISTER), (uint16)-ret);
+      goto errout_with_class;
+    }
+#endif
+
+  /* Register the single port supported by this implementation */
+
+  sprintf(devname, "/dev/ttyUSB%d", minor);
+  ret = uart_register(devname, &priv->serdev);
+  if (ret)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UARTREGISTER), (uint16)-ret);
+      goto errout_with_class;
+    }
+  return OK;
+
+errout_with_class:
+  usbdev_unregister(&drvr->drvr);
+errout_with_alloc:
+  free(alloc);
+  return ret;
+}
diff --git a/include/nuttx/usbdev_trace.h b/include/nuttx/usbdev_trace.h
index 804ea2047034545a324797d76d44f3cfcaa7fe11..abb6bc720e5caa1c0f1868f76cc774bd70d32ef9 100644
--- a/include/nuttx/usbdev_trace.h
+++ b/include/nuttx/usbdev_trace.h
@@ -136,29 +136,33 @@
 
 /* Values of the class error ID used by the USB serial driver */
 
-#define USBSER_TRACEERR_ALLOCCTRLREQ      0x0001
-#define USBSER_TRACEERR_ALREADYCLOSED     0x0002
-#define USBSER_TRACEERR_CONSOLEREGISTER   0x0003
-#define USBSER_TRACEERR_DEVREGISTER       0x0004
-#define USBSER_TRACEERR_EPRESPQ           0x0005
-#define USBSER_TRACEERR_GETUNKNOWNDESC    0x0006
-#define USBSER_TRACEERR_INALLOCEPFAIL     0x0007
-#define USBSER_TRACEERR_INCONFIGEPFAIL    0x0008
-#define USBSER_TRACEERR_INVALIDARG        0x0009
-#define USBSER_TRACEERR_EP0NOTBOUND       0x000a
-#define USBSER_TRACEERR_OUTALLOCEPFAIL    0x000b
-#define USBSER_TRACEERR_OUTCONFIGEPFAIL   0x000c
-#define USBSER_TRACEERR_RDALLOCREQ        0x000d
-#define USBSER_TRACEERR_RDSHUTDOWN        0x000e
-#define USBSER_TRACEERR_RDSUBMIT          0x000f
-#define USBSER_TRACEERR_RDUNEXPECTED      0x0010
-#define USBSER_TRACEERR_REQRESULT         0x0011
-#define USBSER_TRACEERR_SETUPNOTCONNECTED 0x0012
-#define USBSER_TRACEERR_SUBMITFAIL        0x0013
-#define USBSER_TRACEERR_UARTREGISTER      0x0014
-#define USBSER_TRACEERR_WRALLOCREQ        0x0015
-#define USBSER_TRACEERR_WRSHUTDOWN        0x0016
-#define USBSER_TRACEERR_WRUNEXPECTED      0x0017
+#define USBSER_TRACEERR_ALLOCCTRLREQ       0x0001
+#define USBSER_TRACEERR_ALREADYCLOSED      0x0002
+#define USBSER_TRACEERR_CONSOLEREGISTER    0x0003
+#define USBSER_TRACEERR_DEVREGISTER        0x0004
+#define USBSER_TRACEERR_EPRESPQ            0x0005
+#define USBSER_TRACEERR_GETUNKNOWNDESC     0x0006
+#define USBSER_TRACEERR_INALLOCEPFAIL      0x0007
+#define USBSER_TRACEERR_INCONFIGEPFAIL     0x0008
+#define USBSER_TRACEERR_INVALIDARG         0x0009
+#define USBSER_TRACEERR_EP0NOTBOUND        0x000a
+#define USBSER_TRACEERR_OUTALLOCEPFAIL     0x000b
+#define USBSER_TRACEERR_OUTCONFIGEPFAIL    0x000c
+#define USBSER_TRACEERR_RDALLOCREQ         0x000d
+#define USBSER_TRACEERR_RDSHUTDOWN         0x000e
+#define USBSER_TRACEERR_RDSUBMIT           0x000f
+#define USBSER_TRACEERR_RDUNEXPECTED       0x0010
+#define USBSER_TRACEERR_REQRESULT          0x0011
+#define USBSER_TRACEERR_SETUPNOTCONNECTED  0x0012
+#define USBSER_TRACEERR_SUBMITFAIL         0x0013
+#define USBSER_TRACEERR_UARTREGISTER       0x0014
+#define USBSER_TRACEERR_UNSUPPORTEDCTRLREQ 0x0015
+#define USBSER_TRACEERR_UNSUPPORTEDRWREQ   0x0016
+#define USBSER_TRACEERR_UNSUPPORTEDSTDREQ  0x0017
+#define USBSER_TRACEERR_UNSUPPORTEDTYPE    0x0018
+#define USBSER_TRACEERR_WRALLOCREQ         0x0019
+#define USBSER_TRACEERR_WRSHUTDOWN         0x001a
+#define USBSER_TRACEERR_WRUNEXPECTED       0x001b
 
 /****************************************************************************
  * Public Types