update files to correct FSF address
[openocd.git] / src / jtag / drivers / OpenULINK / src / usb.c
1 /***************************************************************************
2 * Copyright (C) 2011 by Martin Schmoelzer *
3 * <martin.schmoelzer@student.tuwien.ac.at> *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
19 ***************************************************************************/
20
21 /**
22 * @file
23 * Defines USB descriptors, interrupt routines and helper functions.
24 * To minimize code size, we make the following assumptions:
25 * - The OpenULINK has exactly one configuration
26 * - and exactly one alternate setting
27 *
28 * Therefore, we do not have to support the Set Configuration USB request.
29 */
30
31 #include "usb.h"
32 #include "delay.h"
33 #include "io.h"
34
35 /* Also update external declarations in "include/usb.h" if making changes to
36 * these variables! */
37 volatile bool EP2_out;
38 volatile bool EP2_in;
39
40 volatile __xdata __at 0x7FE8 struct setup_data setup_data;
41
42 /* Define number of endpoints (except Control Endpoint 0) in a central place.
43 * Be sure to include the neccessary endpoint descriptors! */
44 #define NUM_ENDPOINTS 2
45
46 /*
47 * Normally, we would initialize the descriptor structures in C99 style:
48 *
49 * __code usb_device_descriptor_t device_descriptor = {
50 * .bLength = foo,
51 * .bDescriptorType = bar,
52 * .bcdUSB = 0xABCD,
53 * ...
54 * };
55 *
56 * But SDCC currently does not support this, so we have to do it the
57 * old-fashioned way...
58 */
59
60 __code struct usb_device_descriptor device_descriptor = {
61 /* .bLength = */ sizeof(struct usb_device_descriptor),
62 /* .bDescriptorType = */ DESCRIPTOR_TYPE_DEVICE,
63 /* .bcdUSB = */ 0x0110, /* BCD: 01.00 (Version 1.0 USB spec) */
64 /* .bDeviceClass = */ 0xFF, /* 0xFF = vendor-specific */
65 /* .bDeviceSubClass = */ 0xFF,
66 /* .bDeviceProtocol = */ 0xFF,
67 /* .bMaxPacketSize0 = */ 64,
68 /* .idVendor = */ 0xC251,
69 /* .idProduct = */ 0x2710,
70 /* .bcdDevice = */ 0x0100,
71 /* .iManufacturer = */ 1,
72 /* .iProduct = */ 2,
73 /* .iSerialNumber = */ 3,
74 /* .bNumConfigurations = */ 1
75 };
76
77 /* WARNING: ALL config, interface and endpoint descriptors MUST be adjacent! */
78
79 __code struct usb_config_descriptor config_descriptor = {
80 /* .bLength = */ sizeof(struct usb_config_descriptor),
81 /* .bDescriptorType = */ DESCRIPTOR_TYPE_CONFIGURATION,
82 /* .wTotalLength = */ sizeof(struct usb_config_descriptor) +
83 sizeof(struct usb_interface_descriptor) +
84 (NUM_ENDPOINTS *
85 sizeof(struct usb_endpoint_descriptor)),
86 /* .bNumInterfaces = */ 1,
87 /* .bConfigurationValue = */ 1,
88 /* .iConfiguration = */ 4, /* String describing this configuration */
89 /* .bmAttributes = */ 0x80, /* Only MSB set according to USB spec */
90 /* .MaxPower = */ 50 /* 100 mA */
91 };
92
93 __code struct usb_interface_descriptor interface_descriptor00 = {
94 /* .bLength = */ sizeof(struct usb_interface_descriptor),
95 /* .bDescriptorType = */ DESCRIPTOR_TYPE_INTERFACE,
96 /* .bInterfaceNumber = */ 0,
97 /* .bAlternateSetting = */ 0,
98 /* .bNumEndpoints = */ NUM_ENDPOINTS,
99 /* .bInterfaceClass = */ 0xFF,
100 /* .bInterfaceSubclass = */ 0xFF,
101 /* .bInterfaceProtocol = */ 0xFF,
102 /* .iInterface = */ 0
103 };
104
105 __code struct usb_endpoint_descriptor Bulk_EP2_IN_Endpoint_Descriptor = {
106 /* .bLength = */ sizeof(struct usb_endpoint_descriptor),
107 /* .bDescriptorType = */ 0x05,
108 /* .bEndpointAddress = */ 2 | USB_DIR_IN,
109 /* .bmAttributes = */ 0x02,
110 /* .wMaxPacketSize = */ 64,
111 /* .bInterval = */ 0
112 };
113
114 __code struct usb_endpoint_descriptor Bulk_EP2_OUT_Endpoint_Descriptor = {
115 /* .bLength = */ sizeof(struct usb_endpoint_descriptor),
116 /* .bDescriptorType = */ 0x05,
117 /* .bEndpointAddress = */ 2 | USB_DIR_OUT,
118 /* .bmAttributes = */ 0x02,
119 /* .wMaxPacketSize = */ 64,
120 /* .bInterval = */ 0
121 };
122
123 __code struct usb_language_descriptor language_descriptor = {
124 /* .bLength = */ 4,
125 /* .bDescriptorType = */ DESCRIPTOR_TYPE_STRING,
126 /* .wLANGID = */ {0x0409 /* US English */}
127 };
128
129 __code struct usb_string_descriptor strManufacturer =
130 STR_DESCR(9, 'O', 'p', 'e', 'n', 'U', 'L', 'I', 'N', 'K');
131
132 __code struct usb_string_descriptor strProduct =
133 STR_DESCR(9, 'O', 'p', 'e', 'n', 'U', 'L', 'I', 'N', 'K');
134
135 __code struct usb_string_descriptor strSerialNumber =
136 STR_DESCR(6, '0', '0', '0', '0', '0', '1');
137
138 __code struct usb_string_descriptor strConfigDescr =
139 STR_DESCR(12, 'J', 'T', 'A', 'G', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r');
140
141 /* Table containing pointers to string descriptors */
142 __code struct usb_string_descriptor *__code en_string_descriptors[4] = {
143 &strManufacturer,
144 &strProduct,
145 &strSerialNumber,
146 &strConfigDescr
147 };
148
149 void sudav_isr(void) __interrupt SUDAV_ISR
150 {
151 CLEAR_IRQ();
152
153 usb_handle_setup_data();
154
155 USBIRQ = SUDAVIR;
156 EP0CS |= HSNAK;
157 }
158
159 void sof_isr(void) __interrupt SOF_ISR
160 {
161 }
162 void sutok_isr(void) __interrupt SUTOK_ISR
163 {
164 }
165 void suspend_isr(void) __interrupt SUSPEND_ISR
166 {
167 }
168 void usbreset_isr(void) __interrupt USBRESET_ISR
169 {
170 }
171 void ibn_isr(void) __interrupt IBN_ISR
172 {
173 }
174
175 void ep0in_isr(void) __interrupt EP0IN_ISR
176 {
177 }
178 void ep0out_isr(void) __interrupt EP0OUT_ISR
179 {
180 }
181 void ep1in_isr(void) __interrupt EP1IN_ISR
182 {
183 }
184 void ep1out_isr(void) __interrupt EP1OUT_ISR
185 {
186 }
187
188 /**
189 * EP2 IN: called after the transfer from uC->Host has finished: we sent data
190 */
191 void ep2in_isr(void) __interrupt EP2IN_ISR
192 {
193 EP2_in = 1;
194
195 CLEAR_IRQ();
196 IN07IRQ = IN2IR;/* Clear OUT2 IRQ */
197 }
198
199 /**
200 * EP2 OUT: called after the transfer from Host->uC has finished: we got data
201 */
202 void ep2out_isr(void) __interrupt EP2OUT_ISR
203 {
204 EP2_out = 1;
205
206 CLEAR_IRQ();
207 OUT07IRQ = OUT2IR; /* Clear OUT2 IRQ */
208 }
209
210 void ep3in_isr(void) __interrupt EP3IN_ISR
211 {
212 }
213 void ep3out_isr(void) __interrupt EP3OUT_ISR
214 {
215 }
216 void ep4in_isr(void) __interrupt EP4IN_ISR
217 {
218 }
219 void ep4out_isr(void) __interrupt EP4OUT_ISR
220 {
221 }
222 void ep5in_isr(void) __interrupt EP5IN_ISR
223 {
224 }
225 void ep5out_isr(void) __interrupt EP5OUT_ISR
226 {
227 }
228 void ep6in_isr(void) __interrupt EP6IN_ISR
229 {
230 }
231 void ep6out_isr(void) __interrupt EP6OUT_ISR
232 {
233 }
234 void ep7in_isr(void) __interrupt EP7IN_ISR
235 {
236 }
237 void ep7out_isr(void) __interrupt EP7OUT_ISR
238 {
239 }
240
241 /**
242 * Return the control/status register for an endpoint
243 *
244 * @param ep endpoint address
245 * @return on success: pointer to Control & Status register for endpoint
246 * specified in \a ep
247 * @return on failure: NULL
248 */
249 __xdata uint8_t *usb_get_endpoint_cs_reg(uint8_t ep)
250 {
251 /* Mask direction bit */
252 uint8_t ep_num = ep & 0x7F;
253
254 switch (ep_num) {
255 case 0:
256 return &EP0CS;
257 break;
258 case 1:
259 return ep & 0x80 ? &IN1CS : &OUT1CS;
260 break;
261 case 2:
262 return ep & 0x80 ? &IN2CS : &OUT2CS;
263 break;
264 case 3:
265 return ep & 0x80 ? &IN3CS : &OUT3CS;
266 break;
267 case 4:
268 return ep & 0x80 ? &IN4CS : &OUT4CS;
269 break;
270 case 5:
271 return ep & 0x80 ? &IN5CS : &OUT5CS;
272 break;
273 case 6:
274 return ep & 0x80 ? &IN6CS : &OUT6CS;
275 break;
276 case 7:
277 return ep & 0x80 ? &IN7CS : &OUT7CS;
278 break;
279 }
280
281 return NULL;
282 }
283
284 void usb_reset_data_toggle(uint8_t ep)
285 {
286 /* TOGCTL register:
287 +----+-----+-----+------+-----+-------+-------+-------+
288 | Q | S | R | IO | 0 | EP2 | EP1 | EP0 |
289 +----+-----+-----+------+-----+-------+-------+-------+
290
291 To reset data toggle bits, we have to write the endpoint direction (IN/OUT)
292 to the IO bit and the endpoint number to the EP2..EP0 bits. Then, in a
293 separate write cycle, the R bit needs to be set.
294 */
295 uint8_t togctl_value = (ep & 0x80 >> 3) | (ep & 0x7);
296
297 /* First step: Write EP number and direction bit */
298 TOGCTL = togctl_value;
299
300 /* Second step: Set R bit */
301 togctl_value |= TOG_R;
302 TOGCTL = togctl_value;
303 }
304
305 /**
306 * Handle GET_STATUS request.
307 *
308 * @return on success: true
309 * @return on failure: false
310 */
311 bool usb_handle_get_status(void)
312 {
313 uint8_t *ep_cs;
314
315 switch (setup_data.bmRequestType) {
316 case GS_DEVICE:
317 /* Two byte response: Byte 0, Bit 0 = self-powered, Bit 1 = remote wakeup.
318 * Byte 1: reserved, reset to zero */
319 IN0BUF[0] = 0;
320 IN0BUF[1] = 0;
321
322 /* Send response */
323 IN0BC = 2;
324 break;
325 case GS_INTERFACE:
326 /* Always return two zero bytes according to USB 1.1 spec, p. 191 */
327 IN0BUF[0] = 0;
328 IN0BUF[1] = 0;
329
330 /* Send response */
331 IN0BC = 2;
332 break;
333 case GS_ENDPOINT:
334 /* Get stall bit for endpoint specified in low byte of wIndex */
335 ep_cs = usb_get_endpoint_cs_reg(setup_data.wIndex & 0xff);
336
337 if (*ep_cs & EPSTALL)
338 IN0BUF[0] = 0x01;
339 else
340 IN0BUF[0] = 0x00;
341
342 /* Second byte sent has to be always zero */
343 IN0BUF[1] = 0;
344
345 /* Send response */
346 IN0BC = 2;
347 break;
348 default:
349 return false;
350 break;
351 }
352
353 return true;
354 }
355
356 /**
357 * Handle CLEAR_FEATURE request.
358 *
359 * @return on success: true
360 * @return on failure: false
361 */
362 bool usb_handle_clear_feature(void)
363 {
364 __xdata uint8_t *ep_cs;
365
366 switch (setup_data.bmRequestType) {
367 case CF_DEVICE:
368 /* Clear remote wakeup not supported: stall EP0 */
369 STALL_EP0();
370 break;
371 case CF_ENDPOINT:
372 if (setup_data.wValue == 0) {
373 /* Unstall the endpoint specified in wIndex */
374 ep_cs = usb_get_endpoint_cs_reg(setup_data.wIndex);
375 if (!ep_cs)
376 return false;
377 *ep_cs &= ~EPSTALL;
378 } else {
379 /* Unsupported feature, stall EP0 */
380 STALL_EP0();
381 }
382 break;
383 default:
384 /* Vendor commands... */
385 }
386
387 return true;
388 }
389
390 /**
391 * Handle SET_FEATURE request.
392 *
393 * @return on success: true
394 * @return on failure: false
395 */
396 bool usb_handle_set_feature(void)
397 {
398 __xdata uint8_t *ep_cs;
399
400 switch (setup_data.bmRequestType) {
401 case SF_DEVICE:
402 if (setup_data.wValue == 2)
403 return true;
404 break;
405 case SF_ENDPOINT:
406 if (setup_data.wValue == 0) {
407 /* Stall the endpoint specified in wIndex */
408 ep_cs = usb_get_endpoint_cs_reg(setup_data.wIndex);
409 if (!ep_cs)
410 return false;
411 *ep_cs |= EPSTALL;
412 } else {
413 /* Unsupported endpoint feature */
414 return false;
415 }
416 break;
417 default:
418 /* Vendor commands... */
419 break;
420 }
421
422 return true;
423 }
424
425 /**
426 * Handle GET_DESCRIPTOR request.
427 *
428 * @return on success: true
429 * @return on failure: false
430 */
431 bool usb_handle_get_descriptor(void)
432 {
433 __xdata uint8_t descriptor_type;
434 __xdata uint8_t descriptor_index;
435
436 descriptor_type = (setup_data.wValue & 0xff00) >> 8;
437 descriptor_index = setup_data.wValue & 0x00ff;
438
439 switch (descriptor_type) {
440 case DESCRIPTOR_TYPE_DEVICE:
441 SUDPTRH = HI8(&device_descriptor);
442 SUDPTRL = LO8(&device_descriptor);
443 break;
444 case DESCRIPTOR_TYPE_CONFIGURATION:
445 SUDPTRH = HI8(&config_descriptor);
446 SUDPTRL = LO8(&config_descriptor);
447 break;
448 case DESCRIPTOR_TYPE_STRING:
449 if (setup_data.wIndex == 0) {
450 /* Supply language descriptor */
451 SUDPTRH = HI8(&language_descriptor);
452 SUDPTRL = LO8(&language_descriptor);
453 } else if (setup_data.wIndex == 0x0409 /* US English */) {
454 /* Supply string descriptor */
455 SUDPTRH = HI8(en_string_descriptors[descriptor_index - 1]);
456 SUDPTRL = LO8(en_string_descriptors[descriptor_index - 1]);
457 } else
458 return false;
459 break;
460 default:
461 /* Unsupported descriptor type */
462 return false;
463 break;
464 }
465
466 return true;
467 }
468
469 /**
470 * Handle SET_INTERFACE request.
471 */
472 void usb_handle_set_interface(void)
473 {
474 /* Reset Data Toggle */
475 usb_reset_data_toggle(USB_DIR_IN | 2);
476 usb_reset_data_toggle(USB_DIR_OUT | 2);
477
478 /* Unstall & clear busy flag of all valid IN endpoints */
479 IN2CS = 0 | EPBSY;
480
481 /* Unstall all valid OUT endpoints, reset bytecounts */
482 OUT2CS = 0;
483 OUT2BC = 0;
484 }
485
486 /**
487 * Handle the arrival of a USB Control Setup Packet.
488 */
489 void usb_handle_setup_data(void)
490 {
491 switch (setup_data.bRequest) {
492 case GET_STATUS:
493 if (!usb_handle_get_status())
494 STALL_EP0();
495 break;
496 case CLEAR_FEATURE:
497 if (!usb_handle_clear_feature())
498 STALL_EP0();
499 break;
500 case 2: case 4:
501 /* Reserved values */
502 STALL_EP0();
503 break;
504 case SET_FEATURE:
505 if (!usb_handle_set_feature())
506 STALL_EP0();
507 break;
508 case SET_ADDRESS:
509 /* Handled by USB core */
510 break;
511 case SET_DESCRIPTOR:
512 /* Set Descriptor not supported. */
513 STALL_EP0();
514 break;
515 case GET_DESCRIPTOR:
516 if (!usb_handle_get_descriptor())
517 STALL_EP0();
518 break;
519 case GET_CONFIGURATION:
520 /* OpenULINK has only one configuration, return its index */
521 IN0BUF[0] = config_descriptor.bConfigurationValue;
522 IN0BC = 1;
523 break;
524 case SET_CONFIGURATION:
525 /* OpenULINK has only one configuration -> nothing to do */
526 break;
527 case GET_INTERFACE:
528 /* OpenULINK only has one interface, return its number */
529 IN0BUF[0] = interface_descriptor00.bInterfaceNumber;
530 IN0BC = 1;
531 break;
532 case SET_INTERFACE:
533 usb_handle_set_interface();
534 break;
535 case SYNCH_FRAME:
536 /* Isochronous endpoints not used -> nothing to do */
537 break;
538 default:
539 /* Any other requests: do nothing */
540 break;
541 }
542 }
543
544 /**
545 * USB initialization. Configures USB interrupts, endpoints and performs
546 * ReNumeration.
547 */
548 void usb_init(void)
549 {
550 /* Mark endpoint 2 IN & OUT as valid */
551 IN07VAL = IN2VAL;
552 OUT07VAL = OUT2VAL;
553
554 /* Make sure no isochronous endpoints are marked valid */
555 INISOVAL = 0;
556 OUTISOVAL = 0;
557
558 /* Disable isochronous endpoints. This makes the isochronous data buffers
559 * available as 8051 XDATA memory at address 0x2000 - 0x27FF */
560 ISOCTL = ISODISAB;
561
562 /* Enable USB Autovectoring */
563 USBBAV |= AVEN;
564
565 /* Enable SUDAV interrupt */
566 USBIEN |= SUDAVIE;
567
568 /* Enable EP2 OUT & IN interrupts */
569 OUT07IEN = OUT2IEN;
570 IN07IEN = IN2IEN;
571
572 /* Enable USB interrupt (EIE register) */
573 EUSB = 1;
574
575 /* Perform ReNumeration */
576 USBCS = DISCON | RENUM;
577 delay_ms(200);
578 USBCS = DISCOE | RENUM;
579 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)