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

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)