src-avr: USB work in progress
[fw/altos] / src-avr / ao_usb_avr.c
1 /*
2  * Copyright © 2011 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include "ao.h"
19 #include "ao_usb.h"
20
21 struct ao_task __xdata ao_usb_task;
22
23 struct ao_usb_setup {
24         uint8_t         dir_type_recip;
25         uint8_t         request;
26         uint16_t        value;
27         uint16_t        index;
28         uint16_t        length;
29 } __xdata ao_usb_setup;
30
31 static __xdata uint8_t  ao_usb_ep0_state;
32 static const uint8_t * __xdata ao_usb_ep0_in_data;
33 static __xdata uint8_t  ao_usb_ep0_in_len;
34 static __xdata uint8_t  ao_usb_ep0_in_pending;
35 static __xdata uint8_t  ao_usb_ep0_in_buf[2];
36 static __xdata uint8_t  ao_usb_ep0_out_len;
37 static __xdata uint8_t *__xdata ao_usb_ep0_out_data;
38
39 static __xdata uint8_t  ao_usb_in_flushed;
40 static __xdata uint8_t  ao_usb_running;
41 static __xdata uint8_t  ao_usb_configuration;
42
43 void
44 ao_usb_set_address(uint8_t address)
45 {
46         UDADDR = (0 << ADDEN) | address;
47         ao_usb_running = 1;
48 }
49
50 #define EP_SIZE(s)      ((s) == 64 ? 0x30 :     \
51                         ((s) == 32 ? 0x20 :     \
52                         ((s) == 16 ? 0x10 :     \
53                                      0x00)))
54
55 static void
56 ao_usb_dump_ep(uint8_t ep)
57 {
58         UENUM = ep;
59         printf ("EP %d: UECONX %02x UECFG0X %02x UECFG1X %02x UEIENX %02x UESTA0X %02x UESTA1X %02X\n",
60                 ep, UECONX, UECFG0X, UECFG1X, UEIENX, UESTA0X, UESTA1X);
61 }
62
63 static void
64 ao_usb_set_ep0(void)
65 {
66         printf ("set_ep0\n");
67         /* Set the CONTROL max packet size, single buffered */
68         UENUM = 0;
69         UECONX = (1 << EPEN);                                   /* Enable */
70
71         UECFG0X = ((0 << EPTYPE0) |                             /* Control */
72                    (0 << EPDIR));                               /* Out (ish) */
73
74         UECFG1X = (EP_SIZE(AO_USB_CONTROL_SIZE) |               /* Size */
75                    (0 << EPBK0) |                               /* Single bank */
76                    (1 << ALLOC));
77
78         UEIENX = ((1 << RXSTPE) |                               /* Enable SETUP interrupt */
79                   (1 << RXOUTE) |                               /* Enable OUT interrupt */
80                   (1 << TXINE));                                /* Enable IN complete interrupt */
81
82         ao_usb_dump_ep(0);
83 }
84
85 static void
86 ao_usb_set_configuration(void)
87 {
88         /* Set the IN max packet size, double buffered */
89         UENUM = AO_USB_IN_EP;
90         UECONX = (1 << EPEN);                                   /* Enable */
91
92         UECFG0X = ((2 << EPTYPE0) |                             /* Bulk */
93                    (1 << EPDIR));                               /* In */
94
95         UECFG1X = (EP_SIZE(AO_USB_IN_SIZE) |                    /* Size */
96                    (1 << EPBK0) |                               /* Double bank */
97                    (1 << ALLOC));                               /* Allocate */
98
99         UEIENX = ((1 << TXINE));                                /* Enable IN complete interrupt */
100
101         ao_usb_dump_ep(AO_USB_IN_EP);
102
103         /* Set the OUT max packet size, double buffered */
104         UENUM = AO_USB_OUT_EP;
105         UECONX |= (1 << EPEN);                                  /* Enable */
106
107         UECFG0X = ((2 << EPTYPE0) |                             /* Bulk */
108                    (0 << EPDIR));                               /* Out */
109
110         UECFG1X = (EP_SIZE(AO_USB_OUT_SIZE) |                   /* Size */
111                    (1 << EPBK0) |                               /* Double bank */
112                    (1 << ALLOC));                               /* Allocate */
113
114         UEIENX = ((1 << RXOUTE));                               /* Enable OUT complete interrupt */
115
116         ao_usb_dump_ep(AO_USB_OUT_EP);
117 }
118
119 ISR(USB_GEN_vect)
120 {
121         ao_wakeup(&ao_usb_task);
122 }
123
124
125 __xdata static struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8};
126
127 /* Walk through the list of descriptors and find a match
128  */
129 static void
130 ao_usb_get_descriptor(uint16_t value)
131 {
132         const uint8_t           *__xdata descriptor;
133         __xdata uint8_t         type = value >> 8;
134         __xdata uint8_t         index = value;
135
136         descriptor = ao_usb_descriptors;
137         while (descriptor[0] != 0) {
138                 if (descriptor[1] == type && index-- == 0) {
139                         if (type == AO_USB_DESC_CONFIGURATION)
140                                 ao_usb_ep0_in_len = descriptor[2];
141                         else
142                                 ao_usb_ep0_in_len = descriptor[0];
143                         ao_usb_ep0_in_data = descriptor;
144                         break;
145                 }
146                 descriptor += descriptor[0];
147         }
148 }
149
150 /* Send an IN data packet */
151 static void
152 ao_usb_ep0_flush(void)
153 {
154         __xdata uint8_t this_len;
155
156         /* If the IN packet hasn't been picked up, just return */
157         UENUM = 0;
158         if (!(UEINTX & (1 << TXINI)))
159                 return;
160
161         this_len = ao_usb_ep0_in_len;
162         if (this_len > AO_USB_CONTROL_SIZE)
163                 this_len = AO_USB_CONTROL_SIZE;
164
165         ao_usb_ep0_in_len -= this_len;
166
167         /* Set IN interrupt enable */
168         if (ao_usb_ep0_in_len == 0 && this_len != AO_USB_CONTROL_SIZE) {
169                 ao_usb_ep0_in_pending = 0;
170                 UEIENX = ((1 << RXSTPE) | (1 << RXOUTE));                       /* Disable IN interrupt */
171         } else {
172                 ao_usb_ep0_in_pending = 1;
173                 UEIENX = ((1 << RXSTPE) | (1 << RXOUTE) | (1 << TXINE));        /* Enable IN interrupt */
174         }
175
176         printf ("Flush EP0 len %d:", this_len);
177         while (this_len--) {
178                 uint8_t c = *ao_usb_ep0_in_data++;
179                 printf(" %02x", c);
180                 UEDATX = c;
181         }
182         printf ("\n");
183
184         /* Clear the TXINI bit to send the packet */
185         UEINTX = ~(1 << TXINI);
186 }
187
188 /* Read data from the ep0 OUT fifo */
189 static void
190 ao_usb_ep0_fill(uint8_t len)
191 {
192         if (len > ao_usb_ep0_out_len)
193                 len = ao_usb_ep0_out_len;
194         ao_usb_ep0_out_len -= len;
195
196         printf ("EP0 UEINTX %02x UEBCLX %d UEBCHX %d\n",
197                 UEINTX, UEBCLX, UEBCHX);
198         /* Pull all of the data out of the packet */
199         printf ("Fill EP0 len %d:", len);
200         UENUM = 0;
201         while (len--) {
202                 uint8_t c = UEDATX;
203                 *ao_usb_ep0_out_data++ = c;
204                 printf (" %02x", c);
205         }
206         printf ("\n");
207 }
208
209 void
210 ao_usb_ep0_queue_byte(uint8_t a)
211 {
212         ao_usb_ep0_in_buf[ao_usb_ep0_in_len++] = a;
213 }
214
215 static void
216 ao_usb_ep0_setup(void)
217 {
218         /* Pull the setup packet out of the fifo */
219         ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_setup;
220         ao_usb_ep0_out_len = 8;
221         ao_usb_ep0_fill(8);
222
223         /* ACK packet */
224         UENUM = 0;
225         UEINTX = ~(1 << RXSTPI);
226         if (ao_usb_ep0_out_len != 0) {
227                 printf ("invalid setup packet length\n");
228                 return;
229         }
230
231         /* Figure out how to ACK the setup packet */
232         if (ao_usb_setup.dir_type_recip & AO_USB_DIR_IN) {
233                 if (ao_usb_setup.length)
234                         ao_usb_ep0_state = AO_USB_EP0_DATA_IN;
235                 else
236                         ao_usb_ep0_state = AO_USB_EP0_IDLE;
237         } else {
238                 if (ao_usb_setup.length)
239                         ao_usb_ep0_state = AO_USB_EP0_DATA_OUT;
240                 else
241                         ao_usb_ep0_state = AO_USB_EP0_IDLE;
242         }
243 /*
244         UENUM = 0;
245         if (ao_usb_ep0_state == AO_USB_EP0_IDLE)
246                 USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END;
247         else
248                 USBCS0 = USBCS0_CLR_OUTPKT_RDY;
249 */
250
251         ao_usb_ep0_in_data = ao_usb_ep0_in_buf;
252         ao_usb_ep0_in_len = 0;
253         switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_TYPE_MASK) {
254         case AO_USB_TYPE_STANDARD:
255                 printf ("Standard setup packet\n");
256                 switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_RECIP_MASK) {
257                 case AO_USB_RECIP_DEVICE:
258                         printf ("Device setup packet\n");
259                         switch(ao_usb_setup.request) {
260                         case AO_USB_REQ_GET_STATUS:
261                                 printf ("get status\n");
262                                 ao_usb_ep0_queue_byte(0);
263                                 ao_usb_ep0_queue_byte(0);
264                                 break;
265                         case AO_USB_REQ_SET_ADDRESS:
266                                 printf ("set address %d\n", ao_usb_setup.value);
267                                 ao_usb_set_address(ao_usb_setup.value);
268                                 break;
269                         case AO_USB_REQ_GET_DESCRIPTOR:
270                                 printf ("get descriptor %d\n", ao_usb_setup.value);
271                                 ao_usb_get_descriptor(ao_usb_setup.value);
272                                 break;
273                         case AO_USB_REQ_GET_CONFIGURATION:
274                                 printf ("get configuration %d\n", ao_usb_configuration);
275                                 ao_usb_ep0_queue_byte(ao_usb_configuration);
276                                 break;
277                         case AO_USB_REQ_SET_CONFIGURATION:
278                                 ao_usb_configuration = ao_usb_setup.value;
279                                 printf ("set configuration %d\n", ao_usb_configuration);
280                                 ao_usb_set_configuration();
281                                 break;
282                         }
283                         break;
284                 case AO_USB_RECIP_INTERFACE:
285 #ifndef AVR
286                         #pragma disable_warning 110
287 #endif
288                         printf ("Interface setup packet\n");
289                         switch(ao_usb_setup.request) {
290                         case AO_USB_REQ_GET_STATUS:
291                                 ao_usb_ep0_queue_byte(0);
292                                 ao_usb_ep0_queue_byte(0);
293                                 break;
294                         case AO_USB_REQ_GET_INTERFACE:
295                                 ao_usb_ep0_queue_byte(0);
296                                 break;
297                         case AO_USB_REQ_SET_INTERFACE:
298                                 break;
299                         }
300                         break;
301                 case AO_USB_RECIP_ENDPOINT:
302                         printf ("Endpoint setup packet\n");
303                         switch(ao_usb_setup.request) {
304                         case AO_USB_REQ_GET_STATUS:
305                                 ao_usb_ep0_queue_byte(0);
306                                 ao_usb_ep0_queue_byte(0);
307                                 break;
308                         }
309                         break;
310                 }
311                 break;
312         case AO_USB_TYPE_CLASS:
313                 printf ("Class setup packet\n");
314                 switch (ao_usb_setup.request) {
315                 case SET_LINE_CODING:
316                         printf ("set line coding\n");
317                         ao_usb_ep0_out_len = 7;
318                         ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_line_coding;
319                         break;
320                 case GET_LINE_CODING:
321                         printf ("get line coding\n");
322                         ao_usb_ep0_in_len = 7;
323                         ao_usb_ep0_in_data = (uint8_t *) &ao_usb_line_coding;
324                         break;
325                 case SET_CONTROL_LINE_STATE:
326                         break;
327                 }
328                 break;
329         }
330         if (ao_usb_ep0_state != AO_USB_EP0_DATA_OUT) {
331                 if (ao_usb_setup.length < ao_usb_ep0_in_len)
332                         ao_usb_ep0_in_len = ao_usb_setup.length;
333                 printf ("Start ep0 in delivery\n");
334                 ao_usb_ep0_flush();
335         }
336 }
337
338 /* End point 0 receives all of the control messages. */
339 static void
340 ao_usb_ep0(void)
341 {
342         uint8_t intx, udint;
343
344         printf ("usb task started\n");
345         ao_usb_ep0_state = AO_USB_EP0_IDLE;
346         for (;;) {
347                 cli();
348                 for (;;) {
349                         udint = UDINT;
350                         UDINT = 0;
351 //                      printf ("UDINT %02x\n", udint);
352                         if (udint & (1 << EORSTI)) {
353                                 ao_usb_configuration = 0;
354                                 ao_usb_set_ep0();
355                         }
356                         UENUM = 0;
357                         intx = UEINTX;
358 //                      printf ("UEINTX %02x\n", intx);
359                         if (intx & ((1 << RXSTPI) | (1 << RXOUTI) | (1 << TXINI)))
360                                 break;
361                         printf ("usb task sleeping...\n");
362                         ao_sleep(&ao_usb_task);
363                 }
364                 sei();
365                 printf ("UEINTX for ep0 is %02x\n", intx);
366                 if (intx & (1 << RXSTPI)) {
367                         ao_usb_ep0_setup();
368                 }
369                 if (intx & (1 << RXOUTI)) {
370                         ao_usb_ep0_fill(UEBCLX);
371                         UENUM = 0;
372                         UEINTX = ~(1 << RXOUTI);
373                         ao_usb_ep0_flush();
374                 }
375                 if (intx & (1 << TXINI) && ao_usb_ep0_in_pending) {
376                         UDADDR |= (1 << ADDEN);
377                         printf ("continue sending ep0 IN data\n");
378                         ao_usb_ep0_flush();
379                 }
380         }
381 }
382
383 /* Wait for a free IN buffer */
384 static void
385 ao_usb_in_wait(void)
386 {
387         for (;;) {
388                 UENUM = AO_USB_IN_EP;
389                 if (UEINTX & (1 << RWAL))
390                         break;
391                 for (;;) {
392                         UENUM = AO_USB_IN_EP;
393                         if ((UEINTX & (1 << TXINI)))
394                                 break;
395                         ao_sleep(&ao_usb_in_flushed);
396                 }
397                 UEINTX = ~(1 << TXINI);
398         }
399 }
400
401 static void
402 ao_usb_in_send(void)
403 {
404         UENUM = AO_USB_IN_EP;
405         UEINTX = (uint8_t) ~(1 << FIFOCON);
406 }
407
408 void
409 ao_usb_flush(void) __critical
410 {
411         if (!ao_usb_running)
412                 return;
413
414         /* If there are pending bytes, or if the last packet was full,
415          * send another IN packet
416          */
417         if (!ao_usb_in_flushed) {
418                 ao_usb_in_flushed = 1;
419                 ao_usb_in_wait();
420                 ao_usb_in_send();
421         }
422 }
423
424 void
425 ao_usb_putchar(char c) __critical __reentrant
426 {
427         if (!ao_usb_running)
428                 return;
429
430         ao_usb_in_flushed = 0;
431
432         /* Queue a byte */
433         UENUM = AO_USB_IN_EP;
434         UEDATX = c;
435
436         /* Send the packet when full */
437         if ((UEINTX & (1 << RWAL)) == 0)
438                 ao_usb_in_send();
439 }
440
441 static char
442 _ao_usb_pollchar(void)
443 {
444         char c;
445
446         UENUM = AO_USB_OUT_EP;
447         while ((UEINTX & (1 << RWAL)) == 0) {
448
449                 /* Ack the last packet */
450                 UEINTX = (uint8_t) ~(1 << FIFOCON);
451
452                 /* Check to see if a packet has arrived */
453                 if ((UEINTX & (1 << RXOUTI)) == 0)
454                         return AO_READ_AGAIN;
455
456                 /* Ack the interrupt */
457                 UEINTX = ~(1 << RXOUTI);
458         }
459
460         /* Pull a character out of the fifo */
461         c = UEDATX;
462         return c;
463 }
464
465 char
466 ao_usb_pollchar(void)
467 {
468         char    c;
469         cli();
470         c = _ao_usb_pollchar();
471         sei();
472         return c;
473 }
474
475 char
476 ao_usb_getchar(void) __critical
477 {
478         char    c;
479
480         cli();
481         while ((c = ao_usb_pollchar()) == AO_READ_AGAIN)
482                 ao_sleep(&ao_stdin_ready);
483         sei();
484         return c;
485 }
486
487 /* Endpoint interrupt */
488 ISR(USB_COM_vect)
489 {
490         uint8_t i = UEINT;
491
492         ao_led_toggle(AO_LED_RED);
493         UEINT = 0;
494         if (i & (1 << 0))
495                 ao_wakeup(&ao_usb_task);
496         if (i & (1 << AO_USB_IN_EP))
497                 ao_wakeup(&ao_usb_in_flushed);
498         if (i & (1 << AO_USB_OUT_EP))
499                 ao_wakeup(&ao_stdin_ready);
500 }
501
502 #if AVR_VCC_5V
503 #define AO_PAD_REGULATOR_INIT   (1 << UVREGE)   /* Turn on pad regulator */
504 #endif
505 #if AVR_VCC_3V3
506 #define AO_PAD_REGULATOR_INIT   0               /* Turn off pad regulator */
507 #endif
508
509 #if AVR_CLOCK == 16000000UL
510 #define AO_USB_PLL_INPUT_PRESCALER      (1 << PINDIV)   /* Divide 16MHz clock by 2 */
511 #endif
512 #if AVR_CLOCK == 8000000UL
513 #define AO_USB_PLL_INPUT_PRESCALER      0               /* Don't divide clock */
514 #endif
515
516 void
517 ao_usb_disable(void)
518 {
519         /* Unplug from the bus */
520         UDCON = (1 << DETACH);
521
522         /* Disable the interface */
523         USBCON = 0;
524
525         /* Disable the PLL */
526         PLLCSR = 0;
527
528         /* Turn off the pad regulator */
529         UHWCON = 0;
530 }
531
532 #define AO_USB_CON ((1 << USBE) |       /* USB enable */ \
533                     (0 << RSTCPU) |     /* do not reset CPU */  \
534                     (0 << LSM) |        /* Full speed mode */   \
535                     (0 << RMWKUP))      /* no remote wake-up */ \
536
537 void
538 ao_usb_enable(void)
539 {
540         /* Configure pad regulator */
541         UHWCON = AO_PAD_REGULATOR_INIT;
542
543         /* Enable USB device, but freeze the clocks until initialized */
544         USBCON = AO_USB_CON | (1 <<FRZCLK);
545
546         /* Enable PLL with appropriate divider */
547         PLLCSR = AO_USB_PLL_INPUT_PRESCALER | (1 << PLLE);
548
549         /* Wait for PLL to lock */
550         loop_until_bit_is_set(PLLCSR, (1 << PLOCK));
551
552         /* Enable USB, enable the VBUS pad */
553         USBCON = AO_USB_CON | (1 << OTGPADE);
554
555         /* Enable global interrupts */
556         UDIEN = (1 << EORSTE);          /* End of reset interrupt */
557
558         ao_usb_configuration = 0;
559
560         printf ("ao_usb_enable\n");
561
562         UDCON = (0 << DETACH);  /* Clear the DETACH bit to plug into the bus */
563 }
564
565 void
566 ao_usb_init(void)
567 {
568         ao_usb_enable();
569
570         printf ("ao_usb_init\n");
571         ao_add_task(&ao_usb_task, ao_usb_ep0, "usb");
572 //      ao_add_stdio(ao_usb_pollchar, ao_usb_putchar, ao_usb_flush);
573 }