Arrow / Mbed OS DAPLink Reset
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers usbd_max32620.c Source File

usbd_max32620.c

00001 /* CMSIS-DAP Interface Firmware
00002  * Copyright (c) 2009-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include <string.h>
00018 #include "rl_usb.h"
00019 #include "util.h"
00020 
00021 #include "max32620.h"
00022 #include "usb_regs.h"
00023 #include "clkman_regs.h"
00024 #include "pwrman_regs.h"
00025 #include "tmr_regs.h"
00026 
00027 #define __NO_USB_LIB_C
00028 #include "usb_config.c"
00029 
00030 #define EPNUM_MASK  (~USB_ENDPOINT_DIRECTION_MASK)
00031 
00032 #define INIT_INTS     (MXC_F_USB_DEV_INTEN_BRST | MXC_F_USB_DEV_INTFL_BRST_DN | MXC_F_USB_DEV_INTEN_VBUS | MXC_F_USB_DEV_INTFL_NO_VBUS)
00033 #define CONNECT_INTS  (MXC_F_USB_DEV_INTEN_SETUP | MXC_F_USB_DEV_INTEN_EP_IN | MXC_F_USB_DEV_INTEN_EP_OUT | MXC_F_USB_DEV_INTEN_DMA_ERR)
00034 
00035 typedef struct {
00036     volatile uint32_t buf0_desc;
00037     volatile uint32_t buf0_address;
00038     volatile uint32_t buf1_desc;
00039     volatile uint32_t buf1_address;
00040 } ep_buffer_t;
00041 
00042 typedef struct {
00043     ep_buffer_t out_buffer;
00044     ep_buffer_t in_buffer;
00045 } ep0_buffer_t;
00046 
00047 typedef struct {
00048     ep0_buffer_t ep0;
00049     ep_buffer_t ep[MXC_USB_NUM_EP - 1];
00050 } ep_buffer_descriptor_t;
00051 
00052 typedef struct {
00053   U8 type;
00054   U16 len;
00055 } ep_info_t;
00056 
00057 /* static storage for endpoint buffer descriptor table, must be 512 byte aligned for DMA */
00058 __attribute__ ((aligned (512)))
00059 ep_buffer_descriptor_t ep_buffer_descriptor;
00060 
00061 static uint32_t ep_buffer[MXC_USB_NUM_EP][MXC_USB_MAX_PACKET / sizeof(uint32_t)];
00062 static ep_info_t ep_info[MXC_USB_NUM_EP];
00063 static volatile int suspended;
00064 static volatile int setup_waiting;
00065 static volatile int ep0_expect_zlp;
00066 
00067 #if CDC_ENDPOINT
00068 /* CDC-ACM class processes FIFOs in the SOF interrupt. The USB Device interface
00069  * of Maxim's microcontrollers does not provide and SOF interrupt. A periodic
00070  * timer interrupt is used instead.
00071  */
00072 /******************************************************************************/
00073 void TMR0_IRQHandler(void)
00074 {
00075     MXC_TMR0->intfl = MXC_TMR0->intfl;
00076 
00077     if (usbd_configured()) {
00078         USBD_CDC_ACM_SOF_Event();
00079     }
00080 }
00081 #endif
00082 
00083 /******************************************************************************/
00084 static ep_buffer_t *get_desc(U32 EPNum)
00085 {
00086   ep_buffer_t *desc;
00087 
00088   if (EPNum == 0x80) {
00089     desc = &ep_buffer_descriptor.ep0.in_buffer;
00090   } else if (EPNum == 0x00) {
00091     desc = &ep_buffer_descriptor.ep0.out_buffer;
00092   } else {
00093     desc = &ep_buffer_descriptor.ep[(EPNum & EPNUM_MASK) - 1];
00094   }
00095 
00096   return desc;
00097 }
00098 
00099 /*
00100  *  USB Device Interrupt enable
00101  *   Called by USBD_Init to enable the USB Interrupt
00102  *    Return Value:    None
00103  */
00104 
00105 void          USBD_IntrEna(void)
00106 {
00107     NVIC_EnableIRQ(USB_IRQn );            /* Enable OTG interrupt */
00108 }
00109 
00110 /******************************************************************************/
00111 /*
00112  *  Usb interrupt enable/disable
00113  *    Parameters:      ena: enable/disable
00114  *                       0: disable interrupt
00115  *                       1: enable interrupt
00116  */
00117 #ifdef __RTX
00118 void __svc(1) USBD_Intr (int ena);
00119 void __SVC_1 (int ena)
00120 {
00121   if (ena) {
00122     NVIC_EnableIRQ(USB_IRQn );           /* Enable USB interrupt               */
00123   } else {
00124     NVIC_DisableIRQ(USB_IRQn );          /* Disable USB interrupt              */
00125   }
00126 }
00127 #endif
00128 
00129 /******************************************************************************/
00130 static void reset_state(void)
00131 {
00132   unsigned int ep;
00133 
00134   suspended = 0;
00135   setup_waiting = 0;
00136   ep0_expect_zlp = 0;
00137   memset(ep_info, 0, sizeof(ep_info));
00138 
00139   MXC_USB->ep[0] |= (MXC_S_USB_EP_DIR_CONTROL | MXC_F_USB_EP_INT_EN | MXC_F_USB_EP_DT);
00140   for (ep = 1; ep < MXC_USB_NUM_EP; ep++) {
00141     MXC_USB->ep[ep] = MXC_F_USB_EP_DT;
00142   }
00143 }
00144 
00145 /*
00146  *  USB Device Initialize Function
00147  *   Called by the User to initialize USB Device
00148  *    Return Value:    None
00149  */
00150 void USBD_Init (void)
00151 {
00152     uint32_t reg;
00153 
00154     /* Enable USB power domain */
00155     MXC_PWRMAN->pwr_rst_ctrl |= MXC_F_PWRMAN_PWR_RST_CTRL_USB_POWERED;
00156   /* Setup the USB clocking, select  */
00157   MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_USB_CLOCK_ENABLE;
00158     /* Force USB clock gater */
00159     reg = MXC_CLKMAN->clk_gate_ctrl0;
00160     reg &= ~MXC_F_CLKMAN_CLK_GATE_CTRL0_USB_CLK_GATER;
00161     reg |= (0x2 << MXC_F_CLKMAN_CLK_GATE_CTRL0_USB_CLK_GATER_POS);
00162     MXC_CLKMAN->clk_gate_ctrl0 = reg;
00163 
00164   MXC_USB->cn = 0;
00165   MXC_USB->cn = MXC_F_USB_CN_USB_EN;
00166   MXC_USB->dev_inten = 0;
00167   MXC_USB->dev_intfl = 0xFFFF;  // clear interrupts
00168   MXC_USB->dev_cn = 0;
00169   MXC_USB->dev_cn |= MXC_F_USB_DEV_CN_URST;
00170   MXC_USB->dev_cn = 0;
00171 
00172   reset_state();
00173 
00174   /* set the descriptor location */
00175   MXC_USB->ep_base = (uint32_t)&ep_buffer_descriptor;
00176 
00177   /* enable some interrupts */
00178   MXC_USB->dev_inten = INIT_INTS;
00179   NVIC_EnableIRQ(USB_IRQn );
00180 }
00181 
00182 /*
00183  *  USB Device Connect Function
00184  *   Called by the User to Connect/Disconnect USB Device
00185  *    Parameters:      con:   Connect/Disconnect
00186  *    Return Value:    None
00187  */
00188 void USBD_Connect (BOOL con)
00189 {
00190   if (con) {
00191     MXC_USB->dev_intfl = 0xFFFF;  // clear interrupts
00192     MXC_USB->dev_inten |= CONNECT_INTS;
00193     MXC_USB->ep[0] |= MXC_F_USB_EP_INT_EN;
00194     MXC_USB->dev_cn |= (MXC_F_USB_DEV_CN_CONNECT | MXC_F_USB_DEV_CN_FIFO_MODE);
00195   } else {
00196     MXC_USB->dev_inten &= ~CONNECT_INTS;
00197     MXC_USB->ep[0] &= ~MXC_F_USB_EP_INT_EN;
00198     MXC_USB->dev_cn &= ~MXC_F_USB_DEV_CN_CONNECT;
00199   }
00200 }
00201 
00202 /*
00203  *  USB Device Remote Wakeup Configuration Function
00204  *    Parameters:      cfg:   Device Enable/Disable
00205  *    Return Value:    None
00206  */
00207 void USBD_WakeUpCfg (BOOL cfg)
00208 {
00209 }
00210 
00211 /*
00212  *  USB Device Set Address Function
00213  *    Parameters:      adr:   USB Device Address
00214  *    Return Value:    None
00215  */
00216 void USBD_SetAddress (U32 adr, U32 setup)
00217 {
00218   /* Performed by Hardware */
00219 }
00220 
00221 /*
00222  *  USB Device Configure Function
00223  *    Parameters:      cfg:   Device Configure/Deconfigure
00224  *    Return Value:    None
00225  */
00226 void USBD_Configure (BOOL cfg)
00227 {
00228 #if CDC_ENDPOINT
00229     /* CDC-ACM class processes FIFOs in the SOF interrupt. The USB Device interface
00230      * of Maxim's microcontrollers does not provide and SOF interrupt. A periodic
00231      * timer interrupt is used instead.
00232      */
00233 
00234     #define SOF_INT_US  1000
00235 
00236     if (cfg) {
00237         // Setup timer interrupt for SOF
00238         MXC_TMR0->ctrl = MXC_S_TMR_CTRL_MODE_CONTINUOUS;
00239         MXC_TMR0->count32 = 0;
00240         MXC_TMR0->term_cnt32 = (SystemCoreClock / 1000000) * SOF_INT_US;
00241 
00242         // Enable the interrupt
00243         MXC_TMR0->intfl = MXC_TMR0->intfl;
00244         NVIC_EnableIRQ(TMR0_0_IRQn);
00245         MXC_TMR0->inten = MXC_F_TMR_INTEN_TIMER0;
00246 
00247         // Start the timer
00248         MXC_TMR0->ctrl |= MXC_F_TMR_CTRL_ENABLE0;
00249 
00250     } else {
00251         // Disable tmr
00252         MXC_TMR0->ctrl &= ~(MXC_F_TMR_CTRL_ENABLE0);
00253     }
00254 #endif
00255 }
00256 
00257 /*
00258  *  Configure USB Device Endpoint according to Descriptor
00259  *    Parameters:      pEPD:  Pointer to Device Endpoint Descriptor
00260  *    Return Value:    None
00261  */
00262 void USBD_ConfigEP (USB_ENDPOINT_DESCRIPTOR *pEPD)
00263 {
00264   U32 EPNum;
00265 
00266   EPNum = pEPD->bEndpointAddress & EPNUM_MASK;
00267 
00268   if (EPNum < MXC_USB_NUM_EP) {
00269 
00270     // Clear existing configurations
00271     MXC_USB->ep[EPNum] = MXC_F_USB_EP_DT;
00272 
00273     if (pEPD->bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK) {
00274       ep_info[EPNum].type = MXC_S_USB_EP_DIR_IN;
00275     } else {
00276       ep_info[EPNum].type = MXC_S_USB_EP_DIR_OUT;
00277     }
00278 
00279     ep_info[EPNum].len = pEPD->wMaxPacketSize;
00280   }
00281 }
00282 
00283 /*
00284  *  Set Direction for USB Device Control Endpoint
00285  *    Parameters:      dir:   Out (dir == 0), In (dir <> 0)
00286  *    Return Value:    None
00287  */
00288 void USBD_DirCtrlEP (U32 dir)
00289 {
00290   /* Not needed */
00291 }
00292 
00293 /*
00294  *  Enable USB Device Endpoint
00295  *    Parameters:      EPNum: Device Endpoint Number
00296  *                       EPNum.0..3: Address
00297  *                       EPNum.7:    Dir
00298  *    Return Value:    None
00299  */
00300 void USBD_EnableEP (U32 EPNum)
00301 {
00302   ep_buffer_t *desc = get_desc(EPNum);
00303 
00304   EPNum &= EPNUM_MASK;
00305   MXC_USB->ep[EPNum] |= (MXC_F_USB_EP_INT_EN | ep_info[EPNum].type | MXC_F_USB_EP_DT);
00306 
00307   if (ep_info[EPNum].type == MXC_S_USB_EP_DIR_OUT) {
00308     // This is an OUT endpoint. Go ahead and register a request.
00309     desc = get_desc(EPNum);
00310     desc->buf0_address = (uint32_t)ep_buffer[EPNum];
00311     desc->buf0_desc = sizeof(ep_buffer[EPNum]);
00312     MXC_USB->out_owner = (1 << EPNum);
00313   }
00314 }
00315 
00316 /*
00317  *  Disable USB Device Endpoint
00318  *    Parameters:      EPNum: Device Endpoint Number
00319  *                       EPNum.0..3: Address
00320  *                       EPNum.7:    Dir
00321  *    Return Value:    None
00322  */
00323 void USBD_DisableEP (U32 EPNum)
00324 {
00325   EPNum &= EPNUM_MASK;
00326   MXC_USB->ep[EPNum] = 0;
00327 }
00328 
00329 /*
00330  *  Reset USB Device Endpoint
00331  *    Parameters:      EPNum: Device Endpoint Number
00332  *                       EPNum.0..3: Address
00333  *                       EPNum.7:    Dir
00334  *    Return Value:    None
00335  */
00336 void USBD_ResetEP (U32 EPNum)
00337 {
00338   ep_buffer_t *desc = get_desc(EPNum);
00339 
00340   EPNum &= EPNUM_MASK;
00341   MXC_USB->ep[EPNum] |= MXC_F_USB_EP_DT;
00342 
00343   if (ep_info[EPNum].type == MXC_S_USB_EP_DIR_OUT) {
00344     // This is an OUT endpoint. Go ahead and register a request.
00345     desc = get_desc(EPNum);
00346     desc->buf0_address = (uint32_t)ep_buffer[EPNum];
00347     desc->buf0_desc = sizeof(ep_buffer[EPNum]);
00348     MXC_USB->out_owner = (1 << EPNum);
00349   }
00350 }
00351 
00352 /*
00353  *  Set Stall for USB Device Endpoint
00354  *    Parameters:      EPNum: Device Endpoint Number
00355  *                       EPNum.0..3: Address
00356  *                       EPNum.7:    Dir
00357  *    Return Value:    None
00358  */
00359 void USBD_SetStallEP (U32 EPNum)
00360 {
00361   EPNum &= EPNUM_MASK;
00362 
00363   if (EPNum == 0) {
00364     MXC_USB->ep[0] |= (MXC_F_USB_EP_ST_STALL | MXC_F_USB_EP_STALL);
00365   } else {
00366     MXC_USB->ep[EPNum] |= MXC_F_USB_EP_STALL;
00367   }
00368 }
00369 
00370 /*
00371  *  Clear Stall for USB Device Endpoint
00372  *    Parameters:      EPNum: Device Endpoint Number
00373  *                       EPNum.0..3: Address
00374  *                       EPNum.7:    Dir
00375  *    Return Value:    None
00376  */
00377 void USBD_ClrStallEP (U32 EPNum)
00378 {
00379   USBD_ResetEP(EPNum);
00380   MXC_USB->ep[EPNum & EPNUM_MASK] &= ~MXC_F_USB_EP_STALL;
00381 }
00382 
00383 /*
00384  *  Read USB Device Endpoint Data
00385  *    Parameters:      EPNum: Device Endpoint Number
00386  *                       EPNum.0..3: Address
00387  *                       EPNum.7:    Dir
00388  *                     pData: Pointer to Data Buffer
00389  *    Return Value:    Number of bytes read
00390  */
00391 U32 USBD_ReadEP (U32 EPNum, U8 *pData, U32 size)
00392 {
00393     U32 cnt;
00394   ep_buffer_t *desc = get_desc(EPNum);
00395   USB_SETUP_PACKET *sup;
00396 
00397   EPNum &= EPNUM_MASK;
00398 
00399   if ((EPNum == 0) && setup_waiting) {
00400         cnt = USBD_MAX_PACKET0;
00401 
00402         if (size < cnt) {
00403             cnt = size;
00404         }
00405     setup_waiting = 0;
00406     memcpy(pData, (void*)&MXC_USB->setup0, cnt);
00407     sup = (USB_SETUP_PACKET*)pData;
00408 
00409     if ( (sup->bmRequestType.Dir == REQUEST_HOST_TO_DEVICE) && (sup->wLength > 0) ) {
00410       // There is an OUT stage for this setup packet. Register a request.
00411       if (!(MXC_USB->out_owner & 1)) {
00412         desc = &ep_buffer_descriptor.ep0.out_buffer;
00413         desc->buf0_address = (uint32_t)ep_buffer[0];
00414         desc->buf0_desc = sup->wLength;
00415         MXC_USB->out_owner = 1;
00416       }
00417     }
00418   } else {
00419     cnt = desc->buf0_desc;
00420 
00421         if (size < cnt) {
00422             cnt = size;
00423         }
00424     memcpy(pData, ep_buffer[EPNum], cnt);
00425 
00426     // Register the next request.
00427     desc->buf0_address = (uint32_t)ep_buffer[EPNum];
00428     desc->buf0_desc = sizeof(ep_buffer[EPNum]);
00429     MXC_USB->out_owner = (1 << EPNum);
00430   }
00431 
00432   return cnt;
00433 }
00434 
00435 /*
00436  *  Write USB Device Endpoint Data
00437  *    Parameters:      EPNum: Endpoint Number
00438  *                       EPNum.0..3: Address
00439  *                       EPNum.7:    Dir
00440  *                     pData: Pointer to Data Buffer
00441  *                     cnt:   Number of bytes to write
00442  *    Return Value:    Number of bytes written
00443  */
00444 U32 USBD_WriteEP (U32 EPNum, U8 *pData, U32 cnt)
00445 {
00446   ep_buffer_t *desc = get_desc(EPNum);
00447   uint32_t mask;
00448 
00449   EPNum &= EPNUM_MASK;
00450   mask = (1 << EPNum);
00451 
00452   if (MXC_USB->in_owner & mask) {
00453     return 0;
00454   }
00455 
00456   if (EPNum == 0) {
00457     // Prepare to ACK the status stage.
00458     MXC_USB->ep[0] |= MXC_F_USB_EP_ST_ACK;
00459 
00460     if ((cnt == 0) && !ep0_expect_zlp) {
00461       // This is a status stage ACK. Handled in hardware.
00462       return 0;
00463     } else if (cnt == USBD_MAX_PACKET0) {
00464       ep0_expect_zlp = 1;
00465     } else {
00466       ep0_expect_zlp = 0;
00467     }
00468   }
00469 
00470   if (cnt > MXC_USB_MAX_PACKET) {
00471     cnt = MXC_USB_MAX_PACKET;
00472   }
00473 
00474   /* prepare data to be sent */
00475   memcpy(ep_buffer[EPNum], pData, cnt);
00476   desc->buf0_address = (uint32_t)ep_buffer[EPNum];
00477   desc->buf0_desc = cnt;
00478 
00479   /* start the transaction */
00480   MXC_USB->in_owner = mask;
00481 
00482   return cnt;
00483 }
00484 
00485 /*
00486  *  USB Device Interrupt Service Routine
00487  */
00488 void USB_IRQHandler (void)
00489 {
00490     NVIC_DisableIRQ(USB_IRQn );
00491     USBD_SignalHandler();
00492 }
00493 
00494 void USBD_Handler(void)
00495 {
00496 
00497 #ifdef __RTX
00498   while(1) {}
00499 #else
00500 
00501 #endif
00502 
00503   uint32_t irq_flags;
00504   unsigned int ep;
00505   uint32_t ep_int, mask;
00506 
00507   // Read and clear interrupts
00508   irq_flags = MXC_USB->dev_intfl;
00509   MXC_USB->dev_intfl = irq_flags;
00510 
00511   /* reset interrupt */
00512   if (irq_flags & MXC_F_USB_DEV_INTFL_BRST) {
00513     if (suspended) {
00514       suspended = 0;
00515 #ifdef __RTX
00516       if (USBD_RTX_DevTask) { isr_evt_set(USBD_EVT_RESUME, USBD_RTX_DevTask); }
00517 #else
00518       if (USBD_P_Resume_Event) { USBD_P_Resume_Event(); }
00519 #endif
00520     }
00521 
00522     reset_state();
00523     usbd_reset_core();
00524 
00525 #ifdef __RTX
00526     if (USBD_RTX_DevTask) { isr_evt_set(USBD_EVT_RESET, USBD_RTX_DevTask); }
00527 #else
00528     if (USBD_P_Reset_Event) { USBD_P_Reset_Event(); }
00529 #endif
00530 
00531   }
00532 
00533   /* reset done interrupt */
00534   if (irq_flags & MXC_F_USB_DEV_INTFL_BRST_DN) {
00535     reset_state();
00536   }
00537 
00538   /* suspend interrupt */
00539   if (irq_flags & MXC_F_USB_DEV_INTFL_SUSP) {
00540     suspended = 1;
00541 #ifdef __RTX
00542     if (USBD_RTX_DevTask) { isr_evt_set(USBD_EVT_SUSPEND, USBD_RTX_DevTask); }
00543 #else
00544     if (USBD_P_Suspend_Event) { USBD_P_Suspend_Event(); }
00545 #endif
00546   }
00547 
00548   if (irq_flags & MXC_F_USB_DEV_INTFL_VBUS) {
00549 #ifdef __RTX
00550     if (USBD_RTX_DevTask) { isr_evt_set(USBD_EVT_POWER_ON,  USBD_RTX_DevTask); }
00551 #else
00552     if (USBD_P_Power_Event) { USBD_P_Power_Event(1); }
00553 #endif
00554   }
00555 
00556   if (irq_flags & MXC_F_USB_DEV_INTFL_NO_VBUS) {
00557 #ifdef __RTX
00558     if (USBD_RTX_DevTask) { isr_evt_set(USBD_EVT_POWER_OFF, USBD_RTX_DevTask); }
00559 #else
00560     if (USBD_P_Power_Event) { USBD_P_Power_Event(0); }
00561 #endif
00562   }
00563 
00564   if (irq_flags & MXC_F_USB_DEV_INTFL_SETUP) {
00565     setup_waiting = 1;
00566 #ifdef __RTX
00567     if (USBD_RTX_EPTask[0]) { isr_evt_set(USBD_EVT_SETUP, USBD_RTX_EPTask[0]); }
00568 #else
00569     if (USBD_P_EP[0]) { USBD_P_EP[0](USBD_EVT_SETUP); }
00570 #endif
00571   }
00572 
00573   if (irq_flags & MXC_F_USB_DEV_INTFL_EP_IN) {
00574 
00575     // Read and clear endpoint interrupts
00576     ep_int = MXC_USB->in_int;
00577     MXC_USB->in_int = ep_int;
00578 
00579     mask = 1;
00580     for (ep = 0; ep < MXC_USB_NUM_EP; ep++) {
00581       if (ep_int & mask) {
00582 #ifdef __RTX
00583         if (USBD_RTX_EPTask[ep]) { isr_evt_set(USBD_EVT_IN,  USBD_RTX_EPTask[ep]); }
00584 #else
00585         if (USBD_P_EP[ep]) { USBD_P_EP[ep](USBD_EVT_IN); }
00586 #endif
00587       }
00588 
00589       mask <<= 1;
00590     }
00591   }
00592 
00593   if (irq_flags & MXC_F_USB_DEV_INTFL_EP_OUT) {
00594 
00595     // Read and clear endpoint interrupts
00596     ep_int = MXC_USB->out_int;
00597     MXC_USB->out_int = ep_int;
00598 
00599     mask = 1;
00600     for (ep = 0; ep < MXC_USB_NUM_EP; ep++) {
00601       if (ep_int & mask) {
00602 #ifdef __RTX
00603         if (USBD_RTX_EPTask[ep]) { isr_evt_set(USBD_EVT_OUT, USBD_RTX_EPTask[ep]); }
00604 #else
00605         if (USBD_P_EP[ep]) { USBD_P_EP[ep](USBD_EVT_OUT); }
00606 #endif
00607       }
00608 
00609       mask <<= 1;
00610     }
00611   }
00612 
00613   if (irq_flags & MXC_F_USB_DEV_INTFL_DMA_ERR) {
00614     // Read and clear endpoint interrupts
00615     ep_int = MXC_USB->dma_err_int;
00616     MXC_USB->dma_err_int = ep_int;
00617     while(1); // not recoverable
00618   }
00619 
00620   NVIC_EnableIRQ(USB_IRQn );
00621 
00622 }