diff --git a/drivers/usbdev/usbdev_serial.c b/drivers/usbdev/usbdev_serial.c
index dd771a413659723d3ab8472dcaae17cc2a4e4222..baa11b667d7a57ae140a40b1bb768aff897e79fa 100644
--- a/drivers/usbdev/usbdev_serial.c
+++ b/drivers/usbdev/usbdev_serial.c
@@ -238,11 +238,15 @@ struct usbser_dev_s
 {
   FAR struct uart_dev_s    serdev;    /* Serial device structure */
   FAR struct usbdev_s     *usbdev;    /* usbdev driver pointer */
-  ubyte                    config;    /* Configuration number */
-  ubyte                    nwrq;      /* Number of queue write requests (in reqlist)*/
-  ubyte                    nrdq;      /* Number of queue read requests (in epbulkout) */
-  boolean                  open;      /* TRUE: Driver has been opened */
-  ubyte                    linest[7]; /* Fake line status */
+
+  ubyte config;                       /* Configuration number */
+  ubyte nwrq;                         /* Number of queue write requests (in reqlist)*/
+  ubyte nrdq;                         /* Number of queue read requests (in epbulkout) */
+  ubyte open      : 1;                /* 1: Driver has been opened */
+  ubyte rxenabled : 1;                /* 1: UART RX "interrupts" enabled */
+  ubyte linest[7];                    /* Fake line status */
+  sint16 rxhead;                      /* Working head; used when rx int disabled */
+
   FAR struct usbdev_ep_s  *epintin;   /* Address of Interrupt IN endpoint */
   FAR struct usbdev_ep_s  *epbulkin;  /* Address of Bulk IN endpoint */
   FAR struct usbdev_ep_s  *epbulkout; /* Address of Bulk OUT endpoint */
@@ -288,7 +292,7 @@ struct usbser_alloc_s
 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,
+static inline int usbclass_recvpacket(FAR struct usbser_dev_s *priv,
                  char *packet, uint16 size);
 
 /* Request helpers *********************************************************/
@@ -314,11 +318,11 @@ static int     usbclass_setconfig(FAR struct usbser_dev_s *priv,
 
 /* Completion event handlers ***********************************************/
 
-static void    usbclass_setupcomplete(FAR struct usbdev_ep_s *ep,
+static void    usbclass_ep0incomplete(FAR struct usbdev_ep_s *ep,
                  FAR struct usbdev_req_s *req);
-static void    usbclass_rdcomplete(FAR struct usbdev_ep_s *ep,
+static void    usbclass_epbulkoutcomplete(FAR struct usbdev_ep_s *ep,
                  FAR struct usbdev_req_s *req);
-static void    usbclass_wrcomplete(FAR struct usbdev_ep_s *ep,
+static void    usbclass_epbulkincomplete(FAR struct usbdev_ep_s *ep,
                  FAR struct usbdev_req_s *req);
 
 /* USB class device ********************************************************/
@@ -624,20 +628,33 @@ static int usbclass_sndpacket(FAR struct usbser_dev_s *priv)
  *   interrupt level (with interrupts disabled).  This function handles the USB packet
  *   and provides the received data to the uart RX buffer.
  *
+ * Assumptions:
+ *   Called from the USB interrupt handler with interrupts disabled.
+ *
  ************************************************************************************/
 
-static int usbclass_recvpacket(FAR struct usbser_dev_s *priv, char *packet, uint16 size)
+static inline int usbclass_recvpacket(FAR struct usbser_dev_s *priv,
+                                      char *packet, uint16 size)
 {
   FAR uart_dev_t *serdev = &priv->serdev;
   FAR struct uart_buffer_s *recv = &serdev->recv;
+  uint16 currhead;
   uint16 nexthead;
 
-  /* Get the next head index */
+  /* Get the next head index. During the time that RX interrupts are disabled, the
+   * the serial driver will be extracting data from the circular buffer and modifying
+   * recv.tail.  During this time, we should avoid modifying recv.head; Instead we will
+   * use a shadow copy of the index.  When interrupts are restored, the real recv.head
+   * will be updated with this indes.
+   */
 
-  nexthead = recv->head + 1;
-  if (nexthead >= recv->size)
+  if (priv->rxenabled)
+    {
+      currhead = recv->head;
+    }
+  else
     {
-      nexthead = 0;
+      currhead = priv->rxhead;
     }
 
   /* Then copy data into the RX buffer until either: (1) all of the data has been
@@ -647,27 +664,61 @@ static int usbclass_recvpacket(FAR struct usbser_dev_s *priv, char *packet, uint
 
   while (nexthead != recv->tail && size > 0)
     {
+      /* Pre-increment the head index and check for wrap around.  We need to do this
+       * so that we can determine if the circular buffer will overrun BEFORE we
+       * overrun the buffer!
+       */
+
+      nexthead = currhead + 1;
+      if (nexthead >= recv->size)
+        {
+          nexthead = 0;
+        }
+
       /* Copy one byte to the head of the circular RX buffer */
 
-      recv->buffer[recv->head] = *packet++;
+      recv->buffer[currhead] = *packet++;
 
       /* Update counts and indices */
 
-      recv->head = nexthead;
+      currhead = nexthead;
       size--;
-      if (++nexthead >= recv->size)
-        {
-           nexthead = 0;
-        }
 
-      /* Wake up the serial driver if it is waiting for incoming data */
+      /* Wake up the serial driver if it is waiting for incoming data. If we
+       * are running in an interrupt handler, then the serial driver will
+       * not run until the interrupt handler returns.  But we will exercise
+       * care in the following just in case the serial driver does run.
+       */
 
-      if (serdev->recvwaiting)
+      if (priv->rxenabled && serdev->recvwaiting)
         {
+          recv->head          = currhead;
           serdev->recvwaiting = FALSE;
           sem_post(&serdev->recvsem);
+          currhead            = recv->head;
         }
     }
+
+  /* Write back the head pointer using the shadow index if RX "interrupts"
+   * are disabled.
+   */
+
+  if (priv->rxenabled)
+    {
+      recv->head = currhead;
+    }
+  else
+    {
+      priv->rxhead = currhead;
+    }
+
+  /* Return an error if the entire packet could not be transferred */
+
+  if (size > 0)
+    {
+      usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RXOVERRUN), 0);
+      return -ENOSPC;
+    }
   return OK;
 }
 
@@ -1024,7 +1075,7 @@ static int usbclass_setconfig(FAR struct usbser_dev_s *priv, ubyte config)
   for (i = 0; i < CONFIG_USBSER_NRDREQS; i++)
     {
       req           = priv->rdreqs[i].req;
-      req->callback = usbclass_rdcomplete;
+      req->callback = usbclass_epbulkoutcomplete;
       ret           = EP_SUBMIT(priv->epbulkout, req);
       if (ret != OK)
         {
@@ -1043,14 +1094,14 @@ errout:
 }
 
 /****************************************************************************
- * Name: usbclass_setupcomplete
+ * Name: usbclass_ep0incomplete
  *
  * Description:
  *   Handle completion of EP0 control operations
  *
  ****************************************************************************/
 
-static void usbclass_setupcomplete(FAR struct usbdev_ep_s *ep, struct usbdev_req_s *req)
+static void usbclass_ep0incomplete(FAR struct usbdev_ep_s *ep, struct usbdev_req_s *req)
 {
   if (req->result || req->xfrd != req->len)
     {
@@ -1059,16 +1110,17 @@ static void usbclass_setupcomplete(FAR struct usbdev_ep_s *ep, struct usbdev_req
 }
 
 /****************************************************************************
- * Name: usbclass_rdcomplete
+ * Name: usbclass_epbulkoutcomplete
  *
  * Description:
- *   Handle completion of read request
- *
+ *   Handle completion of read request on the bulk OUT endpoint.  This
+ *   is handled like the receipt of serial data on the "UART"
  ****************************************************************************/
 
-static void usbclass_rdcomplete(FAR struct usbdev_ep_s *ep, struct usbdev_req_s *req)
+static void usbclass_epbulkoutcomplete(FAR struct usbdev_ep_s *ep, struct usbdev_req_s *req)
 {
   FAR struct usbser_dev_s *priv;
+  irqstate_t flags;
   int ret;
 
   /* Sanity check */
@@ -1087,6 +1139,7 @@ static void usbclass_rdcomplete(FAR struct usbdev_ep_s *ep, struct usbdev_req_s
 
   /* Process the received data unless this is some unusual condition */
 
+  flags = irqsave();
   switch (req->result)
     {
     case 0: /* Normal completion */
@@ -1097,6 +1150,7 @@ static void usbclass_rdcomplete(FAR struct usbdev_ep_s *ep, struct usbdev_req_s
     case -ESHUTDOWN: /* Disconnection */
       usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSHUTDOWN), 0);
       priv->nrdq--;
+      irqrestore(flags);
       return;
 
     default: /* Some other error occurred */
@@ -1112,10 +1166,11 @@ static void usbclass_rdcomplete(FAR struct usbdev_ep_s *ep, struct usbdev_req_s
     {
       usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16)-req->result);
     }
+  irqrestore(flags);
 }
 
 /****************************************************************************
- * Name: usbclass_wrcomplete
+ * Name: usbclass_epbulkincomplete
  *
  * Description:
  *   Handle completion of write request.  This function probably executes
@@ -1123,7 +1178,7 @@ static void usbclass_rdcomplete(FAR struct usbdev_ep_s *ep, struct usbdev_req_s
  *
  ****************************************************************************/
 
-static void usbclass_wrcomplete(FAR struct usbdev_ep_s *ep, struct usbdev_req_s *req)
+static void usbclass_epbulkincomplete(FAR struct usbdev_ep_s *ep, struct usbdev_req_s *req)
 {
   FAR struct usbser_dev_s *priv;
   FAR struct usbser_req_s *reqcontainer;
@@ -1208,7 +1263,7 @@ static int usbclass_bind(FAR struct usbdev_s *dev, FAR struct usbdevclass_driver
       ret = -ENOMEM;
       goto errout;
     }
-  priv->ctrlreq->callback = usbclass_setupcomplete;
+  priv->ctrlreq->callback = usbclass_ep0incomplete;
 
   /* Pre-allocate all endpoints... the endpoints will not be functional
    * until the SET CONFIGURATION request is processed in usbclass_setconfig.
@@ -1263,7 +1318,7 @@ static int usbclass_bind(FAR struct usbdev_s *dev, FAR struct usbdevclass_driver
           goto errout;
         }
       reqcontainer->req->private  = reqcontainer;
-      reqcontainer->req->callback = usbclass_rdcomplete;
+      reqcontainer->req->callback = usbclass_epbulkoutcomplete;
     }
 
   /* Pre-allocate write request containers and put in a free list */
@@ -1279,7 +1334,7 @@ static int usbclass_bind(FAR struct usbdev_s *dev, FAR struct usbdevclass_driver
           goto errout;
         }
       reqcontainer->req->private  = reqcontainer;
-      reqcontainer->req->callback = usbclass_wrcomplete;
+      reqcontainer->req->callback = usbclass_epbulkincomplete;
 
       flags = irqsave();
       sq_addlast((sq_entry_t*)reqcontainer, &priv->reqlist);
@@ -1664,7 +1719,7 @@ static int usbclass_setup(FAR struct usbdev_s *dev, const struct usb_ctrlreq_s *
         {
           usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPRESPQ), (uint16)-ret);
           ctrlreq->result = OK;
-          usbclass_setupcomplete(dev->ep0, ctrlreq);
+          usbclass_ep0incomplete(dev->ep0, ctrlreq);
         }
     }
 
@@ -1762,7 +1817,7 @@ static int usbser_setup(FAR struct uart_dev_s *dev)
 
   /* Mark the device as opened */
 
-  priv->open = TRUE;
+  priv->open = 1;
   return OK;
 }
 
@@ -1812,7 +1867,7 @@ static void usbser_shutdown(FAR struct uart_dev_s *dev)
   /* Make sure that we are disconnected from the host */
 
   usbclass_resetconfig(priv);
-  priv->open = FALSE;
+  priv->open = 0;
   irqrestore(flags);
 }
 
@@ -1863,6 +1918,8 @@ static void usbser_detach(FAR struct uart_dev_s *dev)
 static void usbser_rxint(FAR struct uart_dev_s *dev, boolean enable)
 {
   FAR struct usbser_dev_s *priv;
+  FAR uart_dev_t *serdev;
+  irqstate_t flags;
 
   usbtrace(USBSER_CLASSAPI_RXINT, (uint16)enable);
 
@@ -1878,20 +1935,69 @@ static void usbser_rxint(FAR struct uart_dev_s *dev, boolean enable)
 
   /* Extract reference to private data */
 
-  priv = (FAR struct usbser_dev_s*)dev->priv;
+  priv   = (FAR struct usbser_dev_s*)dev->priv;
+  serdev = &priv->serdev;
 
-  /* I think we can simulate this behavior by stalling and/or resuming the
-   * OUT endpoint.
+  /* We need exclusive access to the RX buffer and private structure
+   * in the following.
    */
 
+  flags = irqsave();
   if (enable)
     {
-      EP_RESUME(priv->epbulkout);
+       /* RX "interrupts" are enabled.  Is this a transition from disabled
+        * to enabled state?
+        */
+
+       if (!priv->rxenabled)
+         {
+           /* Yes.  During the time that RX interrupts are disabled, the
+            * the serial driver will be extracting data from the circular
+            * buffer and modifying recv.tail.  During this time, we
+            * should avoid modifying recv.head; When interrupts are restored,
+            * we can update the head pointer for all of the data that we
+            * put into cicular buffer while "interrupts" were disabled.
+            */
+
+          if (priv->rxhead != serdev->recv.head)
+            {
+              serdev->recv.head = priv->rxhead;
+
+              /* Is the serial driver waiting for more data? */
+
+              if (serdev->recvwaiting)
+                {
+                  /* Yes... signal the availability of new data */
+
+                  sem_post(&serdev->recvsem);
+                  serdev->recvwaiting = FALSE;
+                }
+            }
+
+          /* RX "interrupts are no longer disabled */
+
+          priv->rxenabled = 1;
+        }
     }
-  else
+
+  /* RX "interrupts" are disabled.  Is this a transition from enabled
+   * to disabled state?
+   */
+
+  else if (priv->rxenabled)
     {
-      EP_STALL(priv->epbulkout);
+      /* Yes.  During the time that RX interrupts are disabled, the
+       * the serial driver will be extracting data from the circular
+       * buffer and modifying recv.tail.  During this time, we
+       * should avoid modifying recv.head; When interrupts are disabled,
+       * we use a shadow index and continue adding data to the circular
+       * buffer.
+       */
+
+      priv->rxhead    = serdev->recv.head;
+      priv->rxenabled = 0;
     }
+  irqrestore(flags);
 }
 
 /****************************************************************************