www.pudn.com > USB_HID.rar > usbhw.c


/*---------------------------------------------------------------------------- 
 *      U S B  -  K e r n e l 
 *---------------------------------------------------------------------------- 
 *      Name:    USBHW.C 
 *      Purpose: USB Hardware Layer Module for Philips LPC214x 
 *      Version: V1.04 
 *---------------------------------------------------------------------------- 
 *      This file is part of the uVision/ARM development tools. 
 *      Copyright (c) 2005 Keil Software. All rights reserved. 
 *---------------------------------------------------------------------------*/ 
 
#include                         /* LPC214x definitions */ 
 
#include "type.h" 
 
#include "usb.h" 
#include "usbcfg.h" 
#include "usbreg.h" 
#include "usbhw.h" 
#include "usbcore.h" 
#include "usbuser.h" 
 
 
#define EP_MSK_CTRL 0x0001      /* Control Endpoint Logical Address Mask */ 
#define EP_MSK_BULK 0xC924      /* Bulk Endpoint Logical Address Mask */ 
#define EP_MSK_INT  0x4492      /* Interrupt Endpoint Logical Address Mask */ 
#define EP_MSK_ISO  0x1248      /* Isochronous Endpoint Logical Address Mask */ 
 
 
#if USB_DMA 
 
DWORD UDCA[USB_EP_NUM] __at USB_RAM_ADR;    /* UDCA in USB RAM */ 
DWORD udca[USB_EP_NUM];                     /* UDCA saved values */ 
 
DWORD DDMemMap[2];                          /* DMA Descriptor Memory Usage */ 
 
#endif 
 
 
/* 
 *  Get Endpoint Physical Address 
 *    Parameters:      EPNum: Endpoint Number 
 *                       EPNum.0..3: Address 
 *                       EPNum.7:    Dir 
 *    Return Value:    Endpoint Physical Address 
 */ 
 
DWORD EPAdr (DWORD EPNum) { 
  DWORD val; 
 
  val = (EPNum & 0x0F) << 1; 
  if (EPNum & 0x80) { 
    val += 1; 
  } 
  return (val); 
} 
 
 
/* 
 *  Write Command 
 *    Parameters:      cmd:   Command 
 *    Return Value:    None 
 */ 
 
void WrCmd (DWORD cmd) { 
 
  CMD_CODE = cmd; 
  while ((DEV_INT_STAT & CCEMTY_INT) == 0); 
  DEV_INT_CLR = CCEMTY_INT; 
} 
 
 
/* 
 *  Write Command Data 
 *    Parameters:      cmd:   Command 
 *                     val:   Data 
 *    Return Value:    None 
 */ 
 
void WrCmdDat (DWORD cmd, DWORD val) { 
 
  CMD_CODE = cmd; 
  while ((DEV_INT_STAT & CCEMTY_INT) == 0); 
  DEV_INT_CLR = CCEMTY_INT; 
  CMD_CODE = val; 
  while ((DEV_INT_STAT & CCEMTY_INT) == 0); 
  DEV_INT_CLR = CCEMTY_INT; 
} 
 
 
/* 
 *  Read Command Data 
 *    Parameters:      cmd:   Command 
 *    Return Value:    Data Value 
 */ 
 
DWORD RdCmdDat (DWORD cmd) { 
  DWORD val; 
 
  DEV_INT_CLR = CDFULL_INT; 
  CMD_CODE = cmd; 
  while ((DEV_INT_STAT & CCEMTY_INT) == 0); 
  DEV_INT_CLR = CCEMTY_INT; 
  while ((DEV_INT_STAT & CDFULL_INT) == 0); 
  val = CMD_DATA; 
  DEV_INT_CLR = CDFULL_INT; 
  return (val); 
} 
 
 
/* 
 *  USB Initialize Function 
 *   Called by the User to initialize USB 
 *    Return Value:    None 
 */ 
 
void USB_Init (void) { 
 
  PCONP |= 0x80000000;                      /* Turn On USB PCLK */ 
 
  /* Configure 48MHz USB Clock;  FOsc = 12MHz, M = 4, P = 2 */ 
  PLL48CFG  = 0x23;                         /* M = 4, P = 2 */ 
  PLL48CON  = PLLCON_PLLE;                  /* PLL Enable */ 
  PLL48FEED = 0xAA;                         /* Feed Sequence 1 */ 
  PLL48FEED = 0x55;                         /* Feed Sequence 2 */ 
 
  while ((PLL48STAT & PLLSTAT_PLOCK) == 0); /* Wait for PLL Lock */ 
 
  PLL48CON  = PLLCON_PLLE | PLLCON_PLLC;    /* PLL Enable & Connect */ 
  PLL48FEED = 0xAA;                         /* Feed Sequence 1 */ 
  PLL48FEED = 0x55;                         /* Feed Sequence 2 */ 
 
  VICVectAddr0 = (unsigned long)USB_ISR;    /* USB Interrupt -> Vector 0 */ 
  VICVectCntl0 = 0x20 | 22;                 /* USB Interrupt -> IRQ Slot 0 */ 
  VICIntEnable = 1 << 22;                   /* Enable USB Interrupt */ 
 
  DEV_INT_EN = DEV_STAT_INT;                /* Enable Device Status Interrupt */ 
 
#if 1 /* Partial Manual Reset since Automatic Bus Reset is not working */ 
  USB_Reset(); 
  USB_SetAddress(0); 
#endif 
} 
 
 
/* 
 *  USB Connect Function 
 *   Called by the User to Connect/Disconnect USB 
 *    Parameters:      con:   Connect/Disconnect 
 *    Return Value:    None 
 */ 
 
void USB_Connect (BOOL con) { 
  WrCmdDat(CMD_SET_DEV_STAT, DAT_WR_BYTE(con ? DEV_CON : 0)); 
} 
 
 
/* 
 *  USB Reset Function 
 *   Called automatically on USB Reset 
 *    Return Value:    None 
 */ 
 
void USB_Reset (void) { 
#if USB_DMA 
  DWORD n; 
#endif 
 
  EP_INDEX = 0; 
  MAXPACKET_SIZE = USB_MAX_PACKET0; 
  EP_INDEX = 1; 
  MAXPACKET_SIZE = USB_MAX_PACKET0; 
  while ((DEV_INT_STAT & EP_RLZED_INT) == 0); 
 
  EP_INT_CLR  = 0xFFFFFFFF; 
  EP_INT_EN   = 0xFFFFFFFF ^ USB_DMA_EP; 
  DEV_INT_CLR = 0xFFFFFFFF; 
  DEV_INT_EN  = DEV_STAT_INT    | EP_SLOW_INT    | 
               (USB_SOF_EVENT   ? FRAME_INT : 0) | 
               (USB_ERROR_EVENT ? ERR_INT   : 0); 
 
#if USB_DMA 
  UDCA_HEAD   = USB_RAM_ADR; 
  DMA_REQ_CLR = 0xFFFFFFFF; 
  EP_DMA_DIS  = 0xFFFFFFFF; 
  EP_DMA_EN   = USB_DMA_EP; 
  EOT_INT_CLR = 0xFFFFFFFF; 
  NDD_REQ_INT_CLR = 0xFFFFFFFF; 
  SYS_ERR_INT_CLR = 0xFFFFFFFF; 
  DMA_INT_EN  = 0x00000007; 
  DDMemMap[0] = 0x00000000; 
  DDMemMap[1] = 0x00000000; 
  for (n = 0; n < USB_EP_NUM; n++) { 
    udca[n] = 0; 
    UDCA[n] = 0; 
  } 
#endif 
} 
 
 
/* 
 *  USB Suspend Function 
 *   Called automatically on USB Suspend 
 *    Return Value:    None 
 */ 
 
void USB_Suspend (void) { 
  /* Performed by Hardware */ 
} 
 
 
/* 
 *  USB Resume Function 
 *   Called automatically on USB Resume 
 *    Return Value:    None 
 */ 
 
void USB_Resume (void) { 
  /* Performed by Hardware */ 
} 
 
 
/* 
 *  USB Remote Wakeup Function 
 *   Called automatically on USB Remote Wakeup 
 *    Return Value:    None 
 */ 
 
void USB_WakeUp (void) { 
 
  if (USB_DeviceStatus & USB_GETSTATUS_REMOTE_WAKEUP) { 
    WrCmdDat(CMD_SET_DEV_STAT, DAT_WR_BYTE(DEV_CON)); 
  } 
} 
 
 
/* 
 *  USB Remote Wakeup Configuration Function 
 *    Parameters:      cfg:   Enable/Disable 
 *    Return Value:    None 
 */ 
 
void USB_WakeUpCfg (BOOL cfg) { 
  cfg;  /* Not needed */ 
} 
 
 
/* 
 *  USB Set Address Function 
 *    Parameters:      adr:   USB Address 
 *    Return Value:    None 
 */ 
 
void USB_SetAddress (DWORD adr) { 
  WrCmdDat(CMD_SET_ADDR, DAT_WR_BYTE(DEV_EN | adr)); /* Don't wait for next */ 
  WrCmdDat(CMD_SET_ADDR, DAT_WR_BYTE(DEV_EN | adr)); /*  Setup Status Phase */ 
} 
 
 
/* 
 *  USB Configure Function 
 *    Parameters:      cfg:   Configure/Deconfigure 
 *    Return Value:    None 
 */ 
 
void USB_Configure (BOOL cfg) { 
 
  WrCmdDat(CMD_CFG_DEV, DAT_WR_BYTE(cfg ? CONF_DVICE : 0)); 
 
  REALIZE_EP = 0x00000003; 
  while ((DEV_INT_STAT & EP_RLZED_INT) == 0); 
  DEV_INT_CLR = EP_RLZED_INT; 
} 
 
 
/* 
 *  Configure USB Endpoint according to Descriptor 
 *    Parameters:      pEPD:  Pointer to Endpoint Descriptor 
 *    Return Value:    None 
 */ 
 
void USB_ConfigEP (USB_ENDPOINT_DESCRIPTOR *pEPD) { 
  DWORD num; 
 
  num = EPAdr(pEPD->bEndpointAddress); 
  REALIZE_EP |= (1 << num); 
  EP_INDEX = num; 
  MAXPACKET_SIZE = pEPD->wMaxPacketSize; 
  while ((DEV_INT_STAT & EP_RLZED_INT) == 0); 
  DEV_INT_CLR = EP_RLZED_INT; 
} 
 
 
/* 
 *  Set Direction for USB Control Endpoint 
 *    Parameters:      dir:   Out (dir == 0), In (dir <> 0) 
 *    Return Value:    None 
 */ 
 
void USB_DirCtrlEP (DWORD dir) { 
  dir;  /* Not needed */ 
} 
 
 
/* 
 *  Enable USB Endpoint 
 *    Parameters:      EPNum: Endpoint Number 
 *                       EPNum.0..3: Address 
 *                       EPNum.7:    Dir 
 *    Return Value:    None 
 */ 
 
void USB_EnableEP (DWORD EPNum) { 
  WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(0)); 
} 
 
 
/* 
 *  Disable USB Endpoint 
 *    Parameters:      EPNum: Endpoint Number 
 *                       EPNum.0..3: Address 
 *                       EPNum.7:    Dir 
 *    Return Value:    None 
 */ 
 
void USB_DisableEP (DWORD EPNum) { 
  WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(EP_STAT_DA)); 
} 
 
 
/* 
 *  Reset USB Endpoint 
 *    Parameters:      EPNum: Endpoint Number 
 *                       EPNum.0..3: Address 
 *                       EPNum.7:    Dir 
 *    Return Value:    None 
 */ 
 
void USB_ResetEP (DWORD EPNum) { 
  WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(0)); 
} 
 
 
/* 
 *  Set Stall for USB Endpoint 
 *    Parameters:      EPNum: Endpoint Number 
 *                       EPNum.0..3: Address 
 *                       EPNum.7:    Dir 
 *    Return Value:    None 
 */ 
 
void USB_SetStallEP (DWORD EPNum) { 
  WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(EP_STAT_ST)); 
} 
 
 
/* 
 *  Clear Stall for USB Endpoint 
 *    Parameters:      EPNum: Endpoint Number 
 *                       EPNum.0..3: Address 
 *                       EPNum.7:    Dir 
 *    Return Value:    None 
 */ 
 
void USB_ClrStallEP (DWORD EPNum) { 
  WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(0)); 
} 
 
 
/* 
 *  Read USB Endpoint Data 
 *    Parameters:      EPNum: Endpoint Number 
 *                       EPNum.0..3: Address 
 *                       EPNum.7:    Dir 
 *                     pData: Pointer to Data Buffer 
 *    Return Value:    Number of bytes read 
 */ 
 
DWORD USB_ReadEP (DWORD EPNum, BYTE *pData) { 
  DWORD cnt, n; 
 
  USB_CTRL = ((EPNum & 0x0F) << 2) | CTRL_RD_EN; 
 
  do { 
    cnt = RX_PLENGTH; 
  } while ((cnt & PKT_RDY) == 0); 
  cnt &= PKT_LNGTH_MASK; 
 
  for (n = 0; n < (cnt + 3) / 4; n++) { 
    *((__packed DWORD *)pData) = RX_DATA; 
    pData += 4; 
  } 
 
  USB_CTRL = 0; 
 
  if (((EP_MSK_ISO >> EPNum) & 1) == 0) {   /* Non-Isochronous Endpoint */ 
    WrCmd(CMD_SEL_EP(EPAdr(EPNum))); 
    WrCmd(CMD_CLR_BUF); 
  } 
 
  return (cnt); 
} 
 
 
/* 
 *  Write USB Endpoint Data 
 *    Parameters:      EPNum: Endpoint Number 
 *                       EPNum.0..3: Address 
 *                       EPNum.7:    Dir 
 *                     pData: Pointer to Data Buffer 
 *                     cnt:   Number of bytes to write 
 *    Return Value:    Number of bytes written 
 */ 
 
DWORD USB_WriteEP (DWORD EPNum, BYTE *pData, DWORD cnt) { 
  DWORD n; 
 
  USB_CTRL = ((EPNum & 0x0F) << 2) | CTRL_WR_EN; 
 
  TX_PLENGTH = cnt; 
 
  for (n = 0; n < (cnt + 3) / 4; n++) { 
    TX_DATA = *((__packed DWORD *)pData); 
    pData += 4; 
  } 
 
  USB_CTRL = 0; 
 
  WrCmd(CMD_SEL_EP(EPAdr(EPNum))); 
  WrCmd(CMD_VALID_BUF); 
 
  return (cnt); 
} 
 
 
#if USB_DMA 
 
 
/* DMA Descriptor Memory Layout */ 
const DWORD DDAdr[2] = { DD_NISO_ADR, DD_ISO_ADR }; 
const DWORD DDSz [2] = { 16,          20         }; 
 
 
/* 
 *  Setup USB DMA Transfer for selected Endpoint 
 *    Parameters:      EPNum: Endpoint Number 
 *                     pDD: Pointer to DMA Descriptor 
 *    Return Value:    TRUE - Success, FALSE - Error 
 */ 
 
BOOL USB_DMA_Setup(DWORD EPNum, USB_DMA_DESCRIPTOR *pDD) { 
  DWORD num, ptr, nxt, iso, n; 
 
  iso = pDD->Cfg.Type.IsoEP;                /* Iso or Non-Iso Descriptor */ 
  num = EPAdr(EPNum);                       /* Endpoint's Physical Address */ 
 
  ptr = 0;                                  /* Current Descriptor */ 
  nxt = udca[num];                          /* Initial Descriptor */ 
  while (nxt) {                             /* Go through Descriptor List */ 
    ptr = nxt;                              /* Current Descriptor */ 
    if (!pDD->Cfg.Type.Link) {              /* Check for Linked Descriptors */ 
      n = (ptr - DDAdr[iso]) / DDSz[iso];   /* Descriptor Index */ 
      DDMemMap[iso] &= ~(1 << n);           /* Unmark Memory Usage */ 
    } 
    nxt = *((DWORD *)ptr);                  /* Next Descriptor */ 
  } 
 
  for (n = 0; n < 32; n++) {                /* Search for available Memory */ 
    if ((DDMemMap[iso] & (1 << n)) == 0) { 
      break;                                /* Memory found */ 
    } 
  } 
  if (n == 32) return (FALSE);              /* Memory not available */ 
 
  DDMemMap[iso] |= 1 << n;                  /* Mark Memory Usage */ 
  nxt = DDAdr[iso] + n * DDSz[iso];         /* Next Descriptor */ 
 
  if (ptr && pDD->Cfg.Type.Link) { 
    *((DWORD *)(ptr + 0))  = nxt;           /* Link in new Descriptor */ 
    *((DWORD *)(ptr + 4)) |= 0x00000004;    /* Next DD is Valid */ 
  } else { 
    udca[num] = nxt;                        /* Save new Descriptor */ 
    UDCA[num] = nxt;                        /* Update UDCA in USB */ 
  } 
 
  /* Fill in DMA Descriptor */ 
  *(((DWORD *)nxt)++) =  0;                 /* Next DD Pointer */ 
  *(((DWORD *)nxt)++) =  pDD->Cfg.Type.ATLE | 
                       (pDD->Cfg.Type.IsoEP << 4) | 
                       (pDD->MaxSize <<  5) | 
                       (pDD->BufLen  << 16); 
  *(((DWORD *)nxt)++) =  pDD->BufAdr; 
  *(((DWORD *)nxt)++) =  pDD->Cfg.Type.LenPos << 8; 
  if (iso) { 
    *((DWORD *)nxt) =  pDD->InfoAdr; 
  } 
 
  return (TRUE); /* Success */ 
} 
 
 
/* 
 *  Enable USB DMA Endpoint 
 *    Parameters:      EPNum: Endpoint Number 
 *                       EPNum.0..3: Address 
 *                       EPNum.7:    Dir 
 *    Return Value:    None 
 */ 
 
void USB_DMA_Enable (DWORD EPNum) { 
  EP_DMA_EN = 1 << EPAdr(EPNum); 
} 
 
 
/* 
 *  Disable USB DMA Endpoint 
 *    Parameters:      EPNum: Endpoint Number 
 *                       EPNum.0..3: Address 
 *                       EPNum.7:    Dir 
 *    Return Value:    None 
 */ 
 
void USB_DMA_Disable (DWORD EPNum) { 
  EP_DMA_DIS = 1 << EPAdr(EPNum); 
} 
 
 
/* 
 *  Get USB DMA Endpoint Status 
 *    Parameters:      EPNum: Endpoint Number 
 *                       EPNum.0..3: Address 
 *                       EPNum.7:    Dir 
 *    Return Value:    DMA Status 
 */ 
 
DWORD USB_DMA_Status (DWORD EPNum) { 
  DWORD ptr, val; 
 
  ptr = UDCA[EPAdr(EPNum)];                 /* Current Descriptor */ 
  if (ptr == 0) return (USB_DMA_INVALID); 
 
  val = *((DWORD *)(ptr + 3*4));            /* Status Information */ 
  switch ((val >> 1) & 0x0F) { 
    case 0x00:                              /* Not serviced */ 
      return (USB_DMA_IDLE); 
    case 0x01:                              /* Being serviced */ 
      return (USB_DMA_BUSY); 
    case 0x02:                              /* Normal Completition */ 
      return (USB_DMA_DONE); 
    case 0x03:                              /* Data Under Run */ 
      return (USB_DMA_UNDER_RUN); 
    case 0x08:                              /* Data Over Run */ 
      return (USB_DMA_OVER_RUN); 
    case 0x09:                              /* System Error */ 
      return (USB_DMA_ERROR); 
  } 
 
  return (USB_DMA_UNKNOWN); 
} 
 
 
/* 
 *  Get USB DMA Endpoint Current Buffer Address 
 *    Parameters:      EPNum: Endpoint Number 
 *                       EPNum.0..3: Address 
 *                       EPNum.7:    Dir 
 *    Return Value:    DMA Address (or -1 when DMA is Invalid) 
 */ 
 
DWORD USB_DMA_BufAdr (DWORD EPNum) { 
  DWORD ptr, val; 
 
  ptr = UDCA[EPAdr(EPNum)];                 /* Current Descriptor */ 
  if (ptr == 0) return (-1);                /* DMA Invalid */ 
 
  val = *((DWORD *)(ptr + 2*4));            /* Buffer Address */ 
 
  return (val);                             /* Current Address */ 
} 
 
 
/* 
 *  Get USB DMA Endpoint Current Buffer Count 
 *   Number of transfered Bytes or Iso Packets 
 *    Parameters:      EPNum: Endpoint Number 
 *                       EPNum.0..3: Address 
 *                       EPNum.7:    Dir 
 *    Return Value:    DMA Count (or -1 when DMA is Invalid) 
 */ 
 
DWORD USB_DMA_BufCnt (DWORD EPNum) { 
  DWORD ptr, val; 
 
  ptr = UDCA[EPAdr(EPNum)];                 /* Current Descriptor */ 
  if (ptr == 0) return (-1);                /* DMA Invalid */ 
 
  val = *((DWORD *)(ptr + 3*4));            /* Status Information */ 
 
  return (val >> 16);                       /* Current Count */ 
} 
 
 
#endif /* USB_DMA */ 
 
 
/* 
 *  Get USB Last Frame Number 
 *    Parameters:      None 
 *    Return Value:    Frame Number 
 */ 
 
DWORD USB_GetFrame (void) { 
  DWORD val; 
 
  WrCmd(CMD_RD_FRAME); 
  val = RdCmdDat(DAT_RD_FRAME); 
  val = val | (RdCmdDat(DAT_RD_FRAME) << 8); 
 
  return (val); 
} 
 
 
/* 
 *  USB Interrupt Service Routine 
 */ 
 
void USB_ISR (void) __irq { 
  DWORD disr, eisr, val, n, m; 
 
  disr = DEV_INT_STAT;                      /* Device Interrupt Status */ 
 
  /* Device Status Interrupt (Reset, Suspend/Resume, Connect change) */ 
  if (disr & DEV_STAT_INT) { 
    WrCmd(CMD_GET_DEV_STAT); 
    val = RdCmdDat(DAT_GET_DEV_STAT);       /* Device Status */ 
    if (val & DEV_RST) {                    /* Reset */ 
      USB_Reset(); 
#if   USB_RESET_EVENT 
      USB_Reset_Event(); 
#endif 
      goto isr_end; 
    } 
    if (val & DEV_SUS_CH) {                 /* Suspend/Resume */ 
      if (val & DEV_SUS) {                  /* Suspend */ 
        USB_Suspend(); 
#if     USB_SUSPEND_EVENT 
        USB_Suspend_Event(); 
#endif 
      } else {                              /* Resume */ 
        USB_Resume(); 
#if     USB_RESUME_EVENT 
        USB_Resume_Event(); 
#endif 
      } 
      goto isr_end; 
    } 
    if (val & DEV_CON_CH) {                 /* Connect change */ 
#if   USB_POWER_EVENT 
      USB_Power_Event(val & DEV_CON); 
#endif 
      goto isr_end; 
    } 
  } 
 
#if USB_SOF_EVENT 
  /* Start of Frame Interrupt */ 
  if (disr & FRAME_INT) { 
    USB_SOF_Event(); 
  } 
#endif 
 
#if USB_ERROR_EVENT 
  /* Error Interrupt */ 
  if (disr & ERR_INT) { 
    WrCmd(CMD_RD_ERR_STAT); 
    val = RdCmdDat(DAT_RD_ERR_STAT); 
    USB_Error_Event(val); 
  } 
#endif 
 
  /* Endpoint's Slow Interrupt */ 
  if (disr & EP_SLOW_INT) { 
 
    while (eisr = EP_INT_STAT) {            /* Endpoint Interrupt Status */ 
 
      for (n = 0; n < USB_EP_NUM; n++) {    /* Check All Endpoints */ 
        if (eisr & (1 << n)) { 
          m = n >> 1; 
 
          EP_INT_CLR = 1 << n; 
          while ((DEV_INT_STAT & CDFULL_INT) == 0); 
          val = CMD_DATA; 
          DEV_INT_CLR = CDFULL_INT; 
 
          if ((n & 1) == 0) {               /* OUT Endpoint */ 
            if (n == 0) {                   /* Control OUT Endpoint */ 
              if (val & EP_SEL_STP) {       /* Setup Packet */ 
                if (USB_P_EP[0]) { 
                  USB_P_EP[0](USB_EVT_SETUP); 
                  continue; 
                } 
              } 
            } 
            if (USB_P_EP[m]) { 
              USB_P_EP[m](USB_EVT_OUT); 
            } 
          } else {                          /* IN Endpoint */ 
            if (USB_P_EP[m]) { 
              USB_P_EP[m](USB_EVT_IN); 
            } 
          } 
        } 
      } 
    } 
  } 
 
#if USB_DMA 
 
  if (DMA_INT_STAT & 0x00000001) {          /* End of Transfer Interrupt */ 
    eisr = EOT_INT_STAT; 
    for (n = 2; n < USB_EP_NUM; n++) {      /* Check All Endpoints */ 
      if (eisr & (1 << n)) { 
        m = n >> 1; 
        if ((n & 1) == 0) {                 /* OUT Endpoint */ 
          if (USB_P_EP[m]) { 
            USB_P_EP[m](USB_EVT_OUT_DMA_EOT); 
          } 
        } else {                            /* IN Endpoint */ 
          if (USB_P_EP[m]) { 
            USB_P_EP[m](USB_EVT_IN_DMA_EOT); 
          } 
        } 
      } 
    } 
    EOT_INT_CLR = eisr; 
  } 
 
  if (DMA_INT_STAT & 0x00000002) {          /* New DD Request Interrupt */ 
    eisr = NDD_REQ_INT_STAT; 
    for (n = 2; n < USB_EP_NUM; n++) {      /* Check All Endpoints */ 
      if (eisr & (1 << n)) { 
        m = n >> 1; 
        if ((n & 1) == 0) {                 /* OUT Endpoint */ 
          if (USB_P_EP[m]) { 
            USB_P_EP[m](USB_EVT_OUT_DMA_NDR); 
          } 
        } else {                            /* IN Endpoint */ 
          if (USB_P_EP[m]) { 
            USB_P_EP[m](USB_EVT_IN_DMA_NDR); 
          } 
        } 
      } 
    } 
    NDD_REQ_INT_CLR = eisr; 
  } 
 
  if (DMA_INT_STAT & 0x00000004) {          /* System Error Interrupt */ 
    eisr = SYS_ERR_INT_STAT; 
    for (n = 2; n < USB_EP_NUM; n++) {      /* Check All Endpoints */ 
      if (eisr & (1 << n)) { 
        m = n >> 1; 
        if ((n & 1) == 0) {                 /* OUT Endpoint */ 
          if (USB_P_EP[m]) { 
            USB_P_EP[m](USB_EVT_OUT_DMA_ERR); 
          } 
        } else {                            /* IN Endpoint */ 
          if (USB_P_EP[m]) { 
            USB_P_EP[m](USB_EVT_IN_DMA_ERR); 
          } 
        } 
      } 
    } 
    SYS_ERR_INT_CLR = eisr; 
  } 
 
#endif /* USB_DMA */ 
 
isr_end: 
  DEV_INT_CLR = disr; 
  VICVectAddr = 0;                          /* Acknowledge Interrupt */ 
}