Skip to content
Snippets Groups Projects
lpc214x_usbdev.c 78.8 KiB
Newer Older
  putreg32(0, LPC214X_USBDEV_EPINTEN);

  /* Frame is Hp interrupt */

  putreg32(1, LPC214X_USBDEV_DEVINTPRI);

  /* Clear all pending interrupts */

  putreg32(0xffffffff, LPC214X_USBDEV_EPINTCLR);
  putreg32(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 */

  putreg32(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);
1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808
      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 = getreg32(LPC214X_USBDEV_DEVINTST);

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

  if ((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 */

         putreg32(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 */

          putreg32(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 */

          putreg32(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 */

          putreg32(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 */

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

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

              epintstatus = getreg32(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 ((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 = getreg32(LPC214X_USBDEV_EOTINTST);
      if (getreg32(LPC214X_USBDEV_DMAINTEN) & 1)
        {
          dmaintstatus |= tmp;
        }
      putreg32(tmp, LPC214X_USBDEV_EOTINTCLR);

      tmp = getreg32(LPC214X_USBDEV_NDDRINTST);
      if (getreg32(LPC214X_USBDEV_DMAINTEN) & 2)
        {
          dmaintstatus |= tmp;
        }
      putreg32(tmp, LPC214X_USBDEV_NDDRINTCLR);

      tmp = getreg32(LPC214X_USBDEV_SYSERRINTST);
      if (getreg32(LPC214X_USBDEV_DMAINTEN) & 4)
        {
          dmaintstatus |= tmp;
        }
      putreg32(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 */

  putreg32(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);

  /* Realize the endpoint */

  lpc214x_eprealize(privep, 1, GETUINT16(desc->mxpacketsize));

  /* Enable and reset EP -- twice */

  lpc214x_usbcmd(CMD_USB_EP_SETSTATUS | epphy, 0);
  lpc214x_usbcmd(CMD_USB_EP_SETSTATUS | epphy, 0);

#ifdef CONFIG_LPC214X_USBDEV_DMA
  /* Enable DMA Ep interrupt (WO) */

   putreg32(1 << epphy, LPC214X_USBDEV_EPDMAEN);
#else
  /* Enable Ep interrupt (R/W) */

   inten = getreg32(LPC214X_USBDEV_EPINTEN);
   inten |= (1 << epphy);
   putreg32(inten, LPC214X_USBDEV_EPINTEN);
#endif
   return OK;
}

/*******************************************************************************
 * Name: lpc214x_epdisable
 *
 * Description:
 *   The endpoint will no longer be used
 *
 *******************************************************************************/

static int lpc214x_epdisable(FAR struct usbdev_ep_s *ep)
{
  FAR struct lpc214x_ep_s *privep = (FAR struct lpc214x_ep_s *)ep;
  irqstate_t flags;
  uint32 mask = (1 << privep->epphy);
  uint32 reg;

#ifdef CONFIG_DEBUG
  if (!ep)
    {
      usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_INVALIDPARMS), 0);
      return -EINVAL;
    }
#endif
  usbtrace(TRACE_EPDISABLE, privep->epphy);

  /* Cancel any ongoing activity */