1 /***************************************************************************
2 * Copyright (C) 2011-2013 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 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
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,
60 .bNumConfigurations
= 1
63 /* WARNING: ALL config, interface and endpoint descriptors MUST be adjacent! */
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
)),
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 */
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,
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
),
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,
108 __code
struct usb_language_descriptor language_descriptor
= {
110 .bDescriptorType
= DESCRIPTOR_TYPE_STRING
,
111 .wLANGID
= {0x0409 /* US English */}
114 __code
struct usb_string_descriptor strManufacturer
=
115 STR_DESCR(9, 'O', 'p', 'e', 'n', 'U', 'L', 'I', 'N', 'K');
117 __code
struct usb_string_descriptor strProduct
=
118 STR_DESCR(9, 'O', 'p', 'e', 'n', 'U', 'L', 'I', 'N', 'K');
120 __code
struct usb_string_descriptor strSerialNumber
=
121 STR_DESCR(6, '0', '0', '0', '0', '0', '1');
123 __code
struct usb_string_descriptor strConfigDescr
=
124 STR_DESCR(12, 'J', 'T', 'A', 'G', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r');
126 /* Table containing pointers to string descriptors */
127 __code
struct usb_string_descriptor
*__code en_string_descriptors
[4] = {
134 void sudav_isr(void) __interrupt SUDAV_ISR
138 usb_handle_setup_data();
144 void sof_isr(void) __interrupt SOF_ISR
147 void sutok_isr(void) __interrupt SUTOK_ISR
150 void suspend_isr(void) __interrupt SUSPEND_ISR
153 void usbreset_isr(void) __interrupt USBRESET_ISR
156 void ibn_isr(void) __interrupt IBN_ISR
160 void ep0in_isr(void) __interrupt EP0IN_ISR
163 void ep0out_isr(void) __interrupt EP0OUT_ISR
166 void ep1in_isr(void) __interrupt EP1IN_ISR
169 void ep1out_isr(void) __interrupt EP1OUT_ISR
174 * EP2 IN: called after the transfer from uC->Host has finished: we sent data
176 void ep2in_isr(void) __interrupt EP2IN_ISR
181 IN07IRQ
= IN2IR
;/* Clear OUT2 IRQ */
185 * EP2 OUT: called after the transfer from Host->uC has finished: we got data
187 void ep2out_isr(void) __interrupt EP2OUT_ISR
192 OUT07IRQ
= OUT2IR
; /* Clear OUT2 IRQ */
195 void ep3in_isr(void) __interrupt EP3IN_ISR
198 void ep3out_isr(void) __interrupt EP3OUT_ISR
201 void ep4in_isr(void) __interrupt EP4IN_ISR
204 void ep4out_isr(void) __interrupt EP4OUT_ISR
207 void ep5in_isr(void) __interrupt EP5IN_ISR
210 void ep5out_isr(void) __interrupt EP5OUT_ISR
213 void ep6in_isr(void) __interrupt EP6IN_ISR
216 void ep6out_isr(void) __interrupt EP6OUT_ISR
219 void ep7in_isr(void) __interrupt EP7IN_ISR
222 void ep7out_isr(void) __interrupt EP7OUT_ISR
227 * Return the control/status register for an endpoint
229 * @param ep endpoint address
230 * @return on success: pointer to Control & Status register for endpoint
232 * @return on failure: NULL
234 __xdata
uint8_t *usb_get_endpoint_cs_reg(uint8_t ep
)
236 /* Mask direction bit */
237 uint8_t ep_num
= ep
& 0x7F;
244 return ep
& 0x80 ? &IN1CS
: &OUT1CS
;
247 return ep
& 0x80 ? &IN2CS
: &OUT2CS
;
250 return ep
& 0x80 ? &IN3CS
: &OUT3CS
;
253 return ep
& 0x80 ? &IN4CS
: &OUT4CS
;
256 return ep
& 0x80 ? &IN5CS
: &OUT5CS
;
259 return ep
& 0x80 ? &IN6CS
: &OUT6CS
;
262 return ep
& 0x80 ? &IN7CS
: &OUT7CS
;
269 void usb_reset_data_toggle(uint8_t ep
)
272 +----+-----+-----+------+-----+-------+-------+-------+
273 | Q | S | R | IO | 0 | EP2 | EP1 | EP0 |
274 +----+-----+-----+------+-----+-------+-------+-------+
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.
280 uint8_t togctl_value
= (ep
& 0x80 >> 3) | (ep
& 0x7);
282 /* First step: Write EP number and direction bit */
283 TOGCTL
= togctl_value
;
285 /* Second step: Set R bit */
286 togctl_value
|= TOG_R
;
287 TOGCTL
= togctl_value
;
291 * Handle GET_STATUS request.
293 * @return on success: true
294 * @return on failure: false
296 bool usb_handle_get_status(void)
300 switch (setup_data
.bmRequestType
) {
302 /* Two byte response: Byte 0, Bit 0 = self-powered, Bit 1 = remote wakeup.
303 * Byte 1: reserved, reset to zero */
311 /* Always return two zero bytes according to USB 1.1 spec, p. 191 */
319 /* Get stall bit for endpoint specified in low byte of wIndex */
320 ep_cs
= usb_get_endpoint_cs_reg(setup_data
.wIndex
& 0xff);
322 if (*ep_cs
& EPSTALL
)
327 /* Second byte sent has to be always zero */
342 * Handle CLEAR_FEATURE request.
344 * @return on success: true
345 * @return on failure: false
347 bool usb_handle_clear_feature(void)
349 __xdata
uint8_t *ep_cs
;
351 switch (setup_data
.bmRequestType
) {
353 /* Clear remote wakeup not supported: stall EP0 */
357 if (setup_data
.wValue
== 0) {
358 /* Unstall the endpoint specified in wIndex */
359 ep_cs
= usb_get_endpoint_cs_reg(setup_data
.wIndex
);
364 /* Unsupported feature, stall EP0 */
369 /* Vendor commands... */
376 * Handle SET_FEATURE request.
378 * @return on success: true
379 * @return on failure: false
381 bool usb_handle_set_feature(void)
383 __xdata
uint8_t *ep_cs
;
385 switch (setup_data
.bmRequestType
) {
387 if (setup_data
.wValue
== 2)
391 if (setup_data
.wValue
== 0) {
392 /* Stall the endpoint specified in wIndex */
393 ep_cs
= usb_get_endpoint_cs_reg(setup_data
.wIndex
);
398 /* Unsupported endpoint feature */
403 /* Vendor commands... */
411 * Handle GET_DESCRIPTOR request.
413 * @return on success: true
414 * @return on failure: false
416 bool usb_handle_get_descriptor(void)
418 __xdata
uint8_t descriptor_type
;
419 __xdata
uint8_t descriptor_index
;
421 descriptor_type
= (setup_data
.wValue
& 0xff00) >> 8;
422 descriptor_index
= setup_data
.wValue
& 0x00ff;
424 switch (descriptor_type
) {
425 case DESCRIPTOR_TYPE_DEVICE
:
426 SUDPTRH
= HI8(&device_descriptor
);
427 SUDPTRL
= LO8(&device_descriptor
);
429 case DESCRIPTOR_TYPE_CONFIGURATION
:
430 SUDPTRH
= HI8(&config_descriptor
);
431 SUDPTRL
= LO8(&config_descriptor
);
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]);
446 /* Unsupported descriptor type */
455 * Handle SET_INTERFACE request.
457 void usb_handle_set_interface(void)
459 /* Reset Data Toggle */
460 usb_reset_data_toggle(USB_DIR_IN
| 2);
461 usb_reset_data_toggle(USB_DIR_OUT
| 2);
463 /* Unstall & clear busy flag of all valid IN endpoints */
466 /* Unstall all valid OUT endpoints, reset bytecounts */
472 * Handle the arrival of a USB Control Setup Packet.
474 void usb_handle_setup_data(void)
476 switch (setup_data
.bRequest
) {
478 if (!usb_handle_get_status())
482 if (!usb_handle_clear_feature())
486 /* Reserved values */
490 if (!usb_handle_set_feature())
494 /* Handled by USB core */
497 /* Set Descriptor not supported. */
501 if (!usb_handle_get_descriptor())
504 case GET_CONFIGURATION
:
505 /* OpenULINK has only one configuration, return its index */
506 IN0BUF
[0] = config_descriptor
.bConfigurationValue
;
509 case SET_CONFIGURATION
:
510 /* OpenULINK has only one configuration -> nothing to do */
513 /* OpenULINK only has one interface, return its number */
514 IN0BUF
[0] = interface_descriptor00
.bInterfaceNumber
;
518 usb_handle_set_interface();
521 /* Isochronous endpoints not used -> nothing to do */
524 /* Any other requests: do nothing */
530 * USB initialization. Configures USB interrupts, endpoints and performs
535 /* Mark endpoint 2 IN & OUT as valid */
539 /* Make sure no isochronous endpoints are marked valid */
543 /* Disable isochronous endpoints. This makes the isochronous data buffers
544 * available as 8051 XDATA memory at address 0x2000 - 0x27FF */
547 /* Enable USB Autovectoring */
550 /* Enable SUDAV interrupt */
553 /* Enable EP2 OUT & IN interrupts */
557 /* Enable USB interrupt (EIE register) */
560 /* Perform ReNumeration */
561 USBCS
= DISCON
| RENUM
;
563 USBCS
= DISCOE
| RENUM
;