*
* 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
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)
USBCS0 = cs0;
}
-__xdata static struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8};
+__xdata struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8};
/* Walk through the list of descriptors and find a match
*/
*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
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) {
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:
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;
}
}
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)
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;
}
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)
}
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;
}
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
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;
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);
}