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

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)