USB working up through reading strings
[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_ep0_setup(void)
305 {
306         /* Pull the setup packet out of the fifo */
307         ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_setup;
308         ao_usb_ep0_out_len = 8;
309         ao_usb_ep0_fill();
310         if (ao_usb_ep0_out_len != 0)
311                 return;
312
313         /* Figure out how to ACK the setup packet */
314         if (ao_usb_setup.dir_type_recip & AO_USB_DIR_IN) {
315                 if (ao_usb_setup.length)
316                         ao_usb_ep0_state = AO_USB_EP0_DATA_IN;
317                 else
318                         ao_usb_ep0_state = AO_USB_EP0_IDLE;
319         } else {
320                 if (ao_usb_setup.length)
321                         ao_usb_ep0_state = AO_USB_EP0_DATA_OUT;
322                 else
323                         ao_usb_ep0_state = AO_USB_EP0_IDLE;
324         }
325         USBINDEX = 0;
326         if (ao_usb_ep0_state == AO_USB_EP0_IDLE)
327                 USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END;
328         else
329                 USBCS0 = USBCS0_CLR_OUTPKT_RDY;
330         
331         ao_usb_ep0_in_data = ao_usb_ep0_in_buf;
332         ao_usb_ep0_in_len = 0;
333         switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_TYPE_MASK) {
334         case AO_USB_TYPE_STANDARD:
335                 switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_RECIP_MASK) {
336                 case AO_USB_RECIP_DEVICE:
337                         switch(ao_usb_setup.request) {
338                         case AO_USB_REQ_GET_STATUS:
339                                 ao_usb_ep0_queue_byte(0);
340                                 ao_usb_ep0_queue_byte(0);
341                                 break;
342                         case AO_USB_REQ_SET_ADDRESS:
343                                 ao_usb_set_address(ao_usb_setup.value);
344                                 break;
345                         case AO_USB_REQ_GET_DESCRIPTOR:
346                                 ao_usb_get_descriptor(ao_usb_setup.value);
347                                 break;
348                         case AO_USB_REQ_GET_CONFIGURATION:
349                                 ao_usb_ep0_queue_byte(ao_usb_configuration);
350                                 break;
351                         case AO_USB_REQ_SET_CONFIGURATION:
352                                 ao_usb_configuration = ao_usb_setup.value;
353                                 break;
354                         }
355                         break;
356                 case AO_USB_RECIP_INTERFACE:
357                         switch(ao_usb_setup.request) {
358                         case AO_USB_REQ_GET_STATUS:
359                                 ao_usb_ep0_queue_byte(0);
360                                 ao_usb_ep0_queue_byte(0);
361                                 break;
362                         case AO_USB_REQ_GET_INTERFACE:
363                                 ao_usb_ep0_queue_byte(0);
364                                 break;
365                         case AO_USB_REQ_SET_INTERFACE:
366                                 break;
367                         }
368                         break;
369                 case AO_USB_RECIP_ENDPOINT:
370                         switch(ao_usb_setup.request) {
371                         case AO_USB_REQ_GET_STATUS:
372                                 ao_usb_ep0_queue_byte(0);
373                                 ao_usb_ep0_queue_byte(0);
374                                 break;
375                         }
376                         break;
377                 }
378                 break;
379         case AO_USB_TYPE_CLASS:
380                 switch (ao_usb_setup.request) {
381                 case SET_LINE_CODING:
382                         ao_usb_ep0_out_len = 7;
383                         ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_line_coding;
384                         break;
385                 case GET_LINE_CODING:
386                         ao_usb_ep0_in_len = 7;
387                         ao_usb_ep0_in_data = (uint8_t *) &ao_usb_line_coding;
388                         break;
389                 case SET_CONTROL_LINE_STATE:
390                         break;
391                 }
392                 break;
393         }
394         if (ao_usb_ep0_state != AO_USB_EP0_DATA_OUT) {
395                 if (ao_usb_setup.length < ao_usb_ep0_in_len)
396                         ao_usb_ep0_in_len = ao_usb_setup.length;
397                 ao_usb_ep0_flush();
398         }
399 }
400
401 /* End point 0 receives all of the control messages. */
402 static void
403 ao_usb_ep0(void)
404 {
405         uint8_t cs0;
406
407         ao_usb_ep0_state = AO_USB_EP0_IDLE;
408         for (;;) {
409                 ao_interrupt_disable();
410                 for (;;) {
411                         if (ao_usb_iif & 1) {
412                                 ao_usb_iif &= ~1;
413                                 break;
414                         }
415                         ao_sleep(&ao_usb_task);
416                 }
417                 ao_interrupt_enable();
418                 USBINDEX = 0;
419                 cs0 = USBCS0;
420                 if (cs0 & USBCS0_SETUP_END) {
421                         ao_usb_ep0_state = AO_USB_EP0_IDLE;
422                         USBCS0 = USBCS0_CLR_SETUP_END;
423                 }
424                 if (cs0 & USBCS0_SENT_STALL) {
425                         ao_usb_ep0_state = AO_USB_EP0_IDLE;
426                         USBCS0 &= ~USBCS0_SENT_STALL;
427                 }
428                 if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN &&
429                     (cs0 & USBCS0_INPKT_RDY) == 0)
430                 {
431                         ao_usb_ep0_flush();
432                 }
433                 if (cs0 & USBCS0_OUTPKT_RDY) {
434                         switch (ao_usb_ep0_state) {
435                         case AO_USB_EP0_IDLE:
436                                 ao_usb_ep0_setup();
437                                 break;
438                         case AO_USB_EP0_DATA_OUT:
439                                 ao_usb_ep0_fill();
440                                 if (ao_usb_ep0_out_len == 0)
441                                         ao_usb_ep0_state = AO_USB_EP0_IDLE;
442                                 USBINDEX = 0;
443                                 if (ao_usb_ep0_state == AO_USB_EP0_IDLE)
444                                         USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END;
445                                 else
446                                         USBCS0 = USBCS0_CLR_OUTPKT_RDY;
447                                 break;
448                         }
449                 }
450         }
451 }
452
453 void
454 ao_usb_flush(void)
455 {
456         ao_interrupt_disable();
457         if (ao_usb_in_bytes) {
458                 USBINDEX = AO_USB_IN_EP;
459                 USBCSIL |= USBCSIL_INPKT_RDY;
460                 ao_usb_in_bytes = 0;
461         }
462         ao_interrupt_enable();
463 }
464
465 void
466 ao_usb_putchar(uint8_t c)
467 {
468         ao_interrupt_disable();
469         for (;;) {
470                 USBINDEX = AO_USB_IN_EP;
471                 if ((USBCSIL & USBCSIL_INPKT_RDY) == 0)
472                         break;
473                 ao_sleep(&ao_usb_in_bytes);
474         }
475         USBFIFO[AO_USB_IN_EP << 1] = c;
476         if (++ao_usb_in_bytes == AO_USB_IN_SIZE)
477                 ao_usb_flush();
478         ao_interrupt_enable();
479 }
480
481 uint8_t
482 ao_usb_getchar(void)
483 {
484         uint8_t c;
485         ao_interrupt_disable();
486         while (ao_usb_out_bytes == 0) {
487                 for (;;) {
488                         USBINDEX = AO_USB_OUT_EP;
489                         if ((USBCSOL & USBCSOL_OUTPKT_RDY) != 0)
490                                 break;
491                         ao_sleep(&ao_usb_out_bytes);
492                 }
493                 ao_usb_out_bytes = (USBCNTH << 8) | USBCNTL;
494         }
495         --ao_usb_out_bytes;
496         c = USBFIFO[AO_USB_OUT_EP << 1];
497         ao_interrupt_enable();
498         return c;
499 }
500
501 void
502 ao_usb_init(void)
503 {
504         /* Turn on the USB controller */
505         SLEEP |= SLEEP_USB_EN;
506
507         /* Set the IN max packet size, double buffered */
508         USBINDEX = AO_USB_IN_EP;
509         USBMAXI = AO_USB_IN_SIZE >> 3;
510         USBCSIH |= USBCSIH_IN_DBL_BUF;
511
512         /* Set the OUT max packet size, double buffered */
513         USBINDEX = AO_USB_OUT_EP;
514         USBMAXO = AO_USB_OUT_SIZE >> 3;
515         USBCSOH = USBCSOH_OUT_DBL_BUF;
516         
517         /* IN interrupts on the control an IN endpoints */
518         USBIIE = (1 << AO_USB_CONTROL_EP) | (1 << AO_USB_IN_EP);
519
520         /* OUT interrupts on the OUT endpoint */
521         USBOIE = (1 << AO_USB_OUT_EP);
522
523         /* Ignore control interrupts */
524         USBCIE = 0;
525         
526         /* enable USB interrupts */
527         IEN2 |= IEN2_USBIE;
528
529         /* Clear any pending interrupts */
530         USBCIF = 0;
531         USBOIF = 0;
532         USBIIF = 0;
533         
534         ao_add_task(&ao_usb_task, ao_usb_ep0);
535 }