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

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)