Skip to content
Snippets Groups Projects
lpc214x_usbdev.c 80.7 KiB
Newer Older

  /* End of Transfer Interrupt Clear */

  putreq32(0xffffffff, LPC214X_USBDEV_EOTINTCLR);

  /* New DD Request Interrupt Clear */

  putreq32(0xffffffff, LPC214X_USBDEV_NDDRINTCLR);

  /* System Error Interrupt Clear */

  putreq32(0xffffffff, LPC214X_USBDEV_SYSERRINTCLR);

  /* Nullify all pointers in the UDCA */

  for (i = 0; i < LPC214X_NPHYSENDPOINTS; ++i)
    {
      USB_UDCA[i] = NULL;
    }

  /* Set USB UDCA Head register */

  lpc214x_putreg((uint32)USB_UDCA, LPC214X_USBDEV_UDCAH);

  /* Invalidate all DMA descriptors */

  for (i = 0; i < CONFIG_LPC214X_USBDEV_NDMADESCRIPTORS; ++i)
    {
      memset(&USB_DDESC[i], 0, USB_DDESCSIZE);
    }

  /* Enable DMA interrupts */

  lpc214x_putreg(enable, LPC214X_USBDEV_DMAINTEN);
}
#endif

/*******************************************************************************
 * Name: lpc214x_usbreset
 *
 * Description:
 *   Reset Usb engine
 *
 *******************************************************************************/

static void lpc214x_usbreset(struct lpc214x_usbdev_s *priv)
{
  /* Disable all endpoint interrupts */

  lpc214x_putreg(0, LPC214X_USBDEV_EPINTEN);

  /* Frame is Hp interrupt */

  lpc214x_putreg(1, LPC214X_USBDEV_DEVINTPRI);

  /* Clear all pending interrupts */

  lpc214x_putreg(0xffffffff, LPC214X_USBDEV_EPINTCLR);
  lpc214x_putreg(0xffffffff, LPC214X_USBDEV_DEVINTCLR);

  /* Periperhal address is needed */

  priv->paddrset = 0;

  /* Endpoints not yet configured */

  lpc214x_usbcmd(CMD_USB_DEV_CONFIG, 0);

  /* EndPoint 0 initialization */

  lpc214x_ep0configure(priv);

#ifdef CONFIG_LPC214X_USBDEV_DMA
  /* Enable End_of_Transfer_Interrupt and System_Error_Interrupt USB DMA
   * interrupts
   */

  lpc214x_dmareset(CONFIG_LPC214X_USBDEV_DMAINTMASK);

#endif

  /* Enable Device interrupts */

  lpc214x_putreg(USB_SLOW_INT|USB_DEVSTATUS_INT|USB_FAST_INT|USB_FRAME_INT|USB_ERROR_INT,
                 LPC214X_USBDEV_DEVINTEN);
}

/*******************************************************************************
 * Name: lpc214x_dispatchrequest
 *
 * Description:
 *   Provide unhandled setup actions to the class driver. This is logically part
 *   of the USB interrupt handler.
 *
 *******************************************************************************/

static void lpc214x_dispatchrequest(struct lpc214x_usbdev_s *priv,
patacongo's avatar
patacongo committed
                                    const struct usb_ctrlreq_s *ctrl)
{
  int ret;

  usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_DISPATCH), 0);
  if (priv && priv->driver)
    {
patacongo's avatar
patacongo committed
      ret = CLASS_SETUP(priv->driver, &priv->usbdev, ctrl);
      if (ret < 0)
        {
          /* Stall on failure */

          priv->stalled = 1;
        }
      else
        {
          lpc214x_epwrite(LPC214X_EP0_IN, NULL, 0);
          priv->ep0state = LPC214X_EP0SHORTWRITE;
        }
    }
}

/*******************************************************************************
 * Name: lpc214x_ep0setup
 *
 * Description:
 *   USB Ctrl EP Setup Event. This is logically part of the USB interrupt
 *   handler.
 *
 *******************************************************************************/

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 = (struct lpc214x_req_s *)sq_peek(&ep0->reqlist);
patacongo's avatar
patacongo committed
  struct usb_ctrlreq_s ctrl;
  uint16 index;
  ubyte  epphy;
  ubyte  response[2];
  int    ret;

  /* Starting a control request? */

  if (priv->usbdev.speed == USB_SPEED_UNKNOWN)
    {
      priv->usbdev.speed = USB_SPEED_FULL;
      lpc214x_usbcmd(CMD_USB_DEV_CONFIG, 1);
    }

  /* Terminate any pending requests */

  while (!sq_empty(&ep0->reqlist))
    {
      sint16 result = OK;
      if (privreq->req.xfrd != privreq->req.len)
        {
          result = -EPROTO;
        }

patacongo's avatar
patacongo committed
      usbtrace(TRACE_COMPLETE(ep0->epphy), privreq->req.xfrd);
      lpc214x_reqcomplete(ep0, result);
    }

  /* Assume NOT stalled */

  ep0->stalled  = 0;
  priv->stalled = 0;

  /* Read EP0 data */

patacongo's avatar
patacongo committed
  ret = lpc214x_epread(LPC214X_EP0_OUT, (ubyte*)&ctrl, sizeof(struct usb_ctrlreq_s));
  if (ret <= 0)
    {
      return;
    }

  /* Dispatch any non-standard requests */

patacongo's avatar
patacongo committed
  ep0->in = (ctrl.type & USB_DIR_IN) != 0;
  if ((ctrl.type & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD)
patacongo's avatar
patacongo committed
      lpc214x_dispatchrequest(priv, &ctrl);
      return;
    }

  /* Handle standard request.  Pick off the things of interest to the
   * USB device controller driver; pass what is left to the class driver
   */

patacongo's avatar
patacongo committed
  switch (ctrl.req)
    {
    case USB_REQ_GETSTATUS:
      {
        /* Length must be 2, from device, and value == 0 */

patacongo's avatar
patacongo committed
        if (!priv->paddrset || GETUINT16(ctrl.len) != 2 ||
            (ctrl.type & USB_REQ_DIR_IN) == 0 || GETUINT16(ctrl.value) != 0)
patacongo's avatar
patacongo committed
            switch (ctrl.type & USB_REQ_RECIPIENT_MASK)
              {
              case USB_REQ_RECIPIENT_ENDPOINT:
                {
                  usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPGETSTATUS), 0);
patacongo's avatar
patacongo committed
                  epphy = USB_EPNO(GETUINT16(ctrl.index)) << 1;
                  if (epphy < LPC214X_NPHYSENDPOINTS)
                    {
                       if ((lpc214x_usbcmd(CMD_USB_EP_SELECT|epphy, 0) & CMD_USB_EPSELECT_ST) != 0)
                         {
                           response[0] = 1; /* Stalled */
                         }
                       else
                         {
                           response[0] = 0; /* Not stalled */
                         }
                      response[1] = 0;
                      lpc214x_epwrite(LPC214X_EP0_IN, response, 2);
                      priv->ep0state = LPC214X_EP0SHORTWRITE;
                    }
                  else
                    {
                      priv->stalled = 1;
                    }
                }
                break;

              case USB_REQ_RECIPIENT_DEVICE:
                {
patacongo's avatar
patacongo committed
                  index = GETUINT16(ctrl.index);
                  if (index == 0)
                    {
                      usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_DEVGETSTATUS), 0);

                      /* Features:  Remote Wakeup=YES; selfpowered=? */

                      response[0] = (priv->selfpowered << USB_FEATURE_SELFPOWERED) |
                                    (1 << USB_FEATURE_REMOTEWAKEUP);
                      response[1] = 0;
                      lpc214x_epwrite(LPC214X_EP0_IN, response, 2);
                      priv->ep0state = LPC214X_EP0SHORTWRITE;
                    }
                  else
                    {
                      priv->stalled = 1;
                    }
                }
                break;

              case USB_REQ_RECIPIENT_INTERFACE:
                {
                  usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_IFGETSTATUS), 0);
                  response[0] = 0;
                  response[1] = 0;
                  lpc214x_epwrite(LPC214X_EP0_IN, response, 2);
                  priv->ep0state = LPC214X_EP0SHORTWRITE;
                }
                break;

              default:
                {
                  priv->stalled = 1;
                }
                break;
              }
          }
      }
      break;

    case USB_REQ_CLEARFEATURE:
      {
        usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_CLEARFEATURE), 0);
patacongo's avatar
patacongo committed
        if (ctrl.type != USB_REQ_RECIPIENT_ENDPOINT)
patacongo's avatar
patacongo committed
            lpc214x_dispatchrequest(priv, &ctrl);
patacongo's avatar
patacongo committed
        else if (priv->paddrset && GETUINT16(ctrl.value) == USB_ENDPOINT_HALT &&
                 GETUINT16(ctrl.index) < LPC214X_NLOGENDPOINTS && GETUINT16(ctrl.len) == 0)
patacongo's avatar
patacongo committed
            ubyte epphys = LPC214X_EP_LOG2PHY(GETUINT16(ctrl.index));
            priv->eplist[epphys].halted = 0;
            lpc214x_epwrite(LPC214X_EP0_IN, NULL, 0);
            priv->ep0state = LPC214X_EP0STATUSIN;
          }
        else
          {
              priv->stalled = 1;
          }
      }
      break;

    case USB_REQ_SETFEATURE:
      {
        usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_SETFEATURE), 0);
patacongo's avatar
patacongo committed
        if (ctrl.type == USB_REQ_RECIPIENT_DEVICE &&
            GETUINT16(ctrl.value) == USB_FEATURE_TESTMODE)
patacongo's avatar
patacongo committed
            uvdbg("test mode: %d\n", GETUINT16(ctrl.index));
patacongo's avatar
patacongo committed
        else if (ctrl.type != USB_REQ_RECIPIENT_ENDPOINT)
patacongo's avatar
patacongo committed
           lpc214x_dispatchrequest(priv, &ctrl);
patacongo's avatar
patacongo committed
        else if (priv->paddrset && GETUINT16(ctrl.value) == USB_ENDPOINT_HALT &&
                 GETUINT16(ctrl.index) < LPC214X_NLOGENDPOINTS && GETUINT16(ctrl.len) == 0)
patacongo's avatar
patacongo committed
            ubyte epphys = LPC214X_EP_LOG2PHY(GETUINT16(ctrl.index));
            priv->eplist[epphys].halted = 1;
            lpc214x_epwrite(LPC214X_EP0_IN, NULL, 0);
            priv->ep0state = LPC214X_EP0STATUSIN;
          }
        else
          {
             priv->stalled = 1;
          }
      }
      break;

    case USB_REQ_SETADDRESS:
      {
        usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_SETADDRESS), 0);
patacongo's avatar
patacongo committed
        if ((ctrl.type == USB_REQ_RECIPIENT_DEVICE) &&
            (GETUINT16(ctrl.index)  == 0) && (GETUINT16(ctrl.len) == 0) &&
            (GETUINT16(ctrl.value) < 128))
          {
            lpc214x_epwrite(LPC214X_EP0_IN, NULL, 0);
patacongo's avatar
patacongo committed
            priv->eplist[LPC214X_EP0_OUT].eplog = ctrl.value[0];
            priv->eplist[LPC214X_EP0_IN].eplog  = ctrl.value[0];
            priv->ep0state = LPC214X_EP0SETADDRESS;
          }
        else
          {
            priv->stalled = 1;
          }
      }
      break;

    case USB_REQ_GETDESCRIPTOR:
    case USB_REQ_SETDESCRIPTOR:
    case USB_REQ_GETCONFIGURATION:
      {
patacongo's avatar
patacongo committed
        if (priv->paddrset && (GETUINT16(ctrl.value) == 0) &&
            (GETUINT16(ctrl.index) == 0) && (GETUINT16(ctrl.len) == 1))
patacongo's avatar
patacongo committed
            lpc214x_dispatchrequest(priv, &ctrl);
          }
        else
          {
            priv->stalled = 1;
          }
      }
      break;


    case USB_REQ_SETCONFIGURATION:
    case USB_REQ_GETINTERFACE:
    case USB_REQ_SETINTERFACE:
      {
patacongo's avatar
patacongo committed
       lpc214x_dispatchrequest(priv, &ctrl);
      }
      break;

    case USB_REQ_SYNCHFRAME:
      break;

    default:
      priv->stalled = 1;
      break;
    }

  if (priv->stalled)
    {
      usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_STALLED), priv->ep0state);
      lpc214x_epstall(&ep0->ep, FALSE);
      lpc214x_epstall(&ep0->ep, FALSE);
    }
}

/*******************************************************************************
 * Name: lpc214x_ep0dataoutinterrupt
 *
 * Description:
 *   USB Ctrl EP Data OUT Event. This is logically part of the USB interrupt
 *   handler.
 *
 *******************************************************************************/

static inline void lpc214x_ep0dataoutinterrupt(struct lpc214x_usbdev_s *priv)
{
  struct lpc214x_ep_s *ep0;
  uint32 pktlen;

  /* Copy new setup packet int setup buffer */

  switch (priv->ep0state)
    {
    case LPC214X_EP0SHORTWRITE:
      {
        priv->ep0state = LPC214X_EP0STATUSOUT;
        pktlen = lpc214x_epread(LPC214X_EP0_OUT, NULL, CONFIG_USBDEV_EP0_MAXSIZE);
        if (LPC214X_READOVERRUN(pktlen))
          {
            lpc214x_ep0setup(priv);
          }
      }
      break;

    case LPC214X_EP0SHORTWRSENT:
      {
        priv->ep0state = LPC214X_EP0IDLE;
        pktlen = lpc214x_epread(LPC214X_EP0_OUT, NULL, CONFIG_USBDEV_EP0_MAXSIZE);
        if (LPC214X_READOVERRUN(pktlen))
          {
            lpc214x_ep0setup(priv);
          }
      }
      break;

    case LPC214X_EP0IDLE:
      {
        ep0 = &priv->eplist[LPC214X_EP0_OUT];
        if (!sq_empty(&ep0->reqlist))
          {
            lpc214x_wrrequest(ep0);
          }
      }
      break;

    default:
      priv->stalled = 1;
      break;
    }

  if (priv->stalled)
    {
      usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_STALLED), priv->ep0state);
      ep0 = &priv->eplist[LPC214X_EP0_OUT];
      lpc214x_epstall(&ep0->ep, FALSE);
      lpc214x_epstall(&ep0->ep, FALSE);
    }
  return;
}

/*******************************************************************************
 * Name: lpc214x_ep0dataininterrupt
 *
 * Description:
 *   USB Ctrl EP Data IN Event. This is logically part of the USB interrupt
 *   handler.
 *
 *******************************************************************************/

static inline void lpc214x_ep0dataininterrupt(struct lpc214x_usbdev_s *priv)
{
  struct lpc214x_ep_s *ep0;

  switch (priv->ep0state)
    {
    case LPC214X_EP0STATUSOUT:
    case LPC214X_EP0STATUSIN:
      priv->ep0state = LPC214X_EP0IDLE;
      break;

    case LPC214X_EP0SHORTWRITE:
      priv->ep0state = LPC214X_EP0SHORTWRSENT;
      break;

    case LPC214X_EP0SETADDRESS:
      {
        usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_SETADDRESS), 0);

        /* Set EP0 logical address */

        ubyte eplog = priv->eplist[LPC214X_EP0_OUT].eplog;
        lpc214x_usbcmd(CMD_USB_DEV_SETADDRESS, CMD_USB_SETADDRESS_DEVEN | eplog);
        lpc214x_usbcmd(CMD_USB_DEV_SETADDRESS, CMD_USB_SETADDRESS_DEVEN | eplog);

        /* Not yet fully configured */

        lpc214x_usbcmd(CMD_USB_DEV_CONFIG, 0);
        if (eplog)
          {
            priv->paddrset = 1;
            priv->ep0state = LPC214X_EP0IDLE;
          }
      }
      break;

    default:
      priv->stalled = 1;
      break;
    }

  if (priv->stalled)
    {
      usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_STALLED), priv->ep0state);
      ep0 = &priv->eplist[LPC214X_EP0_IN];
      lpc214x_epstall(&ep0->ep, FALSE);
      lpc214x_epstall(&ep0->ep, FALSE);
    }
}

/*******************************************************************************
 * Name: lpc214x_usbinterrupt
 *
 * Description:
 *   USB interrupt handler
 *
 *******************************************************************************/

static int lpc214x_usbinterrupt(int irq, FAR void *context)
{
  struct lpc214x_usbdev_s *priv = &g_usbdev;
  struct lpc214x_ep_s *privep ;

  uint32 devintstatus;  /* Sampled state of the device interrupt status register */
  uint32 epintstatus;   /* Sampled state of the endpoint interrupt status register */
#ifdef CONFIG_LPC214X_USBDEV_DMA
  uint32 dmaintstatus;  /* Sampled state of dma interrupt status register */
#endif
  uint32 softprio;      /* Current priority interrupt bitset */
  uint32 pending;       /* Pending subset of priority interrupt bitset */
  ubyte  epphy;         /* Physical endpoint number being processed */
  int    i;

  usbtrace(TRACE_INTENTRY(LPC214X_TRACEINTID_USB), 0);

  /* Read the device interrupt status register */

  devintstatus = lpc214x_getreg(LPC214X_USBDEV_DEVINTST);

#ifdef CONFIG_LPC214X_USBDEV_DMA
  /* Check for low priority and high priority (non-DMA) interrupts */

  if ((lpc214x_getreg(LPC214X_USBDEV_INTST) & (USBDEV_INTST_REQLP|USBDEV_INTST_REQHP)) != 0)
    {
#endif
#ifdef CONFIG_LPC214X_USBDEV_EPFAST_INTERRUPT
      /* Fast EP interrupt */

      if ((devintstatus & USBDEV_DEVINT_EPFAST) != 0)
        {
          /* Clear Fast EP interrupt */

         lpc214x_putreg(USBDEV_DEVINT_EPFAST, LPC214X_USBDEV_DEVINTCLR);
         usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPFAST), 0);

         /* Do what? */
        }

#endif

#if CONFIG_DEBUG
      /* USB engine error interrupt */

      if ((devintstatus & USBDEV_DEVINT_EPRINT))
        {
          ubyte errcode;

          /* Clear the error interrupt */

          lpc214x_putreg(USBDEV_DEVINT_EPRINT, LPC214X_USBDEV_DEVINTCLR);

          /* And show what error occurred */

          errcode  = (ubyte)lpc214x_usbcmd(CMD_USB_DEV_READERRORSTATUS, 0) & 0x0f;
          usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPRINT), (uint16)errcode);
        }
#endif

#ifdef CONFIG_LPC214X_USBDEV_FRAME_INTERRUPT
      /* Frame interrupt */

      if ((devintstatus & USBDEV_DEVINT_FRAME) != 0)
        {
          /* Clear the frame interrupt */

          lpc214x_putreg(USBDEV_DEVINT_FRAME, LPC214X_USBDEV_DEVINTCLR);
          usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_FRAME), 0);

          /* Then read the start of frame value */

          priv->sof = (uint16)lpc214x_usbcmd(CMD_USB_DEV_READFRAMENO, 0);
        }
#endif

      /* Device Status interrupt */

      if ((devintstatus & USBDEV_DEVINT_DEVSTAT) != 0)
        {
          /* Clear Device status interrupt */

          lpc214x_putreg(USBDEV_DEVINT_DEVSTAT, LPC214X_USBDEV_DEVINTCLR);

          /* Get device status */

          g_usbdev.devstatus = lpc214x_usbcmd(CMD_USB_DEV_GETSTATUS, 0);
          usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_DEVSTAT), (uint16)g_usbdev.devstatus);

          /* Device connection status */

          if (DEVSTATUS_CONNCHG(g_usbdev.devstatus))
            {
              usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_CONNECTCHG), 0);
              if (DEVSTATUS_CONNECT(g_usbdev.devstatus))
                {
                   /* Host is connected */

                   if (!priv->attached)
                     {
                       /* We have a transition from unattached to attached */

                       usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_CONNECTED), 0);
                       priv->usbdev.speed = USB_SPEED_UNKNOWN;
                       lpc214x_usbcmd(CMD_USB_DEV_CONFIG, 0);
                       priv->attached     = 1;
                    }
                 }

               /* Otherwise the host is not attached */

               else if (priv->attached)
                 {
                   usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_DISCONNECTED), 0);
                   priv->usbdev.speed = USB_SPEED_UNKNOWN;
                   lpc214x_usbcmd(CMD_USB_DEV_CONFIG, 0);
                   priv->attached = 0;
                   priv->paddrset = 0;
                 }
            }

          /* Device suspend status */

          if (DEVSTATUS_SUSPCHG(g_usbdev.devstatus))
            {
              usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_SUSPENDCHG), 0);
            }

          /* Device reset */

          if (DEVSTATUS_RESET(g_usbdev.devstatus))
            {
              usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_DEVRESET), 0);
              lpc214x_usbreset(priv);
            }
        }

      /* Slow EP interrupt */

      if ((devintstatus & USBDEV_DEVINT_EPSLOW) != 0)
        {
          /* Clear Slow EP interrupt */

          lpc214x_putreg(USBDEV_DEVINT_EPSLOW, LPC214X_USBDEV_DEVINTCLR);
          usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPSLOW), 0);

          do
            {
              /* Read the endpoint interrupt status register */

              epintstatus = lpc214x_getreg(LPC214X_USBDEV_EPINTST);

              /* Loop twice:  Process software high priority interrupts
               * on the first pass and low priority interrupts on the
               * second.
               */

              softprio = priv->softprio;
              for (i = 0; i < 2; i++, softprio = ~softprio)
                {
                  /* On the first time through the loop, pending will be
                   * the bitset of high priority pending interrupts; on the
                   * second time throught it will be the bitset of low
                   * priority interrupts.
                   */

                  pending = epintstatus & softprio;

                  /* EP0 OUT interrupt indicated by bit0 == 1 */

                  if ((pending & 1) != 0)
                    {
                      /* Clear the endpoint interrupt */

                      uint32 result = lpc214x_epclrinterrupt(LPC214X_CTRLEP_OUT);
                      if (result & USBDEV_EPSETUPPACKET)
                        {
                          usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EP0SETUP), (uint16)result);
                          lpc214x_ep0setup(priv);
                        }
                      else
                        {
                          usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EP0OUT), priv->ep0state);
                          lpc214x_ep0dataoutinterrupt(priv);
                        }
                      break;
                    }

                  /* EP0 IN interrupt indicated by bit1 == 1 */

                  if ((pending & 2) != 0)
                    {
                      /* Clear the endpoint interrupt */

                      usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EP0IN), priv->ep0state);
                      (void)lpc214x_epclrinterrupt(LPC214X_CTRLEP_IN);
                      lpc214x_ep0dataininterrupt(priv);
                    }
                  pending >>= 2;

                  /* All other endpoints EP 1-31 */

                  for (epphy = 2; pending; epphy++, pending >>= 1)
                    {
                      /* Is the endpoint interrupt pending? */

                      if ((pending & 1) != 0)
                        {
                           /* Yes.. clear the endpoint interrupt */

                          (void)lpc214x_epclrinterrupt(epphy);

                          /* Get the endpoint sructure corresponding to the physical
                           * endpoint number.
                           */

                          privep =  &priv->eplist[epphy];

                          /* Check for complete on IN or OUT endpoint.  Odd physical
                           * endpoint addresses are IN endpoints.
                           */

                          if ((epphy & 1) != 0)
                            {
                              /* IN: device-to-host */

                              usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPOUT), (uint16)epphy);
                              if (priv->usbdev.speed == USB_SPEED_UNKNOWN)
                                {
                                  priv->usbdev.speed = USB_SPEED_FULL;
                                  lpc214x_usbcmd(CMD_USB_DEV_CONFIG, 1);
                                }

                              /* Write host data from the current write request */

                              if (!sq_empty(&privep->reqlist))
                                {
                                  lpc214x_wrrequest(privep);
                                }
                           }
                          else
                            {
                              /* OUT: host-to-device */

                              usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPIN), (uint16)epphy);

                              /* Read host data into the current read request */

                             if (!sq_empty(&privep->reqlist))
                                 {
                                  lpc214x_rdrequest(privep);
                                }
                              else
                                {
                                  uvdbg("Pending interrupt\n");
                                  priv->rxpending = 1;
                                }
                            }
                        }
                    }
                }
            }
          while (epintstatus);
        }
#ifdef CONFIG_LPC214X_USBDEV_DMA
    }

  /* Check for DMA interrupts */

  if ((lpc214x_getreg(LPC214X_USBDEV_INTST) & USBDEV_INTST_REQDMA) != 0)
    {
      /* First Software High priority and then low priority */

      uint32 tmp;

      /* Collect the DMA interrupt sources */

      dmaintstatus = 0;
      tmp = lpc214x_getreg(LPC214X_USBDEV_EOTINTST);
      if (lpc214x_getreg(LPC214X_USBDEV_DMAINTEN) & 1)
      lpc214x_putreg(tmp, LPC214X_USBDEV_EOTINTCLR);
      tmp = lpc214x_getreg(LPC214X_USBDEV_NDDRINTST);
      if (lpc214x_getreg(LPC214X_USBDEV_DMAINTEN) & 2)
      lpc214x_putreg(tmp, LPC214X_USBDEV_NDDRINTCLR);
      tmp = lpc214x_getreg(LPC214X_USBDEV_SYSERRINTST);
      if (lpc214x_getreg(LPC214X_USBDEV_DMAINTEN) & 4)
      lpc214x_putreg(tmp, LPC214X_USBDEV_SYSERRINTCLR);

      /* Loop twice:  Process software high priority interrupts on the
       * first pass and low priority interrupts on the second.
       */

      softprio = priv->softprio;
      for (i = 0; i < 2; i++, softprio = ~softprio)
        {
          /* On the first time through the loop, pending will be
           * the bitset of high priority pending interrupts; on the
           * second time throught it will be the bitset of low
           * priority interrupts. Note that EP0 IN and OUT are
           * omitted.
           */

          pending = (dmaintstatus & softprio) >> 2;
          for (epphy = 2; pending; epphy++, pending >>= 1)
            {
              if ((pending & 1) != 0)
                {
                  usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPDMA), (uint16)epphy);
#warning DO WHAT?
                }
            }
        }
    }
#endif
  usbtrace(TRACE_INTEXIT(LPC214X_TRACEINTID_USB), 0);
  return OK;
}

/*******************************************************************************
 * Name: lpc214x_dmasetup
 *
 * Description:
 *   Setup for DMA Transfer
 *
 *******************************************************************************/

#ifdef CONFIG_LPC214X_USBDEV_DMA
static int lpc214x_dmasetup(struct lpc214x_usbdev_s *priv, ubyte epphy,
                            uint32 epmaxsize, uint32 nbytes, uint32 *isocpacket,
                            boolean isochronous);
{
  struct lpc214x_dmadesc_s *dmadesc = priv;
  uint32 reg;

#ifdef CONFIG_DEBUG
  if (!priv || epphy < 2)
    {
      usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_INVALIDPARMS), 0);
      return -EINVAL;
    }
#endif

  /* Check if a DMA descriptor has been assigned.  If not, than that indicates
   * that we will have to do parallel I/O
   */

  if (!dmadesc)
    {
      usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_NODMADESC), 0);
      return -EBUSY;
    }

  /* Verify that the DMA descriptor is available */

  if ((dmadesc->status & USB_DMADESC_STATUSMASK) == USB_DMADESC_BEINGSERVICED)
    {
      usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_DMABUSY), 0);
      return -EBUSY; /* Shouldn't happen */
    }

  /* Init DMA Descriptor */

  dmadesc->nexdesc = 0;
  dmadesc->config  = USB_DMADESC_MODENORMAL |
                     ((epmaxsize << USB_DMADESC_PKTSIZESHIFT) & USB_DMADESC_PKTSIZEMASK) |
                     ((nbytes << USB_DMADESC_BULENSHIFT) & USB_DMADESC_BUFLENMASK);

#ifdef CONFIG_USBDEV_ISOCHRONOUS
  if (isochronous)
    {
      dmadesc->config |= USB_DMADESC_ISCOEP;
    }
#endif

  dmadesc->start = (uint32)&dmadesc->buffer;
  dmadesc->status = 0;

#ifdef CONFIG_USBDEV_ISOCHRONOUS
  dmadesc->size = (uint32)packet;
#endif

  /* Enable DMA tranfer for this endpoint */

  putreq32(1 << epphy, LPC214X_USBDEV_EPDMAEN);

  /* Check state of IN/OUT Ep buffer */

  reg = lpc214x_usbcmd(CMD_USB_EP_SELECT | epphy, 0);

  if (((epphy & 1) != 0 &&  (reg & 0x60) == 0) ||
      ((epphy & 1) == 0 &&  (reg & 0x60) == 0x60))
    {
      /* DMA should be "being serviced" */

      if ((dmadesc->status & USB_DMADESC_STATUSMASK) != USB_DMADESC_BEINGSERVICED))
        {
          /* Re-trigger the DMA Transfer */

          putreq21(1 << epphy, LPC214X_USBDEV_DMARCLR);
          putreq32(1 << epphy, LPC214X_USBDEV_EPDMAEN);
        }
    }
  return OK;
}
#endif /* CONFIG_LPC214X_USBDEV_DMA */

/*******************************************************************************
 * Name: lpc214x_dmarestart
 *
 * Description:
 *   Restart DMA Transfer
 *
 *******************************************************************************/

#ifdef CONFIG_LPC214X_USBDEV_DMA
static void lpc214x_dmarestart(ubyte epphy, uint32 descndx)
{
  uint32 reg;

  /* Clear DMA descriptor status */

  USB_DmaDesc[descndx].status = 0;

  /* Enable DMA transfer on the endpoint */

  lpc214x_putreg(1 << epph, LPC214X_USBDEV_EPDMAEN);

  /* Check the state of IN/OUT EP buffer */

  uint32 reg = lpc214x_usbcmd(CMD_USB_EP_SELECT | epphy, 0);
  if (((epphy & 1) != 0 &&  (reg & 0x60) == 0) ||
      ((epphy & 1) == 0 &&  (reg & 0x60) == 0x60))
    {
      /* Re-trigger the DMA Transfer */

      putreq21(1 << epphy, LPC214X_USBDEV_DMARCLR);
      putreq32(1 << epphy, LPC214X_USBDEV_EPDMAEN);
    }
}
#endif /* CONFIG_LPC214X_USBDEV_DMA */

/*******************************************************************************
 * Name: lpc214x_dmadisable
 *
 * Description:
 *   Disable DMA transfer for the EP
 *
 *******************************************************************************/

#ifdef CONFIG_LPC214X_USBDEV_DMA
static void lpc214x_dmadisable(ubyte epphy)
{
  EPDMADIS = 1 << epphy;
}
#endif /* CONFIG_LPC214X_USBDEV_DMA */

/*******************************************************************************
 * Endpoint operations
 *******************************************************************************/

/*******************************************************************************
 * Name: lpc214x_epconfigure
 *
 * Description:
 *   Configure endpoint, making it usable
 *
 *******************************************************************************/

static int lpc214x_epconfigure(FAR struct usbdev_ep_s *ep,
                               FAR const struct usb_epdesc_s *desc)
{
  FAR struct lpc214x_ep_s *privep = (FAR struct lpc214x_ep_s *)ep;
  uint32 inten;
  int eplog;
  int epphy;

  usbtrace(TRACE_EPCONFIGURE, privep->epphy);

  eplog = desc->addr;
  epphy = LPC214X_EP_LOG2PHY(eplog);