X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=src%2Fcc1111%2Fao_usb.c;h=7d363c08fe92ef86cdff5eec64745c43bbbf104f;hp=08cb73900c6462fe52d7d8bfafe1b6a28ff47d90;hb=1085ec5d57e0ed5d132f2bbdac1a0b6a32c0ab4a;hpb=9513be7f9d3d0b0ec29f6487fa9dc8f1ac24d0de diff --git a/src/cc1111/ao_usb.c b/src/cc1111/ao_usb.c index 08cb7390..7d363c08 100644 --- a/src/cc1111/ao_usb.c +++ b/src/cc1111/ao_usb.c @@ -3,7 +3,8 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of @@ -24,7 +25,7 @@ static __xdata uint16_t ao_usb_in_bytes; static __pdata uint16_t ao_usb_in_bytes_last; static __xdata uint16_t ao_usb_out_bytes; static __pdata uint8_t ao_usb_iif; -static __pdata uint8_t ao_usb_running; +__pdata uint8_t ao_usb_running; static void ao_usb_set_interrupts(void) @@ -62,6 +63,9 @@ ao_usb_isr(void) __interrupt 6 ao_btm_isr(); #endif #endif +#if HAS_P2_ISR + ao_p2_isr(); +#endif } struct ao_usb_setup { @@ -149,19 +153,17 @@ ao_usb_ep0_fill(void) *ao_usb_ep0_out_data++ = USBFIFO[0]; } -void +static void ao_usb_ep0_queue_byte(uint8_t a) { ao_usb_ep0_in_buf[ao_usb_ep0_in_len++] = a; } -void +static void ao_usb_set_address(uint8_t address) { ao_usb_running = 1; - USBADDR = address | 0x80; - while (USBADDR & 0x80) - ; + USBADDR = address; } static void @@ -188,24 +190,6 @@ ao_usb_ep0_setup(void) if (ao_usb_ep0_out_len != 0) return; - /* Figure out how to ACK the setup packet */ - if (ao_usb_setup.dir_type_recip & AO_USB_DIR_IN) { - if (ao_usb_setup.length) - ao_usb_ep0_state = AO_USB_EP0_DATA_IN; - else - ao_usb_ep0_state = AO_USB_EP0_IDLE; - } else { - if (ao_usb_setup.length) - ao_usb_ep0_state = AO_USB_EP0_DATA_OUT; - else - ao_usb_ep0_state = AO_USB_EP0_IDLE; - } - USBINDEX = 0; - if (ao_usb_ep0_state == AO_USB_EP0_IDLE) - USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END; - else - USBCS0 = USBCS0_CLR_OUTPKT_RDY; - ao_usb_ep0_in_data = ao_usb_ep0_in_buf; ao_usb_ep0_in_len = 0; switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_TYPE_MASK) { @@ -218,6 +202,11 @@ ao_usb_ep0_setup(void) ao_usb_ep0_queue_byte(0); break; case AO_USB_REQ_SET_ADDRESS: +#if USB_FORCE_FLIGHT_IDLE + /* Go to idle mode if USB is connected + */ + ao_flight_force_idle = 1; +#endif ao_usb_set_address(ao_usb_setup.value); break; case AO_USB_REQ_GET_DESCRIPTOR: @@ -258,23 +247,52 @@ ao_usb_ep0_setup(void) break; case AO_USB_TYPE_CLASS: switch (ao_usb_setup.request) { - case SET_LINE_CODING: + case AO_USB_SET_LINE_CODING: ao_usb_ep0_out_len = 7; ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_line_coding; break; - case GET_LINE_CODING: + case AO_USB_GET_LINE_CODING: ao_usb_ep0_in_len = 7; ao_usb_ep0_in_data = (uint8_t *) &ao_usb_line_coding; break; - case SET_CONTROL_LINE_STATE: + case AO_USB_SET_CONTROL_LINE_STATE: break; } break; } - if (ao_usb_ep0_state != AO_USB_EP0_DATA_OUT) { + + /* Figure out how to ACK the setup packet and the + * next state + */ + USBINDEX = 0; + if (ao_usb_ep0_in_len) { + + /* Sending data back to the host + */ + ao_usb_ep0_state = AO_USB_EP0_DATA_IN; + USBCS0 = USBCS0_CLR_OUTPKT_RDY; if (ao_usb_setup.length < ao_usb_ep0_in_len) ao_usb_ep0_in_len = ao_usb_setup.length; ao_usb_ep0_flush(); + } else if (ao_usb_ep0_out_len) { + + /* Receiving data from the host + */ + ao_usb_ep0_state = AO_USB_EP0_DATA_OUT; + USBCS0 = USBCS0_CLR_OUTPKT_RDY; + } else if (ao_usb_setup.length) { + + /* Uh-oh, the host expected to send or receive data + * and we don't know what to do. + */ + ao_usb_ep0_state = AO_USB_EP0_STALL; + USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_SEND_STALL; + } else { + + /* Simple setup packet with no data + */ + ao_usb_ep0_state = AO_USB_EP0_IDLE; + USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END; } } @@ -296,12 +314,12 @@ ao_usb_ep0(void) USBINDEX = 0; cs0 = USBCS0; if (cs0 & USBCS0_SETUP_END) { - ao_usb_ep0_state = AO_USB_EP0_IDLE; USBCS0 = USBCS0_CLR_SETUP_END; + ao_usb_ep0_state = AO_USB_EP0_IDLE; } if (cs0 & USBCS0_SENT_STALL) { + USBCS0 = 0; ao_usb_ep0_state = AO_USB_EP0_IDLE; - USBCS0 &= ~USBCS0_SENT_STALL; } if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN && (cs0 & USBCS0_INPKT_RDY) == 0) @@ -315,12 +333,11 @@ ao_usb_ep0(void) break; case AO_USB_EP0_DATA_OUT: ao_usb_ep0_fill(); - if (ao_usb_ep0_out_len == 0) - ao_usb_ep0_state = AO_USB_EP0_IDLE; USBINDEX = 0; - if (ao_usb_ep0_state == AO_USB_EP0_IDLE) + if (ao_usb_ep0_out_len == 0) { + ao_usb_ep0_state = AO_USB_EP0_IDLE; USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END; - else + } else USBCS0 = USBCS0_CLR_OUTPKT_RDY; break; } @@ -379,10 +396,10 @@ ao_usb_putchar(char c) __critical __reentrant ao_usb_in_send(); } -char -ao_usb_pollchar(void) __critical +int +_ao_usb_pollchar(void) { - char c; + uint8_t c; if (ao_usb_out_bytes == 0) { USBINDEX = AO_USB_OUT_EP; if ((USBCSOL & USBCSOL_OUTPKT_RDY) == 0) @@ -404,12 +421,14 @@ ao_usb_pollchar(void) __critical } char -ao_usb_getchar(void) __critical +ao_usb_getchar(void) { - char c; + int c; - while ((c = ao_usb_pollchar()) == AO_READ_AGAIN) + ao_arch_block_interrupts(); + while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN) ao_sleep(&ao_stdin_ready); + ao_arch_release_interrupts(); return c; } @@ -430,6 +449,9 @@ ao_usb_enable(void) USBCIF = 0; USBOIF = 0; USBIIF = 0; +#if HAS_USB_PULLUP + ao_gpio_set(AO_USB_PULLUP_PORT, AO_USB_PULLUP_PIN, AO_USB_PULLUP, 0); +#endif } void @@ -441,6 +463,10 @@ ao_usb_disable(void) USBCIE = 0; IEN2 &= ~IEN2_USBIE; +#if HAS_USB_PULLUP + ao_gpio_set(AO_USB_PULLUP_PORT, AO_USB_PULLUP_PIN, AO_USB_PULLUP, 0); +#endif + /* Clear any pending interrupts */ USBCIF = 0; USBOIF = 0; @@ -453,8 +479,11 @@ ao_usb_disable(void) void ao_usb_init(void) { +#if HAS_USB_PULLUP + ao_enable_output(AO_USB_PULLUP_PORT, AO_USB_PULLUP_PIN, AO_USB_PULLUP, 0); +#endif ao_usb_enable(); ao_add_task(&ao_usb_task, ao_usb_ep0, "usb"); - ao_add_stdio(ao_usb_pollchar, ao_usb_putchar, ao_usb_flush); + ao_add_stdio(_ao_usb_pollchar, ao_usb_putchar, ao_usb_flush); }