10 static TFnDevIntHandler *_pfnDevIntHandler = NULL; /** Installed device interrupt handler */
11 static TFnEPIntHandler *_apfnEPIntHandlers [16]; /** Installed endpoint interrupt handlers */
12 static TFnFrameHandler *_pfnFrameHandler = NULL; /** Installed frame interrupt handlers */
14 #define EP2IDX(bEP) ((((bEP)&0xF)<<1)|(((bEP)&0x80)>>7)) /** convert from endpoint address to endpoint index */
15 #define IDX2EP(idx) ((((idx)<<7)&0x80)|(((idx)>>1)&0xF)) /** convert from endpoint index to endpoint address */
17 static void usbISR (void) __attribute__ ((naked));
20 // Local function to wait for a device interrupt (and clear it)
22 static void usbWaitForDeviceInterrupt (U32 dwIntr)
24 while ((USB_DevIntSt & dwIntr) != dwIntr)
27 USB_DevIntClr = dwIntr;
31 // Local function to send a command to the USB protocol engine
33 static void usbHardwareCommand (U8 bCmd)
35 USB_DevIntClr = USB_DevIntClr_CDFULL | USB_DevIntClr_CCEMTY;
36 USB_CmdCode = 0x00000500 | (bCmd << 16);
37 usbWaitForDeviceInterrupt (USB_DevIntSt_CCEMTY);
41 // Local function to send a command + data to the USB protocol engine
43 static void usbHardwareCommandWrite (U8 bCmd, U16 bData)
45 usbHardwareCommand (bCmd);
46 USB_CmdCode = 0x00000100 | (bData << 16);
47 usbWaitForDeviceInterrupt (USB_DevIntSt_CCEMTY);
51 // Local function to send a command to the USB protocol engine and read data
53 static U8 usbHardwareCommandRead (U8 bCmd)
55 usbHardwareCommand (bCmd);
56 USB_CmdCode = 0x00000200 | (bCmd << 16);
57 usbWaitForDeviceInterrupt (USB_DevIntSt_CDFULL);
62 // 'Realizes' an endpoint, meaning that buffer space is reserved for
63 // it. An endpoint needs to be realised before it can be used.
65 // From experiments, it appears that a USB reset causes USBReEP to
66 // re-initialise to 3 (= just the control endpoints).
67 // However, a USB bus reset does not disturb the USBMaxPSize settings.
69 static void usbHardwareEndpointRealize (int idx, U16 wMaxPSize)
71 USB_ReEP |= (1 << idx);
73 USB_MaxPSize = wMaxPSize;
74 usbWaitForDeviceInterrupt (USB_DevIntSt_EPRLZED);
78 // Enables or disables an endpoint
80 static void usbHardwareEndpointEnable (int idx, BOOL fEnable)
82 usbHardwareCommandWrite (CMD_EP_SET_STATUS | idx, fEnable ? 0 : EP_DA);
86 // Configures an endpoint and enables it
88 void usbHardwareEndpointConfig (U8 bEP, U16 wMaxPacketSize)
93 usbHardwareEndpointRealize (idx, wMaxPacketSize);
94 usbHardwareEndpointEnable (idx, TRUE);
98 // Registers an endpoint event callback
100 void usbHardwareRegisterEPIntHandler (U8 bEP, TFnEPIntHandler *pfnHandler)
106 _apfnEPIntHandlers [idx / 2] = pfnHandler;
107 USB_EpIntEn |= (1 << idx);
108 USB_DevIntEn |= USB_DevIntEn_EPSLOW;
112 // Registers an device status callback
114 void usbHardwareRegisterDevIntHandler (TFnDevIntHandler *pfnHandler)
116 _pfnDevIntHandler = pfnHandler;
117 USB_DevIntEn |= USB_DevIntEn_DEVSTAT;
121 // Registers the frame callback
123 void usbHardwareRegisterFrameHandler (TFnFrameHandler *pfnHandler)
125 _pfnFrameHandler = pfnHandler;
126 USB_DevIntEn |= USB_DevIntEn_FRAME;
130 // Sets the USB address.
132 void usbHardwareSetAddress (U8 bAddr)
134 usbHardwareCommandWrite (CMD_DEV_SET_ADDRESS, DEV_EN | bAddr);
138 // Connects or disconnects from the USB bus
140 void usbHardwareConnect (BOOL fConnect)
142 usbHardwareCommandWrite (CMD_DEV_STATUS, fConnect ? CON : 0);
146 // Enables interrupt on NAK condition
148 // For IN endpoints a NAK is generated when the host wants to read data
149 // from the device, but none is available in the endpoint buffer.
150 // For OUT endpoints a NAK is generated when the host wants to write data
151 // to the device, but the endpoint buffer is still full.
153 // The endpoint interrupt handlers can distinguish regular (ACK) interrupts
154 // from NAK interrupt by checking the bits in their bEPStatus argument.
156 void usbHardwareNakIntEnable (U8 bIntBits)
158 usbHardwareCommandWrite (CMD_DEV_SET_MODE, bIntBits);
162 // Gets the stalled property of an endpoint
164 BOOL usbHardwareEndpointIsStalled (U8 bEP)
166 int idx = EP2IDX (bEP);
168 return (usbHardwareCommandRead (CMD_EP_SELECT | idx) & EP_STATUS_STALLED);
172 // Sets the stalled property of an endpoint
174 void usbHardwareEndpointStall (U8 bEP, BOOL fStall)
176 int idx = EP2IDX (bEP);
178 usbHardwareCommandWrite (CMD_EP_SET_STATUS | idx, fStall ? EP_ST : 0);
182 // Writes data to an endpoint buffer
184 int usbHardwareEndpointWrite (U8 bEP, U8 *pbBuf, int iLen)
190 USB_Ctrl = USB_Ctrl_WREN | ((bEP & 0xF) << 2);
193 while (USB_Ctrl & USB_Ctrl_WREN)
195 USB_TxData = (pbBuf [3] << 24) | (pbBuf [2] << 16) | (pbBuf [1] << 8) | pbBuf [0];
199 usbHardwareCommand (CMD_EP_SELECT | idx);
200 usbHardwareCommand (CMD_EP_VALIDATE_BUFFER);
206 // Reads data from an endpoint buffer
208 int usbHardwareEndpointRead (U8 bEP, U8 *pbBuf, int iMaxLen)
215 USB_Ctrl = USB_Ctrl_RDEN | ((bEP & 0xF) << 2);
221 while ((dwLen & USB_RxPLen_PKTRDY) == 0);
223 if ((dwLen & USB_RxPLen_DV) == 0)
226 dwLen &= USB_RxPLen_PKTLENGTH_MASK;
228 while (USB_Ctrl & USB_Ctrl_RDEN)
234 for (i = 0; i < 4; i++)
237 *pbBuf++ = dwData & 0xFF;
244 usbHardwareCommand (CMD_EP_SELECT | idx);
245 usbHardwareCommand (CMD_EP_CLEAR_BUFFER);
252 // Sets the 'configured' state.
254 void usbHardwareConfigDevice (BOOL fConfigured)
256 usbHardwareCommandWrite (CMD_DEV_CONFIG, fConfigured ? CONF_DEVICE : 0);
262 void usbSetupInterruptHandler (void)
265 // Set up USB interrupt, use highest priority ISR slot
267 VIC_IntSelect &= ~VIC_IntSelect_USB;
268 VIC_VectAddr1 = (portLONG) usbISR;
269 VIC_VectCntl1 = VIC_VectCntl_ENABLE | VIC_Channel_USB;
270 VIC_IntEnable = VIC_IntEnable_USB;
274 // USB interrupt handler
278 portENTER_SWITCHING_ISR ();
282 U8 bEPStat, bDevStat, bStat;
284 portBASE_TYPE xTaskWoken = pdFALSE;
286 dwStatus = USB_DevIntSt;
288 if (dwStatus & USB_DevIntSt_DEVSTAT)
290 USB_DevIntClr = USB_DevIntClr_DEVSTAT;
291 bDevStat = usbHardwareCommandRead (CMD_DEV_STATUS);
293 if (bDevStat & (CON_CH | SUS_CH | RST))
295 bStat = ((bDevStat & CON) ? DEV_STATUS_CONNECT : 0) |
296 ((bDevStat & SUS) ? DEV_STATUS_SUSPEND : 0) |
297 ((bDevStat & RST) ? DEV_STATUS_RESET : 0);
299 if (_pfnDevIntHandler != NULL)
300 _pfnDevIntHandler (bStat);
304 if (dwStatus & USB_DevIntSt_EPSLOW)
306 USB_DevIntClr = USB_DevIntClr_EPSLOW;
308 for (i = 0; i < 32; i++)
312 if (USB_EpIntSt & dwIntBit)
314 USB_EpIntClr = dwIntBit;
315 usbWaitForDeviceInterrupt (USB_DevIntSt_CDFULL);
316 bEPStat = USB_CmdData;
318 bStat = ((bEPStat & EPSTAT_FE) ? EP_STATUS_DATA : 0) |
319 ((bEPStat & EPSTAT_ST) ? EP_STATUS_STALLED : 0) |
320 ((bEPStat & EPSTAT_STP) ? EP_STATUS_SETUP : 0) |
321 ((bEPStat & EPSTAT_EPN) ? EP_STATUS_NACKED : 0) |
322 ((bEPStat & EPSTAT_PO) ? EP_STATUS_ERROR : 0);
324 if (bEPStat & (1 <<5))
328 if (bEPStat & (1 <<6))
332 if (_apfnEPIntHandlers [i / 2] != NULL)
333 xTaskWoken |= _apfnEPIntHandlers [i / 2] (IDX2EP (i), bStat);
338 if (dwStatus & USB_DevIntSt_FRAME)
340 USB_DevIntClr = USB_DevIntClr_FRAME;
342 if (_pfnFrameHandler != NULL)
343 _pfnFrameHandler (0);
346 VIC_VectAddr = (unsigned portLONG) 0;
348 portEXIT_SWITCHING_ISR (xTaskWoken);
352 // Initializes the USB hardware
354 // This function assumes that the hardware is connected as shown in
355 // section 10.1 of the LPC2148 data sheet:
356 // * P0.31 controls a switch to connect a 1.5k pull-up to D+ if low.
357 // * P0.23 is connected to USB VCC.
359 BOOL usbHardwareInit (void)
362 // Configure P0.23 for Vbus sense, P0.31 as USB connect indicator
364 PCB_PINSEL1 = (PCB_PINSEL1 & ~PCB_PINSEL1_P023_GPIO) | PCB_PINSEL1_P023_VBUS;
365 GPIO0_IODIR &= ~GPIO_IO_P23;
366 PCB_PINSEL1 = (PCB_PINSEL1 & ~PCB_PINSEL1_P031_GPIO) | PCB_PINSEL1_P031_CONNECT;
371 SCB_PCONP |= SCB_PCONP_PUSB;
376 USB_PLLCON = USB_PLLCON_PLLE;
377 USB_PLLCFG = USB_PLLCFG_DIV2 | USB_PLLCFG_MUL4;
378 USB_PLLFEED = USB_PLLFEED_FEED1;
379 USB_PLLFEED = USB_PLLFEED_FEED2;
382 // Wait for PLL to lock up
384 while (!(USB_PLLSTAT & USB_PLLSTAT_PLOCK))
387 USB_PLLCON = USB_PLLCON_PLLC | USB_PLLCON_PLLE;
388 USB_PLLFEED = USB_PLLFEED_FEED1;
389 USB_PLLFEED = USB_PLLFEED_FEED2;
392 // Disable/clear all interrupts for now
394 USB_DevIntEn = USB_DevIntEn_NONE;
395 USB_EpIntEn = USB_EpIntEn_NONE;
396 USB_DevIntClr = USB_DevIntClr_ALL;
397 USB_EpIntClr = USB_EpIntClr_ALL;
400 // Setup control endpoints
402 usbHardwareEndpointConfig (0x00, MAX_PACKET_SIZE0);
403 usbHardwareEndpointConfig (0x80, MAX_PACKET_SIZE0);
406 // By default, only ACKs generate interrupts
408 usbHardwareNakIntEnable (0);