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

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)