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