1 /***************************************************************************
2 * Copyright (C) 2011 by Martin Schmoelzer *
3 * <martin.schmoelzer@student.tuwien.ac.at> *
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. *
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. *
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 ***************************************************************************/
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
28 * Therefore, we do not have to support the Set Configuration USB request.
35 /* Also update external declarations in "include/usb.h" if making changes to
37 volatile bool EP2_out
;
40 volatile __xdata __at
0x7FE8 struct setup_data setup_data
;
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
47 * Normally, we would initialize the descriptor structures in C99 style:
49 * __code usb_device_descriptor_t device_descriptor = {
51 * .bDescriptorType = bar,
56 * But SDCC currently does not support this, so we have to do it the
57 * old-fashioned way...
60 __code
struct usb_device_descriptor device_descriptor
= {
61 /* .bLength = */ sizeof(struct usb_device_descriptor
),
62 /* .bDescriptorType = */ DESCRIPTOR_TYPE_DEVICE
,
63 /* .bcdUSB = */ 0x0110, /* BCD: 01.00 (Version 1.0 USB spec) */
64 /* .bDeviceClass = */ 0xFF, /* 0xFF = vendor-specific */
65 /* .bDeviceSubClass = */ 0xFF,
66 /* .bDeviceProtocol = */ 0xFF,
67 /* .bMaxPacketSize0 = */ 64,
68 /* .idVendor = */ 0xC251,
69 /* .idProduct = */ 0x2710,
70 /* .bcdDevice = */ 0x0100,
71 /* .iManufacturer = */ 1,
73 /* .iSerialNumber = */ 3,
74 /* .bNumConfigurations = */ 1
77 /* WARNING: ALL config, interface and endpoint descriptors MUST be adjacent! */
79 __code
struct usb_config_descriptor config_descriptor
= {
80 /* .bLength = */ sizeof(struct usb_config_descriptor
),
81 /* .bDescriptorType = */ DESCRIPTOR_TYPE_CONFIGURATION
,
82 /* .wTotalLength = */ sizeof(struct usb_config_descriptor
) +
83 sizeof(struct usb_interface_descriptor
) +
85 sizeof(struct usb_endpoint_descriptor
)),
86 /* .bNumInterfaces = */ 1,
87 /* .bConfigurationValue = */ 1,
88 /* .iConfiguration = */ 4, /* String describing this configuration */
89 /* .bmAttributes = */ 0x80, /* Only MSB set according to USB spec */
90 /* .MaxPower = */ 50 /* 100 mA */
93 __code
struct usb_interface_descriptor interface_descriptor00
= {
94 /* .bLength = */ sizeof(struct usb_interface_descriptor
),
95 /* .bDescriptorType = */ DESCRIPTOR_TYPE_INTERFACE
,
96 /* .bInterfaceNumber = */ 0,
97 /* .bAlternateSetting = */ 0,
98 /* .bNumEndpoints = */ NUM_ENDPOINTS
,
99 /* .bInterfaceClass = */ 0xFF,
100 /* .bInterfaceSubclass = */ 0xFF,
101 /* .bInterfaceProtocol = */ 0xFF,
102 /* .iInterface = */ 0
105 __code
struct usb_endpoint_descriptor Bulk_EP2_IN_Endpoint_Descriptor
= {
106 /* .bLength = */ sizeof(struct usb_endpoint_descriptor
),
107 /* .bDescriptorType = */ 0x05,
108 /* .bEndpointAddress = */ 2 | USB_DIR_IN
,
109 /* .bmAttributes = */ 0x02,
110 /* .wMaxPacketSize = */ 64,
114 __code
struct usb_endpoint_descriptor Bulk_EP2_OUT_Endpoint_Descriptor
= {
115 /* .bLength = */ sizeof(struct usb_endpoint_descriptor
),
116 /* .bDescriptorType = */ 0x05,
117 /* .bEndpointAddress = */ 2 | USB_DIR_OUT
,
118 /* .bmAttributes = */ 0x02,
119 /* .wMaxPacketSize = */ 64,
123 __code
struct usb_language_descriptor language_descriptor
= {
125 /* .bDescriptorType = */ DESCRIPTOR_TYPE_STRING
,
126 /* .wLANGID = */ {0x0409 /* US English */}
129 __code
struct usb_string_descriptor strManufacturer
=
130 STR_DESCR(9, 'O', 'p', 'e', 'n', 'U', 'L', 'I', 'N', 'K');
132 __code
struct usb_string_descriptor strProduct
=
133 STR_DESCR(9, 'O', 'p', 'e', 'n', 'U', 'L', 'I', 'N', 'K');
135 __code
struct usb_string_descriptor strSerialNumber
=
136 STR_DESCR(6, '0', '0', '0', '0', '0', '1');
138 __code
struct usb_string_descriptor strConfigDescr
=
139 STR_DESCR(12, 'J', 'T', 'A', 'G', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r');
141 /* Table containing pointers to string descriptors */
142 __code
struct usb_string_descriptor
*__code en_string_descriptors
[4] = {
149 void sudav_isr(void) __interrupt SUDAV_ISR
153 usb_handle_setup_data();
159 void sof_isr(void) __interrupt SOF_ISR
162 void sutok_isr(void) __interrupt SUTOK_ISR
165 void suspend_isr(void) __interrupt SUSPEND_ISR
168 void usbreset_isr(void) __interrupt USBRESET_ISR
171 void ibn_isr(void) __interrupt IBN_ISR
175 void ep0in_isr(void) __interrupt EP0IN_ISR
178 void ep0out_isr(void) __interrupt EP0OUT_ISR
181 void ep1in_isr(void) __interrupt EP1IN_ISR
184 void ep1out_isr(void) __interrupt EP1OUT_ISR
189 * EP2 IN: called after the transfer from uC->Host has finished: we sent data
191 void ep2in_isr(void) __interrupt EP2IN_ISR
196 IN07IRQ
= IN2IR
;/* Clear OUT2 IRQ */
200 * EP2 OUT: called after the transfer from Host->uC has finished: we got data
202 void ep2out_isr(void) __interrupt EP2OUT_ISR
207 OUT07IRQ
= OUT2IR
; /* Clear OUT2 IRQ */
210 void ep3in_isr(void) __interrupt EP3IN_ISR
213 void ep3out_isr(void) __interrupt EP3OUT_ISR
216 void ep4in_isr(void) __interrupt EP4IN_ISR
219 void ep4out_isr(void) __interrupt EP4OUT_ISR
222 void ep5in_isr(void) __interrupt EP5IN_ISR
225 void ep5out_isr(void) __interrupt EP5OUT_ISR
228 void ep6in_isr(void) __interrupt EP6IN_ISR
231 void ep6out_isr(void) __interrupt EP6OUT_ISR
234 void ep7in_isr(void) __interrupt EP7IN_ISR
237 void ep7out_isr(void) __interrupt EP7OUT_ISR
242 * Return the control/status register for an endpoint
244 * @param ep endpoint address
245 * @return on success: pointer to Control & Status register for endpoint
247 * @return on failure: NULL
249 __xdata
uint8_t *usb_get_endpoint_cs_reg(uint8_t ep
)
251 /* Mask direction bit */
252 uint8_t ep_num
= ep
& 0x7F;
259 return ep
& 0x80 ? &IN1CS
: &OUT1CS
;
262 return ep
& 0x80 ? &IN2CS
: &OUT2CS
;
265 return ep
& 0x80 ? &IN3CS
: &OUT3CS
;
268 return ep
& 0x80 ? &IN4CS
: &OUT4CS
;
271 return ep
& 0x80 ? &IN5CS
: &OUT5CS
;
274 return ep
& 0x80 ? &IN6CS
: &OUT6CS
;
277 return ep
& 0x80 ? &IN7CS
: &OUT7CS
;
284 void usb_reset_data_toggle(uint8_t ep
)
287 +----+-----+-----+------+-----+-------+-------+-------+
288 | Q | S | R | IO | 0 | EP2 | EP1 | EP0 |
289 +----+-----+-----+------+-----+-------+-------+-------+
291 To reset data toggle bits, we have to write the endpoint direction (IN/OUT)
292 to the IO bit and the endpoint number to the EP2..EP0 bits. Then, in a
293 separate write cycle, the R bit needs to be set.
295 uint8_t togctl_value
= (ep
& 0x80 >> 3) | (ep
& 0x7);
297 /* First step: Write EP number and direction bit */
298 TOGCTL
= togctl_value
;
300 /* Second step: Set R bit */
301 togctl_value
|= TOG_R
;
302 TOGCTL
= togctl_value
;
306 * Handle GET_STATUS request.
308 * @return on success: true
309 * @return on failure: false
311 bool usb_handle_get_status(void)
315 switch (setup_data
.bmRequestType
) {
317 /* Two byte response: Byte 0, Bit 0 = self-powered, Bit 1 = remote wakeup.
318 * Byte 1: reserved, reset to zero */
326 /* Always return two zero bytes according to USB 1.1 spec, p. 191 */
334 /* Get stall bit for endpoint specified in low byte of wIndex */
335 ep_cs
= usb_get_endpoint_cs_reg(setup_data
.wIndex
& 0xff);
337 if (*ep_cs
& EPSTALL
)
342 /* Second byte sent has to be always zero */
357 * Handle CLEAR_FEATURE request.
359 * @return on success: true
360 * @return on failure: false
362 bool usb_handle_clear_feature(void)
364 __xdata
uint8_t *ep_cs
;
366 switch (setup_data
.bmRequestType
) {
368 /* Clear remote wakeup not supported: stall EP0 */
372 if (setup_data
.wValue
== 0) {
373 /* Unstall the endpoint specified in wIndex */
374 ep_cs
= usb_get_endpoint_cs_reg(setup_data
.wIndex
);
379 /* Unsupported feature, stall EP0 */
384 /* Vendor commands... */
391 * Handle SET_FEATURE request.
393 * @return on success: true
394 * @return on failure: false
396 bool usb_handle_set_feature(void)
398 __xdata
uint8_t *ep_cs
;
400 switch (setup_data
.bmRequestType
) {
402 if (setup_data
.wValue
== 2)
406 if (setup_data
.wValue
== 0) {
407 /* Stall the endpoint specified in wIndex */
408 ep_cs
= usb_get_endpoint_cs_reg(setup_data
.wIndex
);
413 /* Unsupported endpoint feature */
418 /* Vendor commands... */
426 * Handle GET_DESCRIPTOR request.
428 * @return on success: true
429 * @return on failure: false
431 bool usb_handle_get_descriptor(void)
433 __xdata
uint8_t descriptor_type
;
434 __xdata
uint8_t descriptor_index
;
436 descriptor_type
= (setup_data
.wValue
& 0xff00) >> 8;
437 descriptor_index
= setup_data
.wValue
& 0x00ff;
439 switch (descriptor_type
) {
440 case DESCRIPTOR_TYPE_DEVICE
:
441 SUDPTRH
= HI8(&device_descriptor
);
442 SUDPTRL
= LO8(&device_descriptor
);
444 case DESCRIPTOR_TYPE_CONFIGURATION
:
445 SUDPTRH
= HI8(&config_descriptor
);
446 SUDPTRL
= LO8(&config_descriptor
);
448 case DESCRIPTOR_TYPE_STRING
:
449 if (setup_data
.wIndex
== 0) {
450 /* Supply language descriptor */
451 SUDPTRH
= HI8(&language_descriptor
);
452 SUDPTRL
= LO8(&language_descriptor
);
453 } else if (setup_data
.wIndex
== 0x0409 /* US English */) {
454 /* Supply string descriptor */
455 SUDPTRH
= HI8(en_string_descriptors
[descriptor_index
- 1]);
456 SUDPTRL
= LO8(en_string_descriptors
[descriptor_index
- 1]);
461 /* Unsupported descriptor type */
470 * Handle SET_INTERFACE request.
472 void usb_handle_set_interface(void)
474 /* Reset Data Toggle */
475 usb_reset_data_toggle(USB_DIR_IN
| 2);
476 usb_reset_data_toggle(USB_DIR_OUT
| 2);
478 /* Unstall & clear busy flag of all valid IN endpoints */
481 /* Unstall all valid OUT endpoints, reset bytecounts */
487 * Handle the arrival of a USB Control Setup Packet.
489 void usb_handle_setup_data(void)
491 switch (setup_data
.bRequest
) {
493 if (!usb_handle_get_status())
497 if (!usb_handle_clear_feature())
501 /* Reserved values */
505 if (!usb_handle_set_feature())
509 /* Handled by USB core */
512 /* Set Descriptor not supported. */
516 if (!usb_handle_get_descriptor())
519 case GET_CONFIGURATION
:
520 /* OpenULINK has only one configuration, return its index */
521 IN0BUF
[0] = config_descriptor
.bConfigurationValue
;
524 case SET_CONFIGURATION
:
525 /* OpenULINK has only one configuration -> nothing to do */
528 /* OpenULINK only has one interface, return its number */
529 IN0BUF
[0] = interface_descriptor00
.bInterfaceNumber
;
533 usb_handle_set_interface();
536 /* Isochronous endpoints not used -> nothing to do */
539 /* Any other requests: do nothing */
545 * USB initialization. Configures USB interrupts, endpoints and performs
550 /* Mark endpoint 2 IN & OUT as valid */
554 /* Make sure no isochronous endpoints are marked valid */
558 /* Disable isochronous endpoints. This makes the isochronous data buffers
559 * available as 8051 XDATA memory at address 0x2000 - 0x27FF */
562 /* Enable USB Autovectoring */
565 /* Enable SUDAV interrupt */
568 /* Enable EP2 OUT & IN interrupts */
572 /* Enable USB interrupt (EIE register) */
575 /* Perform ReNumeration */
576 USBCS
= DISCON
| RENUM
;
578 USBCS
= DISCOE
| RENUM
;
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)