USB device stack

Dependents:   blinky_max32630fthr FTHR_USB_serial FTHR_OLED HSP_RPC_GUI_3_0_1 ... more

Fork of USBDevice by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBHAL_LPC11U.cpp Source File

USBHAL_LPC11U.cpp

00001 /* Copyright (c) 2010-2011 mbed.org, MIT License
00002 *
00003 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00004 * and associated documentation files (the "Software"), to deal in the Software without
00005 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
00006 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
00007 * Software is furnished to do so, subject to the following conditions:
00008 *
00009 * The above copyright notice and this permission notice shall be included in all copies or
00010 * substantial portions of the Software.
00011 *
00012 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00013 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00014 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00015 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00016 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00017 */
00018 
00019 #if defined(TARGET_LPC11UXX) || defined(TARGET_LPC11U6X) || defined(TARGET_LPC1347) || defined(TARGET_LPC1549)
00020 
00021 #if defined(TARGET_LPC1347) || defined(TARGET_LPC1549)
00022 #define USB_IRQ USB_IRQ_IRQn
00023 #else
00024 #define USB_IRQ USB_IRQn
00025 #endif
00026 
00027 #include "USBHAL.h"
00028 
00029 USBHAL * USBHAL::instance;
00030 #if defined(TARGET_LPC1549)
00031 static uint8_t usbmem[2048] __attribute__((aligned(2048)));
00032 #endif
00033 
00034 // Valid physical endpoint numbers are 0 to (NUMBER_OF_PHYSICAL_ENDPOINTS-1)
00035 #define LAST_PHYSICAL_ENDPOINT (NUMBER_OF_PHYSICAL_ENDPOINTS-1)
00036 
00037 // Convert physical endpoint number to register bit
00038 #define EP(endpoint) (1UL<<endpoint)
00039 
00040 // Convert physical to logical
00041 #define PHY_TO_LOG(endpoint)    ((endpoint)>>1)
00042 
00043 // Get endpoint direction
00044 #define IN_EP(endpoint)     ((endpoint) & 1U ? true : false)
00045 #define OUT_EP(endpoint)    ((endpoint) & 1U ? false : true)
00046 
00047 // USB RAM
00048 #if defined(TARGET_LPC1549)
00049 #define USB_RAM_START ((uint32_t)usbmem)
00050 #define USB_RAM_SIZE  sizeof(usbmem)
00051 #else
00052 #define USB_RAM_START (0x20004000)
00053 #define USB_RAM_SIZE  (0x00000800)
00054 #endif
00055 
00056 // SYSAHBCLKCTRL
00057 #if defined(TARGET_LPC1549)
00058 #define CLK_USB     (1UL<<23)
00059 #else
00060 #define CLK_USB     (1UL<<14)
00061 #define CLK_USBRAM  (1UL<<27)
00062 #endif
00063 
00064 // USB Information register
00065 #define FRAME_NR(a)     ((a) & 0x7ff)   // Frame number
00066 
00067 // USB Device Command/Status register
00068 #define DEV_ADDR_MASK   (0x7f)          // Device address
00069 #define DEV_ADDR(a)     ((a) & DEV_ADDR_MASK)
00070 #define DEV_EN          (1UL<<7)        // Device enable
00071 #define SETUP           (1UL<<8)        // SETUP token received
00072 #define PLL_ON          (1UL<<9)        // PLL enabled in suspend
00073 #define DCON            (1UL<<16)       // Device status - connect
00074 #define DSUS            (1UL<<17)       // Device status - suspend
00075 #define DCON_C          (1UL<<24)       // Connect change
00076 #define DSUS_C          (1UL<<25)       // Suspend change
00077 #define DRES_C          (1UL<<26)       // Reset change
00078 #define VBUSDEBOUNCED   (1UL<<28)       // Vbus detected
00079 
00080 // Endpoint Command/Status list
00081 #define CMDSTS_A                 (1UL<<31)          // Active
00082 #define CMDSTS_D                 (1UL<<30)          // Disable
00083 #define CMDSTS_S                 (1UL<<29)          // Stall
00084 #define CMDSTS_TR                (1UL<<28)          // Toggle Reset
00085 #define CMDSTS_RF                (1UL<<27)          // Rate Feedback mode
00086 #define CMDSTS_TV                (1UL<<27)          // Toggle Value
00087 #define CMDSTS_T                 (1UL<<26)          // Endpoint Type
00088 #define CMDSTS_NBYTES(n)         (((n)&0x3ff)<<16)  // Number of bytes
00089 #define CMDSTS_ADDRESS_OFFSET(a) (((a)>>6)&0xffff)  // Buffer start address
00090 
00091 #define BYTES_REMAINING(s)       (((s)>>16)&0x3ff)  // Bytes remaining after transfer
00092 
00093 // USB Non-endpoint interrupt sources
00094 #define FRAME_INT   (1UL<<30)
00095 #define DEV_INT     (1UL<<31)
00096 
00097 static volatile int epComplete = 0;
00098 
00099 // One entry for a double-buffered logical endpoint in the endpoint
00100 // command/status list. Endpoint 0 is single buffered, out[1] is used
00101 // for the SETUP packet and in[1] is not used
00102 typedef struct {
00103     uint32_t out[2];
00104     uint32_t in[2];
00105 } PACKED EP_COMMAND_STATUS;
00106 
00107 typedef struct {
00108     uint8_t out[MAX_PACKET_SIZE_EP0];
00109     uint8_t in[MAX_PACKET_SIZE_EP0];
00110     uint8_t setup[SETUP_PACKET_SIZE];
00111 } PACKED CONTROL_TRANSFER;
00112 
00113 typedef struct {
00114     uint32_t    maxPacket;
00115     uint32_t    buffer[2];
00116     uint32_t    options;
00117 } PACKED EP_STATE;
00118 
00119 static volatile EP_STATE endpointState[NUMBER_OF_PHYSICAL_ENDPOINTS];
00120 
00121 // Pointer to the endpoint command/status list
00122 static EP_COMMAND_STATUS *ep = NULL;
00123 
00124 // Pointer to endpoint 0 data (IN/OUT and SETUP)
00125 static CONTROL_TRANSFER *ct = NULL;
00126 
00127 // Shadow DEVCMDSTAT register to avoid accidentally clearing flags or
00128 // initiating a remote wakeup event.
00129 static volatile uint32_t devCmdStat;
00130 
00131 // Pointers used to allocate USB RAM
00132 static uint32_t usbRamPtr = USB_RAM_START;
00133 static uint32_t epRamPtr = 0; // Buffers for endpoints > 0 start here
00134 
00135 #define ROUND_UP_TO_MULTIPLE(x, m) ((((x)+((m)-1))/(m))*(m))
00136 
00137 void USBMemCopy(uint8_t *dst, uint8_t *src, uint32_t size);
00138 void USBMemCopy(uint8_t *dst, uint8_t *src, uint32_t size) {
00139     if (size > 0) {
00140         do {
00141             *dst++ = *src++;
00142         } while (--size > 0);
00143     }
00144 }
00145 
00146 
00147 USBHAL::USBHAL(void) {
00148     NVIC_DisableIRQ(USB_IRQ);
00149 
00150     // fill in callback array
00151     epCallback[0] = &USBHAL::EP1_OUT_callback;
00152     epCallback[1] = &USBHAL::EP1_IN_callback;
00153     epCallback[2] = &USBHAL::EP2_OUT_callback;
00154     epCallback[3] = &USBHAL::EP2_IN_callback;
00155     epCallback[4] = &USBHAL::EP3_OUT_callback;
00156     epCallback[5] = &USBHAL::EP3_IN_callback;
00157     epCallback[6] = &USBHAL::EP4_OUT_callback;
00158     epCallback[7] = &USBHAL::EP4_IN_callback;
00159 
00160 #if defined(TARGET_LPC1549)
00161     /* Set USB PLL input to system oscillator */
00162     LPC_SYSCON->USBPLLCLKSEL = 0x01;
00163 
00164     /* Setup USB PLL  (FCLKIN = 12MHz) * 4 = 48MHz
00165        MSEL = 3 (this is pre-decremented), PSEL = 1 (for P = 2)
00166        FCLKOUT = FCLKIN * (MSEL + 1) = 12MHz * 4 = 48MHz
00167        FCCO = FCLKOUT * 2 * P = 48MHz * 2 * 2 = 192MHz (within FCCO range) */
00168     LPC_SYSCON->USBPLLCTRL = (0x3 | (1UL << 6));
00169 
00170     /* Powerup USB PLL */
00171     LPC_SYSCON->PDRUNCFG &= ~(CLK_USB);
00172 
00173     /* Wait for PLL to lock */
00174     while(!(LPC_SYSCON->USBPLLSTAT & 0x01));
00175 
00176     /* enable USB main clock */
00177     LPC_SYSCON->USBCLKSEL = 0x02;
00178     LPC_SYSCON->USBCLKDIV = 1;
00179 
00180     /* Enable AHB clock to the USB block. */
00181     LPC_SYSCON->SYSAHBCLKCTRL1 |= CLK_USB;
00182 
00183     /* power UP USB Phy */
00184     LPC_SYSCON->PDRUNCFG &= ~(1UL << 9);
00185 
00186     /* Reset USB block */
00187     LPC_SYSCON->PRESETCTRL1 |= (CLK_USB);
00188     LPC_SYSCON->PRESETCTRL1 &= ~(CLK_USB);
00189 
00190 #else
00191     #if defined(TARGET_LPC11U35_401) || defined(TARGET_LPC11U35_501)
00192     // USB_VBUS input with pull-down
00193     LPC_IOCON->PIO0_3 = 0x00000009;
00194     #endif
00195 
00196     // nUSB_CONNECT output
00197     LPC_IOCON->PIO0_6 = 0x00000001;
00198 
00199     // Enable clocks (USB registers, USB RAM)
00200     LPC_SYSCON->SYSAHBCLKCTRL |= CLK_USB | CLK_USBRAM;
00201 
00202     // Ensure device disconnected (DCON not set)
00203     LPC_USB->DEVCMDSTAT = 0;
00204 #endif
00205     // to ensure that the USB host sees the device as
00206     // disconnected if the target CPU is reset.
00207     wait(0.3);
00208 
00209     // Reserve space in USB RAM for endpoint command/status list
00210     // Must be 256 byte aligned
00211     usbRamPtr = ROUND_UP_TO_MULTIPLE(usbRamPtr, 256);
00212     ep = (EP_COMMAND_STATUS *)usbRamPtr;
00213     usbRamPtr += (sizeof(EP_COMMAND_STATUS) * NUMBER_OF_LOGICAL_ENDPOINTS);
00214     LPC_USB->EPLISTSTART = (uint32_t)(ep) & 0xffffff00;
00215 
00216     // Reserve space in USB RAM for Endpoint 0
00217     // Must be 64 byte aligned
00218     usbRamPtr = ROUND_UP_TO_MULTIPLE(usbRamPtr, 64);
00219     ct = (CONTROL_TRANSFER *)usbRamPtr;
00220     usbRamPtr += sizeof(CONTROL_TRANSFER);
00221     LPC_USB->DATABUFSTART =(uint32_t)(ct) & 0xffc00000;
00222 
00223     // Setup command/status list for EP0
00224     ep[0].out[0] = 0;
00225     ep[0].in[0] =  0;
00226     ep[0].out[1] = CMDSTS_ADDRESS_OFFSET((uint32_t)ct->setup);
00227 
00228     // Route all interrupts to IRQ, some can be routed to
00229     // USB_FIQ if you wish.
00230     LPC_USB->INTROUTING = 0;
00231 
00232     // Set device address 0, enable USB device, no remote wakeup
00233     devCmdStat = DEV_ADDR(0) | DEV_EN | DSUS;
00234     LPC_USB->DEVCMDSTAT = devCmdStat;
00235 
00236     // Enable interrupts for device events and EP0
00237     LPC_USB->INTEN = DEV_INT | EP(EP0IN) | EP(EP0OUT) | FRAME_INT;
00238     instance = this;
00239 
00240     //attach IRQ handler and enable interrupts
00241     NVIC_SetVector(USB_IRQ, (uint32_t)&_usbisr);
00242 }
00243 
00244 USBHAL::~USBHAL(void) {
00245     // Ensure device disconnected (DCON not set)
00246     LPC_USB->DEVCMDSTAT = 0;
00247     // Disable USB interrupts
00248     NVIC_DisableIRQ(USB_IRQ);
00249 }
00250 
00251 void USBHAL::connect(void) {
00252     NVIC_EnableIRQ(USB_IRQ);
00253     devCmdStat |= DCON;
00254     LPC_USB->DEVCMDSTAT = devCmdStat;
00255 }
00256 
00257 void USBHAL::disconnect(void) {
00258     NVIC_DisableIRQ(USB_IRQ);
00259     devCmdStat &= ~DCON;
00260     LPC_USB->DEVCMDSTAT = devCmdStat;
00261 }
00262 
00263 void USBHAL::configureDevice(void) {
00264     // Not required
00265 }
00266 
00267 void USBHAL::unconfigureDevice(void) {
00268     // Not required
00269 }
00270 
00271 void USBHAL::EP0setup(uint8_t *buffer) {
00272     // Copy setup packet data
00273     USBMemCopy(buffer, ct->setup, SETUP_PACKET_SIZE);
00274 }
00275 
00276 void USBHAL::EP0read(void) {
00277     // Start an endpoint 0 read
00278 
00279     // The USB ISR will call USBDevice_EP0out() when a packet has been read,
00280     // the USBDevice layer then calls USBBusInterface_EP0getReadResult() to
00281     // read the data.
00282 
00283     ep[0].out[0] = CMDSTS_A |CMDSTS_NBYTES(MAX_PACKET_SIZE_EP0) \
00284                    | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->out);
00285 }
00286 
00287 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {
00288     // Complete an endpoint 0 read
00289     uint32_t bytesRead;
00290 
00291     // Find how many bytes were read
00292     bytesRead = MAX_PACKET_SIZE_EP0 - BYTES_REMAINING(ep[0].out[0]);
00293 
00294     // Copy data
00295     USBMemCopy(buffer, ct->out, bytesRead);
00296     return bytesRead;
00297 }
00298 
00299 
00300 void USBHAL::EP0readStage(void) {
00301     // Not required
00302 }
00303 
00304 void USBHAL::EP0write(uint8_t *buffer, uint32_t size) {
00305     // Start and endpoint 0 write
00306 
00307     // The USB ISR will call USBDevice_EP0in() when the data has
00308     // been written, the USBDevice layer then calls
00309     // USBBusInterface_EP0getWriteResult() to complete the transaction.
00310 
00311     // Copy data
00312     USBMemCopy(ct->in, buffer, size);
00313 
00314     // Start transfer
00315     ep[0].in[0] = CMDSTS_A | CMDSTS_NBYTES(size) \
00316                   | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->in);
00317 }
00318 
00319 
00320 EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) {
00321     uint8_t bf = 0;
00322     uint32_t flags = 0;
00323 
00324     //check which buffer must be filled
00325     if (LPC_USB->EPBUFCFG & EP(endpoint)) {
00326         // Double buffered
00327         if (LPC_USB->EPINUSE & EP(endpoint)) {
00328             bf = 1;
00329         } else {
00330             bf = 0;
00331         }
00332     }
00333 
00334     // if isochronous endpoint, T = 1
00335     if(endpointState[endpoint].options & ISOCHRONOUS)
00336     {
00337         flags |= CMDSTS_T;
00338     }
00339 
00340     //Active the endpoint for reading
00341     ep[PHY_TO_LOG(endpoint)].out[bf] = CMDSTS_A | CMDSTS_NBYTES(maximumSize) \
00342                                        | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->out) | flags;
00343     return EP_PENDING;
00344 }
00345 
00346 EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead) {
00347 
00348     uint8_t bf = 0;
00349 
00350     if (!(epComplete & EP(endpoint)))
00351         return EP_PENDING;
00352     else {
00353         epComplete &= ~EP(endpoint);
00354 
00355         //check which buffer has been filled
00356         if (LPC_USB->EPBUFCFG & EP(endpoint)) {
00357             // Double buffered (here we read the previous buffer which was used)
00358             if (LPC_USB->EPINUSE & EP(endpoint)) {
00359                 bf = 0;
00360             } else {
00361                 bf = 1;
00362             }
00363         }
00364 
00365         // Find how many bytes were read
00366         *bytesRead = (uint32_t) (endpointState[endpoint].maxPacket - BYTES_REMAINING(ep[PHY_TO_LOG(endpoint)].out[bf]));
00367 
00368         // Copy data
00369         USBMemCopy(data, ct->out, *bytesRead);
00370         return EP_COMPLETED;
00371     }
00372 }
00373 
00374 void USBHAL::EP0getWriteResult(void) {
00375     // Not required
00376 }
00377 
00378 void USBHAL::EP0stall(void) {
00379     ep[0].in[0] = CMDSTS_S;
00380     ep[0].out[0] = CMDSTS_S;
00381 }
00382 
00383 void USBHAL::setAddress(uint8_t address) {
00384     devCmdStat &= ~DEV_ADDR_MASK;
00385     devCmdStat |= DEV_ADDR(address);
00386     LPC_USB->DEVCMDSTAT = devCmdStat;
00387 }
00388 
00389 EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) {
00390     uint32_t flags = 0;
00391     uint32_t bf;
00392 
00393     // Validate parameters
00394     if (data == NULL) {
00395         return EP_INVALID;
00396     }
00397 
00398     if (endpoint > LAST_PHYSICAL_ENDPOINT) {
00399         return EP_INVALID;
00400     }
00401 
00402     if ((endpoint==EP0IN) || (endpoint==EP0OUT)) {
00403         return EP_INVALID;
00404     }
00405 
00406     if (size > endpointState[endpoint].maxPacket) {
00407         return EP_INVALID;
00408     }
00409 
00410     if (LPC_USB->EPBUFCFG & EP(endpoint)) {
00411         // Double buffered
00412         if (LPC_USB->EPINUSE & EP(endpoint)) {
00413             bf = 1;
00414         } else {
00415             bf = 0;
00416         }
00417     } else {
00418         // Single buffered
00419         bf = 0;
00420     }
00421 
00422     // Check if already active
00423     if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_A) {
00424         return EP_INVALID;
00425     }
00426 
00427     // Check if stalled
00428     if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_S) {
00429         return EP_STALLED;
00430     }
00431 
00432     // Copy data to USB RAM
00433     USBMemCopy((uint8_t *)endpointState[endpoint].buffer[bf], data, size);
00434 
00435     // Add options
00436     if (endpointState[endpoint].options & RATE_FEEDBACK_MODE) {
00437         flags |= CMDSTS_RF;
00438     }
00439 
00440     if (endpointState[endpoint].options & ISOCHRONOUS) {
00441         flags |= CMDSTS_T;
00442     }
00443 
00444     // Add transfer
00445     ep[PHY_TO_LOG(endpoint)].in[bf] = CMDSTS_ADDRESS_OFFSET( \
00446                                       endpointState[endpoint].buffer[bf]) \
00447                                       | CMDSTS_NBYTES(size) | CMDSTS_A | flags;
00448 
00449     return EP_PENDING;
00450 }
00451 
00452 EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) {
00453     uint32_t bf;
00454 
00455     // Validate parameters
00456     if (endpoint > LAST_PHYSICAL_ENDPOINT) {
00457         return EP_INVALID;
00458     }
00459 
00460     if (OUT_EP(endpoint)) {
00461         return EP_INVALID;
00462     }
00463 
00464     if (LPC_USB->EPBUFCFG & EP(endpoint)) {
00465         // Double buffered     // TODO: FIX THIS
00466         if (LPC_USB->EPINUSE & EP(endpoint)) {
00467             bf = 1;
00468         } else {
00469             bf = 0;
00470         }
00471     } else {
00472         // Single buffered
00473         bf = 0;
00474     }
00475 
00476     // Check if endpoint still active
00477     if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_A) {
00478         return EP_PENDING;
00479     }
00480 
00481     // Check if stalled
00482     if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_S) {
00483         return EP_STALLED;
00484     }
00485 
00486     return EP_COMPLETED;
00487 }
00488 
00489 void USBHAL::stallEndpoint(uint8_t endpoint) {
00490 
00491     // FIX: should this clear active bit?
00492     if (IN_EP(endpoint)) {
00493         ep[PHY_TO_LOG(endpoint)].in[0] |= CMDSTS_S;
00494         ep[PHY_TO_LOG(endpoint)].in[1] |= CMDSTS_S;
00495     } else {
00496         ep[PHY_TO_LOG(endpoint)].out[0] |= CMDSTS_S;
00497         ep[PHY_TO_LOG(endpoint)].out[1] |= CMDSTS_S;
00498     }
00499 }
00500 
00501 void USBHAL::unstallEndpoint(uint8_t endpoint) {
00502     if (LPC_USB->EPBUFCFG & EP(endpoint)) {
00503         // Double buffered
00504         if (IN_EP(endpoint)) {
00505             ep[PHY_TO_LOG(endpoint)].in[0] = 0; // S = 0
00506             ep[PHY_TO_LOG(endpoint)].in[1] = 0; // S = 0
00507 
00508             if (LPC_USB->EPINUSE & EP(endpoint)) {
00509                 ep[PHY_TO_LOG(endpoint)].in[1] = CMDSTS_TR; // S = 0, TR = 1, TV = 0
00510             } else {
00511                 ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR; // S = 0, TR = 1, TV = 0
00512             }
00513         } else {
00514             ep[PHY_TO_LOG(endpoint)].out[0] = 0; // S = 0
00515             ep[PHY_TO_LOG(endpoint)].out[1] = 0; // S = 0
00516 
00517             if (LPC_USB->EPINUSE & EP(endpoint)) {
00518                 ep[PHY_TO_LOG(endpoint)].out[1] = CMDSTS_TR; // S = 0, TR = 1, TV = 0
00519             } else {
00520                 ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR; // S = 0, TR = 1, TV = 0
00521             }
00522         }
00523     } else {
00524         // Single buffered
00525         if (IN_EP(endpoint)) {
00526             ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR;     // S = 0, TR = 1, TV = 0
00527         } else {
00528             ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR;    // S = 0, TR = 1, TV = 0
00529         }
00530     }
00531 }
00532 
00533 bool USBHAL::getEndpointStallState(unsigned char endpoint) {
00534     if (IN_EP(endpoint)) {
00535         if (LPC_USB->EPINUSE & EP(endpoint)) {
00536             if (ep[PHY_TO_LOG(endpoint)].in[1] & CMDSTS_S) {
00537                 return true;
00538             }
00539         } else {
00540             if (ep[PHY_TO_LOG(endpoint)].in[0] & CMDSTS_S) {
00541                 return true;
00542             }
00543         }
00544     } else {
00545         if (LPC_USB->EPINUSE & EP(endpoint)) {
00546             if (ep[PHY_TO_LOG(endpoint)].out[1] & CMDSTS_S) {
00547                 return true;
00548             }
00549         } else {
00550             if (ep[PHY_TO_LOG(endpoint)].out[0] & CMDSTS_S) {
00551                 return true;
00552             }
00553         }
00554     }
00555 
00556     return false;
00557 }
00558 
00559 bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t options) {
00560     uint32_t tmpEpRamPtr;
00561 
00562     if (endpoint > LAST_PHYSICAL_ENDPOINT) {
00563         return false;
00564     }
00565 
00566     // Not applicable to the control endpoints
00567     if ((endpoint==EP0IN) || (endpoint==EP0OUT)) {
00568         return false;
00569     }
00570 
00571     // Allocate buffers in USB RAM
00572     tmpEpRamPtr = epRamPtr;
00573 
00574     // Must be 64 byte aligned
00575     tmpEpRamPtr = ROUND_UP_TO_MULTIPLE(tmpEpRamPtr, 64);
00576 
00577     if ((tmpEpRamPtr + maxPacket) > (USB_RAM_START + USB_RAM_SIZE)) {
00578         // Out of memory
00579         return false;
00580     }
00581 
00582     // Allocate first buffer
00583     endpointState[endpoint].buffer[0] = tmpEpRamPtr;
00584     tmpEpRamPtr += maxPacket;
00585 
00586     if (!(options & SINGLE_BUFFERED)) {
00587         // Must be 64 byte aligned
00588         tmpEpRamPtr = ROUND_UP_TO_MULTIPLE(tmpEpRamPtr, 64);
00589 
00590         if ((tmpEpRamPtr + maxPacket) > (USB_RAM_START + USB_RAM_SIZE)) {
00591             // Out of memory
00592             return false;
00593         }
00594 
00595         // Allocate second buffer
00596         endpointState[endpoint].buffer[1] = tmpEpRamPtr;
00597         tmpEpRamPtr += maxPacket;
00598     }
00599 
00600     // Commit to this USB RAM allocation
00601     epRamPtr = tmpEpRamPtr;
00602 
00603     // Remaining endpoint state values
00604     endpointState[endpoint].maxPacket = maxPacket;
00605     endpointState[endpoint].options = options;
00606 
00607     // Enable double buffering if required
00608     if (options & SINGLE_BUFFERED) {
00609         LPC_USB->EPBUFCFG &= ~EP(endpoint);
00610     } else {
00611         // Double buffered
00612         LPC_USB->EPBUFCFG |= EP(endpoint);
00613     }
00614 
00615     // Enable interrupt
00616     LPC_USB->INTEN |= EP(endpoint);
00617 
00618     // Enable endpoint
00619     unstallEndpoint(endpoint);
00620     return true;
00621 }
00622 
00623 void USBHAL::remoteWakeup(void) {
00624     // Clearing DSUS bit initiates a remote wakeup if the
00625     // device is currently enabled and suspended - otherwise
00626     // it has no effect.
00627     LPC_USB->DEVCMDSTAT = devCmdStat & ~DSUS;
00628 }
00629 
00630 
00631 static void disableEndpoints(void) {
00632     uint32_t logEp;
00633 
00634     // Ref. Table 158 "When a bus reset is received, software
00635     // must set the disable bit of all endpoints to 1".
00636 
00637     for (logEp = 1; logEp < NUMBER_OF_LOGICAL_ENDPOINTS; logEp++) {
00638         ep[logEp].out[0] = CMDSTS_D;
00639         ep[logEp].out[1] = CMDSTS_D;
00640         ep[logEp].in[0] =  CMDSTS_D;
00641         ep[logEp].in[1] =  CMDSTS_D;
00642     }
00643 
00644     // Start of USB RAM for endpoints > 0
00645     epRamPtr = usbRamPtr;
00646 }
00647 
00648 
00649 
00650 void USBHAL::_usbisr(void) {
00651     instance->usbisr();
00652 }
00653 
00654 void USBHAL::usbisr(void) {
00655     // Start of frame
00656     if (LPC_USB->INTSTAT & FRAME_INT) {
00657         // Clear SOF interrupt
00658         LPC_USB->INTSTAT = FRAME_INT;
00659 
00660         // SOF event, read frame number
00661         SOF(FRAME_NR(LPC_USB->INFO));
00662     }
00663 
00664     // Device state
00665     if (LPC_USB->INTSTAT & DEV_INT) {
00666         LPC_USB->INTSTAT = DEV_INT;
00667 
00668         if (LPC_USB->DEVCMDSTAT & DSUS_C) {
00669             // Suspend status changed
00670             LPC_USB->DEVCMDSTAT = devCmdStat | DSUS_C;
00671             if (LPC_USB->DEVCMDSTAT & DSUS) {
00672                 suspendStateChanged(1);
00673             } else {
00674                 suspendStateChanged(0);
00675             }
00676         }
00677 
00678         if (LPC_USB->DEVCMDSTAT & DRES_C) {
00679             // Bus reset
00680             LPC_USB->DEVCMDSTAT = devCmdStat | DRES_C;
00681 
00682             // Disable endpoints > 0
00683             disableEndpoints();
00684 
00685             // Bus reset event
00686             busReset();
00687         }
00688     }
00689 
00690     // Endpoint 0
00691     if (LPC_USB->INTSTAT & EP(EP0OUT)) {
00692         // Clear EP0OUT/SETUP interrupt
00693         LPC_USB->INTSTAT = EP(EP0OUT);
00694 
00695         // Check if SETUP
00696         if (LPC_USB->DEVCMDSTAT & SETUP) {
00697             // Clear Active and Stall bits for EP0
00698             // Documentation does not make it clear if we must use the
00699             // EPSKIP register to achieve this, Fig. 16 and NXP reference
00700             // code suggests we can just clear the Active bits - check with
00701             // NXP to be sure.
00702             ep[0].in[0] = 0;
00703             ep[0].out[0] = 0;
00704 
00705             // Clear EP0IN interrupt
00706             LPC_USB->INTSTAT = EP(EP0IN);
00707 
00708             // Clear SETUP (and INTONNAK_CI/O) in device status register
00709             LPC_USB->DEVCMDSTAT = devCmdStat | SETUP;
00710 
00711             // EP0 SETUP event (SETUP data received)
00712             EP0setupCallback();
00713         } else {
00714             // EP0OUT ACK event (OUT data received)
00715             EP0out();
00716         }
00717     }
00718 
00719     if (LPC_USB->INTSTAT & EP(EP0IN)) {
00720         // Clear EP0IN interrupt
00721         LPC_USB->INTSTAT = EP(EP0IN);
00722 
00723         // EP0IN ACK event (IN data sent)
00724         EP0in();
00725     }
00726 
00727     for (uint8_t num = 2; num < 5*2; num++) {
00728         if (LPC_USB->INTSTAT & EP(num)) {
00729             LPC_USB->INTSTAT = EP(num);
00730             epComplete |= EP(num);
00731             if ((instance->*(epCallback[num - 2]))()) {
00732                 epComplete &= ~EP(num);
00733             }
00734         }
00735     }
00736 }
00737 
00738 #endif