changing circuitry to disable RTC, update initialization to match
[fw/openalt] / usb / usbISR.c
1 #include "FreeRTOS.h"
2 #include "task.h"
3 // #include "usb.h"
4 #include "usbISR.h"
5 #include "usbapi.h"
6
7 //
8 //
9 //
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 */
13
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 */
16
17 static void usbISR (void) __attribute__ ((naked));
18
19 //
20 //  Local function to wait for a device interrupt (and clear it)
21 //
22 static void usbWaitForDeviceInterrupt (U32 dwIntr)
23 {
24   while ((USB_DevIntSt & dwIntr) != dwIntr)
25     ;
26
27   USB_DevIntClr = dwIntr;
28 }
29
30 //
31 //  Local function to send a command to the USB protocol engine
32 //
33 static void usbHardwareCommand (U8 bCmd)
34 {
35   USB_DevIntClr = USB_DevIntClr_CDFULL | USB_DevIntClr_CCEMTY;
36   USB_CmdCode = 0x00000500 | (bCmd << 16);
37   usbWaitForDeviceInterrupt (USB_DevIntSt_CCEMTY);
38 }
39
40 //
41 //  Local function to send a command + data to the USB protocol engine
42 //
43 static void usbHardwareCommandWrite (U8 bCmd, U16 bData)
44 {
45   usbHardwareCommand (bCmd);
46   USB_CmdCode = 0x00000100 | (bData << 16);
47   usbWaitForDeviceInterrupt (USB_DevIntSt_CCEMTY);
48 }
49
50 //
51 //  Local function to send a command to the USB protocol engine and read data
52 //
53 static U8 usbHardwareCommandRead (U8 bCmd)
54 {
55   usbHardwareCommand (bCmd);
56   USB_CmdCode = 0x00000200 | (bCmd << 16);
57   usbWaitForDeviceInterrupt (USB_DevIntSt_CDFULL);
58   return USB_CmdData;
59 }
60
61 //
62 //  'Realizes' an endpoint, meaning that buffer space is reserved for
63 //  it. An endpoint needs to be realised before it can be used.
64 //    
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.
68 //    
69 static void usbHardwareEndpointRealize (int idx, U16 wMaxPSize)
70 {
71   USB_ReEP |= (1 << idx);
72   USB_EpInd = idx;
73   USB_MaxPSize = wMaxPSize;
74   usbWaitForDeviceInterrupt (USB_DevIntSt_EPRLZED);
75 }
76
77 //
78 //  Enables or disables an endpoint
79 //
80 static void usbHardwareEndpointEnable (int idx, BOOL fEnable)
81 {
82   usbHardwareCommandWrite (CMD_EP_SET_STATUS | idx, fEnable ? 0 : EP_DA);
83 }
84
85 //
86 // Configures an endpoint and enables it
87 //
88 void usbHardwareEndpointConfig (U8 bEP, U16 wMaxPacketSize)
89 {
90   int idx;
91   
92   idx = EP2IDX (bEP);
93   usbHardwareEndpointRealize (idx, wMaxPacketSize);
94   usbHardwareEndpointEnable (idx, TRUE);
95 }
96
97 //
98 //  Registers an endpoint event callback
99 //
100 void usbHardwareRegisterEPIntHandler (U8 bEP, TFnEPIntHandler *pfnHandler)
101 {
102   int idx;
103   
104   idx = EP2IDX (bEP);
105
106   _apfnEPIntHandlers [idx / 2] = pfnHandler;
107   USB_EpIntEn |= (1 << idx);
108   USB_DevIntEn |= USB_DevIntEn_EPSLOW;
109 }
110
111 //
112 //  Registers an device status callback
113 //
114 void usbHardwareRegisterDevIntHandler (TFnDevIntHandler *pfnHandler)
115 {
116   _pfnDevIntHandler = pfnHandler;
117   USB_DevIntEn |= USB_DevIntEn_DEVSTAT;
118 }
119
120 //
121 //  Registers the frame callback
122 //
123 void usbHardwareRegisterFrameHandler (TFnFrameHandler *pfnHandler)
124 {
125   _pfnFrameHandler = pfnHandler;
126   USB_DevIntEn |= USB_DevIntEn_FRAME;
127 }
128
129 //
130 //  Sets the USB address.
131 //
132 void usbHardwareSetAddress (U8 bAddr)
133 {
134   usbHardwareCommandWrite (CMD_DEV_SET_ADDRESS, DEV_EN | bAddr);
135 }
136
137 //
138 //  Connects or disconnects from the USB bus
139 //
140 void usbHardwareConnect (BOOL fConnect)
141 {
142   usbHardwareCommandWrite (CMD_DEV_STATUS, fConnect ? CON : 0);
143 }
144
145 //
146 //  Enables interrupt on NAK condition
147 //    
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.
152 //  
153 //  The endpoint interrupt handlers can distinguish regular (ACK) interrupts
154 //  from NAK interrupt by checking the bits in their bEPStatus argument.
155 //  
156 void usbHardwareNakIntEnable (U8 bIntBits)
157 {
158   usbHardwareCommandWrite (CMD_DEV_SET_MODE, bIntBits);
159 }
160
161 //
162 //  Gets the stalled property of an endpoint
163 //
164 BOOL usbHardwareEndpointIsStalled (U8 bEP)
165 {
166   int idx = EP2IDX (bEP);
167
168   return (usbHardwareCommandRead (CMD_EP_SELECT | idx) & EP_STATUS_STALLED);
169 }
170
171 //
172 //  Sets the stalled property of an endpoint
173 //
174 void usbHardwareEndpointStall (U8 bEP, BOOL fStall)
175 {
176   int idx = EP2IDX (bEP);
177
178   usbHardwareCommandWrite (CMD_EP_SET_STATUS | idx, fStall ? EP_ST : 0);
179 }
180
181 //
182 //  Writes data to an endpoint buffer
183 //
184 int usbHardwareEndpointWrite (U8 bEP, U8 *pbBuf, int iLen)
185 {
186   int idx;
187   
188   idx = EP2IDX (bEP);
189   
190   USB_Ctrl = USB_Ctrl_WREN | ((bEP & 0xF) << 2);
191   USB_TxPLen = iLen;
192
193   while (USB_Ctrl & USB_Ctrl_WREN) 
194   {
195     USB_TxData = (pbBuf [3] << 24) | (pbBuf [2] << 16) | (pbBuf [1] << 8) | pbBuf [0];
196     pbBuf += 4;
197   }
198
199   usbHardwareCommand (CMD_EP_SELECT | idx);
200   usbHardwareCommand (CMD_EP_VALIDATE_BUFFER);
201   
202   return iLen;
203 }
204
205 //
206 //  Reads data from an endpoint buffer
207 //
208 int usbHardwareEndpointRead (U8 bEP, U8 *pbBuf, int iMaxLen)
209 {
210   int i, idx;
211   U32 dwData, dwLen;
212   
213   idx = EP2IDX (bEP);
214   
215   USB_Ctrl = USB_Ctrl_RDEN | ((bEP & 0xF) << 2);
216   
217   do 
218   {
219     dwLen = USB_RxPLen;
220   } 
221   while ((dwLen & USB_RxPLen_PKTRDY) == 0);
222   
223   if ((dwLen & USB_RxPLen_DV) == 0)
224     return -1;
225   
226   dwLen &= USB_RxPLen_PKTLENGTH_MASK;
227   
228   while (USB_Ctrl & USB_Ctrl_RDEN) 
229   {
230     dwData = USB_RxData;
231
232     if (pbBuf != NULL) 
233     {
234       for (i = 0; i < 4; i++) 
235       {
236         if (iMaxLen-- != 0) 
237           *pbBuf++ = dwData & 0xFF;
238
239         dwData >>= 8;
240       }
241     }
242   }
243
244   usbHardwareCommand (CMD_EP_SELECT | idx);
245   usbHardwareCommand (CMD_EP_CLEAR_BUFFER);
246   
247   return dwLen;
248 }
249
250
251 //
252 //  Sets the 'configured' state.
253 //
254 void usbHardwareConfigDevice (BOOL fConfigured)
255 {
256   usbHardwareCommandWrite (CMD_DEV_CONFIG, fConfigured ? CONF_DEVICE : 0);
257 }
258
259 //
260 //
261 //
262 void usbSetupInterruptHandler (void)
263 {
264   //
265   //  Set up USB interrupt, use highest priority ISR slot
266   //
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;
271 }
272
273 //
274 //  USB interrupt handler
275 //
276 void usbISR (void)
277 {
278   portENTER_SWITCHING_ISR ();
279
280   U32 dwStatus;
281   U32 dwIntBit;
282   U8  bEPStat, bDevStat, bStat;
283   int i;
284   portBASE_TYPE xTaskWoken = pdFALSE;
285
286   dwStatus = USB_DevIntSt;
287   
288   if (dwStatus & USB_DevIntSt_DEVSTAT) 
289   {
290     USB_DevIntClr = USB_DevIntClr_DEVSTAT;
291     bDevStat = usbHardwareCommandRead (CMD_DEV_STATUS);
292
293     if (bDevStat & (CON_CH | SUS_CH | RST)) 
294     {
295       bStat = ((bDevStat & CON) ? DEV_STATUS_CONNECT : 0) |
296               ((bDevStat & SUS) ? DEV_STATUS_SUSPEND : 0) |
297               ((bDevStat & RST) ? DEV_STATUS_RESET   : 0);
298       
299       if (_pfnDevIntHandler != NULL)
300         _pfnDevIntHandler (bStat);
301     }
302   }
303   
304   if (dwStatus & USB_DevIntSt_EPSLOW) 
305   {
306     USB_DevIntClr = USB_DevIntClr_EPSLOW;
307
308     for (i = 0; i < 32; i++) 
309     {
310       dwIntBit = (1 << i);
311
312       if (USB_EpIntSt & dwIntBit) 
313       {
314         USB_EpIntClr = dwIntBit;
315         usbWaitForDeviceInterrupt (USB_DevIntSt_CDFULL);
316         bEPStat = USB_CmdData;
317
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);
323
324         if (bEPStat & (1 <<5)) 
325         {
326         }
327
328         if (bEPStat & (1 <<6)) 
329         {
330         }
331
332         if (_apfnEPIntHandlers [i / 2] != NULL)
333           xTaskWoken |= _apfnEPIntHandlers [i / 2] (IDX2EP (i), bStat);
334       }
335     }
336   }
337   
338   if (dwStatus & USB_DevIntSt_FRAME) 
339   {
340     USB_DevIntClr = USB_DevIntClr_FRAME;
341
342     if (_pfnFrameHandler != NULL)
343       _pfnFrameHandler (0);
344   }
345
346         VIC_VectAddr = (unsigned portLONG) 0;
347
348   portEXIT_SWITCHING_ISR (xTaskWoken);
349 }
350
351 //
352 //  Initializes the USB hardware
353 //     
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.
358 //
359 BOOL usbHardwareInit (void)
360 {
361   //
362   //  Configure P0.23 for Vbus sense, P0.31 as USB connect indicator
363   //
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;
367
368   //
369   //  Enable PUSB
370   //
371   SCB_PCONP |= SCB_PCONP_PUSB;
372
373   //
374   //  Initialize PLL
375   //
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;
380
381   //
382   //  Wait for PLL to lock up
383   //
384   while (!(USB_PLLSTAT & USB_PLLSTAT_PLOCK))
385     ;
386
387   USB_PLLCON = USB_PLLCON_PLLC | USB_PLLCON_PLLE;
388   USB_PLLFEED = USB_PLLFEED_FEED1;
389   USB_PLLFEED = USB_PLLFEED_FEED2;
390
391   //
392   //  Disable/clear all interrupts for now
393   //
394   USB_DevIntEn = USB_DevIntEn_NONE;
395   USB_EpIntEn = USB_EpIntEn_NONE;
396   USB_DevIntClr = USB_DevIntClr_ALL;
397   USB_EpIntClr = USB_EpIntClr_ALL;
398
399   //
400   //  Setup control endpoints
401   //
402   usbHardwareEndpointConfig (0x00, MAX_PACKET_SIZE0);
403   usbHardwareEndpointConfig (0x80, MAX_PACKET_SIZE0);
404
405   //
406   //  By default, only ACKs generate interrupts
407   //
408   usbHardwareNakIntEnable (0);
409
410   return TRUE;
411 }