]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/USBDevice/USBDevice/USBHAL_LPC17.cpp
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.git] / tool / mbed / mbed-sdk / libraries / USBDevice / USBDevice / USBHAL_LPC17.cpp
1 /* Copyright (c) 2010-2011 mbed.org, MIT License
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
4 * and associated documentation files (the "Software"), to deal in the Software without
5 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
6 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
7 * Software is furnished to do so, subject to the following conditions:
8 *
9 * The above copyright notice and this permission notice shall be included in all copies or
10 * substantial portions of the Software.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17 */
18
19 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
20
21 #include "USBHAL.h"
22
23
24 // Get endpoint direction
25 #define IN_EP(endpoint)     ((endpoint) & 1U ? true : false)
26 #define OUT_EP(endpoint)    ((endpoint) & 1U ? false : true)
27
28 // Convert physical endpoint number to register bit
29 #define EP(endpoint) (1UL<<endpoint)
30
31 // Power Control for Peripherals register
32 #define PCUSB      (1UL<<31)
33
34 // USB Clock Control register
35 #define DEV_CLK_EN (1UL<<1)
36 #define AHB_CLK_EN (1UL<<4)
37
38 // USB Clock Status register
39 #define DEV_CLK_ON (1UL<<1)
40 #define AHB_CLK_ON (1UL<<4)
41
42 // USB Device Interupt registers
43 #define FRAME      (1UL<<0)
44 #define EP_FAST    (1UL<<1)
45 #define EP_SLOW    (1UL<<2)
46 #define DEV_STAT   (1UL<<3)
47 #define CCEMPTY    (1UL<<4)
48 #define CDFULL     (1UL<<5)
49 #define RxENDPKT   (1UL<<6)
50 #define TxENDPKT   (1UL<<7)
51 #define EP_RLZED   (1UL<<8)
52 #define ERR_INT    (1UL<<9)
53
54 // USB Control register
55 #define RD_EN (1<<0)
56 #define WR_EN (1<<1)
57 #define LOG_ENDPOINT(endpoint) ((endpoint>>1)<<2)
58
59 // USB Receive Packet Length register
60 #define DV      (1UL<<10)
61 #define PKT_RDY (1UL<<11)
62 #define PKT_LNGTH_MASK (0x3ff)
63
64 // Serial Interface Engine (SIE)
65 #define SIE_WRITE   (0x01)
66 #define SIE_READ    (0x02)
67 #define SIE_COMMAND (0x05)
68 #define SIE_CMD_CODE(phase, data) ((phase<<8)|(data<<16))
69
70 // SIE Command codes
71 #define SIE_CMD_SET_ADDRESS        (0xD0)
72 #define SIE_CMD_CONFIGURE_DEVICE   (0xD8)
73 #define SIE_CMD_SET_MODE           (0xF3)
74 #define SIE_CMD_READ_FRAME_NUMBER  (0xF5)
75 #define SIE_CMD_READ_TEST_REGISTER (0xFD)
76 #define SIE_CMD_SET_DEVICE_STATUS  (0xFE)
77 #define SIE_CMD_GET_DEVICE_STATUS  (0xFE)
78 #define SIE_CMD_GET_ERROR_CODE     (0xFF)
79 #define SIE_CMD_READ_ERROR_STATUS  (0xFB)
80
81 #define SIE_CMD_SELECT_ENDPOINT(endpoint)                 (0x00+endpoint)
82 #define SIE_CMD_SELECT_ENDPOINT_CLEAR_INTERRUPT(endpoint) (0x40+endpoint)
83 #define SIE_CMD_SET_ENDPOINT_STATUS(endpoint)             (0x40+endpoint)
84
85 #define SIE_CMD_CLEAR_BUFFER    (0xF2)
86 #define SIE_CMD_VALIDATE_BUFFER (0xFA)
87
88 // SIE Device Status register
89 #define SIE_DS_CON    (1<<0)
90 #define SIE_DS_CON_CH (1<<1)
91 #define SIE_DS_SUS    (1<<2)
92 #define SIE_DS_SUS_CH (1<<3)
93 #define SIE_DS_RST    (1<<4)
94
95 // SIE Device Set Address register
96 #define SIE_DSA_DEV_EN  (1<<7)
97
98 // SIE Configue Device register
99 #define SIE_CONF_DEVICE (1<<0)
100
101 // Select Endpoint register
102 #define SIE_SE_FE       (1<<0)
103 #define SIE_SE_ST       (1<<1)
104 #define SIE_SE_STP      (1<<2)
105 #define SIE_SE_PO       (1<<3)
106 #define SIE_SE_EPN      (1<<4)
107 #define SIE_SE_B_1_FULL (1<<5)
108 #define SIE_SE_B_2_FULL (1<<6)
109
110 // Set Endpoint Status command
111 #define SIE_SES_ST      (1<<0)
112 #define SIE_SES_DA      (1<<5)
113 #define SIE_SES_RF_MO   (1<<6)
114 #define SIE_SES_CND_ST  (1<<7)
115
116
117 USBHAL * USBHAL::instance;
118
119 static volatile int epComplete;
120 static uint32_t endpointStallState;
121
122 static void SIECommand(uint32_t command) {
123     // The command phase of a SIE transaction
124     LPC_USB->USBDevIntClr = CCEMPTY;
125     LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_COMMAND, command);
126     while (!(LPC_USB->USBDevIntSt & CCEMPTY));
127 }
128
129 static void SIEWriteData(uint8_t data) {
130     // The data write phase of a SIE transaction
131     LPC_USB->USBDevIntClr = CCEMPTY;
132     LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_WRITE, data);
133     while (!(LPC_USB->USBDevIntSt & CCEMPTY));
134 }
135
136 static uint8_t SIEReadData(uint32_t command) {
137     // The data read phase of a SIE transaction
138     LPC_USB->USBDevIntClr = CDFULL;
139     LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_READ, command);
140     while (!(LPC_USB->USBDevIntSt & CDFULL));
141     return (uint8_t)LPC_USB->USBCmdData;
142 }
143
144 static void SIEsetDeviceStatus(uint8_t status) {
145     // Write SIE device status register
146     SIECommand(SIE_CMD_SET_DEVICE_STATUS);
147     SIEWriteData(status);
148 }
149
150 static uint8_t SIEgetDeviceStatus(void) {
151     // Read SIE device status register
152     SIECommand(SIE_CMD_GET_DEVICE_STATUS);
153     return SIEReadData(SIE_CMD_GET_DEVICE_STATUS);
154 }
155
156 void SIEsetAddress(uint8_t address) {
157     // Write SIE device address register
158     SIECommand(SIE_CMD_SET_ADDRESS);
159     SIEWriteData((address & 0x7f) | SIE_DSA_DEV_EN);
160 }
161
162 static uint8_t SIEselectEndpoint(uint8_t endpoint) {
163     // SIE select endpoint command
164     SIECommand(SIE_CMD_SELECT_ENDPOINT(endpoint));
165     return SIEReadData(SIE_CMD_SELECT_ENDPOINT(endpoint));
166 }
167
168 static uint8_t SIEclearBuffer(void) {
169     // SIE clear buffer command
170     SIECommand(SIE_CMD_CLEAR_BUFFER);
171     return SIEReadData(SIE_CMD_CLEAR_BUFFER);
172 }
173
174 static void SIEvalidateBuffer(void) {
175     // SIE validate buffer command
176     SIECommand(SIE_CMD_VALIDATE_BUFFER);
177 }
178
179 static void SIEsetEndpointStatus(uint8_t endpoint, uint8_t status) {
180     // SIE set endpoint status command
181     SIECommand(SIE_CMD_SET_ENDPOINT_STATUS(endpoint));
182     SIEWriteData(status);
183 }
184
185 static uint16_t SIEgetFrameNumber(void) __attribute__ ((unused));
186 static uint16_t SIEgetFrameNumber(void) {
187     // Read current frame number
188     uint16_t lowByte;
189     uint16_t highByte;
190
191     SIECommand(SIE_CMD_READ_FRAME_NUMBER);
192     lowByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER);
193     highByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER);
194
195     return (highByte << 8) | lowByte;
196 }
197
198 static void SIEconfigureDevice(void) {
199     // SIE Configure device command
200     SIECommand(SIE_CMD_CONFIGURE_DEVICE);
201     SIEWriteData(SIE_CONF_DEVICE);
202 }
203
204 static void SIEunconfigureDevice(void) {
205     // SIE Configure device command
206     SIECommand(SIE_CMD_CONFIGURE_DEVICE);
207     SIEWriteData(0);
208 }
209
210 static void SIEconnect(void) {
211     // Connect USB device
212     uint8_t status = SIEgetDeviceStatus();
213     SIEsetDeviceStatus(status | SIE_DS_CON);
214 }
215
216
217 static void SIEdisconnect(void) {
218     // Disconnect USB device
219     uint8_t status = SIEgetDeviceStatus();
220     SIEsetDeviceStatus(status & ~SIE_DS_CON);
221 }
222
223
224 static uint8_t selectEndpointClearInterrupt(uint8_t endpoint) {
225     // Implemented using using EP_INT_CLR.
226     LPC_USB->USBEpIntClr = EP(endpoint);
227     while (!(LPC_USB->USBDevIntSt & CDFULL));
228     return (uint8_t)LPC_USB->USBCmdData;
229 }
230
231
232 static void enableEndpointEvent(uint8_t endpoint) {
233     // Enable an endpoint interrupt
234     LPC_USB->USBEpIntEn |= EP(endpoint);
235 }
236
237 static void disableEndpointEvent(uint8_t endpoint) __attribute__ ((unused));
238 static void disableEndpointEvent(uint8_t endpoint) {
239     // Disable an endpoint interrupt
240     LPC_USB->USBEpIntEn &= ~EP(endpoint);
241 }
242
243 static volatile uint32_t __attribute__((used)) dummyRead;
244 uint32_t USBHAL::endpointReadcore(uint8_t endpoint, uint8_t *buffer) {
245     // Read from an OUT endpoint
246     uint32_t size;
247     uint32_t i;
248     uint32_t data = 0;
249     uint8_t offset;
250
251     LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | RD_EN;
252     while (!(LPC_USB->USBRxPLen & PKT_RDY));
253
254     size = LPC_USB->USBRxPLen & PKT_LNGTH_MASK;
255
256     offset = 0;
257
258     if (size > 0) {
259         for (i=0; i<size; i++) {
260             if (offset==0) {
261                 // Fetch up to four bytes of data as a word
262                 data = LPC_USB->USBRxData;
263             }
264
265             // extract a byte
266             *buffer = (data>>offset) & 0xff;
267             buffer++;
268
269             // move on to the next byte
270             offset = (offset + 8) % 32;
271         }
272     } else {
273         dummyRead = LPC_USB->USBRxData;
274     }
275
276     LPC_USB->USBCtrl = 0;
277
278     if ((endpoint >> 1) % 3 || (endpoint >> 1) == 0) {
279         SIEselectEndpoint(endpoint);
280         SIEclearBuffer();
281     }
282
283     return size;
284 }
285
286 static void endpointWritecore(uint8_t endpoint, uint8_t *buffer, uint32_t size) {
287     // Write to an IN endpoint
288     uint32_t temp, data;
289     uint8_t offset;
290
291     LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | WR_EN;
292
293     LPC_USB->USBTxPLen = size;
294     offset = 0;
295     data = 0;
296
297     if (size>0) {
298         do {
299             // Fetch next data byte into a word-sized temporary variable
300             temp = *buffer++;
301
302             // Add to current data word
303             temp = temp << offset;
304             data = data | temp;
305
306             // move on to the next byte
307             offset = (offset + 8) % 32;
308             size--;
309
310             if ((offset==0) || (size==0)) {
311                 // Write the word to the endpoint
312                 LPC_USB->USBTxData = data;
313                 data = 0;
314             }
315         } while (size>0);
316     } else {
317         LPC_USB->USBTxData = 0;
318     }
319
320     // Clear WR_EN to cover zero length packet case
321     LPC_USB->USBCtrl=0;
322
323     SIEselectEndpoint(endpoint);
324     SIEvalidateBuffer();
325 }
326
327 USBHAL::USBHAL(void) {
328     // Disable IRQ
329     NVIC_DisableIRQ(USB_IRQn);
330
331     // fill in callback array
332     epCallback[0] = &USBHAL::EP1_OUT_callback;
333     epCallback[1] = &USBHAL::EP1_IN_callback;
334     epCallback[2] = &USBHAL::EP2_OUT_callback;
335     epCallback[3] = &USBHAL::EP2_IN_callback;
336     epCallback[4] = &USBHAL::EP3_OUT_callback;
337     epCallback[5] = &USBHAL::EP3_IN_callback;
338     epCallback[6] = &USBHAL::EP4_OUT_callback;
339     epCallback[7] = &USBHAL::EP4_IN_callback;
340     epCallback[8] = &USBHAL::EP5_OUT_callback;
341     epCallback[9] = &USBHAL::EP5_IN_callback;
342     epCallback[10] = &USBHAL::EP6_OUT_callback;
343     epCallback[11] = &USBHAL::EP6_IN_callback;
344     epCallback[12] = &USBHAL::EP7_OUT_callback;
345     epCallback[13] = &USBHAL::EP7_IN_callback;
346     epCallback[14] = &USBHAL::EP8_OUT_callback;
347     epCallback[15] = &USBHAL::EP8_IN_callback;
348     epCallback[16] = &USBHAL::EP9_OUT_callback;
349     epCallback[17] = &USBHAL::EP9_IN_callback;
350     epCallback[18] = &USBHAL::EP10_OUT_callback;
351     epCallback[19] = &USBHAL::EP10_IN_callback;
352     epCallback[20] = &USBHAL::EP11_OUT_callback;
353     epCallback[21] = &USBHAL::EP11_IN_callback;
354     epCallback[22] = &USBHAL::EP12_OUT_callback;
355     epCallback[23] = &USBHAL::EP12_IN_callback;
356     epCallback[24] = &USBHAL::EP13_OUT_callback;
357     epCallback[25] = &USBHAL::EP13_IN_callback;
358     epCallback[26] = &USBHAL::EP14_OUT_callback;
359     epCallback[27] = &USBHAL::EP14_IN_callback;
360     epCallback[28] = &USBHAL::EP15_OUT_callback;
361     epCallback[29] = &USBHAL::EP15_IN_callback;
362
363     // Enable power to USB device controller
364     LPC_SC->PCONP |= PCUSB;
365
366     // Enable USB clocks
367     LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN;
368     while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON));
369
370     // Configure pins P0.29 and P0.30 to be USB D+ and USB D-
371     LPC_PINCON->PINSEL1 &= 0xc3ffffff;
372     LPC_PINCON->PINSEL1 |= 0x14000000;
373
374     // Disconnect USB device
375     SIEdisconnect();
376
377     // Configure pin P2.9 to be Connect
378     LPC_PINCON->PINSEL4 &= 0xfffcffff;
379     LPC_PINCON->PINSEL4 |= 0x00040000;
380
381     // Connect must be low for at least 2.5uS
382     wait(0.3);
383
384     // Set the maximum packet size for the control endpoints
385     realiseEndpoint(EP0IN, MAX_PACKET_SIZE_EP0, 0);
386     realiseEndpoint(EP0OUT, MAX_PACKET_SIZE_EP0, 0);
387
388     // Attach IRQ
389     instance = this;
390     NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr);
391
392     // Enable interrupts for device events and EP0
393     LPC_USB->USBDevIntEn = EP_SLOW | DEV_STAT | FRAME;
394     enableEndpointEvent(EP0IN);
395     enableEndpointEvent(EP0OUT);
396 }
397
398 USBHAL::~USBHAL(void) {
399     // Ensure device disconnected
400     SIEdisconnect();
401     // Disable USB interrupts
402     NVIC_DisableIRQ(USB_IRQn);
403 }
404
405 void USBHAL::connect(void) {
406     NVIC_EnableIRQ(USB_IRQn);
407     // Connect USB device
408     SIEconnect();
409 }
410
411 void USBHAL::disconnect(void) {
412     NVIC_DisableIRQ(USB_IRQn);
413     // Disconnect USB device
414     SIEdisconnect();
415 }
416
417 void USBHAL::configureDevice(void) {
418     SIEconfigureDevice();
419 }
420
421 void USBHAL::unconfigureDevice(void) {
422     SIEunconfigureDevice();
423 }
424
425 void USBHAL::setAddress(uint8_t address) {
426     SIEsetAddress(address);
427 }
428
429 void USBHAL::EP0setup(uint8_t *buffer) {
430     endpointReadcore(EP0OUT, buffer);
431 }
432
433 void USBHAL::EP0read(void) {
434     // Not required
435 }
436
437 void USBHAL::EP0readStage(void) {
438     // Not required
439 }
440
441 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {
442     return endpointReadcore(EP0OUT, buffer);
443 }
444
445 void USBHAL::EP0write(uint8_t *buffer, uint32_t size) {
446     endpointWritecore(EP0IN, buffer, size);
447 }
448
449 void USBHAL::EP0getWriteResult(void) {
450     // Not required
451 }
452
453 void USBHAL::EP0stall(void) {
454     // This will stall both control endpoints
455     stallEndpoint(EP0OUT);
456 }
457
458 EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) {
459     return EP_PENDING;
460 }
461
462 EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t * buffer, uint32_t *bytesRead) {
463
464     //for isochronous endpoint, we don't wait an interrupt
465     if ((endpoint >> 1) % 3 || (endpoint >> 1) == 0) {
466         if (!(epComplete & EP(endpoint)))
467             return EP_PENDING;
468     }
469
470     *bytesRead = endpointReadcore(endpoint, buffer);
471     epComplete &= ~EP(endpoint);
472     return EP_COMPLETED;
473 }
474
475 EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) {
476     if (getEndpointStallState(endpoint)) {
477         return EP_STALLED;
478     }
479
480     epComplete &= ~EP(endpoint);
481
482     endpointWritecore(endpoint, data, size);
483     return EP_PENDING;
484 }
485
486 EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) {
487     if (epComplete & EP(endpoint)) {
488         epComplete &= ~EP(endpoint);
489         return EP_COMPLETED;
490     }
491
492     return EP_PENDING;
493 }
494
495 bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t flags) {
496     // Realise an endpoint
497     LPC_USB->USBDevIntClr = EP_RLZED;
498     LPC_USB->USBReEp |= EP(endpoint);
499     LPC_USB->USBEpInd = endpoint;
500     LPC_USB->USBMaxPSize = maxPacket;
501
502     while (!(LPC_USB->USBDevIntSt & EP_RLZED));
503     LPC_USB->USBDevIntClr = EP_RLZED;
504
505     // Clear stall state
506     endpointStallState &= ~EP(endpoint);
507
508     enableEndpointEvent(endpoint);
509     return true;
510 }
511
512 void USBHAL::stallEndpoint(uint8_t endpoint) {
513     // Stall an endpoint
514     if ( (endpoint==EP0IN) || (endpoint==EP0OUT) ) {
515         // Conditionally stall both control endpoints
516         SIEsetEndpointStatus(EP0OUT, SIE_SES_CND_ST);
517     } else {
518         SIEsetEndpointStatus(endpoint, SIE_SES_ST);
519
520         // Update stall state
521         endpointStallState |= EP(endpoint);
522     }
523 }
524
525 void USBHAL::unstallEndpoint(uint8_t endpoint) {
526     // Unstall an endpoint. The endpoint will also be reinitialised
527     SIEsetEndpointStatus(endpoint, 0);
528
529     // Update stall state
530     endpointStallState &= ~EP(endpoint);
531 }
532
533 bool USBHAL::getEndpointStallState(uint8_t endpoint) {
534     // Returns true if endpoint stalled
535     return endpointStallState & EP(endpoint);
536 }
537
538 void USBHAL::remoteWakeup(void) {
539     // Remote wakeup
540     uint8_t status;
541
542     // Enable USB clocks
543     LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN;
544     while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON));
545
546     status = SIEgetDeviceStatus();
547     SIEsetDeviceStatus(status & ~SIE_DS_SUS);
548 }
549
550 void USBHAL::_usbisr(void) {
551     instance->usbisr();
552 }
553
554
555 void USBHAL::usbisr(void) {
556     uint8_t devStat;
557
558     if (LPC_USB->USBDevIntSt & FRAME) {
559         // Start of frame event
560         SOF(SIEgetFrameNumber());
561         // Clear interrupt status flag
562         LPC_USB->USBDevIntClr = FRAME;
563     }
564
565     if (LPC_USB->USBDevIntSt & DEV_STAT) {
566         // Device Status interrupt
567         // Must clear the interrupt status flag before reading the device status from the SIE
568         LPC_USB->USBDevIntClr = DEV_STAT;
569
570         // Read device status from SIE
571         devStat = SIEgetDeviceStatus();
572         //printf("devStat: %d\r\n", devStat);
573
574         if (devStat & SIE_DS_SUS_CH) {
575             // Suspend status changed
576             if((devStat & SIE_DS_SUS) != 0) {
577                 suspendStateChanged(0);
578             }
579         }
580
581         if (devStat & SIE_DS_RST) {
582             // Bus reset
583             if((devStat & SIE_DS_SUS) == 0) {
584                 suspendStateChanged(1);
585             }
586             busReset();
587         }
588     }
589
590     if (LPC_USB->USBDevIntSt & EP_SLOW) {
591         // (Slow) Endpoint Interrupt
592
593         // Process each endpoint interrupt
594         if (LPC_USB->USBEpIntSt & EP(EP0OUT)) {
595             if (selectEndpointClearInterrupt(EP0OUT) & SIE_SE_STP) {
596                 // this is a setup packet
597                 EP0setupCallback();
598             } else {
599                 EP0out();
600             }
601             LPC_USB->USBDevIntClr = EP_SLOW;
602         }
603
604         if (LPC_USB->USBEpIntSt & EP(EP0IN)) {
605             selectEndpointClearInterrupt(EP0IN);
606             LPC_USB->USBDevIntClr = EP_SLOW;
607             EP0in();
608         }
609
610         for (uint8_t num = 2; num < 16*2; num++) {
611             if (LPC_USB->USBEpIntSt & EP(num)) {
612                 selectEndpointClearInterrupt(num);
613                 epComplete |= EP(num);
614                 LPC_USB->USBDevIntClr = EP_SLOW;
615                 if ((instance->*(epCallback[num - 2]))()) {
616                     epComplete &= ~EP(num);
617                 }
618             }
619         }
620     }
621 }
622
623 #endif