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