8805e45736953ee2cca1a28309b38133705aad07
[fx2fw-sdcc] / fx2 / usb_common.c
1 /* -*- c++ -*- */\r
2 \r
3 /*-----------------------------------------------------------------------------\r
4 \r
5  * Common USB code for FX2\r
6 \r
7  *-----------------------------------------------------------------------------\r
8 \r
9  * Code taken from USRP2 firmware (GNU Radio Project), version 3.0.2,\r
10 \r
11  * Copyright 2003 Free Software Foundation, Inc.\r
12 \r
13  *-----------------------------------------------------------------------------\r
14 \r
15  * This code is part of usbjtag. usbjtag is free software; you can redistribute\r
16 \r
17  * it and/or modify it under the terms of the GNU General Public License as\r
18 \r
19  * published by the Free Software Foundation; either version 2 of the License,\r
20 \r
21  * or (at your option) any later version. usbjtag is distributed in the hope\r
22 \r
23  * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied\r
24 \r
25  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
26 \r
27  * GNU General Public License for more details.  You should have received a\r
28 \r
29  * copy of the GNU General Public License along with this program in the file\r
30 \r
31  * COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin\r
32 \r
33  * St, Fifth Floor, Boston, MA  02110-1301  USA\r
34 \r
35  *-----------------------------------------------------------------------------\r
36 \r
37  */\r
38 \r
39 \r
40 \r
41 #include "usb_common.h"\r
42 \r
43 #include "fx2regs.h"\r
44 \r
45 #include "syncdelay.h"\r
46 \r
47 #include "fx2utils.h"\r
48 \r
49 #include "isr.h"\r
50 \r
51 #include "usb_descriptors.h"\r
52 \r
53 #include "usb_requests.h"\r
54 \r
55 \r
56 \r
57 extern xdata char str0[];\r
58 \r
59 extern xdata char str1[];\r
60 \r
61 extern xdata char str2[];\r
62 \r
63 extern xdata char str3[];\r
64 \r
65 extern xdata char str4[];\r
66 \r
67 extern xdata char str5[];\r
68 \r
69 \r
70 \r
71 volatile bit _usb_got_SUDAV;\r
72 \r
73 \r
74 \r
75 unsigned char   _usb_config = 0;\r
76 \r
77 unsigned char   _usb_alt_setting = 0;   // FIXME really 1/interface\r
78 \r
79 \r
80 \r
81 xdata unsigned char *current_device_descr;\r
82 \r
83 xdata unsigned char *current_devqual_descr;\r
84 \r
85 xdata unsigned char *current_config_descr;\r
86 \r
87 xdata unsigned char *other_config_descr;\r
88 \r
89 \r
90 \r
91 static void\r
92 \r
93 setup_descriptors (void)\r
94 \r
95 {\r
96 \r
97   if (USBCS & bmHSM){           // high speed mode\r
98 \r
99     current_device_descr  = high_speed_device_descr;\r
100 \r
101     current_devqual_descr = high_speed_devqual_descr;\r
102 \r
103     current_config_descr  = high_speed_config_descr;\r
104 \r
105     other_config_descr    = full_speed_config_descr;\r
106 \r
107         EP8AUTOINLENH = 0x02; SYNCDELAY;                                // Size in bytes of the IN data automatically commited (512 bytes here)\r
108 \r
109         EP8AUTOINLENL = 0x00; SYNCDELAY;                                // Can use signal PKTEND if you want to commit a shorter packet\r
110 \r
111   }\r
112 \r
113   else {\r
114 \r
115     current_device_descr  = full_speed_device_descr;\r
116 \r
117     current_devqual_descr = full_speed_devqual_descr;\r
118 \r
119     current_config_descr  = full_speed_config_descr;\r
120 \r
121     other_config_descr    = high_speed_config_descr;\r
122 \r
123         EP8AUTOINLENH = 0x00; SYNCDELAY;                                // Size in bytes of the IN data automatically commited (64 bytes here)\r
124 \r
125         EP8AUTOINLENL = 0x40; SYNCDELAY;                                // Can use signal PKTEND if you want to commit a shorter packet\r
126 \r
127   }\r
128 \r
129 \r
130 \r
131   // whack the type fields\r
132 \r
133   // FIXME, may not be required.\r
134 \r
135   // current_config_descr[1] = DT_CONFIG;\r
136 \r
137   // other_config_descr[1]   = DT_OTHER_SPEED;\r
138 \r
139 }\r
140 \r
141 \r
142 \r
143 static void\r
144 \r
145 isr_SUDAV (void) interrupt\r
146 \r
147 {\r
148 \r
149   clear_usb_irq ();\r
150 \r
151   _usb_got_SUDAV = 1;\r
152 \r
153 }\r
154 \r
155 \r
156 \r
157 static void\r
158 \r
159 isr_USBRESET (void) interrupt\r
160 \r
161 {\r
162 \r
163   clear_usb_irq ();\r
164 \r
165   setup_descriptors ();\r
166 \r
167 }\r
168 \r
169 \r
170 \r
171 static void\r
172 \r
173 isr_HIGHSPEED (void) interrupt\r
174 \r
175 {\r
176 \r
177   clear_usb_irq ();\r
178 \r
179   setup_descriptors ();\r
180 \r
181 }\r
182 \r
183 \r
184 \r
185 void\r
186 \r
187 usb_install_handlers (void)\r
188 \r
189 {\r
190 \r
191   setup_descriptors ();     // ensure that they're set before use\r
192 \r
193 \r
194 \r
195   hook_uv (UV_SUDAV,     (unsigned short) isr_SUDAV);\r
196 \r
197   hook_uv (UV_USBRESET,  (unsigned short) isr_USBRESET);\r
198 \r
199   hook_uv (UV_HIGHSPEED, (unsigned short) isr_HIGHSPEED);\r
200 \r
201 \r
202 \r
203   USBIE = bmSUDAV | bmURES | bmHSGRANT;\r
204 \r
205 }\r
206 \r
207 \r
208 \r
209 // On the FX2 the only plausible endpoints are 0, 1, 2, 4, 6, 8\r
210 \r
211 // This doesn't check to see that they're enabled\r
212 \r
213 \r
214 \r
215 unsigned char\r
216 \r
217 plausible_endpoint (unsigned char ep)\r
218 \r
219 {\r
220 \r
221   ep &= ~0x80;  // ignore direction bit\r
222 \r
223 \r
224 \r
225   if (ep > 8)\r
226 \r
227     return 0;\r
228 \r
229 \r
230 \r
231   if (ep == 1)\r
232 \r
233     return 1;\r
234 \r
235 \r
236 \r
237   return (ep & 0x1) == 0;       // must be even\r
238 \r
239 }\r
240 \r
241 \r
242 \r
243 // return pointer to control and status register for endpoint.\r
244 \r
245 // only called with plausible_endpoints\r
246 \r
247 \r
248 \r
249 xdata volatile unsigned char *\r
250 \r
251 epcs (unsigned char ep)\r
252 \r
253 {\r
254 \r
255   if (ep == 0x01)               // ep1 has different in and out CS regs\r
256 \r
257     return EP1OUTCS;\r
258 \r
259 \r
260 \r
261   if (ep == 0x81)\r
262 \r
263     return EP1INCS;\r
264 \r
265 \r
266 \r
267   ep &= ~0x80;                  // ignore direction bit\r
268 \r
269 \r
270 \r
271   if (ep == 0x00)               // ep0\r
272 \r
273     return EP0CS;\r
274 \r
275 \r
276 \r
277   return EP2CS + (ep >> 1);     // 2, 4, 6, 8 are consecutive\r
278 \r
279 }\r
280 \r
281 \r
282 \r
283 void\r
284 \r
285 usb_handle_setup_packet (void)\r
286 \r
287 {\r
288 \r
289   _usb_got_SUDAV = 0;\r
290 \r
291 \r
292 \r
293   // handle the standard requests...\r
294 \r
295 \r
296 \r
297   switch (bRequestType & bmRT_TYPE_MASK){\r
298 \r
299 \r
300 \r
301   case bmRT_TYPE_CLASS:\r
302 \r
303   case bmRT_TYPE_RESERVED:\r
304 \r
305     fx2_stall_ep0 ();           // we don't handle these.  indicate error\r
306 \r
307     break;\r
308 \r
309     \r
310 \r
311   case bmRT_TYPE_VENDOR:\r
312 \r
313     // call the application code.\r
314 \r
315     // If it handles the command it returns non-zero\r
316 \r
317 \r
318 \r
319     if (!app_vendor_cmd ())     \r
320 \r
321       fx2_stall_ep0 ();\r
322 \r
323     break;\r
324 \r
325 \r
326 \r
327   case bmRT_TYPE_STD:\r
328 \r
329     // these are the standard requests...\r
330 \r
331 \r
332 \r
333     if ((bRequestType & bmRT_DIR_MASK) == bmRT_DIR_IN){\r
334 \r
335 \r
336 \r
337       ////////////////////////////////////\r
338 \r
339       //    handle the IN requests\r
340 \r
341       ////////////////////////////////////\r
342 \r
343 \r
344 \r
345       switch (bRequest){\r
346 \r
347 \r
348 \r
349       case RQ_GET_CONFIG:\r
350 \r
351         EP0BUF[0] = _usb_config;        // FIXME app should handle\r
352 \r
353         EP0BCH = 0;\r
354 \r
355         EP0BCL = 1;\r
356 \r
357         break;\r
358 \r
359         \r
360 \r
361       // --------------------------------\r
362 \r
363 \r
364 \r
365       case RQ_GET_INTERFACE:\r
366 \r
367         EP0BUF[0] = _usb_alt_setting;   // FIXME app should handle\r
368 \r
369         EP0BCH = 0;\r
370 \r
371         EP0BCL = 1;\r
372 \r
373         break;\r
374 \r
375 \r
376 \r
377       // --------------------------------\r
378 \r
379 \r
380 \r
381       case RQ_GET_DESCR:\r
382 \r
383         switch (wValueH){\r
384 \r
385 \r
386 \r
387         case DT_DEVICE:\r
388 \r
389           SUDPTRH = MSB (current_device_descr);\r
390 \r
391           SUDPTRL = LSB (current_device_descr);\r
392 \r
393           break;\r
394 \r
395           \r
396 \r
397         case DT_DEVQUAL:\r
398 \r
399           SUDPTRH = MSB (current_devqual_descr);\r
400 \r
401           SUDPTRL = LSB (current_devqual_descr);\r
402 \r
403           break;\r
404 \r
405 \r
406 \r
407         case DT_CONFIG:\r
408 \r
409           if (0 && wValueL != 1)        // FIXME only a single configuration\r
410 \r
411             fx2_stall_ep0 ();\r
412 \r
413           else {\r
414 \r
415             SUDPTRH = MSB (current_config_descr);\r
416 \r
417             SUDPTRL = LSB (current_config_descr);\r
418 \r
419           }\r
420 \r
421           break;\r
422 \r
423 \r
424 \r
425         case DT_OTHER_SPEED:\r
426 \r
427           if (0 && wValueL != 1)        // FIXME only a single configuration\r
428 \r
429             fx2_stall_ep0 ();\r
430 \r
431           else {\r
432 \r
433             SUDPTRH = MSB (other_config_descr);\r
434 \r
435             SUDPTRL = LSB (other_config_descr);\r
436 \r
437           }\r
438 \r
439           break;\r
440 \r
441 \r
442 \r
443         case DT_STRING:\r
444 \r
445           if (wValueL >= nstring_descriptors)\r
446 \r
447             fx2_stall_ep0 ();\r
448 \r
449           else {\r
450 \r
451             xdata char *p = string_descriptors[wValueL];\r
452 \r
453             SUDPTRH = MSB (p);\r
454 \r
455             SUDPTRL = LSB (p);\r
456 \r
457           }\r
458 \r
459           break;\r
460 \r
461 \r
462 \r
463         default:\r
464 \r
465           fx2_stall_ep0 ();     // invalid request\r
466 \r
467           break;\r
468 \r
469         }\r
470 \r
471         break;\r
472 \r
473         \r
474 \r
475       // --------------------------------\r
476 \r
477 \r
478 \r
479       case RQ_GET_STATUS:\r
480 \r
481         switch (bRequestType & bmRT_RECIP_MASK){\r
482 \r
483         case bmRT_RECIP_DEVICE:\r
484 \r
485           EP0BUF[0] = 0;\r
486 \r
487           EP0BUF[1] = 0;\r
488 \r
489           EP0BCH = 0;\r
490 \r
491           EP0BCL = 2;\r
492 \r
493           break;\r
494 \r
495 \r
496 \r
497         case bmRT_RECIP_INTERFACE:\r
498 \r
499           EP0BUF[0] = 0;\r
500 \r
501           EP0BUF[1] = 0;\r
502 \r
503           EP0BCH = 0;\r
504 \r
505           EP0BCL = 2;\r
506 \r
507           break;\r
508 \r
509 \r
510 \r
511         case bmRT_RECIP_ENDPOINT:\r
512 \r
513           if (plausible_endpoint (wIndexL)){\r
514 \r
515             EP0BUF[0] = *epcs (wIndexL) & bmEPSTALL;\r
516 \r
517             EP0BUF[1] = 0;\r
518 \r
519             EP0BCH = 0;\r
520 \r
521             EP0BCL = 2;\r
522 \r
523           }\r
524 \r
525           else\r
526 \r
527             fx2_stall_ep0 ();\r
528 \r
529           break;\r
530 \r
531 \r
532 \r
533         default:\r
534 \r
535           fx2_stall_ep0 ();\r
536 \r
537           break;\r
538 \r
539         }\r
540 \r
541         break;\r
542 \r
543 \r
544 \r
545       // --------------------------------\r
546 \r
547 \r
548 \r
549       case RQ_SYNCH_FRAME:      // not implemented\r
550 \r
551       default:\r
552 \r
553         fx2_stall_ep0 ();\r
554 \r
555         break;\r
556 \r
557       }\r
558 \r
559     }\r
560 \r
561 \r
562 \r
563     else {\r
564 \r
565 \r
566 \r
567       ////////////////////////////////////\r
568 \r
569       //    handle the OUT requests\r
570 \r
571       ////////////////////////////////////\r
572 \r
573 \r
574 \r
575       switch (bRequest){\r
576 \r
577 \r
578 \r
579       case RQ_SET_CONFIG:\r
580 \r
581         IOE &= ~(1 << 6);\r
582 \r
583         _usb_config = wValueL;          // FIXME app should handle\r
584 \r
585         break;\r
586 \r
587 \r
588 \r
589       case RQ_SET_INTERFACE:\r
590 \r
591         _usb_alt_setting = wValueL;     // FIXME app should handle\r
592 \r
593         break;\r
594 \r
595 \r
596 \r
597       // --------------------------------\r
598 \r
599 \r
600 \r
601       case RQ_CLEAR_FEATURE:\r
602 \r
603         switch (bRequestType & bmRT_RECIP_MASK){\r
604 \r
605 \r
606 \r
607         case bmRT_RECIP_DEVICE:\r
608 \r
609           switch (wValueL){\r
610 \r
611           case FS_DEV_REMOTE_WAKEUP:\r
612 \r
613           default:\r
614 \r
615             fx2_stall_ep0 ();\r
616 \r
617           }\r
618 \r
619           break;\r
620 \r
621 \r
622 \r
623         case bmRT_RECIP_ENDPOINT:\r
624 \r
625           if (wValueL == FS_ENDPOINT_HALT && plausible_endpoint (wIndexL)){\r
626 \r
627             *epcs (wIndexL) &= ~bmEPSTALL;\r
628 \r
629             fx2_reset_data_toggle (wIndexL);\r
630 \r
631           }\r
632 \r
633           else\r
634 \r
635             fx2_stall_ep0 ();\r
636 \r
637           break;\r
638 \r
639 \r
640 \r
641         default:\r
642 \r
643           fx2_stall_ep0 ();\r
644 \r
645           break;\r
646 \r
647         }\r
648 \r
649         break;\r
650 \r
651 \r
652 \r
653       // --------------------------------\r
654 \r
655 \r
656 \r
657       case RQ_SET_FEATURE:\r
658 \r
659         switch (bRequestType & bmRT_RECIP_MASK){\r
660 \r
661 \r
662 \r
663         case bmRT_RECIP_DEVICE:\r
664 \r
665           switch (wValueL){\r
666 \r
667           case FS_TEST_MODE:\r
668 \r
669             // hardware handles this after we complete SETUP phase handshake\r
670 \r
671             break;\r
672 \r
673 \r
674 \r
675           case FS_DEV_REMOTE_WAKEUP:\r
676 \r
677           default:\r
678 \r
679             fx2_stall_ep0 ();\r
680 \r
681             break;\r
682 \r
683           }\r
684 \r
685         }\r
686 \r
687         break;\r
688 \r
689 \r
690 \r
691       case bmRT_RECIP_ENDPOINT:\r
692 \r
693         switch (wValueL){\r
694 \r
695         case FS_ENDPOINT_HALT:\r
696 \r
697           if (plausible_endpoint (wIndexL))\r
698 \r
699             *epcs (wIndexL) |= bmEPSTALL;\r
700 \r
701           else\r
702 \r
703             fx2_stall_ep0 ();\r
704 \r
705           break;\r
706 \r
707 \r
708 \r
709         default:\r
710 \r
711           fx2_stall_ep0 ();\r
712 \r
713           break;\r
714 \r
715         }\r
716 \r
717         break;\r
718 \r
719 \r
720 \r
721       // --------------------------------\r
722 \r
723 \r
724 \r
725       case RQ_SET_ADDRESS:      // handled by fx2 hardware\r
726 \r
727       case RQ_SET_DESCR:        // not implemented\r
728 \r
729       default:\r
730 \r
731         fx2_stall_ep0 ();\r
732 \r
733       }\r
734 \r
735 \r
736 \r
737     }\r
738 \r
739     break;\r
740 \r
741 \r
742 \r
743   }     // bmRT_TYPE_MASK\r
744 \r
745 \r
746 \r
747   // ack handshake phase of device request\r
748 \r
749   EP0CS |= bmHSNAK;\r
750 \r
751 }\r
752 \r