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

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)