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