build: cleanup src/jtag/drivers directory
[openocd.git] / src / jtag / drivers / OpenULINK / src / usb.c
blobdd791f1b1c353213258b147712cea4f5401d7343
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 ***************************************************************************/
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
27 * Therefore, we do not have to support the Set Configuration USB request.
30 #include "usb.h"
31 #include "delay.h"
32 #include "io.h"
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;
39 volatile __xdata __at 0x7FE8 struct setup_data setup_data;
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
46 * Normally, we would initialize the descriptor structures in C99 style:
48 * __code usb_device_descriptor_t device_descriptor = {
49 * .bLength = foo,
50 * .bDescriptorType = bar,
51 * .bcdUSB = 0xABCD,
52 * ...
53 * };
55 * But SDCC currently does not support this, so we have to do it the
56 * old-fashioned way...
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
76 /* WARNING: ALL config, interface and endpoint descriptors MUST be adjacent! */
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 */
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
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
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
122 __code struct usb_language_descriptor language_descriptor = {
123 /* .bLength = */ 4,
124 /* .bDescriptorType = */ DESCRIPTOR_TYPE_STRING,
125 /* .wLANGID = */ {0x0409 /* US English */}
128 __code struct usb_string_descriptor strManufacturer =
129 STR_DESCR(9, 'O', 'p', 'e', 'n', 'U', 'L', 'I', 'N', 'K');
131 __code struct usb_string_descriptor strProduct =
132 STR_DESCR(9, 'O', 'p', 'e', 'n', 'U', 'L', 'I', 'N', 'K');
134 __code struct usb_string_descriptor strSerialNumber =
135 STR_DESCR(6, '0', '0', '0', '0', '0', '1');
137 __code struct usb_string_descriptor strConfigDescr =
138 STR_DESCR(12, 'J', 'T', 'A', 'G', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r');
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
148 void sudav_isr(void) __interrupt SUDAV_ISR
150 CLEAR_IRQ();
152 usb_handle_setup_data();
154 USBIRQ = SUDAVIR;
155 EP0CS |= HSNAK;
158 void sof_isr(void) __interrupt SOF_ISR
161 void sutok_isr(void) __interrupt SUTOK_ISR
164 void suspend_isr(void) __interrupt SUSPEND_ISR
167 void usbreset_isr(void) __interrupt USBRESET_ISR
170 void ibn_isr(void) __interrupt IBN_ISR
174 void ep0in_isr(void) __interrupt EP0IN_ISR
177 void ep0out_isr(void) __interrupt EP0OUT_ISR
180 void ep1in_isr(void) __interrupt EP1IN_ISR
183 void ep1out_isr(void) __interrupt EP1OUT_ISR
188 * EP2 IN: called after the transfer from uC->Host has finished: we sent data
190 void ep2in_isr(void) __interrupt EP2IN_ISR
192 EP2_in = 1;
194 CLEAR_IRQ();
195 IN07IRQ = IN2IR;/* Clear OUT2 IRQ */
199 * EP2 OUT: called after the transfer from Host->uC has finished: we got data
201 void ep2out_isr(void) __interrupt EP2OUT_ISR
203 EP2_out = 1;
205 CLEAR_IRQ();
206 OUT07IRQ = OUT2IR; /* Clear OUT2 IRQ */
209 void ep3in_isr(void) __interrupt EP3IN_ISR
212 void ep3out_isr(void) __interrupt EP3OUT_ISR
215 void ep4in_isr(void) __interrupt EP4IN_ISR
218 void ep4out_isr(void) __interrupt EP4OUT_ISR
221 void ep5in_isr(void) __interrupt EP5IN_ISR
224 void ep5out_isr(void) __interrupt EP5OUT_ISR
227 void ep6in_isr(void) __interrupt EP6IN_ISR
230 void ep6out_isr(void) __interrupt EP6OUT_ISR
233 void ep7in_isr(void) __interrupt EP7IN_ISR
236 void ep7out_isr(void) __interrupt EP7OUT_ISR
241 * Return the control/status register for an endpoint
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
248 __xdata uint8_t *usb_get_endpoint_cs_reg(uint8_t ep)
250 /* Mask direction bit */
251 uint8_t ep_num = ep & 0x7F;
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;
280 return NULL;
283 void usb_reset_data_toggle(uint8_t ep)
285 /* TOGCTL register:
286 +----+-----+-----+------+-----+-------+-------+-------+
287 | Q | S | R | IO | 0 | EP2 | EP1 | EP0 |
288 +----+-----+-----+------+-----+-------+-------+-------+
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.
294 uint8_t togctl_value = (ep & 0x80 >> 3) | (ep & 0x7);
296 /* First step: Write EP number and direction bit */
297 TOGCTL = togctl_value;
299 /* Second step: Set R bit */
300 togctl_value |= TOG_R;
301 TOGCTL = togctl_value;
305 * Handle GET_STATUS request.
307 * @return on success: true
308 * @return on failure: false
310 bool usb_handle_get_status(void)
312 uint8_t *ep_cs;
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;
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;
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);
336 if (*ep_cs & EPSTALL)
337 IN0BUF[0] = 0x01;
338 else
339 IN0BUF[0] = 0x00;
341 /* Second byte sent has to be always zero */
342 IN0BUF[1] = 0;
344 /* Send response */
345 IN0BC = 2;
346 break;
347 default:
348 return false;
349 break;
352 return true;
356 * Handle CLEAR_FEATURE request.
358 * @return on success: true
359 * @return on failure: false
361 bool usb_handle_clear_feature(void)
363 __xdata uint8_t *ep_cs;
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();
381 break;
382 default:
383 /* Vendor commands... */
386 return true;
390 * Handle SET_FEATURE request.
392 * @return on success: true
393 * @return on failure: false
395 bool usb_handle_set_feature(void)
397 __xdata uint8_t *ep_cs;
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;
415 break;
416 default:
417 /* Vendor commands... */
418 break;
421 return true;
425 * Handle GET_DESCRIPTOR request.
427 * @return on success: true
428 * @return on failure: false
430 bool usb_handle_get_descriptor(void)
432 __xdata uint8_t descriptor_type;
433 __xdata uint8_t descriptor_index;
435 descriptor_type = (setup_data.wValue & 0xff00) >> 8;
436 descriptor_index = setup_data.wValue & 0x00ff;
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;
465 return true;
469 * Handle SET_INTERFACE request.
471 void usb_handle_set_interface(void)
473 /* Reset Data Toggle */
474 usb_reset_data_toggle(USB_DIR_IN | 2);
475 usb_reset_data_toggle(USB_DIR_OUT | 2);
477 /* Unstall & clear busy flag of all valid IN endpoints */
478 IN2CS = 0 | EPBSY;
480 /* Unstall all valid OUT endpoints, reset bytecounts */
481 OUT2CS = 0;
482 OUT2BC = 0;
486 * Handle the arrival of a USB Control Setup Packet.
488 void usb_handle_setup_data(void)
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;
544 * USB initialization. Configures USB interrupts, endpoints and performs
545 * ReNumeration.
547 void usb_init(void)
549 /* Mark endpoint 2 IN & OUT as valid */
550 IN07VAL = IN2VAL;
551 OUT07VAL = OUT2VAL;
553 /* Make sure no isochronous endpoints are marked valid */
554 INISOVAL = 0;
555 OUTISOVAL = 0;
557 /* Disable isochronous endpoints. This makes the isochronous data buffers
558 * available as 8051 XDATA memory at address 0x2000 - 0x27FF */
559 ISOCTL = ISODISAB;
561 /* Enable USB Autovectoring */
562 USBBAV |= AVEN;
564 /* Enable SUDAV interrupt */
565 USBIEN |= SUDAVIE;
567 /* Enable EP2 OUT & IN interrupts */
568 OUT07IEN = OUT2IEN;
569 IN07IEN = IN2IEN;
571 /* Enable USB interrupt (EIE register) */
572 EUSB = 1;
574 /* Perform ReNumeration */
575 USBCS = DISCON | RENUM;
576 delay_ms(200);
577 USBCS = DISCOE | RENUM;