35f00b6c |
1 | /* Teensyduino Core Library |
2 | * http://www.pjrc.com/teensy/ |
3 | * Copyright (c) 2013 PJRC.COM, LLC. |
4 | * |
5 | * Permission is hereby granted, free of charge, to any person obtaining |
6 | * a copy of this software and associated documentation files (the |
7 | * "Software"), to deal in the Software without restriction, including |
8 | * without limitation the rights to use, copy, modify, merge, publish, |
9 | * distribute, sublicense, and/or sell copies of the Software, and to |
10 | * permit persons to whom the Software is furnished to do so, subject to |
11 | * the following conditions: |
12 | * |
a773ac06 |
13 | * 1. The above copyright notice and this permission notice shall be |
35f00b6c |
14 | * included in all copies or substantial portions of the Software. |
15 | * |
a773ac06 |
16 | * 2. If the Software is incorporated into a build system that allows |
35f00b6c |
17 | * selection among a list of target devices, then similar target |
18 | * devices manufactured by PJRC.COM must be included in the list of |
19 | * target devices and selectable in the same manner. |
20 | * |
21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
28 | * SOFTWARE. |
29 | */ |
30 | |
35f00b6c |
31 | #include "usb_dev.h" |
a773ac06 |
32 | #if F_CPU >= 20000000 && defined(NUM_ENDPOINTS) |
33 | |
34 | #include "kinetis.h" |
35 | //#include "HardwareSerial.h" |
35f00b6c |
36 | #include "usb_mem.h" |
37 | |
38 | // buffer descriptor table |
39 | |
40 | typedef struct { |
41 | uint32_t desc; |
42 | void * addr; |
43 | } bdt_t; |
44 | |
45 | __attribute__ ((section(".usbdescriptortable"), used)) |
46 | static bdt_t table[(NUM_ENDPOINTS+1)*4]; |
47 | |
48 | static usb_packet_t *rx_first[NUM_ENDPOINTS]; |
49 | static usb_packet_t *rx_last[NUM_ENDPOINTS]; |
50 | static usb_packet_t *tx_first[NUM_ENDPOINTS]; |
51 | static usb_packet_t *tx_last[NUM_ENDPOINTS]; |
52 | uint16_t usb_rx_byte_count_data[NUM_ENDPOINTS]; |
53 | |
54 | static uint8_t tx_state[NUM_ENDPOINTS]; |
55 | #define TX_STATE_BOTH_FREE_EVEN_FIRST 0 |
56 | #define TX_STATE_BOTH_FREE_ODD_FIRST 1 |
57 | #define TX_STATE_EVEN_FREE 2 |
58 | #define TX_STATE_ODD_FREE 3 |
59 | #define TX_STATE_NONE_FREE_EVEN_FIRST 4 |
60 | #define TX_STATE_NONE_FREE_ODD_FIRST 5 |
61 | |
62 | #define BDT_OWN 0x80 |
63 | #define BDT_DATA1 0x40 |
64 | #define BDT_DATA0 0x00 |
65 | #define BDT_DTS 0x08 |
66 | #define BDT_STALL 0x04 |
67 | #define BDT_PID(n) (((n) >> 2) & 15) |
68 | |
69 | #define BDT_DESC(count, data) (BDT_OWN | BDT_DTS \ |
70 | | ((data) ? BDT_DATA1 : BDT_DATA0) \ |
71 | | ((count) << 16)) |
72 | |
73 | #define TX 1 |
74 | #define RX 0 |
75 | #define ODD 1 |
76 | #define EVEN 0 |
77 | #define DATA0 0 |
78 | #define DATA1 1 |
79 | #define index(endpoint, tx, odd) (((endpoint) << 2) | ((tx) << 1) | (odd)) |
80 | #define stat2bufferdescriptor(stat) (table + ((stat) >> 2)) |
81 | |
82 | |
83 | static union { |
84 | struct { |
85 | union { |
86 | struct { |
87 | uint8_t bmRequestType; |
88 | uint8_t bRequest; |
89 | }; |
90 | uint16_t wRequestAndType; |
91 | }; |
92 | uint16_t wValue; |
93 | uint16_t wIndex; |
94 | uint16_t wLength; |
95 | }; |
96 | struct { |
97 | uint32_t word1; |
98 | uint32_t word2; |
99 | }; |
100 | } setup; |
101 | |
102 | |
103 | #define GET_STATUS 0 |
104 | #define CLEAR_FEATURE 1 |
105 | #define SET_FEATURE 3 |
106 | #define SET_ADDRESS 5 |
107 | #define GET_DESCRIPTOR 6 |
108 | #define SET_DESCRIPTOR 7 |
109 | #define GET_CONFIGURATION 8 |
110 | #define SET_CONFIGURATION 9 |
111 | #define GET_INTERFACE 10 |
112 | #define SET_INTERFACE 11 |
113 | #define SYNCH_FRAME 12 |
114 | |
115 | // SETUP always uses a DATA0 PID for the data field of the SETUP transaction. |
116 | // transactions in the data phase start with DATA1 and toggle (figure 8-12, USB1.1) |
117 | // Status stage uses a DATA1 PID. |
118 | |
119 | static uint8_t ep0_rx0_buf[EP0_SIZE] __attribute__ ((aligned (4))); |
120 | static uint8_t ep0_rx1_buf[EP0_SIZE] __attribute__ ((aligned (4))); |
121 | static const uint8_t *ep0_tx_ptr = NULL; |
122 | static uint16_t ep0_tx_len; |
123 | static uint8_t ep0_tx_bdt_bank = 0; |
124 | static uint8_t ep0_tx_data_toggle = 0; |
125 | uint8_t usb_rx_memory_needed = 0; |
126 | |
127 | volatile uint8_t usb_configuration = 0; |
128 | volatile uint8_t usb_reboot_timer = 0; |
129 | |
130 | |
131 | static void endpoint0_stall(void) |
132 | { |
133 | USB0_ENDPT0 = USB_ENDPT_EPSTALL | USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK; |
134 | } |
135 | |
136 | |
137 | static void endpoint0_transmit(const void *data, uint32_t len) |
138 | { |
139 | #if 0 |
140 | serial_print("tx0:"); |
141 | serial_phex32((uint32_t)data); |
142 | serial_print(","); |
143 | serial_phex16(len); |
144 | serial_print(ep0_tx_bdt_bank ? ", odd" : ", even"); |
145 | serial_print(ep0_tx_data_toggle ? ", d1\n" : ", d0\n"); |
146 | #endif |
147 | table[index(0, TX, ep0_tx_bdt_bank)].addr = (void *)data; |
148 | table[index(0, TX, ep0_tx_bdt_bank)].desc = BDT_DESC(len, ep0_tx_data_toggle); |
149 | ep0_tx_data_toggle ^= 1; |
150 | ep0_tx_bdt_bank ^= 1; |
151 | } |
152 | |
153 | static uint8_t reply_buffer[8]; |
154 | |
155 | static void usb_setup(void) |
156 | { |
157 | const uint8_t *data = NULL; |
158 | uint32_t datalen = 0; |
159 | const usb_descriptor_list_t *list; |
160 | uint32_t size; |
161 | volatile uint8_t *reg; |
162 | uint8_t epconf; |
163 | const uint8_t *cfg; |
164 | int i; |
165 | |
166 | switch (setup.wRequestAndType) { |
167 | case 0x0500: // SET_ADDRESS |
168 | break; |
169 | case 0x0900: // SET_CONFIGURATION |
170 | //serial_print("configure\n"); |
171 | usb_configuration = setup.wValue; |
172 | reg = &USB0_ENDPT1; |
173 | cfg = usb_endpoint_config_table; |
174 | // clear all BDT entries, free any allocated memory... |
175 | for (i=4; i < (NUM_ENDPOINTS+1)*4; i++) { |
176 | if (table[i].desc & BDT_OWN) { |
177 | usb_free((usb_packet_t *)((uint8_t *)(table[i].addr) - 8)); |
178 | } |
179 | } |
180 | // free all queued packets |
181 | for (i=0; i < NUM_ENDPOINTS; i++) { |
182 | usb_packet_t *p, *n; |
183 | p = rx_first[i]; |
184 | while (p) { |
185 | n = p->next; |
186 | usb_free(p); |
187 | p = n; |
188 | } |
189 | rx_first[i] = NULL; |
190 | rx_last[i] = NULL; |
191 | p = tx_first[i]; |
192 | while (p) { |
193 | n = p->next; |
194 | usb_free(p); |
195 | p = n; |
196 | } |
197 | tx_first[i] = NULL; |
198 | tx_last[i] = NULL; |
199 | usb_rx_byte_count_data[i] = 0; |
200 | switch (tx_state[i]) { |
201 | case TX_STATE_EVEN_FREE: |
202 | case TX_STATE_NONE_FREE_EVEN_FIRST: |
203 | tx_state[i] = TX_STATE_BOTH_FREE_EVEN_FIRST; |
204 | break; |
205 | case TX_STATE_ODD_FREE: |
206 | case TX_STATE_NONE_FREE_ODD_FIRST: |
207 | tx_state[i] = TX_STATE_BOTH_FREE_ODD_FIRST; |
208 | break; |
209 | default: |
210 | break; |
211 | } |
212 | } |
213 | usb_rx_memory_needed = 0; |
214 | for (i=1; i <= NUM_ENDPOINTS; i++) { |
215 | epconf = *cfg++; |
216 | *reg = epconf; |
217 | reg += 4; |
218 | if (epconf & USB_ENDPT_EPRXEN) { |
219 | usb_packet_t *p; |
220 | p = usb_malloc(); |
221 | if (p) { |
222 | table[index(i, RX, EVEN)].addr = p->buf; |
223 | table[index(i, RX, EVEN)].desc = BDT_DESC(64, 0); |
224 | } else { |
225 | table[index(i, RX, EVEN)].desc = 0; |
226 | usb_rx_memory_needed++; |
227 | } |
228 | p = usb_malloc(); |
229 | if (p) { |
230 | table[index(i, RX, ODD)].addr = p->buf; |
231 | table[index(i, RX, ODD)].desc = BDT_DESC(64, 1); |
232 | } else { |
233 | table[index(i, RX, ODD)].desc = 0; |
234 | usb_rx_memory_needed++; |
235 | } |
236 | } |
237 | table[index(i, TX, EVEN)].desc = 0; |
238 | table[index(i, TX, ODD)].desc = 0; |
239 | } |
240 | break; |
241 | case 0x0880: // GET_CONFIGURATION |
242 | reply_buffer[0] = usb_configuration; |
243 | datalen = 1; |
244 | data = reply_buffer; |
245 | break; |
246 | case 0x0080: // GET_STATUS (device) |
247 | reply_buffer[0] = 0; |
248 | reply_buffer[1] = 0; |
249 | datalen = 2; |
250 | data = reply_buffer; |
251 | break; |
252 | case 0x0082: // GET_STATUS (endpoint) |
253 | if (setup.wIndex > NUM_ENDPOINTS) { |
254 | // TODO: do we need to handle IN vs OUT here? |
255 | endpoint0_stall(); |
256 | return; |
257 | } |
258 | reply_buffer[0] = 0; |
259 | reply_buffer[1] = 0; |
260 | if (*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4) & 0x02) reply_buffer[0] = 1; |
261 | data = reply_buffer; |
262 | datalen = 2; |
263 | break; |
264 | case 0x0102: // CLEAR_FEATURE (endpoint) |
265 | i = setup.wIndex & 0x7F; |
266 | if (i > NUM_ENDPOINTS || setup.wValue != 0) { |
267 | // TODO: do we need to handle IN vs OUT here? |
268 | endpoint0_stall(); |
269 | return; |
270 | } |
271 | (*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4)) &= ~0x02; |
272 | // TODO: do we need to clear the data toggle here? |
273 | break; |
274 | case 0x0302: // SET_FEATURE (endpoint) |
275 | i = setup.wIndex & 0x7F; |
276 | if (i > NUM_ENDPOINTS || setup.wValue != 0) { |
277 | // TODO: do we need to handle IN vs OUT here? |
278 | endpoint0_stall(); |
279 | return; |
280 | } |
281 | (*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4)) |= 0x02; |
282 | // TODO: do we need to clear the data toggle here? |
283 | break; |
284 | case 0x0680: // GET_DESCRIPTOR |
285 | case 0x0681: |
286 | //serial_print("desc:"); |
287 | //serial_phex16(setup.wValue); |
288 | //serial_print("\n"); |
289 | for (list = usb_descriptor_list; 1; list++) { |
290 | if (list->addr == NULL) break; |
a773ac06 |
291 | //if (setup.wValue == list->wValue && |
35f00b6c |
292 | //(setup.wIndex == list->wIndex) || ((setup.wValue >> 8) == 3)) { |
293 | if (setup.wValue == list->wValue && setup.wIndex == list->wIndex) { |
294 | data = list->addr; |
295 | if ((setup.wValue >> 8) == 3) { |
296 | // for string descriptors, use the descriptor's |
297 | // length field, allowing runtime configured |
298 | // length. |
299 | datalen = *(list->addr); |
300 | } else { |
301 | datalen = list->length; |
302 | } |
303 | #if 0 |
304 | serial_print("Desc found, "); |
305 | serial_phex32((uint32_t)data); |
306 | serial_print(","); |
307 | serial_phex16(datalen); |
308 | serial_print(","); |
309 | serial_phex(data[0]); |
310 | serial_phex(data[1]); |
311 | serial_phex(data[2]); |
312 | serial_phex(data[3]); |
313 | serial_phex(data[4]); |
314 | serial_phex(data[5]); |
315 | serial_print("\n"); |
316 | #endif |
317 | goto send; |
318 | } |
319 | } |
320 | //serial_print("desc: not found\n"); |
321 | endpoint0_stall(); |
322 | return; |
323 | #if defined(CDC_STATUS_INTERFACE) |
324 | case 0x2221: // CDC_SET_CONTROL_LINE_STATE |
325 | usb_cdc_line_rtsdtr = setup.wValue; |
326 | //serial_print("set control line state\n"); |
327 | break; |
328 | case 0x2321: // CDC_SEND_BREAK |
329 | break; |
330 | case 0x2021: // CDC_SET_LINE_CODING |
331 | //serial_print("set coding, waiting...\n"); |
332 | return; |
333 | #endif |
334 | |
335 | // TODO: this does not work... why? |
336 | #if defined(SEREMU_INTERFACE) || defined(KEYBOARD_INTERFACE) |
337 | case 0x0921: // HID SET_REPORT |
338 | //serial_print(":)\n"); |
339 | return; |
340 | case 0x0A21: // HID SET_IDLE |
341 | break; |
342 | // case 0xC940: |
343 | #endif |
344 | default: |
345 | endpoint0_stall(); |
346 | return; |
347 | } |
348 | send: |
349 | //serial_print("setup send "); |
350 | //serial_phex32(data); |
351 | //serial_print(","); |
352 | //serial_phex16(datalen); |
353 | //serial_print("\n"); |
354 | |
355 | if (datalen > setup.wLength) datalen = setup.wLength; |
356 | size = datalen; |
357 | if (size > EP0_SIZE) size = EP0_SIZE; |
358 | endpoint0_transmit(data, size); |
359 | data += size; |
360 | datalen -= size; |
361 | if (datalen == 0 && size < EP0_SIZE) return; |
362 | |
363 | size = datalen; |
364 | if (size > EP0_SIZE) size = EP0_SIZE; |
365 | endpoint0_transmit(data, size); |
366 | data += size; |
367 | datalen -= size; |
368 | if (datalen == 0 && size < EP0_SIZE) return; |
369 | |
370 | ep0_tx_ptr = data; |
371 | ep0_tx_len = datalen; |
372 | } |
373 | |
374 | |
375 | |
376 | //A bulk endpoint's toggle sequence is initialized to DATA0 when the endpoint |
377 | //experiences any configuration event (configuration events are explained in |
378 | //Sections 9.1.1.5 and 9.4.5). |
379 | |
380 | //Configuring a device or changing an alternate setting causes all of the status |
381 | //and configuration values associated with endpoints in the affected interfaces |
382 | //to be set to their default values. This includes setting the data toggle of |
383 | //any endpoint using data toggles to the value DATA0. |
384 | |
385 | //For endpoints using data toggle, regardless of whether an endpoint has the |
386 | //Halt feature set, a ClearFeature(ENDPOINT_HALT) request always results in the |
387 | //data toggle being reinitialized to DATA0. |
388 | |
389 | |
390 | |
391 | // #define stat2bufferdescriptor(stat) (table + ((stat) >> 2)) |
392 | |
393 | static void usb_control(uint32_t stat) |
394 | { |
395 | bdt_t *b; |
396 | uint32_t pid, size; |
397 | uint8_t *buf; |
398 | const uint8_t *data; |
399 | |
400 | b = stat2bufferdescriptor(stat); |
401 | pid = BDT_PID(b->desc); |
402 | //count = b->desc >> 16; |
403 | buf = b->addr; |
404 | //serial_print("pid:"); |
405 | //serial_phex(pid); |
406 | //serial_print(", count:"); |
407 | //serial_phex(count); |
408 | //serial_print("\n"); |
409 | |
410 | switch (pid) { |
411 | case 0x0D: // Setup received from host |
412 | //serial_print("PID=Setup\n"); |
413 | //if (count != 8) ; // panic? |
414 | // grab the 8 byte setup info |
415 | setup.word1 = *(uint32_t *)(buf); |
416 | setup.word2 = *(uint32_t *)(buf + 4); |
417 | |
418 | // give the buffer back |
419 | b->desc = BDT_DESC(EP0_SIZE, DATA1); |
420 | //table[index(0, RX, EVEN)].desc = BDT_DESC(EP0_SIZE, 1); |
421 | //table[index(0, RX, ODD)].desc = BDT_DESC(EP0_SIZE, 1); |
422 | |
423 | // clear any leftover pending IN transactions |
424 | ep0_tx_ptr = NULL; |
425 | if (ep0_tx_data_toggle) { |
426 | } |
427 | //if (table[index(0, TX, EVEN)].desc & 0x80) { |
428 | //serial_print("leftover tx even\n"); |
429 | //} |
430 | //if (table[index(0, TX, ODD)].desc & 0x80) { |
431 | //serial_print("leftover tx odd\n"); |
432 | //} |
433 | table[index(0, TX, EVEN)].desc = 0; |
434 | table[index(0, TX, ODD)].desc = 0; |
435 | // first IN after Setup is always DATA1 |
436 | ep0_tx_data_toggle = 1; |
437 | |
438 | #if 0 |
439 | serial_print("bmRequestType:"); |
440 | serial_phex(setup.bmRequestType); |
441 | serial_print(", bRequest:"); |
442 | serial_phex(setup.bRequest); |
443 | serial_print(", wValue:"); |
444 | serial_phex16(setup.wValue); |
445 | serial_print(", wIndex:"); |
446 | serial_phex16(setup.wIndex); |
447 | serial_print(", len:"); |
448 | serial_phex16(setup.wLength); |
449 | serial_print("\n"); |
450 | #endif |
451 | // actually "do" the setup request |
452 | usb_setup(); |
453 | // unfreeze the USB, now that we're ready |
454 | USB0_CTL = USB_CTL_USBENSOFEN; // clear TXSUSPENDTOKENBUSY bit |
455 | break; |
456 | case 0x01: // OUT transaction received from host |
457 | case 0x02: |
458 | //serial_print("PID=OUT\n"); |
459 | #ifdef CDC_STATUS_INTERFACE |
460 | if (setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/) { |
461 | int i; |
462 | uint8_t *dst = (uint8_t *)usb_cdc_line_coding; |
463 | //serial_print("set line coding "); |
464 | for (i=0; i<7; i++) { |
465 | //serial_phex(*buf); |
466 | *dst++ = *buf++; |
467 | } |
468 | //serial_phex32(usb_cdc_line_coding[0]); |
469 | //serial_print("\n"); |
470 | if (usb_cdc_line_coding[0] == 134) usb_reboot_timer = 15; |
471 | endpoint0_transmit(NULL, 0); |
472 | } |
473 | #endif |
474 | #ifdef KEYBOARD_INTERFACE |
475 | if (setup.word1 == 0x02000921 && setup.word2 == ((1<<16)|KEYBOARD_INTERFACE)) { |
476 | keyboard_leds = buf[0]; |
477 | endpoint0_transmit(NULL, 0); |
478 | } |
479 | #endif |
480 | #ifdef SEREMU_INTERFACE |
481 | if (setup.word1 == 0x03000921 && setup.word2 == ((4<<16)|SEREMU_INTERFACE) |
482 | && buf[0] == 0xA9 && buf[1] == 0x45 && buf[2] == 0xC2 && buf[3] == 0x6B) { |
483 | usb_reboot_timer = 5; |
484 | endpoint0_transmit(NULL, 0); |
485 | } |
486 | #endif |
487 | // give the buffer back |
488 | b->desc = BDT_DESC(EP0_SIZE, DATA1); |
489 | break; |
490 | |
491 | case 0x09: // IN transaction completed to host |
492 | //serial_print("PID=IN:"); |
493 | //serial_phex(stat); |
494 | //serial_print("\n"); |
495 | |
496 | // send remaining data, if any... |
497 | data = ep0_tx_ptr; |
498 | if (data) { |
499 | size = ep0_tx_len; |
500 | if (size > EP0_SIZE) size = EP0_SIZE; |
501 | endpoint0_transmit(data, size); |
502 | data += size; |
503 | ep0_tx_len -= size; |
504 | ep0_tx_ptr = (ep0_tx_len > 0 || size == EP0_SIZE) ? data : NULL; |
505 | } |
506 | |
507 | if (setup.bRequest == 5 && setup.bmRequestType == 0) { |
508 | setup.bRequest = 0; |
509 | //serial_print("set address: "); |
510 | //serial_phex16(setup.wValue); |
511 | //serial_print("\n"); |
512 | USB0_ADDR = setup.wValue; |
513 | } |
514 | |
515 | break; |
516 | //default: |
517 | //serial_print("PID=unknown:"); |
518 | //serial_phex(pid); |
519 | //serial_print("\n"); |
520 | } |
521 | USB0_CTL = USB_CTL_USBENSOFEN; // clear TXSUSPENDTOKENBUSY bit |
522 | } |
523 | |
524 | |
525 | |
526 | |
527 | |
528 | |
529 | usb_packet_t *usb_rx(uint32_t endpoint) |
530 | { |
531 | usb_packet_t *ret; |
532 | endpoint--; |
533 | if (endpoint >= NUM_ENDPOINTS) return NULL; |
1ad7d1dd |
534 | __mask_irq(); |
35f00b6c |
535 | ret = rx_first[endpoint]; |
536 | if (ret) { |
537 | rx_first[endpoint] = ret->next; |
538 | usb_rx_byte_count_data[endpoint] -= ret->len; |
539 | } |
1ad7d1dd |
540 | __unmask_irq(); |
35f00b6c |
541 | //serial_print("rx, epidx="); |
542 | //serial_phex(endpoint); |
543 | //serial_print(", packet="); |
544 | //serial_phex32(ret); |
545 | //serial_print("\n"); |
546 | return ret; |
547 | } |
548 | |
549 | static uint32_t usb_queue_byte_count(const usb_packet_t *p) |
550 | { |
551 | uint32_t count=0; |
552 | |
1ad7d1dd |
553 | __mask_irq(); |
35f00b6c |
554 | for ( ; p; p = p->next) { |
555 | count += p->len; |
556 | } |
1ad7d1dd |
557 | __unmask_irq(); |
35f00b6c |
558 | return count; |
559 | } |
560 | |
561 | // TODO: make this an inline function... |
562 | /* |
563 | uint32_t usb_rx_byte_count(uint32_t endpoint) |
564 | { |
565 | endpoint--; |
566 | if (endpoint >= NUM_ENDPOINTS) return 0; |
567 | return usb_rx_byte_count_data[endpoint]; |
568 | //return usb_queue_byte_count(rx_first[endpoint]); |
569 | } |
570 | */ |
571 | |
572 | uint32_t usb_tx_byte_count(uint32_t endpoint) |
573 | { |
574 | endpoint--; |
575 | if (endpoint >= NUM_ENDPOINTS) return 0; |
576 | return usb_queue_byte_count(tx_first[endpoint]); |
577 | } |
578 | |
579 | uint32_t usb_tx_packet_count(uint32_t endpoint) |
580 | { |
581 | const usb_packet_t *p; |
582 | uint32_t count=0; |
583 | |
584 | endpoint--; |
585 | if (endpoint >= NUM_ENDPOINTS) return 0; |
1ad7d1dd |
586 | __mask_irq(); |
35f00b6c |
587 | for (p = tx_first[endpoint]; p; p = p->next) count++; |
1ad7d1dd |
588 | __unmask_irq(); |
35f00b6c |
589 | return count; |
590 | } |
591 | |
592 | |
593 | // Called from usb_free, but only when usb_rx_memory_needed > 0, indicating |
594 | // receive endpoints are starving for memory. The intention is to give |
595 | // endpoints needing receive memory priority over the user's code, which is |
596 | // likely calling usb_malloc to obtain memory for transmitting. When the |
597 | // user is creating data very quickly, their consumption could starve reception |
598 | // without this prioritization. The packet buffer (input) is assigned to the |
599 | // first endpoint needing memory. |
600 | // |
601 | void usb_rx_memory(usb_packet_t *packet) |
602 | { |
603 | unsigned int i; |
604 | const uint8_t *cfg; |
605 | |
606 | cfg = usb_endpoint_config_table; |
607 | //serial_print("rx_mem:"); |
1ad7d1dd |
608 | __mask_irq(); |
35f00b6c |
609 | for (i=1; i <= NUM_ENDPOINTS; i++) { |
610 | if (*cfg++ & USB_ENDPT_EPRXEN) { |
611 | if (table[index(i, RX, EVEN)].desc == 0) { |
612 | table[index(i, RX, EVEN)].addr = packet->buf; |
613 | table[index(i, RX, EVEN)].desc = BDT_DESC(64, 0); |
614 | usb_rx_memory_needed--; |
1ad7d1dd |
615 | __unmask_irq(); |
35f00b6c |
616 | //serial_phex(i); |
617 | //serial_print(",even\n"); |
618 | return; |
619 | } |
620 | if (table[index(i, RX, ODD)].desc == 0) { |
621 | table[index(i, RX, ODD)].addr = packet->buf; |
622 | table[index(i, RX, ODD)].desc = BDT_DESC(64, 1); |
623 | usb_rx_memory_needed--; |
1ad7d1dd |
624 | __unmask_irq(); |
35f00b6c |
625 | //serial_phex(i); |
626 | //serial_print(",odd\n"); |
627 | return; |
628 | } |
629 | } |
630 | } |
1ad7d1dd |
631 | __unmask_irq(); |
35f00b6c |
632 | // we should never reach this point. If we get here, it means |
633 | // usb_rx_memory_needed was set greater than zero, but no memory |
a773ac06 |
634 | // was actually needed. |
35f00b6c |
635 | usb_rx_memory_needed = 0; |
636 | usb_free(packet); |
637 | return; |
638 | } |
639 | |
640 | //#define index(endpoint, tx, odd) (((endpoint) << 2) | ((tx) << 1) | (odd)) |
641 | //#define stat2bufferdescriptor(stat) (table + ((stat) >> 2)) |
642 | |
643 | void usb_tx(uint32_t endpoint, usb_packet_t *packet) |
644 | { |
645 | bdt_t *b = &table[index(endpoint, TX, EVEN)]; |
646 | uint8_t next; |
647 | |
648 | endpoint--; |
649 | if (endpoint >= NUM_ENDPOINTS) return; |
1ad7d1dd |
650 | __mask_irq(); |
35f00b6c |
651 | //serial_print("txstate="); |
652 | //serial_phex(tx_state[endpoint]); |
653 | //serial_print("\n"); |
654 | switch (tx_state[endpoint]) { |
655 | case TX_STATE_BOTH_FREE_EVEN_FIRST: |
656 | next = TX_STATE_ODD_FREE; |
657 | break; |
658 | case TX_STATE_BOTH_FREE_ODD_FIRST: |
659 | b++; |
660 | next = TX_STATE_EVEN_FREE; |
661 | break; |
662 | case TX_STATE_EVEN_FREE: |
663 | next = TX_STATE_NONE_FREE_ODD_FIRST; |
664 | break; |
665 | case TX_STATE_ODD_FREE: |
666 | b++; |
667 | next = TX_STATE_NONE_FREE_EVEN_FIRST; |
668 | break; |
669 | default: |
670 | if (tx_first[endpoint] == NULL) { |
671 | tx_first[endpoint] = packet; |
672 | } else { |
673 | tx_last[endpoint]->next = packet; |
674 | } |
675 | tx_last[endpoint] = packet; |
1ad7d1dd |
676 | __unmask_irq(); |
35f00b6c |
677 | return; |
678 | } |
679 | tx_state[endpoint] = next; |
680 | b->addr = packet->buf; |
681 | b->desc = BDT_DESC(packet->len, ((uint32_t)b & 8) ? DATA1 : DATA0); |
1ad7d1dd |
682 | __unmask_irq(); |
35f00b6c |
683 | } |
684 | |
685 | |
686 | |
687 | |
688 | |
689 | |
690 | void _reboot_Teensyduino_(void) |
691 | { |
692 | // TODO: initialize R0 with a code.... |
a773ac06 |
693 | __asm__ volatile("bkpt"); |
35f00b6c |
694 | } |
695 | |
696 | |
697 | |
698 | void usb_isr(void) |
699 | { |
700 | uint8_t status, stat, t; |
701 | |
702 | //serial_print("isr"); |
703 | //status = USB0_ISTAT; |
704 | //serial_phex(status); |
705 | //serial_print("\n"); |
706 | restart: |
707 | status = USB0_ISTAT; |
708 | |
709 | if ((status & USB_INTEN_SOFTOKEN /* 04 */ )) { |
710 | if (usb_configuration) { |
711 | t = usb_reboot_timer; |
712 | if (t) { |
713 | usb_reboot_timer = --t; |
714 | if (!t) _reboot_Teensyduino_(); |
715 | } |
716 | #ifdef CDC_DATA_INTERFACE |
717 | t = usb_cdc_transmit_flush_timer; |
718 | if (t) { |
719 | usb_cdc_transmit_flush_timer = --t; |
720 | if (t == 0) usb_serial_flush_callback(); |
721 | } |
722 | #endif |
723 | #ifdef SEREMU_INTERFACE |
724 | t = usb_seremu_transmit_flush_timer; |
725 | if (t) { |
726 | usb_seremu_transmit_flush_timer = --t; |
727 | if (t == 0) usb_seremu_flush_callback(); |
728 | } |
729 | #endif |
730 | #ifdef MIDI_INTERFACE |
731 | usb_midi_flush_output(); |
732 | #endif |
733 | #ifdef FLIGHTSIM_INTERFACE |
734 | usb_flightsim_flush_callback(); |
735 | #endif |
736 | } |
737 | USB0_ISTAT = USB_INTEN_SOFTOKEN; |
738 | } |
739 | |
740 | if ((status & USB_ISTAT_TOKDNE /* 08 */ )) { |
741 | uint8_t endpoint; |
742 | stat = USB0_STAT; |
743 | //serial_print("token: ep="); |
744 | //serial_phex(stat >> 4); |
745 | //serial_print(stat & 0x08 ? ",tx" : ",rx"); |
746 | //serial_print(stat & 0x04 ? ",odd\n" : ",even\n"); |
747 | endpoint = stat >> 4; |
748 | if (endpoint == 0) { |
749 | usb_control(stat); |
750 | } else { |
751 | bdt_t *b = stat2bufferdescriptor(stat); |
752 | usb_packet_t *packet = (usb_packet_t *)((uint8_t *)(b->addr) - 8); |
753 | #if 0 |
754 | serial_print("ep:"); |
755 | serial_phex(endpoint); |
756 | serial_print(", pid:"); |
757 | serial_phex(BDT_PID(b->desc)); |
758 | serial_print(((uint32_t)b & 8) ? ", odd" : ", even"); |
759 | serial_print(", count:"); |
760 | serial_phex(b->desc >> 16); |
761 | serial_print("\n"); |
762 | #endif |
763 | endpoint--; // endpoint is index to zero-based arrays |
764 | |
765 | if (stat & 0x08) { // transmit |
766 | usb_free(packet); |
767 | packet = tx_first[endpoint]; |
768 | if (packet) { |
769 | //serial_print("tx packet\n"); |
770 | tx_first[endpoint] = packet->next; |
771 | b->addr = packet->buf; |
772 | switch (tx_state[endpoint]) { |
773 | case TX_STATE_BOTH_FREE_EVEN_FIRST: |
774 | tx_state[endpoint] = TX_STATE_ODD_FREE; |
775 | break; |
776 | case TX_STATE_BOTH_FREE_ODD_FIRST: |
777 | tx_state[endpoint] = TX_STATE_EVEN_FREE; |
778 | break; |
779 | case TX_STATE_EVEN_FREE: |
780 | tx_state[endpoint] = TX_STATE_NONE_FREE_ODD_FIRST; |
781 | break; |
782 | case TX_STATE_ODD_FREE: |
783 | tx_state[endpoint] = TX_STATE_NONE_FREE_EVEN_FIRST; |
784 | break; |
785 | default: |
786 | break; |
787 | } |
788 | b->desc = BDT_DESC(packet->len, ((uint32_t)b & 8) ? DATA1 : DATA0); |
789 | } else { |
790 | //serial_print("tx no packet\n"); |
791 | switch (tx_state[endpoint]) { |
792 | case TX_STATE_BOTH_FREE_EVEN_FIRST: |
793 | case TX_STATE_BOTH_FREE_ODD_FIRST: |
794 | break; |
795 | case TX_STATE_EVEN_FREE: |
796 | tx_state[endpoint] = TX_STATE_BOTH_FREE_EVEN_FIRST; |
797 | break; |
798 | case TX_STATE_ODD_FREE: |
799 | tx_state[endpoint] = TX_STATE_BOTH_FREE_ODD_FIRST; |
800 | break; |
801 | default: |
802 | tx_state[endpoint] = ((uint32_t)b & 8) ? |
803 | TX_STATE_ODD_FREE : TX_STATE_EVEN_FREE; |
804 | break; |
805 | } |
806 | } |
807 | } else { // receive |
808 | packet->len = b->desc >> 16; |
809 | if (packet->len > 0) { |
810 | packet->index = 0; |
811 | packet->next = NULL; |
812 | if (rx_first[endpoint] == NULL) { |
813 | //serial_print("rx 1st, epidx="); |
814 | //serial_phex(endpoint); |
815 | //serial_print(", packet="); |
816 | //serial_phex32((uint32_t)packet); |
817 | //serial_print("\n"); |
818 | rx_first[endpoint] = packet; |
819 | } else { |
820 | //serial_print("rx Nth, epidx="); |
821 | //serial_phex(endpoint); |
822 | //serial_print(", packet="); |
823 | //serial_phex32((uint32_t)packet); |
824 | //serial_print("\n"); |
825 | rx_last[endpoint]->next = packet; |
826 | } |
827 | rx_last[endpoint] = packet; |
828 | usb_rx_byte_count_data[endpoint] += packet->len; |
829 | // TODO: implement a per-endpoint maximum # of allocated packets |
830 | // so a flood of incoming data on 1 endpoint doesn't starve |
831 | // the others if the user isn't reading it regularly |
832 | packet = usb_malloc(); |
833 | if (packet) { |
834 | b->addr = packet->buf; |
835 | b->desc = BDT_DESC(64, ((uint32_t)b & 8) ? DATA1 : DATA0); |
836 | } else { |
837 | //serial_print("starving "); |
838 | //serial_phex(endpoint + 1); |
839 | //serial_print(((uint32_t)b & 8) ? ",odd\n" : ",even\n"); |
840 | b->desc = 0; |
841 | usb_rx_memory_needed++; |
842 | } |
843 | } else { |
844 | b->desc = BDT_DESC(64, ((uint32_t)b & 8) ? DATA1 : DATA0); |
845 | } |
846 | } |
847 | |
848 | |
849 | |
850 | |
851 | } |
852 | USB0_ISTAT = USB_ISTAT_TOKDNE; |
853 | goto restart; |
854 | } |
855 | |
856 | |
857 | |
858 | if (status & USB_ISTAT_USBRST /* 01 */ ) { |
859 | //serial_print("reset\n"); |
860 | |
861 | // initialize BDT toggle bits |
862 | USB0_CTL = USB_CTL_ODDRST; |
863 | ep0_tx_bdt_bank = 0; |
864 | |
865 | // set up buffers to receive Setup and OUT packets |
866 | table[index(0, RX, EVEN)].desc = BDT_DESC(EP0_SIZE, 0); |
867 | table[index(0, RX, EVEN)].addr = ep0_rx0_buf; |
868 | table[index(0, RX, ODD)].desc = BDT_DESC(EP0_SIZE, 0); |
869 | table[index(0, RX, ODD)].addr = ep0_rx1_buf; |
870 | table[index(0, TX, EVEN)].desc = 0; |
871 | table[index(0, TX, ODD)].desc = 0; |
a773ac06 |
872 | |
35f00b6c |
873 | // activate endpoint 0 |
874 | USB0_ENDPT0 = USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK; |
875 | |
876 | // clear all ending interrupts |
877 | USB0_ERRSTAT = 0xFF; |
878 | USB0_ISTAT = 0xFF; |
879 | |
880 | // set the address to zero during enumeration |
881 | USB0_ADDR = 0; |
882 | |
883 | // enable other interrupts |
884 | USB0_ERREN = 0xFF; |
885 | USB0_INTEN = USB_INTEN_TOKDNEEN | |
886 | USB_INTEN_SOFTOKEN | |
887 | USB_INTEN_STALLEN | |
888 | USB_INTEN_ERROREN | |
889 | USB_INTEN_USBRSTEN | |
890 | USB_INTEN_SLEEPEN; |
891 | |
892 | // is this necessary? |
893 | USB0_CTL = USB_CTL_USBENSOFEN; |
894 | return; |
895 | } |
896 | |
897 | |
898 | if ((status & USB_ISTAT_STALL /* 80 */ )) { |
899 | //serial_print("stall:\n"); |
900 | USB0_ENDPT0 = USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK; |
901 | USB0_ISTAT = USB_ISTAT_STALL; |
902 | } |
903 | if ((status & USB_ISTAT_ERROR /* 02 */ )) { |
904 | uint8_t err = USB0_ERRSTAT; |
905 | USB0_ERRSTAT = err; |
906 | //serial_print("err:"); |
907 | //serial_phex(err); |
908 | //serial_print("\n"); |
909 | USB0_ISTAT = USB_ISTAT_ERROR; |
910 | } |
911 | |
912 | if ((status & USB_ISTAT_SLEEP /* 10 */ )) { |
913 | //serial_print("sleep\n"); |
914 | USB0_ISTAT = USB_ISTAT_SLEEP; |
915 | } |
916 | |
917 | } |
918 | |
919 | |
920 | |
921 | void usb_init(void) |
922 | { |
923 | int i; |
924 | |
925 | //serial_begin(BAUD2DIV(115200)); |
926 | //serial_print("usb_init\n"); |
927 | |
928 | usb_init_serialnumber(); |
929 | |
930 | for (i=0; i <= NUM_ENDPOINTS*4; i++) { |
931 | table[i].desc = 0; |
932 | table[i].addr = 0; |
933 | } |
934 | |
935 | // this basically follows the flowchart in the Kinetis |
936 | // Quick Reference User Guide, Rev. 1, 03/2012, page 141 |
937 | |
938 | // assume 48 MHz clock already running |
939 | // SIM - enable clock |
940 | SIM_SCGC4 |= SIM_SCGC4_USBOTG; |
941 | |
942 | // reset USB module |
943 | USB0_USBTRC0 = USB_USBTRC_USBRESET; |
944 | while ((USB0_USBTRC0 & USB_USBTRC_USBRESET) != 0) ; // wait for reset to end |
945 | |
946 | // set desc table base addr |
947 | USB0_BDTPAGE1 = ((uint32_t)table) >> 8; |
948 | USB0_BDTPAGE2 = ((uint32_t)table) >> 16; |
949 | USB0_BDTPAGE3 = ((uint32_t)table) >> 24; |
950 | |
951 | // clear all ISR flags |
952 | USB0_ISTAT = 0xFF; |
953 | USB0_ERRSTAT = 0xFF; |
954 | USB0_OTGISTAT = 0xFF; |
955 | |
956 | USB0_USBTRC0 |= 0x40; // undocumented bit |
957 | |
958 | // enable USB |
959 | USB0_CTL = USB_CTL_USBENSOFEN; |
960 | USB0_USBCTRL = 0; |
961 | |
962 | // enable reset interrupt |
963 | USB0_INTEN = USB_INTEN_USBRSTEN; |
964 | |
965 | // enable interrupt in NVIC... |
966 | NVIC_SET_PRIORITY(IRQ_USBOTG, 112); |
967 | NVIC_ENABLE_IRQ(IRQ_USBOTG); |
968 | |
969 | // enable d+ pullup |
970 | USB0_CONTROL = USB_CONTROL_DPPULLUPNONOTG; |
971 | } |
972 | |
973 | |
a773ac06 |
974 | #else // F_CPU < 20 MHz && defined(NUM_ENDPOINTS) |
975 | |
976 | void usb_init(void) |
977 | { |
978 | } |
35f00b6c |
979 | |
a773ac06 |
980 | #endif // F_CPU >= 20 MHz && defined(NUM_ENDPOINTS) |