USB: ensure interrupts are disabled while getting LPC serial number
[clinton/Smoothieware.git] / src / libs / USBDevice / USBDevice / USBHAL_LPC17.cpp
CommitLineData
47b0bbd2
MM
1/* Copyright (c) 2010-2011 mbed.org, MIT License\r
2*\r
3* Permission is hereby granted, free of charge, to any person obtaining a copy of this software\r
4* and associated documentation files (the "Software"), to deal in the Software without\r
5* restriction, including without limitation the rights to use, copy, modify, merge, publish,\r
6* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the\r
7* Software is furnished to do so, subject to the following conditions:\r
8*\r
9* The above copyright notice and this permission notice shall be included in all copies or\r
10* substantial portions of the Software.\r
11*\r
12* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING\r
13* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
14* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\r
15* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
16* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
17*/\r
18\r
19#if defined(TARGET_LPC1768) || defined (__LPC17XX__)\r
20\r
21// void setled(int, bool);\r
22#define setled(a, b) do {} while (0)\r
23\r
24#include "USBHAL.h"\r
25\r
26#include <cstdio>\r
27\r
28#include <LPC17xx.h>\r
29\r
30#ifdef MBED\r
31 #include <score_cm3.h>\r
32#else\r
33 #include <lpc17xx_nvic.h>\r
34#endif\r
35\r
36#include "debug.h"\r
37\r
38#ifndef ENTER_ISR\r
39 #define ENTER_ISR() do {} while (0)\r
40#endif\r
41\r
42#ifndef LEAVE_ISR\r
43 #define LEAVE_ISR() do {} while (0)\r
44#endif\r
45\r
46#define iprintf(...)\r
47\r
48// Get endpoint direction\r
49#define IN_EP(endpoint) ((endpoint) & 1U ? true : false)\r
50#define OUT_EP(endpoint) ((endpoint) & 1U ? false : true)\r
51\r
52#define IN_BEP(endpoint) ((endpoint) & 0x80 ? true : false)\r
53#define OUT_BEP(endpoint) ((endpoint) & 0x80 ? false : true)\r
54\r
55// Convert physical endpoint number to register bit\r
56#define EP(endpoint) (1UL<<endpoint)\r
57\r
58#define ISOCHRONOUS_ENDPOINTS ((1UL << 3) | (1UL << 6) | (1UL << 9) | (1UL << 12))\r
59\r
60#define IS_ISOCHRONOUS(bEP) ((1UL << (bEP & 0x0F)) & ISOCHRONOUS_ENDPOINTS)\r
61\r
62// Power Control for Peripherals register\r
63#define PCUSB (1UL<<31)\r
64\r
65// USB Clock Control register\r
66#define DEV_CLK_EN (1UL<<1)\r
67#define AHB_CLK_EN (1UL<<4)\r
68\r
69// USB Clock Status register\r
70#define DEV_CLK_ON (1UL<<1)\r
71#define AHB_CLK_ON (1UL<<4)\r
72\r
73// USB Device Interupt registers\r
74#define FRAME (1UL<<0)\r
75#define EP_FAST (1UL<<1)\r
76#define EP_SLOW (1UL<<2)\r
77#define DEV_STAT (1UL<<3)\r
78#define CCEMPTY (1UL<<4)\r
79#define CDFULL (1UL<<5)\r
80#define RxENDPKT (1UL<<6)\r
81#define TxENDPKT (1UL<<7)\r
82#define EP_RLZED (1UL<<8)\r
83#define ERR_INT (1UL<<9)\r
84\r
85/* USBRxPLen bits */\r
86#define PKT_LNGTH (1<<0)\r
87#define PKT_LNGTH_MASK 0x3FF\r
88#define DV (1<<10)\r
89#define PKT_RDY (1<<11)\r
90\r
91/* Select Endpoint command read bits */\r
92#define EPSTAT_FE (1<<0)\r
93#define EPSTAT_ST (1<<1)\r
94#define EPSTAT_STP (1<<2)\r
95#define EPSTAT_PO (1<<3)\r
96#define EPSTAT_EPN (1<<4)\r
97#define EPSTAT_B1FULL (1<<5)\r
98#define EPSTAT_B2FULL (1<<6)\r
99\r
100// endpoint status sent through callback\r
101#define EP_STATUS_DATA (1<<0) /**< EP has data */\r
102#define EP_STATUS_STALLED (1<<1) /**< EP is stalled */\r
103#define EP_STATUS_SETUP (1<<2) /**< EP received setup packet */\r
104#define EP_STATUS_ERROR (1<<3) /**< EP data was overwritten by setup packet */\r
105#define EP_STATUS_NACKED (1<<4) /**< EP sent NAK */\r
106\r
107// USB Control register\r
108#define RD_EN (1<<0)\r
109#define WR_EN (1<<1)\r
110#define LOG_ENDPOINT(endpoint) ((endpoint>>1)<<2)\r
111\r
112// USB Receive Packet Length register\r
113// #define DV (1UL<<10)\r
114// #define PKT_RDY (1UL<<11)\r
115// #define PKT_LNGTH_MASK (0x3ff)\r
116\r
117// Serial Interface Engine (SIE)\r
118#define SIE_WRITE (0x01)\r
119#define SIE_READ (0x02)\r
120#define SIE_COMMAND (0x05)\r
121#define SIE_CMD_CODE(phase, data) ((phase<<8)|(data<<16))\r
122\r
123// SIE Command codes\r
124#define SIE_CMD_SET_ADDRESS (0xD0)\r
125#define SIE_CMD_CONFIGURE_DEVICE (0xD8)\r
126#define SIE_CMD_SET_MODE (0xF3)\r
127#define SIE_CMD_READ_FRAME_NUMBER (0xF5)\r
128#define SIE_CMD_READ_TEST_REGISTER (0xFD)\r
129#define SIE_CMD_SET_DEVICE_STATUS (0xFE)\r
130#define SIE_CMD_GET_DEVICE_STATUS (0xFE)\r
131#define SIE_CMD_GET_ERROR_CODE (0xFF)\r
132#define SIE_CMD_READ_ERROR_STATUS (0xFB)\r
133\r
134#define SIE_CMD_SELECT_ENDPOINT(endpoint) (0x00+endpoint)\r
135#define SIE_CMD_SELECT_ENDPOINT_CLEAR_INTERRUPT(endpoint) (0x40+endpoint)\r
136#define SIE_CMD_SET_ENDPOINT_STATUS(endpoint) (0x40+endpoint)\r
137\r
138#define SIE_CMD_CLEAR_BUFFER (0xF2)\r
139#define SIE_CMD_VALIDATE_BUFFER (0xFA)\r
140\r
141// SIE Device Status register\r
142#define SIE_DS_CON (1<<0)\r
143#define SIE_DS_CON_CH (1<<1)\r
144#define SIE_DS_SUS (1<<2)\r
145#define SIE_DS_SUS_CH (1<<3)\r
146#define SIE_DS_RST (1<<4)\r
147\r
148// SIE Device Set Address register\r
149#define SIE_DSA_DEV_EN (1<<7)\r
150\r
151// SIE Configue Device register\r
152#define SIE_CONF_DEVICE (1<<0)\r
153\r
154// Select Endpoint register\r
155#define SIE_SE_FE (1<<0)\r
156#define SIE_SE_ST (1<<1)\r
157#define SIE_SE_STP (1<<2)\r
158#define SIE_SE_PO (1<<3)\r
159#define SIE_SE_EPN (1<<4)\r
160#define SIE_SE_B_1_FULL (1<<5)\r
161#define SIE_SE_B_2_FULL (1<<6)\r
162\r
163// Set Endpoint Status command\r
164#define SIE_SES_ST (1<<0)\r
165#define SIE_SES_DA (1<<5)\r
166#define SIE_SES_RF_MO (1<<6)\r
167#define SIE_SES_CND_ST (1<<7)\r
168\r
169// endpoint modes\r
170#define SIE_MODE_AP_CLK (1<<0)\r
171#define SIE_MODE_INAK_CI (1<<1)\r
172#define SIE_MODE_INAK_CO (1<<2)\r
173#define SIE_MODE_INAK_II (1<<3)\r
174#define SIE_MODE_INAK_IO (1<<4)\r
175#define SIE_MODE_INAK_BI (1<<5)\r
176#define SIE_MODE_INAK_BO (1<<6)\r
177\r
178USBHAL * USBHAL::instance;\r
179\r
180// volatile uint32_t epComplete;\r
181volatile uint32_t USBEpIntEn;\r
182uint32_t endpointStallState;\r
183\r
184static void SIECommand(uint32_t command) {\r
185 // The command phase of a SIE transaction\r
186 LPC_USB->USBDevIntClr = CCEMPTY;\r
187 LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_COMMAND, command);\r
188 setled(4, 1); while (!(LPC_USB->USBDevIntSt & CCEMPTY)); setled(4, 0);\r
189}\r
190\r
191static void SIEWriteData(uint8_t data) {\r
192 // The data write phase of a SIE transaction\r
193 LPC_USB->USBDevIntClr = CCEMPTY;\r
194 LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_WRITE, data);\r
195 setled(4, 1); while (!(LPC_USB->USBDevIntSt & CCEMPTY)); setled(4, 0);\r
196}\r
197\r
198static uint8_t SIEReadData(uint32_t command) {\r
199 // The data read phase of a SIE transaction\r
200 LPC_USB->USBDevIntClr = CDFULL;\r
201 LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_READ, command);\r
202 setled(4, 1); while (!(LPC_USB->USBDevIntSt & CDFULL)); setled(4, 0);\r
203 return (uint8_t)LPC_USB->USBCmdData;\r
204}\r
205\r
206static void SIEsetDeviceStatus(uint8_t status) {\r
207 // Write SIE device status register\r
208// iprintf("SIEsetDeviceStatus: %02X\n", status);\r
209 SIECommand(SIE_CMD_SET_DEVICE_STATUS);\r
210// iprintf("SIEsetDeviceStatus Write\n");\r
211 SIEWriteData(status);\r
212// iprintf("SIEsetDeviceStatus OK\n");\r
213}\r
214\r
215static uint8_t SIEgetDeviceStatus(void) {\r
216 // Read SIE device status register\r
217 SIECommand(SIE_CMD_GET_DEVICE_STATUS);\r
218 return SIEReadData(SIE_CMD_GET_DEVICE_STATUS);\r
219}\r
220\r
221static void SIEsetMode(uint8_t mode) {\r
222 SIECommand(SIE_CMD_SET_MODE);\r
223 SIEWriteData(mode);\r
224}\r
225\r
226static void SIEsetAddress(uint8_t address) {\r
227 // Write SIE device address register\r
228 SIECommand(SIE_CMD_SET_ADDRESS);\r
229 SIEWriteData((address & 0x7f) | SIE_DSA_DEV_EN);\r
230}\r
231\r
232static uint8_t SIEselectEndpoint(uint8_t bEP) {\r
233 uint8_t endpoint = EP2IDX(bEP);\r
234\r
235 // SIE select endpoint command\r
236 SIECommand(SIE_CMD_SELECT_ENDPOINT(endpoint));\r
237 return SIEReadData(SIE_CMD_SELECT_ENDPOINT(endpoint));\r
238}\r
239\r
240static uint8_t SIEclearBuffer(void) {\r
241 // SIE clear buffer command\r
242 SIECommand(SIE_CMD_CLEAR_BUFFER);\r
243 return SIEReadData(SIE_CMD_CLEAR_BUFFER);\r
244}\r
245\r
246static void SIEvalidateBuffer(void) {\r
247 // SIE validate buffer command\r
248 SIECommand(SIE_CMD_VALIDATE_BUFFER);\r
249}\r
250\r
251static void SIEsetEndpointStatus(uint8_t bEP, uint8_t status) {\r
252 uint8_t endpoint = EP2IDX(bEP);\r
253\r
254 // SIE set endpoint status command\r
255 SIECommand(SIE_CMD_SET_ENDPOINT_STATUS(endpoint));\r
256 SIEWriteData(status);\r
257}\r
258\r
259static uint16_t SIEgetFrameNumber(void) __attribute__ ((unused));\r
260static uint16_t SIEgetFrameNumber(void) {\r
261 // Read current frame number\r
262 uint16_t lowByte;\r
263 uint16_t highByte;\r
264\r
265 SIECommand(SIE_CMD_READ_FRAME_NUMBER);\r
266 lowByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER);\r
267 highByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER);\r
268\r
269 return (highByte << 8) | lowByte;\r
270}\r
271\r
272static void SIEconfigureDevice(void) {\r
273 // SIE Configure device command\r
274 SIECommand(SIE_CMD_CONFIGURE_DEVICE);\r
275 SIEWriteData(SIE_CONF_DEVICE);\r
276}\r
277\r
278static void SIEunconfigureDevice(void) {\r
279 // SIE Configure device command\r
280 SIECommand(SIE_CMD_CONFIGURE_DEVICE);\r
281 SIEWriteData(0);\r
282}\r
283\r
284static void SIEconnect(void) {\r
285 // Connect USB device\r
286 uint8_t status;\r
287\r
288 status = SIEgetDeviceStatus();\r
289// iprintf("USBHAL::SIEconnect status is %02X\n", status);\r
290 SIEsetDeviceStatus(status | SIE_DS_CON);\r
291// iprintf("USBHAL::SIEconnect ok\n");\r
292}\r
293\r
294\r
295static void SIEdisconnect(void) {\r
296 // Disconnect USB device\r
297 uint8_t status;\r
298\r
299 status = SIEgetDeviceStatus();\r
300 SIEsetDeviceStatus(status & ~SIE_DS_CON);\r
301}\r
302\r
303\r
304static uint8_t selectEndpointClearInterrupt(uint8_t bEP) {\r
305 uint8_t endpoint = EP2IDX(bEP);\r
306\r
307 // Implemented using using EP_INT_CL\r
308 LPC_USB->USBEpIntClr = EP(endpoint);\r
309 setled(4, 1); while (!(LPC_USB->USBDevIntSt & CDFULL)); setled(4, 0);\r
310 return (uint8_t)LPC_USB->USBCmdData;\r
311}\r
312\r
313static void enableEndpointEvent(uint8_t bEP) {\r
314 uint8_t endpoint = EP2IDX(bEP);\r
315\r
316 // Enable an endpoint interrupt\r
317 LPC_USB->USBEpIntEn |= EP(endpoint);\r
318}\r
319\r
320static void disableEndpointEvent(uint8_t bEP) __attribute__ ((unused));\r
321static void disableEndpointEvent(uint8_t bEP) {\r
322 uint8_t endpoint = EP2IDX(bEP);\r
323\r
324 // Disable an endpoint interrupt\r
325 LPC_USB->USBEpIntEn &= ~EP(endpoint);\r
326}\r
327\r
328static volatile uint32_t __attribute__((used)) dummyRead;\r
329\r
330\r
331uint32_t USBHAL::endpointReadcore(uint8_t bEP, uint8_t *buffer)\r
332{\r
333 // Read from an OUT endpoint\r
334 uint32_t size;\r
335 uint32_t i;\r
336 uint32_t data = 0;\r
337 uint8_t offset;\r
338 uint8_t endpoint = EP2IDX(bEP);\r
339\r
340 uint8_t irq = NVIC_GetActive(USB_IRQn);\r
341 NVIC_DisableIRQ(USB_IRQn);\r
342\r
343// iprintf("epReadCore 0x%02X = %d, 0x%02X\n", bEP, endpoint, LOG_ENDPOINT(endpoint));\r
344\r
345 LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | RD_EN;\r
346\r
347// iprintf("0x%02lX\n", LPC_USB->USBCtrl);\r
348\r
349 setled(4, 1); while (!(LPC_USB->USBRxPLen & PKT_RDY))\r
350 {\r
351// iprintf("ep not ready, Waiting for data...\n");\r
352 }\r
353 setled(4, 0);\r
354\r
355// iprintf("0x%02lX 0x%02lX\n", LPC_USB->USBCtrl, LPC_USB->USBRxPLen);\r
356\r
357 size = LPC_USB->USBRxPLen & PKT_LNGTH_MASK;\r
358\r
359 if ((IS_ISOCHRONOUS(bEP) == 0) && (size > 64))\r
360 {\r
361// iprintf("BOGUS SIZE FOR EP 0x%02X! Got %ld, max is 64!\n", bEP, size);\r
362 size = 64;\r
363 }\r
364\r
365// iprintf("Reading %ld bytes\n", size);\r
366\r
367 offset = 0;\r
368\r
369 if (size > 0)\r
370 {\r
371 for (i = 0; i < size; i++)\r
372 {\r
373 if (offset==0)\r
374 {\r
375 // Fetch up to four bytes of data as a word\r
376 data = LPC_USB->USBRxData;\r
377 }\r
378\r
379 // extract a byte\r
380 *buffer = (data>>offset) & 0xff;\r
381 buffer++;\r
382\r
383 // move on to the next byte\r
384 offset = (offset + 8) & 24;\r
385 }\r
386 } else\r
387 {\r
388 dummyRead = LPC_USB->USBRxData;\r
389 }\r
390\r
391 setled(4, 1); while ((LPC_USB->USBDevIntSt & RxENDPKT) == 0)\r
392 dummyRead = LPC_USB->USBRxData;\r
393 setled(4, 0);\r
394\r
395// iprintf("Read %ld\n", size);\r
396\r
397 if (can_transfer[endpoint] != 0)\r
398 can_transfer[endpoint]--;\r
399\r
400 LPC_USB->USBCtrl = 0;\r
401\r
402 if (IS_ISOCHRONOUS(bEP) == 0)\r
403 {\r
404// iprintf("Buffer Clear 0x%02X\n", bEP);\r
405 SIEselectEndpoint(bEP);\r
406 if (SIEclearBuffer())\r
407 {\r
408// iprintf("EP%dIN OVERRUN\n", bEP & 0x0F);\r
409 }\r
410 }\r
411\r
412 if (irq)\r
413 NVIC_EnableIRQ(USB_IRQn);\r
414\r
415 return size;\r
416}\r
417\r
418static void endpointWritecore(uint8_t bEP, uint8_t *buffer, uint32_t size)\r
419{\r
420 // Write to an IN endpoint\r
421// uint32_t temp, data;\r
422// uint8_t offset;\r
423 uint8_t endpoint = EP2IDX(bEP);\r
424\r
425 LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | WR_EN;\r
426\r
427 LPC_USB->USBTxPLen = size;\r
428// offset = 0;\r
429// data = 0;\r
430// iprintf("EP%d%s(%d) W:", (endpoint >> 1), ((endpoint & 1)?"IN":"OUT"), endpoint);\r
431 while (LPC_USB->USBCtrl & WR_EN)\r
432 {\r
433// iprintf("0x%02X 0x%02X 0x%02X 0x%02X ", buffer[0], buffer[1], buffer[2], buffer[3]);\r
434 LPC_USB->USBTxData = (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];\r
435 buffer += 4;\r
436 }\r
437\r
438// iprintf("!_(%ld)>", size);\r
439\r
440 // Clear WR_EN to cover zero length packet case\r
441 LPC_USB->USBCtrl = 0;\r
442\r
443 SIEselectEndpoint(bEP);\r
444 SIEvalidateBuffer();\r
445\r
446 uint8_t status __attribute__ ((unused)) = SIEselectEndpoint(bEP);\r
447// iprintf("EP 0x%02X ST 0x%02X\n", bEP, status);\r
448}\r
449\r
450\r
451USBHAL::USBHAL(void) {\r
452 instance = this;\r
453}\r
454\r
455void USBHAL::init() {\r
456 // Disable IRQ\r
457 NVIC_DisableIRQ(USB_IRQn);\r
458\r
459 // Enable power to USB device controller\r
460 LPC_SC->PCONP |= PCUSB;\r
461\r
462 // Enable USB clocks\r
463 LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN;\r
464 setled(4, 1); while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON)); setled(4, 0);\r
465\r
466 // Configure pins P0.29 and P0.30 to be USB D+ and USB D-\r
467 LPC_PINCON->PINSEL1 &= 0xc3ffffff;\r
468 LPC_PINCON->PINSEL1 |= 0x14000000;\r
469\r
470 // Disconnect USB device\r
471 SIEdisconnect();\r
472\r
473 // Configure pin P2.9 to be Connect\r
474 LPC_PINCON->PINSEL4 &= 0xfffcffff;\r
475 LPC_PINCON->PINSEL4 |= 0x00040000;\r
476\r
477 // Connect must be low for at least 2.5uS\r
478 // wait(0.3);\r
479\r
480 // Set the maximum packet size for the control endpoints\r
481 realiseEndpoint(IDX2EP(EP0IN), MAX_PACKET_SIZE_EP0, 0);\r
482 realiseEndpoint(IDX2EP(EP0OUT), MAX_PACKET_SIZE_EP0, 0);\r
483\r
484 // Attach IRQ\r
485// instance = this;\r
486 // NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr);\r
487 // NVIC_EnableIRQ(USB_IRQn);\r
488\r
489 USBEpIntEn = 0x3;\r
490\r
491 // Enable interrupts for device events and EP0\r
492// LPC_USB->USBDevIntEn = EP_SLOW | DEV_STAT | FRAME;\r
493 LPC_USB->USBDevIntEn = EP_SLOW | DEV_STAT;\r
494 // enableEndpointEvent(EP0IN);\r
495 // enableEndpointEvent(EP0OUT);\r
496}\r
497\r
498USBHAL::~USBHAL(void) {\r
499 // Ensure device disconnected\r
500 SIEdisconnect();\r
501\r
502 // Disable USB interrupts\r
503 NVIC_DisableIRQ(USB_IRQn);\r
504}\r
505\r
506uint32_t USBHAL::getSerialNumber(int length, uint32_t *buf) {\r
507 #define IAP_LOCATION 0x1FFF1FF1\r
508 uint32_t command[1];\r
509 uint32_t result[5];\r
510 typedef void (*IAP)(uint32_t*, uint32_t*);\r
511 IAP iap = (IAP) IAP_LOCATION;\r
512\r
b3e299cb
MM
513 __disable_irq();\r
514\r
47b0bbd2
MM
515 command[0] = 58;\r
516// iprintf("Getting Serial...\n");\r
517 iap(command, result);\r
518// iprintf("HW Serial Number: %08lX %08lX %08lX %08lX\n", result[1], result[2], result[3], result[4]);\r
519 int i;\r
520 for (i = 0; i < 4; i++) {\r
521 if (i < length) {\r
522 buf[i] = result[i + 1];\r
523 }\r
524 }\r
b3e299cb
MM
525\r
526 __enable_irq();\r
527\r
47b0bbd2
MM
528 return i;\r
529}\r
530\r
531void USBHAL::connect(void) {\r
532 // Connect USB device\r
533// iprintf("USBHAL::connect\n");\r
534 NVIC_EnableIRQ(USB_IRQn);\r
535 SIEconnect();\r
536// iprintf("USBHAL::connect OK\n");\r
537}\r
538\r
539void USBHAL::disconnect(void) {\r
540 // Disconnect USB device\r
541 SIEdisconnect();\r
542}\r
543\r
544void USBHAL::configureDevice(void) {\r
545 SIEconfigureDevice();\r
546}\r
547\r
548void USBHAL::unconfigureDevice(void) {\r
549 SIEunconfigureDevice();\r
550}\r
551\r
552void USBHAL::setAddress(uint8_t address) {\r
553 SIEsetAddress(address);\r
554// SIEsetMode(SIE_MODE_INAK_CI | SIE_MODE_INAK_CO | SIE_MODE_INAK_BI | SIE_MODE_INAK_BO);\r
555 SIEsetMode(SIE_MODE_INAK_CI | SIE_MODE_INAK_CO);\r
556}\r
557\r
558void USBHAL::EP0setup(uint8_t *buffer) {\r
559 endpointReadcore(IDX2EP(EP0OUT), buffer);\r
560}\r
561\r
562void USBHAL::EP0read(void) {\r
563 // Not required\r
564}\r
565\r
566uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {\r
567 return endpointReadcore(IDX2EP(EP0OUT), buffer);\r
568}\r
569\r
570void USBHAL::EP0write(uint8_t *buffer, uint32_t size) {\r
571 endpointWritecore(IDX2EP(EP0IN), buffer, size);\r
572}\r
573\r
574void USBHAL::EP0getWriteResult(void) {\r
575 // Not required\r
576}\r
577\r
578void USBHAL::EP0stall(void) {\r
579 // This will stall both control endpoints\r
580 stallEndpoint(IDX2EP(EP0OUT));\r
581}\r
582\r
583EP_STATUS USBHAL::endpointRead(uint8_t bEP, uint32_t maximumSize) {\r
584 return EP_PENDING;\r
585}\r
586\r
587EP_STATUS USBHAL::endpointReadResult(uint8_t bEP, uint8_t * buffer, uint32_t *bytesRead)\r
588{\r
589 uint8_t endpoint = EP2IDX(bEP);\r
590\r
591// iprintf("epReadResult 0x%02X = %d\n", bEP, endpoint);\r
592\r
593 //for isochronous endpoint, we don't wait an interrupt\r
594 if (IS_ISOCHRONOUS(bEP) == 0) {\r
595// iprintf("not Isochronous\n");\r
596// if (!(epComplete & EP(endpoint)))\r
597 if (can_transfer[endpoint] == 0)\r
598 {\r
599// iprintf("Pending\n");\r
600 return EP_PENDING;\r
601 }\r
602 }\r
603\r
604// iprintf("reading...\n");\r
605\r
606 __disable_irq();\r
607 __ISB();\r
608\r
609 if (can_transfer[endpoint])\r
610 {\r
611 can_transfer[endpoint]--;\r
612 __enable_irq();\r
613 *bytesRead = endpointReadcore(bEP, buffer);\r
614 }\r
615 else {\r
616 __enable_irq();\r
617 *bytesRead = 0;\r
618 }\r
619// epComplete &= ~EP(endpoint);\r
620\r
621// iprintf("OK\n");\r
622\r
623 return EP_COMPLETED;\r
624}\r
625\r
626EP_STATUS USBHAL::endpointWrite(uint8_t bEP, uint8_t *data, uint32_t size)\r
627{\r
628 uint8_t endpoint = EP2IDX(bEP);\r
629\r
630 if (getEndpointStallState(bEP)) {\r
631 return EP_STALLED;\r
632 }\r
633\r
634 do {\r
635 __disable_irq();\r
636 __ISB();\r
637\r
638 if (can_transfer[endpoint])\r
639 {\r
640 can_transfer[endpoint]--;\r
641 __enable_irq();\r
642 endpointWritecore(bEP, data, size);\r
643 return EP_PENDING;\r
644 }\r
645 __enable_irq();\r
646 endpointSetInterrupt(bEP, true);\r
647 } while (1);\r
648}\r
649\r
650EP_STATUS USBHAL::endpointWriteResult(uint8_t bEP)\r
651{\r
652 uint8_t endpoint = EP2IDX(bEP);\r
653\r
654// if (epComplete & EP(endpoint)) {\r
655 if (can_transfer[endpoint] < 2) {\r
656// epComplete &= ~EP(endpoint);\r
657 return EP_COMPLETED;\r
658 }\r
659\r
660 return EP_PENDING;\r
661}\r
662\r
663uint8_t USBHAL::endpointStatus(uint8_t bEP)\r
664{\r
665 uint8_t bEPStat = SIEselectEndpoint(EP2IDX(bEP));\r
666\r
667 uint8_t bStat __attribute__ ((unused))\r
668 = ((bEPStat & EPSTAT_FE ) ? EP_STATUS_DATA : 0) |\r
669 ((bEPStat & EPSTAT_ST ) ? EP_STATUS_STALLED : 0) |\r
670 ((bEPStat & EPSTAT_STP) ? EP_STATUS_SETUP : 0) |\r
671 ((bEPStat & EPSTAT_EPN) ? EP_STATUS_NACKED : 0) |\r
672 ((bEPStat & EPSTAT_PO ) ? EP_STATUS_ERROR : 0);\r
673\r
674 return bEPStat;\r
675}\r
676\r
677bool USBHAL::realiseEndpoint(uint8_t bEP, uint32_t maxPacket, uint32_t flags)\r
678{\r
679 uint8_t endpoint = EP2IDX(bEP);\r
680\r
681 // Realise an endpoint\r
682 LPC_USB->USBDevIntClr = EP_RLZED;\r
683 LPC_USB->USBReEp |= EP(endpoint);\r
684 LPC_USB->USBEpInd = endpoint;\r
685 LPC_USB->USBMaxPSize = maxPacket;\r
686\r
687 setled(4, 1); while (!(LPC_USB->USBDevIntSt & EP_RLZED)); setled(4, 0);\r
688 LPC_USB->USBDevIntClr = EP_RLZED;\r
689\r
690 // Clear stall state\r
691// endpointStallState &= ~EP(endpoint);\r
692 unstallEndpoint(bEP);\r
693\r
694 enableEndpointEvent(bEP);\r
695\r
696 /*\r
697 * if this is an OUT endpoint, enable interrupts so we can receive any\r
698 * data the host sends to us.\r
699 *\r
700 * if this is an IN endpoint, don't enable interrupts just yet, but have\r
701 * an event waiting so we can immediately interrupt later on when the\r
702 * user app calls endpointSetInterrupt(bEP, true)\r
703 */\r
704\r
705 if (IN_BEP(bEP))\r
706 {\r
707// epComplete |= EP(endpoint);\r
708 can_transfer[endpoint] = 2;\r
709 }\r
710 else\r
711 {\r
712 can_transfer[endpoint] = 0;\r
713 endpointSetInterrupt(bEP, true);\r
714 }\r
715\r
716// iprintf("EP 0x%02X realised @%ld!\n", bEP, maxPacket);\r
717 return true;\r
718}\r
719\r
720void USBHAL::stallEndpoint(uint8_t bEP)\r
721{\r
722 uint8_t endpoint = EP2IDX(bEP);\r
723\r
724 // Stall an endpoint\r
725 if ( (endpoint==EP0IN) || (endpoint==EP0OUT) ) {\r
726 // Conditionally stall both control endpoints\r
727 SIEsetEndpointStatus(IDX2EP(EP0OUT), SIE_SES_CND_ST);\r
728 } else {\r
729 SIEsetEndpointStatus(bEP, SIE_SES_ST);\r
730\r
731 // Update stall state\r
732 endpointStallState |= EP(endpoint);\r
733 }\r
734}\r
735\r
736void USBHAL::unstallEndpoint(uint8_t bEP)\r
737{\r
738 uint8_t endpoint = EP2IDX(bEP);\r
739\r
740 // Unstall an endpoint. The endpoint will also be reinitialised\r
741 SIEsetEndpointStatus(bEP, 0);\r
742\r
743 // Update stall state\r
744 endpointStallState &= ~EP(endpoint);\r
745}\r
746\r
747bool USBHAL::getEndpointStallState(uint8_t bEP)\r
748{\r
749 // Returns true if endpoint stalled\r
750 return endpointStallState & EP(EP2IDX(bEP));\r
751}\r
752\r
753void USBHAL::remoteWakeup(void)\r
754{\r
755 // Remote wakeup\r
756 uint8_t status;\r
757\r
758 // Enable USB clocks\r
759 LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN;\r
760 setled(4, 1); while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON)); setled(4, 0);\r
761\r
762 status = SIEgetDeviceStatus();\r
763 SIEsetDeviceStatus(status & ~SIE_DS_SUS);\r
764}\r
765\r
766uint16_t USBHAL::lastFrame(void)\r
767{\r
768 return SIEgetFrameNumber();\r
769}\r
770\r
771extern "C" {\r
772 __attribute__ ((interrupt)) void USB_IRQHandler() {\r
773// iprintf("!0x%08lX/0x%08lX:", LPC_USB->USBDevIntSt, LPC_USB->USBDevIntEn);\r
774 ENTER_ISR();\r
775 USBHAL::_usbisr();\r
776 LEAVE_ISR();\r
777 }\r
778}\r
779\r
780void USBHAL::_usbisr(void) {\r
781 instance->usbisr();\r
782}\r
783\r
784bool USBHAL::endpointSetInterrupt(uint8_t bEP, bool enabled)\r
785{\r
786 uint8_t endpoint = EP2IDX(bEP);\r
787\r
788 bool r = USBEpIntEn | EP(endpoint);\r
789\r
790 if (enabled)\r
791 {\r
792 __disable_irq();\r
793 USBEpIntEn |= EP(endpoint);\r
794 if (can_transfer[endpoint])\r
795 endpointTriggerInterrupt(bEP);\r
796// LPC_USB->USBEpIntSet = EP(endpoint);\r
797 __enable_irq();\r
798 }\r
799 else\r
800 {\r
801 USBEpIntEn &= ~EP(endpoint);\r
802 }\r
803\r
804 return r;\r
805}\r
806\r
807bool USBHAL::endpointGetInterrupt(uint8_t bEP)\r
808{\r
809 uint8_t endpoint = EP2IDX(bEP);\r
810\r
811 return USBEpIntEn | EP(endpoint);\r
812}\r
813\r
814void USBHAL::endpointTriggerInterrupt(uint8_t bEP)\r
815{\r
816 uint8_t endpoint = EP2IDX(bEP);\r
817\r
818 LPC_USB->USBEpIntSet = EP(endpoint);\r
819}\r
820\r
821void USBHAL::usbisr(void)\r
822{\r
823 uint8_t devStat;\r
824\r
825 if (LPC_USB->USBDevIntSt & FRAME)\r
826 {\r
827// iprintf("F");\r
828 // Start of frame event\r
829// SOF(SIEgetFrameNumber());\r
830 USBEvent_Frame(SIEgetFrameNumber());\r
831 // Clear interrupt status flag\r
832 LPC_USB->USBDevIntClr = FRAME;\r
833\r
834// static uint8_t lst;\r
835// uint8_t st = SIEselectEndpoint(0x80);\r
836// if (st != lst)\r
837// {\r
838// iprintf("EP1S:%02X\n", st);\r
839// lst = st;\r
840// }\r
841 }\r
842\r
843 if (LPC_USB->USBDevIntSt & DEV_STAT)\r
844 {\r
845 iprintf("D");\r
846 // Device Status interrupt\r
847 // Must clear the interrupt status flag before reading the device status from the SIE\r
848 LPC_USB->USBDevIntClr = DEV_STAT;\r
849\r
850 // Read device status from SIE\r
851 devStat = SIEgetDeviceStatus();\r
852 //printf("devStat: %d\r\n", devStat);\r
853\r
854 if (devStat & SIE_DS_SUS_CH)\r
855 {\r
856 // Suspend status changed\r
857// if((devStat & SIE_DS_SUS) != 0) {\r
858// USBEvent_suspendStateChanged(false);\r
859// }\r
860 USBEvent_suspendStateChanged(devStat & SIE_DS_SUS);\r
861 }\r
862\r
863 if (devStat & SIE_DS_RST)\r
864 {\r
865 // Bus reset\r
866// if((devStat & SIE_DS_SUS) == 0) {\r
867// USBEvent_suspendStateChanged(true);\r
868// }\r
869 USBEvent_busReset();\r
870\r
871 realiseEndpoint(IDX2EP(EP0IN), MAX_PACKET_SIZE_EP0, 0);\r
872 realiseEndpoint(IDX2EP(EP0OUT), MAX_PACKET_SIZE_EP0, 0);\r
873\r
874 SIEsetMode(SIE_MODE_INAK_CI | SIE_MODE_INAK_CO | SIE_MODE_INAK_BI | SIE_MODE_INAK_BO);\r
875 }\r
876\r
877 if (devStat & SIE_DS_CON_CH)\r
878 {\r
879 USBEvent_connectStateChanged(devStat & SIE_DS_CON);\r
880 }\r
881 }\r
882\r
883 if (LPC_USB->USBDevIntSt & EP_SLOW)\r
884 {\r
885 // (Slow) Endpoint Interrupt\r
886\r
887 // Process each endpoint interrupt\r
888 if (LPC_USB->USBEpIntSt & EP(EP0OUT))\r
889 {\r
47ebf70b
MM
890 uint8_t bEPStat = selectEndpointClearInterrupt(IDX2EP(EP0OUT));\r
891 if (bEPStat & SIE_SE_STP)\r
47b0bbd2
MM
892 {\r
893 // this is a setup packet\r
894 EP0setupCallback();\r
895 }\r
47ebf70b 896 else if (bEPStat & EPSTAT_FE) // OUT endpoint, FE = 1 - data in buffer\r
47b0bbd2
MM
897 {\r
898 EP0out();\r
899 }\r
900 }\r
901 if (LPC_USB->USBEpIntSt & EP(EP0IN))\r
902 {\r
47ebf70b
MM
903 uint8_t bEPStat = selectEndpointClearInterrupt(IDX2EP(EP0IN));\r
904 if ((bEPStat & EPSTAT_FE) == 0) // IN endpoint, FE = 0 - empty space in buffer\r
905 EP0in();\r
47b0bbd2
MM
906 }\r
907\r
908 if (USBEpIntEn & ~(3UL))\r
909 {\r
910 int i;\r
911 uint32_t bitmask;\r
912\r
913 for (i = 2, bitmask = 4; i < 32; i++, bitmask <<= 1)\r
914 {\r
9f0f2c8f 915 uint8_t bEPStat = 255;\r
47b0bbd2
MM
916 uint8_t ep = IDX2EP(i);\r
917 if (LPC_USB->USBEpIntSt & bitmask)\r
918 {\r
919 bEPStat = selectEndpointClearInterrupt(ep);\r
920 if (can_transfer[i] < 2)\r
921 can_transfer[i]++;\r
922 }\r
923\r
924 if ((USBEpIntEn & bitmask) && (can_transfer[i]))\r
925 {\r
9f0f2c8f 926 if (bEPStat == 255)\r
47b0bbd2
MM
927 bEPStat = SIEselectEndpoint(ep);\r
928\r
929 iprintf("!02X", ep);\r
930\r
931 uint8_t bStat = ((bEPStat & EPSTAT_FE ) ? EP_STATUS_DATA : 0) |\r
932 ((bEPStat & EPSTAT_ST ) ? EP_STATUS_STALLED : 0) |\r
933 ((bEPStat & EPSTAT_STP) ? EP_STATUS_SETUP : 0) |\r
934 ((bEPStat & EPSTAT_EPN) ? EP_STATUS_NACKED : 0) |\r
935 ((bEPStat & EPSTAT_PO ) ? EP_STATUS_ERROR : 0);\r
936\r
9f0f2c8f 937 bool r = true;\r
47b0bbd2
MM
938\r
939 if (IN_EP(i))\r
940 {\r
941// iprintf("IN[%02X]:", IDX2EP(i));\r
9f0f2c8f
MM
942 if ((bEPStat & EPSTAT_FE) == 0) // IN endpoint, FE = 0 - empty space in buffer\r
943 r = USBEvent_EPIn(ep, bStat);\r
47b0bbd2
MM
944 }\r
945 else\r
946 {\r
947// iprintf("OUT[%02X]:", IDX2EP(i));\r
9f0f2c8f
MM
948 if (bEPStat & EPSTAT_FE) // OUT endpoint, FE = 1 - data in buffer\r
949 r = USBEvent_EPOut(ep, bStat);\r
47b0bbd2
MM
950 }\r
951\r
952 if (!r)\r
953 {\r
954 USBEpIntEn &= ~bitmask;\r
955 }\r
956// iprintf("\n");\r
957 }\r
958 }\r
959 iprintf("\n");\r
960 }\r
961\r
962 LPC_USB->USBDevIntClr = EP_SLOW;\r
963 }\r
964}\r
965\r
966#endif\r