Spieler splodiert.
[hackover2013-badge-firmware.git] / core / usbcdc / usbhw.c
1 /*----------------------------------------------------------------------------
2 * U S B - K e r n e l
3 *----------------------------------------------------------------------------
4 * Name: usbhw.c
5 * Purpose: USB Hardware Layer Module for Philips LPC17xx
6 * Version: V1.20
7 *----------------------------------------------------------------------------
8 * This software is supplied "AS IS" without any warranties, express,
9 * implied or statutory, including but not limited to the implied
10 * warranties of fitness for purpose, satisfactory quality and
11 * noninfringement. Keil extends you a royalty-free right to reproduce
12 * and distribute executable files created using this software for use
13 * on NXP Semiconductors LPC microcontroller devices only. Nothing else
14 * gives you the right to use this software.
15 *
16 * Copyright (c) 2009 Keil - An ARM Company. All rights reserved.
17 *----------------------------------------------------------------------------
18 * History:
19 * V1.20 Added USB_ClearEPBuf
20 * V1.00 Initial Version
21 *----------------------------------------------------------------------------*/
22 #include "projectconfig.h"
23 #include "usb.h"
24 #include "usbcfg.h"
25 #include "usbreg.h"
26 #include "usbhw.h"
27 #include "usbcore.h"
28 #include "usbuser.h"
29
30
31 /*
32 * USB and IO Clock configuration only.
33 * The same as call PeriClkIOInit(IOCON_USB);
34 * The purpose is to reduce the code space for
35 * overall USB project and reserve code space for
36 * USB debugging.
37 * Parameters: None
38 * Return Value: None
39 */
40 void USBIOClkConfig( void )
41 {
42 /* Enable AHB clock to the GPIO domain. */
43 SCB_SYSAHBCLKCTRL |= SCB_SYSAHBCLKCTRL_GPIO;
44
45 /* Enable Timer32_1, IOCON, and USB blocks */
46 SCB_SYSAHBCLKCTRL |= (SCB_SYSAHBCLKCTRL_CT32B1 | SCB_SYSAHBCLKCTRL_IOCON | SCB_SYSAHBCLKCTRL_USB_REG);
47
48 // Setup USB clock
49 SCB_PDRUNCFG &= ~(SCB_PDSLEEPCFG_USBPAD_PD); // Power-up USB PHY
50 SCB_PDRUNCFG &= ~(SCB_PDSLEEPCFG_USBPLL_PD); // Power-up USB PLL
51
52 SCB_USBPLLCLKSEL = SCB_USBPLLCLKSEL_SOURCE_MAINOSC; // Select PLL Input
53 SCB_USBPLLCLKUEN = SCB_USBPLLCLKUEN_UPDATE; // Update Clock Source
54 SCB_USBPLLCLKUEN = SCB_USBPLLCLKUEN_DISABLE; // Toggle Update Register
55 SCB_USBPLLCLKUEN = SCB_USBPLLCLKUEN_UPDATE;
56
57 // Wait until the USB clock is updated
58 while (!(SCB_USBPLLCLKUEN & SCB_USBPLLCLKUEN_UPDATE));
59
60 // Set USB clock to 48MHz (12MHz x 4)
61 SCB_USBPLLCTRL = (SCB_USBPLLCTRL_MULT_4);
62 while (!(SCB_USBPLLSTAT & SCB_USBPLLSTAT_LOCK)); // Wait Until PLL Locked
63 SCB_USBCLKSEL = SCB_USBCLKSEL_SOURCE_USBPLLOUT;
64
65 // Set USB pin functions
66 IOCON_PIO0_1 &= ~IOCON_PIO0_1_FUNC_MASK;
67 IOCON_PIO0_1 |= IOCON_PIO0_1_FUNC_CLKOUT; // CLK OUT
68 IOCON_PIO0_3 &= ~IOCON_PIO0_3_FUNC_MASK;
69 IOCON_PIO0_3 |= IOCON_PIO0_3_FUNC_USB_VBUS; // VBus
70 IOCON_PIO0_6 &= ~IOCON_PIO0_6_FUNC_MASK;
71 IOCON_PIO0_6 |= IOCON_PIO0_6_FUNC_USB_CONNECT; // Soft Connect
72
73 return;
74 }
75
76 /*
77 * Delay number of clock cycles
78 * Parameters: Delay length
79 * Return Value: None
80 */
81
82 void delay (uint32_t length ) {
83 uint32_t i;
84
85 for ( i = 0; i < length; i++ )
86 {
87 __asm volatile("nop");
88 }
89 return;
90 }
91
92 /*
93 * Get Endpoint Physical Address
94 * Parameters: EPNum: Endpoint Number
95 * EPNum.0..3: Address
96 * EPNum.7: Dir
97 * Return Value: Endpoint Physical Address
98 */
99
100 uint32_t EPAdr (uint32_t EPNum) {
101 uint32_t val;
102
103 val = (EPNum & 0x0F) << 1;
104 if (EPNum & 0x80) {
105 val += 1;
106 }
107 return (val);
108 }
109
110
111 /*
112 * Write Command
113 * Parameters: cmd: Command
114 * Return Value: None
115 */
116
117 void WrCmd (uint32_t cmd) {
118
119 USB_DEVINTCLR = CCEMTY_INT;
120 USB_CMDCODE = cmd;
121 while ((USB_DEVINTST & (CCEMTY_INT | DEV_STAT_INT)) == 0);
122 }
123
124
125 /*
126 * Write Command Data
127 * Parameters: cmd: Command
128 * val: Data
129 * Return Value: None
130 */
131
132 void WrCmdDat (uint32_t cmd, uint32_t val) {
133
134 WrCmd(cmd);
135 WrCmd(val);
136 }
137
138
139 /*
140 * Write Command to Endpoint
141 * Parameters: cmd: Command
142 * val: Data
143 * Return Value: None
144 */
145
146 void WrCmdEP (uint32_t EPNum, uint32_t cmd){
147
148 WrCmd(CMD_SEL_EP(EPAdr(EPNum)));
149 WrCmd(cmd);
150 }
151
152
153 /*
154 * Read Command Data
155 * Parameters: cmd: Command
156 * Return Value: Data Value
157 */
158
159 uint32_t RdCmdDat (uint32_t cmd) {
160
161 USB_DEVINTCLR = CCEMTY_INT | CDFULL_INT;
162 USB_CMDCODE = cmd;
163 while ((USB_DEVINTST & (CDFULL_INT | DEV_STAT_INT)) == 0);
164 return (USB_CMDDATA);
165 }
166
167
168 /*
169 * USB Initialize Function
170 * Called by the User to initialize USB
171 * Return Value: None
172 */
173
174 void USB_Init (void) {
175
176 // Setup USB clock and pins
177 USBIOClkConfig();
178
179 #if USB_FIQ_EVENT
180 /* It's important that only BULK and FRAME(ISO) can be routed
181 to FIQ. */
182 USB_DEVFIQSEL = 0x01; /* SOF Use FIQ */
183
184 /* Enable the USB Interrupt */
185 NVIC_EnableIRQ(USB_FIQn);
186 #endif
187
188 /* Enable the USB Interrupt */
189 NVIC_EnableIRQ(USB_IRQn);
190
191 USB_Reset();
192 USB_SetAddress(0);
193 return;
194 }
195
196
197 /*
198 * USB Connect Function
199 * Called by the User to Connect/Disconnect USB
200 * Parameters: con: Connect/Disconnect
201 * Return Value: None
202 */
203
204 void USB_Connect (uint32_t con) {
205 WrCmdDat(CMD_SET_DEV_STAT, DAT_WR_BYTE(con ? DEV_CON : 0));
206 }
207
208
209 /*
210 * USB Reset Function
211 * Called automatically on USB Reset
212 * Return Value: None
213 */
214
215 void USB_Reset (void) {
216
217 USB_DEVINTCLR = 0x000FFFFF;
218 /* Enable all eight(8) EPs, note: EP won't be ready until it's
219 configured/enabled when device sending SetEPStatus command
220 to the command engine. */
221 USB_DEVINTEN = DEV_STAT_INT | (0xFF<<1) |
222 (USB_SOF_EVENT ? FRAME_INT : 0);
223 return;
224 }
225
226
227 /*
228 * USB Suspend Function
229 * Called automatically on USB Suspend
230 * Return Value: None
231 */
232
233 void USB_Suspend (void) {
234 /* Performed by Hardware */
235 }
236
237
238 /*
239 * USB Resume Function
240 * Called automatically on USB Resume
241 * Return Value: None
242 */
243
244 void USB_Resume (void) {
245 /* Performed by Hardware */
246 }
247
248
249 /*
250 * USB Remote Wakeup Function
251 * Called automatically on USB Remote Wakeup
252 * Return Value: None
253 */
254
255 void USB_WakeUp (void) {
256
257 if (USB_DeviceStatus & USB_GETSTATUS_REMOTE_WAKEUP) {
258 WrCmdDat(CMD_SET_DEV_STAT, DAT_WR_BYTE(DEV_CON));
259 }
260 }
261
262
263 /*
264 * USB Remote Wakeup Configuration Function
265 * Parameters: cfg: Enable/Disable
266 * Return Value: None
267 */
268
269 void USB_WakeUpCfg (uint32_t cfg) {
270 cfg = cfg; /* Not needed */
271 }
272
273
274 /*
275 * USB Set Address Function
276 * Parameters: adr: USB Address
277 * Return Value: None
278 */
279
280 void USB_SetAddress (uint32_t adr) {
281 WrCmdDat(CMD_SET_ADDR, DAT_WR_BYTE(DEV_EN | adr)); /* Don't wait for next */
282 WrCmdDat(CMD_SET_ADDR, DAT_WR_BYTE(DEV_EN | adr)); /* Setup Status Phase */
283 }
284
285
286 /*
287 * USB Configure Function
288 * Parameters: cfg: Configure/Deconfigure
289 * Return Value: None
290 */
291
292 void USB_Configure (uint32_t cfg) {
293
294 WrCmdDat(CMD_CFG_DEV, DAT_WR_BYTE(cfg ? CONF_DVICE : 0));
295 return;
296 }
297
298
299 /*
300 * Configure USB Endpoint according to Descriptor
301 * Parameters: pEPD: Pointer to Endpoint Descriptor
302 * Return Value: None
303 */
304
305 void USB_ConfigEP (USB_ENDPOINT_DESCRIPTOR *pEPD) {
306 return;
307 }
308
309
310 /*
311 * Set Direction for USB Control Endpoint
312 * Parameters: dir: Out (dir == 0), In (dir <> 0)
313 * Return Value: None
314 */
315
316 void USB_DirCtrlEP (uint32_t dir) {
317 dir = dir; /* Not needed */
318 }
319
320
321 /*
322 * Enable USB Endpoint
323 * Parameters: EPNum: Endpoint Number
324 * EPNum.0..3: Address
325 * EPNum.7: Dir
326 * Return Value: None
327 */
328
329 void USB_EnableEP (uint32_t EPNum) {
330 WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(0));
331 }
332
333
334 /*
335 * Disable USB Endpoint
336 * Parameters: EPNum: Endpoint Number
337 * EPNum.0..3: Address
338 * EPNum.7: Dir
339 * Return Value: None
340 */
341
342 void USB_DisableEP (uint32_t EPNum) {
343 WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(EP_STAT_DA));
344 }
345
346
347 /*
348 * Reset USB Endpoint
349 * Parameters: EPNum: Endpoint Number
350 * EPNum.0..3: Address
351 * EPNum.7: Dir
352 * Return Value: None
353 */
354
355 void USB_ResetEP (uint32_t EPNum) {
356 WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(0));
357 }
358
359
360 /*
361 * Set Stall for USB Endpoint
362 * Parameters: EPNum: Endpoint Number
363 * EPNum.0..3: Address
364 * EPNum.7: Dir
365 * Return Value: None
366 */
367
368 void USB_SetStallEP (uint32_t EPNum) {
369 WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(EP_STAT_ST));
370 }
371
372
373 /*
374 * Clear Stall for USB Endpoint
375 * Parameters: EPNum: Endpoint Number
376 * EPNum.0..3: Address
377 * EPNum.7: Dir
378 * Return Value: None
379 */
380
381 void USB_ClrStallEP (uint32_t EPNum) {
382 WrCmdDat(CMD_SET_EP_STAT(EPAdr(EPNum)), DAT_WR_BYTE(0));
383 }
384
385
386 /*
387 * Clear USB Endpoint Buffer
388 * Parameters: EPNum: Endpoint Number
389 * EPNum.0..3: Address
390 * EPNum.7: Dir
391 * Return Value: None
392 */
393
394 void USB_ClearEPBuf (uint32_t EPNum) {
395 WrCmdEP(EPNum, CMD_CLR_BUF);
396 }
397
398
399 /*
400 * Read USB Endpoint Data
401 * Parameters: EPNum: Endpoint Number
402 * EPNum.0..3: Address
403 * EPNum.7: Dir
404 * pData: Pointer to Data Buffer
405 * Return Value: Number of bytes read
406 */
407
408 uint32_t USB_ReadEP (uint32_t EPNum, uint8_t *pData) {
409 uint32_t cnt, n;
410
411 USB_CTRL = ((EPNum & 0x0F) << 2) | CTRL_RD_EN;
412 /* 3 clock cycles to fetch the packet length from RAM. */
413 delay( 5 );
414
415 do {
416 cnt = USB_RXPLEN;
417 } while ((cnt & PKT_DV) == 0);
418 cnt &= PKT_LNGTH_MASK;
419
420 for (n = 0; n < (cnt + 3) / 4; n++) {
421 *((uint32_t __attribute__((packed)) *)pData) = USB_RXDATA;
422 pData += 4;
423 }
424
425 USB_CTRL = 0;
426
427 if ((EPNum & 0x80) != 0x04) { /* Non-Isochronous Endpoint */
428 WrCmdEP(EPNum, CMD_CLR_BUF);
429 }
430
431 return (cnt);
432 }
433
434
435 /*
436 * Write USB Endpoint Data
437 * Parameters: EPNum: Endpoint Number
438 * EPNum.0..3: Address
439 * EPNum.7: Dir
440 * pData: Pointer to Data Buffer
441 * cnt: Number of bytes to write
442 * Return Value: Number of bytes written
443 */
444
445 uint32_t USB_WriteEP (uint32_t EPNum, uint8_t *pData, uint32_t cnt) {
446 uint32_t n;
447
448 USB_CTRL = ((EPNum & 0x0F) << 2) | CTRL_WR_EN;
449 /* 3 clock cycles to fetch the packet length from RAM. */
450 delay( 5 );
451 USB_TXPLEN = cnt;
452
453 for (n = 0; n < (cnt + 3) / 4; n++) {
454 USB_TXDATA = *((uint32_t __attribute__((packed)) *)pData);
455 pData += 4;
456 }
457
458 USB_CTRL = 0;
459
460 WrCmdEP(EPNum, CMD_VALID_BUF);
461
462 return (cnt);
463 }
464
465 /*
466 * Get USB Last Frame Number
467 * Parameters: None
468 * Return Value: Frame Number
469 */
470
471 uint32_t USB_GetFrame (void) {
472 uint32_t val;
473
474 WrCmd(CMD_RD_FRAME);
475 val = RdCmdDat(DAT_RD_FRAME);
476 val = val | (RdCmdDat(DAT_RD_FRAME) << 8);
477
478 return (val);
479 }
480
481
482 /*
483 * USB Interrupt Service Routine
484 */
485
486 #ifdef CFG_USBCDC
487 void USB_IRQHandler (void)
488 {
489 uint32_t disr, val, n, m;
490
491 disr = USB_DEVINTST; /* Device Interrupt Status */
492 USB_DEVINTCLR = disr;
493
494 /* Device Status Interrupt (Reset, Connect change, Suspend/Resume) */
495 if (disr & DEV_STAT_INT) {
496 WrCmd(CMD_GET_DEV_STAT);
497 val = RdCmdDat(DAT_GET_DEV_STAT); /* Device Status */
498 if (val & DEV_RST) { /* Reset */
499 USB_Reset();
500 #if USB_RESET_EVENT
501 USB_Reset_Event();
502 #endif
503 }
504 if (val & DEV_CON_CH) { /* Connect change */
505 #if USB_POWER_EVENT
506 USB_Power_Event(val & DEV_CON);
507 #endif
508 }
509 if (val & DEV_SUS_CH) { /* Suspend/Resume */
510 if (val & DEV_SUS) { /* Suspend */
511 USB_Suspend();
512 #if USB_SUSPEND_EVENT
513 USB_Suspend_Event();
514 #endif
515 } else { /* Resume */
516 USB_Resume();
517 #if USB_RESUME_EVENT
518 USB_Resume_Event();
519 #endif
520 }
521 }
522 goto isr_end;
523 }
524
525 #if USB_SOF_EVENT
526 /* Start of Frame Interrupt */
527 if (disr & FRAME_INT) {
528 USB_DEVINTCLR = FRAME_INT;
529 USB_SOF_Event();
530 SOFIRQCount++;
531 }
532 #endif
533
534 #if USB_ERROR_EVENT
535 /* NO error interrupt anymore, below code can be used
536 as example to get error status from command engine. */
537 /* Error Interrupt */
538 if (disr & ERR_INT) {
539 WrCmd(CMD_RD_ERR_STAT);
540 val = RdCmdDat(DAT_RD_ERR_STAT);
541 USB_Error_Event(val);
542 }
543 #endif
544
545 /* Endpoint's Interrupt */
546 if (disr & (0xFF<<1)) {
547 /* if any of the EP0 through EP7 is set, or bit 1 through 9 on disr */
548 for (n = 0; n < USB_EP_NUM; n++) { /* Check All Endpoints */
549 /* skip frame interrupt at bit 0 in disr */
550 // if (disr & ((1 << n)<<1)) {
551 if ((disr>>1) & (1 << n)) {
552 m = n >> 1;
553 /* clear EP interrupt by sending cmd to the command engine. */
554 WrCmd(CMD_SEL_EP_CLRI(n));
555 val = RdCmdDat(DAT_SEL_EP_CLRI(n));
556 if ((n & 1) == 0) { /* OUT Endpoint */
557 if (n == 0) { /* Control OUT Endpoint */
558 if (val & EP_SEL_STP) { /* Setup Packet */
559 if (USB_P_EP[0]) {
560 USB_P_EP[0](USB_EVT_SETUP);
561 continue;
562 }
563 }
564 }
565 if (USB_P_EP[m]) {
566 USB_P_EP[m](USB_EVT_OUT);
567 }
568 } else { /* IN Endpoint */
569 if (USB_P_EP[m]) {
570 USB_P_EP[m](USB_EVT_IN);
571 }
572 }
573 }
574 }
575 }
576 isr_end:
577 return;
578 }
579 #endif
This page took 0.075488 seconds and 5 git commands to generate.