3e9bb5b39c4ddb153a4fdc29e77646475b304333
[fw/altos] / ao_usb.c
1 /*
2  * Copyright © 2009 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 #define AO_USB_CONTROL_EP       0
24 #define AO_USB_INT_EP           1
25 #define AO_USB_OUT_EP           4
26 #define AO_USB_IN_EP            5
27 #define AO_USB_CONTROL_SIZE     32
28 /*
29  * Double buffer IN and OUT EPs, so each
30  * gets half of the available space
31  */
32 #define AO_USB_IN_SIZE          256
33 #define AO_USB_OUT_SIZE         128
34
35 static uint16_t ao_usb_in_bytes;
36 static uint16_t ao_usb_out_bytes;
37 static __data uint8_t   ao_usb_iif;
38 static __data uint8_t   ao_usb_oif;
39
40 /* This interrupt is shared with port 2, 
41  * so when we hook that up, fix this
42  */
43 void
44 ao_usb_isr(void) interrupt 6
45 {
46         USBIF = 0;
47         ao_usb_iif |= USBIIF;
48         if (ao_usb_iif & 1)
49                 ao_wakeup(&ao_usb_task);
50         if (ao_usb_iif & (1 << AO_USB_IN_EP))
51                 ao_wakeup(&ao_usb_in_bytes);
52
53         ao_usb_oif |= USBOIF;
54         if (ao_usb_oif & (1 << AO_USB_OUT_EP))
55                 ao_wakeup(&ao_usb_out_bytes);
56 }
57
58 #define AO_USB_EP0_IDLE         0
59 #define AO_USB_EP0_DATA_IN      1
60 #define AO_USB_EP0_DATA_OUT     2
61
62 struct ao_usb_setup {
63         uint8_t         dir_type_recip;
64         uint8_t         request;
65         uint16_t        value;
66         uint16_t        index;
67         uint16_t        length;
68 } ao_usb_setup;
69
70 __data uint8_t ao_usb_ep0_state;
71 uint8_t * __data ao_usb_ep0_in_data;
72 __data uint8_t ao_usb_ep0_in_len;
73 __xdata uint8_t ao_usb_ep0_in_buf[2];
74 __data uint8_t ao_usb_ep0_out_len;
75 __xdata uint8_t *__data ao_usb_ep0_out_data;
76 __data uint8_t ao_usb_configuration;
77
78 /* Send an IN data packet */
79 static void
80 ao_usb_ep0_flush(void)
81 {
82         uint8_t this_len;
83         uint8_t cs0;
84         
85         USBINDEX = 0;
86         cs0 = USBCS0;
87         if (cs0 & USBCS0_INPKT_RDY)
88                 ao_panic(0);
89
90         this_len = ao_usb_ep0_in_len;
91         if (this_len > AO_USB_CONTROL_SIZE)
92                 this_len = AO_USB_CONTROL_SIZE;
93         cs0 = USBCS0_INPKT_RDY;
94         if (this_len != AO_USB_CONTROL_SIZE) {
95                 cs0 = USBCS0_INPKT_RDY | USBCS0_DATA_END;
96                 ao_usb_ep0_state = AO_USB_EP0_IDLE;
97         }
98         ao_usb_ep0_in_len -= this_len;
99         while (this_len--)
100                 USBFIFO[0] = *ao_usb_ep0_in_data++;
101         USBINDEX = 0;
102         USBCS0 = cs0;
103 }
104
105 #define LE_WORD(x)    ((x)&0xFF),((x)>>8)
106
107 /* CDC definitions */
108 #define CS_INTERFACE      0x24
109 #define CS_ENDPOINT       0x25
110
111 #define SET_LINE_CODING         0x20
112 #define GET_LINE_CODING         0x21
113 #define SET_CONTROL_LINE_STATE  0x22
114
115 /* Data structure for GET_LINE_CODING / SET_LINE_CODING class requests */
116 struct ao_usb_line_coding {
117         uint32_t        rate;
118         uint8_t         char_format;
119         uint8_t         parity;
120         uint8_t         data_bits;
121 } ;
122
123 static struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8};
124
125 /* USB descriptors in one giant block of bytes */
126 static const uint8_t ao_usb_descriptors [] = 
127 {
128         /* Device descriptor */
129         0x12,
130         AO_USB_DESC_DEVICE,
131         LE_WORD(0x0110),        /*  bcdUSB */
132         0x02,                   /*  bDeviceClass */
133         0x00,                   /*  bDeviceSubClass */
134         0x00,                   /*  bDeviceProtocol */
135         AO_USB_CONTROL_SIZE,    /*  bMaxPacketSize */
136         LE_WORD(0xFFFE),        /*  idVendor */
137         LE_WORD(0x000A),        /*  idProduct */
138         LE_WORD(0x0100),        /*  bcdDevice */
139         0x01,                   /*  iManufacturer */
140         0x02,                   /*  iProduct */
141         0x03,                   /*  iSerialNumber */
142         0x01,                   /*  bNumConfigurations */
143
144         /* Configuration descriptor */
145         0x09,
146         AO_USB_DESC_CONFIGURATION,
147         LE_WORD(67),            /*  wTotalLength */
148         0x02,                   /*  bNumInterfaces */
149         0x01,                   /*  bConfigurationValue */
150         0x00,                   /*  iConfiguration */
151         0xC0,                   /*  bmAttributes */
152         0x32,                   /*  bMaxPower */
153
154         /* Control class interface */
155         0x09,
156         AO_USB_DESC_INTERFACE,
157         0x00,                   /*  bInterfaceNumber */
158         0x00,                   /*  bAlternateSetting */
159         0x01,                   /*  bNumEndPoints */
160         0x02,                   /*  bInterfaceClass */
161         0x02,                   /*  bInterfaceSubClass */
162         0x01,                   /*  bInterfaceProtocol, linux requires value of 1 for the cdc_acm module */
163         0x00,                   /*  iInterface */
164
165         /* Header functional descriptor */
166         0x05,
167         CS_INTERFACE,
168         0x00,                   /*  bDescriptor SubType Header */
169         LE_WORD(0x0110),        /*  CDC version 1.1 */
170
171         /* Call management functional descriptor */
172         0x05,
173         CS_INTERFACE,
174         0x01,                   /* bDescriptor SubType Call Management */
175         0x01,                   /* bmCapabilities = device handles call management */
176         0x01,                   /* bDataInterface call management interface number */
177
178         /* ACM functional descriptor */
179         0x04,
180         CS_INTERFACE,
181         0x02,                   /* bDescriptor SubType Abstract Control Management */
182         0x02,                   /* bmCapabilities = D1 (Set_line_Coding, Set_Control_Line_State, Get_Line_Coding and Serial_State) */
183
184         /* Union functional descriptor */
185         0x05,
186         CS_INTERFACE,
187         0x06,                   /* bDescriptor SubType Union Functional descriptor */
188         0x00,                   /* bMasterInterface */
189         0x01,                   /* bSlaveInterface0 */
190
191         /* Notification EP */
192         0x07,
193         AO_USB_DESC_ENDPOINT,
194         AO_USB_INT_EP|0x80,     /* bEndpointAddress */
195         0x03,                   /* bmAttributes = intr */
196         LE_WORD(8),             /* wMaxPacketSize */
197         0x0A,                   /* bInterval */
198
199         /* Data class interface descriptor */
200         0x09,
201         AO_USB_DESC_INTERFACE,
202         0x01,                   /* bInterfaceNumber */
203         0x00,                   /* bAlternateSetting */
204         0x02,                   /* bNumEndPoints */
205         0x0A,                   /* bInterfaceClass = data */
206         0x00,                   /* bInterfaceSubClass */
207         0x00,                   /* bInterfaceProtocol */
208         0x00,                   /* iInterface */
209
210         /* Data EP OUT */
211         0x07,
212         AO_USB_DESC_ENDPOINT,
213         AO_USB_OUT_EP,          /* bEndpointAddress */
214         0x02,                   /* bmAttributes = bulk */
215         LE_WORD(AO_USB_OUT_SIZE),/* wMaxPacketSize */
216         0x00,                   /* bInterval */
217
218         /* Data EP in */
219         0x07,
220         AO_USB_DESC_ENDPOINT,
221         AO_USB_IN_EP|0x80,      /* bEndpointAddress */
222         0x02,                   /* bmAttributes = bulk */
223         LE_WORD(AO_USB_IN_SIZE),/* wMaxPacketSize */
224         0x00,                   /* bInterval */
225
226         /* String descriptors */
227         0x04,
228         AO_USB_DESC_STRING,
229         LE_WORD(0x0409),
230
231         /* iManufacturer */
232         0x20,
233         AO_USB_DESC_STRING,
234         'a', 0, 'l', 0, 't', 0, 'u', 0, 's', 0, 'm', 0, 'e', 0, 't', 0, 'r', 0, 'u', 0, 'm', 0, '.', 0, 'o', 0, 'r', 0, 'g', 0, 
235
236         /* iProduct */
237         0x16,
238         AO_USB_DESC_STRING,
239         'T', 0, 'e', 0, 'l', 0, 'e', 0, 'M', 0, 'e', 0, 't', 0, 'r', 0, 'u', 0, 'm', 0, 
240
241         /* iSerial */
242         0x0e,
243         AO_USB_DESC_STRING,
244         't', 0, 'e', 0, 'l', 0, 'e', 0, '-', 0, '0', 0, 
245
246         /* Terminating zero */
247         0
248 };
249
250 /* Walk through the list of descriptors and find a match
251  */
252 static void
253 ao_usb_get_descriptor(uint16_t value)
254 {
255         const uint8_t   *descriptor;
256         uint8_t         type = value >> 8;
257         uint8_t         index = value;
258
259         descriptor = ao_usb_descriptors;
260         while (descriptor[0] != 0) {
261                 if (descriptor[1] == type && index-- == 0) {
262                         if (type == AO_USB_DESC_CONFIGURATION)
263                                 ao_usb_ep0_in_len = descriptor[2];
264                         else
265                                 ao_usb_ep0_in_len = descriptor[0];
266                         ao_usb_ep0_in_data = descriptor;
267                         break;
268                 }
269                 descriptor += descriptor[0];
270         }
271 }
272
273 /* Read data from the ep0 OUT fifo
274  */
275 static void
276 ao_usb_ep0_fill(void)
277 {
278         uint8_t len;
279         
280         USBINDEX = 0;
281         len = USBCNT0;
282         if (len > ao_usb_ep0_out_len)
283                 len = ao_usb_ep0_out_len;
284         ao_usb_ep0_out_len -= len;
285         while (len--)
286                 *ao_usb_ep0_out_data++ = USBFIFO[0];
287 }
288
289 void
290 ao_usb_ep0_queue_byte(uint8_t a)
291 {
292         ao_usb_ep0_in_buf[ao_usb_ep0_in_len++] = a;
293 }
294
295 void
296 ao_usb_set_address(uint8_t address)
297 {
298         USBADDR = address | 0x80;
299         while (USBADDR & 0x80)
300                 ;
301 }
302
303 static void
304 ao_usb_set_configuration(void)
305 {
306         uint8_t size;
307
308         /* Set the IN max packet size, double buffered */
309         USBINDEX = AO_USB_IN_EP;
310         size = AO_USB_IN_SIZE >> 3;
311         USBMAXI = size;
312 //      USBCSIH |= USBCSIH_IN_DBL_BUF;
313
314         /* Set the OUT max packet size, double buffered */
315         USBINDEX = AO_USB_OUT_EP;
316         size = AO_USB_OUT_SIZE >> 3;
317         USBMAXO = size;
318 //      USBCSOH = USBCSOH_OUT_DBL_BUF;
319 }
320
321 static void
322 ao_usb_ep0_setup(void)
323 {
324         /* Pull the setup packet out of the fifo */
325         ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_setup;
326         ao_usb_ep0_out_len = 8;
327         ao_usb_ep0_fill();
328         if (ao_usb_ep0_out_len != 0)
329                 return;
330
331         /* Figure out how to ACK the setup packet */
332         if (ao_usb_setup.dir_type_recip & AO_USB_DIR_IN) {
333                 if (ao_usb_setup.length)
334                         ao_usb_ep0_state = AO_USB_EP0_DATA_IN;
335                 else
336                         ao_usb_ep0_state = AO_USB_EP0_IDLE;
337         } else {
338                 if (ao_usb_setup.length)
339                         ao_usb_ep0_state = AO_USB_EP0_DATA_OUT;
340                 else
341                         ao_usb_ep0_state = AO_USB_EP0_IDLE;
342         }
343         USBINDEX = 0;
344         if (ao_usb_ep0_state == AO_USB_EP0_IDLE)
345                 USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END;
346         else
347                 USBCS0 = USBCS0_CLR_OUTPKT_RDY;
348         
349         ao_usb_ep0_in_data = ao_usb_ep0_in_buf;
350         ao_usb_ep0_in_len = 0;
351         switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_TYPE_MASK) {
352         case AO_USB_TYPE_STANDARD:
353                 switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_RECIP_MASK) {
354                 case AO_USB_RECIP_DEVICE:
355                         switch(ao_usb_setup.request) {
356                         case AO_USB_REQ_GET_STATUS:
357                                 ao_usb_ep0_queue_byte(0);
358                                 ao_usb_ep0_queue_byte(0);
359                                 break;
360                         case AO_USB_REQ_SET_ADDRESS:
361                                 ao_usb_set_address(ao_usb_setup.value);
362                                 break;
363                         case AO_USB_REQ_GET_DESCRIPTOR:
364                                 ao_usb_get_descriptor(ao_usb_setup.value);
365                                 break;
366                         case AO_USB_REQ_GET_CONFIGURATION:
367                                 ao_usb_ep0_queue_byte(ao_usb_configuration);
368                                 break;
369                         case AO_USB_REQ_SET_CONFIGURATION:
370                                 ao_usb_configuration = ao_usb_setup.value;
371                                 ao_usb_set_configuration();
372                                 break;
373                         }
374                         break;
375                 case AO_USB_RECIP_INTERFACE:
376                         switch(ao_usb_setup.request) {
377                         case AO_USB_REQ_GET_STATUS:
378                                 ao_usb_ep0_queue_byte(0);
379                                 ao_usb_ep0_queue_byte(0);
380                                 break;
381                         case AO_USB_REQ_GET_INTERFACE:
382                                 ao_usb_ep0_queue_byte(0);
383                                 break;
384                         case AO_USB_REQ_SET_INTERFACE:
385                                 break;
386                         }
387                         break;
388                 case AO_USB_RECIP_ENDPOINT:
389                         switch(ao_usb_setup.request) {
390                         case AO_USB_REQ_GET_STATUS:
391                                 ao_usb_ep0_queue_byte(0);
392                                 ao_usb_ep0_queue_byte(0);
393                                 break;
394                         }
395                         break;
396                 }
397                 break;
398         case AO_USB_TYPE_CLASS:
399                 switch (ao_usb_setup.request) {
400                 case SET_LINE_CODING:
401                         ao_usb_ep0_out_len = 7;
402                         ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_line_coding;
403                         break;
404                 case GET_LINE_CODING:
405                         ao_usb_ep0_in_len = 7;
406                         ao_usb_ep0_in_data = (uint8_t *) &ao_usb_line_coding;
407                         break;
408                 case SET_CONTROL_LINE_STATE:
409                         break;
410                 }
411                 break;
412         }
413         if (ao_usb_ep0_state != AO_USB_EP0_DATA_OUT) {
414                 if (ao_usb_setup.length < ao_usb_ep0_in_len)
415                         ao_usb_ep0_in_len = ao_usb_setup.length;
416                 ao_usb_ep0_flush();
417         }
418 }
419
420 /* End point 0 receives all of the control messages. */
421 static void
422 ao_usb_ep0(void)
423 {
424         uint8_t cs0;
425
426         ao_usb_ep0_state = AO_USB_EP0_IDLE;
427         for (;;) {
428                 ao_interrupt_disable();
429                 for (;;) {
430                         if (ao_usb_iif & 1) {
431                                 ao_usb_iif &= ~1;
432                                 break;
433                         }
434                         ao_sleep(&ao_usb_task);
435                 }
436                 ao_interrupt_enable();
437                 USBINDEX = 0;
438                 cs0 = USBCS0;
439                 if (cs0 & USBCS0_SETUP_END) {
440                         ao_usb_ep0_state = AO_USB_EP0_IDLE;
441                         USBCS0 = USBCS0_CLR_SETUP_END;
442                 }
443                 if (cs0 & USBCS0_SENT_STALL) {
444                         ao_usb_ep0_state = AO_USB_EP0_IDLE;
445                         USBCS0 &= ~USBCS0_SENT_STALL;
446                 }
447                 if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN &&
448                     (cs0 & USBCS0_INPKT_RDY) == 0)
449                 {
450                         ao_usb_ep0_flush();
451                 }
452                 if (cs0 & USBCS0_OUTPKT_RDY) {
453                         switch (ao_usb_ep0_state) {
454                         case AO_USB_EP0_IDLE:
455                                 ao_usb_ep0_setup();
456                                 break;
457                         case AO_USB_EP0_DATA_OUT:
458                                 ao_usb_ep0_fill();
459                                 if (ao_usb_ep0_out_len == 0)
460                                         ao_usb_ep0_state = AO_USB_EP0_IDLE;
461                                 USBINDEX = 0;
462                                 if (ao_usb_ep0_state == AO_USB_EP0_IDLE)
463                                         USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END;
464                                 else
465                                         USBCS0 = USBCS0_CLR_OUTPKT_RDY;
466                                 break;
467                         }
468                 }
469         }
470 }
471
472 void
473 ao_usb_flush(void)
474 {
475         ao_interrupt_disable();
476         if (ao_usb_in_bytes) {
477                 USBINDEX = AO_USB_IN_EP;
478                 USBCSIL |= USBCSIL_INPKT_RDY;
479                 ao_usb_in_bytes = 0;
480         }
481         ao_interrupt_enable();
482 }
483
484 void
485 ao_usb_putchar(uint8_t c)
486 {
487         ao_interrupt_disable();
488         for (;;) {
489                 USBINDEX = AO_USB_IN_EP;
490                 if ((USBCSIL & USBCSIL_INPKT_RDY) == 0)
491                         break;
492                 ao_sleep(&ao_usb_in_bytes);
493         }
494         USBFIFO[AO_USB_IN_EP << 1] = c;
495         if (++ao_usb_in_bytes == AO_USB_IN_SIZE)
496                 ao_usb_flush();
497         ao_interrupt_enable();
498 }
499
500 uint8_t
501 ao_usb_getchar(void)
502 {
503         uint8_t c;
504         ao_interrupt_disable();
505         while (ao_usb_out_bytes == 0) {
506                 for (;;) {
507                         USBINDEX = AO_USB_OUT_EP;
508                         if ((USBCSOL & USBCSOL_OUTPKT_RDY) != 0)
509                                 break;
510                         ao_sleep(&ao_usb_out_bytes);
511                 }
512                 ao_usb_out_bytes = (USBCNTH << 8) | USBCNTL;
513         }
514         --ao_usb_out_bytes;
515         c = USBFIFO[AO_USB_OUT_EP << 1];
516         if (ao_usb_out_bytes == 0) {
517                 USBINDEX = AO_USB_OUT_EP;
518                 USBCSOL &= ~USBCSOL_OUTPKT_RDY;
519         }
520         ao_interrupt_enable();
521         return c;
522 }
523
524 void
525 ao_usb_init(void)
526 {
527         /* Turn on the USB controller */
528         SLEEP |= SLEEP_USB_EN;
529
530         ao_usb_set_configuration();
531         
532         /* IN interrupts on the control an IN endpoints */
533         USBIIE = (1 << AO_USB_CONTROL_EP) | (1 << AO_USB_IN_EP);
534
535         /* OUT interrupts on the OUT endpoint */
536         USBOIE = (1 << AO_USB_OUT_EP);
537
538         /* Ignore control interrupts */
539         USBCIE = 0;
540         
541         /* enable USB interrupts */
542         IEN2 |= IEN2_USBIE;
543
544         /* Clear any pending interrupts */
545         USBCIF = 0;
546         USBOIF = 0;
547         USBIIF = 0;
548         
549         ao_add_task(&ao_usb_task, ao_usb_ep0);
550 }