2 * Copyright © 2009 Keith Packard <keithp@keithp.com>
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.
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.
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.
21 struct ao_task __xdata ao_usb_task;
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
29 * Double buffer IN and OUT EPs, so each
30 * gets half of the available space
32 #define AO_USB_IN_SIZE 256
33 #define AO_USB_OUT_SIZE 128
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;
40 /* This interrupt is shared with port 2,
41 * so when we hook that up, fix this
44 ao_usb_isr(void) interrupt 6
49 ao_wakeup(&ao_usb_task);
50 if (ao_usb_iif & (1 << AO_USB_IN_EP))
51 ao_wakeup(&ao_usb_in_bytes);
54 if (ao_usb_oif & (1 << AO_USB_OUT_EP))
55 ao_wakeup(&ao_usb_out_bytes);
58 #define AO_USB_EP0_IDLE 0
59 #define AO_USB_EP0_DATA_IN 1
60 #define AO_USB_EP0_DATA_OUT 2
63 uint8_t dir_type_recip;
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;
78 /* Send an IN data packet */
80 ao_usb_ep0_flush(void)
87 if (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 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;
98 ao_usb_ep0_in_len -= this_len;
100 USBFIFO[0] = *ao_usb_ep0_in_data++;
105 #define LE_WORD(x) ((x)&0xFF),((x)>>8)
107 /* CDC definitions */
108 #define CS_INTERFACE 0x24
109 #define CS_ENDPOINT 0x25
111 #define SET_LINE_CODING 0x20
112 #define GET_LINE_CODING 0x21
113 #define SET_CONTROL_LINE_STATE 0x22
115 /* Data structure for GET_LINE_CODING / SET_LINE_CODING class requests */
116 struct ao_usb_line_coding {
123 static struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8};
125 /* USB descriptors in one giant block of bytes */
126 static const uint8_t ao_usb_descriptors [] =
128 /* Device descriptor */
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 */
141 0x03, /* iSerialNumber */
142 0x01, /* bNumConfigurations */
144 /* Configuration descriptor */
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 */
154 /* Control class interface */
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 */
165 /* Header functional descriptor */
168 0x00, /* bDescriptor SubType Header */
169 LE_WORD(0x0110), /* CDC version 1.1 */
171 /* Call management functional descriptor */
174 0x01, /* bDescriptor SubType Call Management */
175 0x01, /* bmCapabilities = device handles call management */
176 0x01, /* bDataInterface call management interface number */
178 /* ACM functional descriptor */
181 0x02, /* bDescriptor SubType Abstract Control Management */
182 0x02, /* bmCapabilities = D1 (Set_line_Coding, Set_Control_Line_State, Get_Line_Coding and Serial_State) */
184 /* Union functional descriptor */
187 0x06, /* bDescriptor SubType Union Functional descriptor */
188 0x00, /* bMasterInterface */
189 0x01, /* bSlaveInterface0 */
191 /* Notification EP */
193 AO_USB_DESC_ENDPOINT,
194 AO_USB_INT_EP|0x80, /* bEndpointAddress */
195 0x03, /* bmAttributes = intr */
196 LE_WORD(8), /* wMaxPacketSize */
197 0x0A, /* bInterval */
199 /* Data class interface descriptor */
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 */
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 */
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 */
226 /* String descriptors */
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,
239 'T', 0, 'e', 0, 'l', 0, 'e', 0, 'M', 0, 'e', 0, 't', 0, 'r', 0, 'u', 0, 'm', 0,
244 't', 0, 'e', 0, 'l', 0, 'e', 0, '-', 0, '0', 0,
246 /* Terminating zero */
250 /* Walk through the list of descriptors and find a match
253 ao_usb_get_descriptor(uint16_t value)
255 const uint8_t *descriptor;
256 uint8_t type = value >> 8;
257 uint8_t index = value;
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];
265 ao_usb_ep0_in_len = descriptor[0];
266 ao_usb_ep0_in_data = descriptor;
269 descriptor += descriptor[0];
273 /* Read data from the ep0 OUT fifo
276 ao_usb_ep0_fill(void)
282 if (len > ao_usb_ep0_out_len)
283 len = ao_usb_ep0_out_len;
284 ao_usb_ep0_out_len -= len;
286 *ao_usb_ep0_out_data++ = USBFIFO[0];
290 ao_usb_ep0_queue_byte(uint8_t a)
292 ao_usb_ep0_in_buf[ao_usb_ep0_in_len++] = a;
296 ao_usb_set_address(uint8_t address)
298 USBADDR = address | 0x80;
299 while (USBADDR & 0x80)
304 ao_usb_ep0_setup(void)
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;
310 if (ao_usb_ep0_out_len != 0)
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;
318 ao_usb_ep0_state = AO_USB_EP0_IDLE;
320 if (ao_usb_setup.length)
321 ao_usb_ep0_state = AO_USB_EP0_DATA_OUT;
323 ao_usb_ep0_state = AO_USB_EP0_IDLE;
326 if (ao_usb_ep0_state == AO_USB_EP0_IDLE)
327 USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END;
329 USBCS0 = USBCS0_CLR_OUTPKT_RDY;
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);
342 case AO_USB_REQ_SET_ADDRESS:
343 ao_usb_set_address(ao_usb_setup.value);
345 case AO_USB_REQ_GET_DESCRIPTOR:
346 ao_usb_get_descriptor(ao_usb_setup.value);
348 case AO_USB_REQ_GET_CONFIGURATION:
349 ao_usb_ep0_queue_byte(ao_usb_configuration);
351 case AO_USB_REQ_SET_CONFIGURATION:
352 ao_usb_configuration = ao_usb_setup.value;
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);
362 case AO_USB_REQ_GET_INTERFACE:
363 ao_usb_ep0_queue_byte(0);
365 case AO_USB_REQ_SET_INTERFACE:
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);
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;
385 case GET_LINE_CODING:
386 ao_usb_ep0_in_len = 7;
387 ao_usb_ep0_in_data = (uint8_t *) &ao_usb_line_coding;
389 case SET_CONTROL_LINE_STATE:
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;
401 /* End point 0 receives all of the control messages. */
407 ao_usb_ep0_state = AO_USB_EP0_IDLE;
409 ao_interrupt_disable();
411 if (ao_usb_iif & 1) {
415 ao_sleep(&ao_usb_task);
417 ao_interrupt_enable();
420 if (cs0 & USBCS0_SETUP_END) {
421 ao_usb_ep0_state = AO_USB_EP0_IDLE;
422 USBCS0 = USBCS0_CLR_SETUP_END;
424 if (cs0 & USBCS0_SENT_STALL) {
425 ao_usb_ep0_state = AO_USB_EP0_IDLE;
426 USBCS0 &= ~USBCS0_SENT_STALL;
428 if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN &&
429 (cs0 & USBCS0_INPKT_RDY) == 0)
433 if (cs0 & USBCS0_OUTPKT_RDY) {
434 switch (ao_usb_ep0_state) {
435 case AO_USB_EP0_IDLE:
438 case AO_USB_EP0_DATA_OUT:
440 if (ao_usb_ep0_out_len == 0)
441 ao_usb_ep0_state = AO_USB_EP0_IDLE;
443 if (ao_usb_ep0_state == AO_USB_EP0_IDLE)
444 USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END;
446 USBCS0 = USBCS0_CLR_OUTPKT_RDY;
456 ao_interrupt_disable();
457 if (ao_usb_in_bytes) {
458 USBINDEX = AO_USB_IN_EP;
459 USBCSIL |= USBCSIL_INPKT_RDY;
462 ao_interrupt_enable();
466 ao_usb_putchar(uint8_t c)
468 ao_interrupt_disable();
470 USBINDEX = AO_USB_IN_EP;
471 if ((USBCSIL & USBCSIL_INPKT_RDY) == 0)
473 ao_sleep(&ao_usb_in_bytes);
475 USBFIFO[AO_USB_IN_EP << 1] = c;
476 if (++ao_usb_in_bytes == AO_USB_IN_SIZE)
478 ao_interrupt_enable();
485 ao_interrupt_disable();
486 while (ao_usb_out_bytes == 0) {
488 USBINDEX = AO_USB_OUT_EP;
489 if ((USBCSOL & USBCSOL_OUTPKT_RDY) != 0)
491 ao_sleep(&ao_usb_out_bytes);
493 ao_usb_out_bytes = (USBCNTH << 8) | USBCNTL;
496 c = USBFIFO[AO_USB_OUT_EP << 1];
497 ao_interrupt_enable();
504 /* Turn on the USB controller */
505 SLEEP |= SLEEP_USB_EN;
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;
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;
517 /* IN interrupts on the control an IN endpoints */
518 USBIIE = (1 << AO_USB_CONTROL_EP) | (1 << AO_USB_IN_EP);
520 /* OUT interrupts on the OUT endpoint */
521 USBOIE = (1 << AO_USB_OUT_EP);
523 /* Ignore control interrupts */
526 /* enable USB interrupts */
529 /* Clear any pending interrupts */
534 ao_add_task(&ao_usb_task, ao_usb_ep0);