USB working up through reading strings
authorKeith Packard <keithp@keithp.com>
Tue, 14 Apr 2009 03:39:46 +0000 (20:39 -0700)
committerKeith Packard <keithp@keithp.com>
Tue, 14 Apr 2009 03:39:46 +0000 (20:39 -0700)
ao.h
ao_panic.c
ao_usb.c
ao_usb.h

diff --git a/ao.h b/ao.h
index 7c68645ce88a6741cfc3d64a6e14e05540469001..6de3339f605423ed8c617edf96e994ddda59ade1 100644 (file)
--- a/ao.h
+++ b/ao.h
@@ -25,7 +25,7 @@
 
 #define DATA_TO_XDATA(a)       ((void __xdata *) ((uint8_t) (a) | 0xff00))
 
-#define AO_STACK_START 0x32
+#define AO_STACK_START 0x34
 #define AO_STACK_END   0xfe
 #define AO_STACK_SIZE  (AO_STACK_END - AO_STACK_START + 1)
 
index c9c63b21de0067c8396ffcf4765388214d692052..0f8433dc03e9297a30dcefb7e4849fae26c72eb0 100644 (file)
@@ -21,6 +21,4 @@ void
 ao_panic(uint8_t reason)
 {
        (void) reason;
-       for (;;)
-               ;
 }
index 56036af9489795ddbea098f9ba682afb03cc4612..d8f099c0b6aef985884879210fa656b66293d695 100644 (file)
--- a/ao_usb.c
+++ b/ao_usb.c
@@ -34,6 +34,8 @@ struct ao_task __xdata ao_usb_task;
 
 static uint16_t        ao_usb_in_bytes;
 static uint16_t        ao_usb_out_bytes;
+static __data uint8_t  ao_usb_iif;
+static __data uint8_t  ao_usb_oif;
 
 /* This interrupt is shared with port 2, 
  * so when we hook that up, fix this
@@ -41,16 +43,15 @@ static uint16_t     ao_usb_out_bytes;
 void
 ao_usb_isr(void) interrupt 6
 {
-       uint8_t usb_if;
-
-       usb_if = USBIIF;
-       if (usb_if & 1)
+       USBIF = 0;
+       ao_usb_iif |= USBIIF;
+       if (ao_usb_iif & 1)
                ao_wakeup(&ao_usb_task);
-       if (usb_if & (1 << AO_USB_IN_EP))
+       if (ao_usb_iif & (1 << AO_USB_IN_EP))
                ao_wakeup(&ao_usb_in_bytes);
 
-       usb_if = USBOIF;
-       if (usb_if & (1 << AO_USB_OUT_EP))
+       ao_usb_oif |= USBOIF;
+       if (ao_usb_oif & (1 << AO_USB_OUT_EP))
                ao_wakeup(&ao_usb_out_bytes);
 }
 
@@ -59,9 +60,7 @@ ao_usb_isr(void) interrupt 6
 #define AO_USB_EP0_DATA_OUT    2
 
 struct ao_usb_setup {
-       uint8_t         recip : 5;
-       uint8_t         type : 2;
-       uint8_t         dir : 1;
+       uint8_t         dir_type_recip;
        uint8_t         request;
        uint16_t        value;
        uint16_t        index;
@@ -83,13 +82,15 @@ ao_usb_ep0_flush(void)
        uint8_t this_len;
        uint8_t cs0;
        
-       if (ao_usb_ep0_state != AO_USB_EP0_DATA_IN)
-               return;
+       USBINDEX = 0;
+       cs0 = USBCS0;
+       if (cs0 & USBCS0_INPKT_RDY)
+               ao_panic(0);
 
-       cs0 = USBCS0_INPKT_RDY;
        this_len = ao_usb_ep0_in_len;
        if (this_len > AO_USB_CONTROL_SIZE)
                this_len = AO_USB_CONTROL_SIZE;
+       cs0 = USBCS0_INPKT_RDY;
        if (this_len != AO_USB_CONTROL_SIZE) {
                cs0 = USBCS0_INPKT_RDY | USBCS0_DATA_END;
                ao_usb_ep0_state = AO_USB_EP0_IDLE;
@@ -246,16 +247,18 @@ static const uint8_t ao_usb_descriptors [] =
        0
 };
 
+/* Walk through the list of descriptors and find a match
+ */
 static void
-ao_usb_get_descriptor(uint8_t type, uint8_t id)
+ao_usb_get_descriptor(uint16_t value)
 {
        const uint8_t   *descriptor;
+       uint8_t         type = value >> 8;
+       uint8_t         index = value;
 
        descriptor = ao_usb_descriptors;
-       ao_usb_ep0_in_len = 0;
-       ao_usb_ep0_in_data = NULL;
        while (descriptor[0] != 0) {
-               if (descriptor[1] == type && id-- == 0) {
+               if (descriptor[1] == type && index-- == 0) {
                        if (type == AO_USB_DESC_CONFIGURATION)
                                ao_usb_ep0_in_len = descriptor[2];
                        else
@@ -265,9 +268,10 @@ ao_usb_get_descriptor(uint8_t type, uint8_t id)
                }
                descriptor += descriptor[0];
        }
-       ao_usb_ep0_state = AO_USB_EP0_DATA_IN;
 }
 
+/* Read data from the ep0 OUT fifo
+ */
 static void
 ao_usb_ep0_fill(void)
 {
@@ -283,29 +287,9 @@ ao_usb_ep0_fill(void)
 }
 
 void
-ao_usb_send_two_bytes(uint8_t a, uint8_t b)
+ao_usb_ep0_queue_byte(uint8_t a)
 {
-       ao_usb_ep0_in_buf[0] = a;
-       ao_usb_ep0_in_buf[1] = b;
-       ao_usb_ep0_in_data = ao_usb_ep0_in_buf;
-       ao_usb_ep0_in_len = 2;
-       ao_usb_ep0_state = AO_USB_EP0_DATA_IN;
-}
-
-void
-ao_usb_send_one_byte(uint8_t a)
-{
-       ao_usb_ep0_in_buf[0] = a;
-       ao_usb_ep0_in_data = ao_usb_ep0_in_buf;
-       ao_usb_ep0_in_len = 1;
-       ao_usb_ep0_state = AO_USB_EP0_DATA_IN;
-}
-
-void
-ao_usb_send_zero_bytes(void)
-{
-       ao_usb_ep0_in_len = 0;
-       ao_usb_ep0_state = AO_USB_EP0_DATA_IN;
+       ao_usb_ep0_in_buf[ao_usb_ep0_in_len++] = a;
 }
 
 void
@@ -319,28 +303,50 @@ ao_usb_set_address(uint8_t address)
 static void
 ao_usb_ep0_setup(void)
 {
+       /* Pull the setup packet out of the fifo */
        ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_setup;
        ao_usb_ep0_out_len = 8;
        ao_usb_ep0_fill();
-       if (ao_usb_ep0_out_len > 0)
+       if (ao_usb_ep0_out_len != 0)
                return;
-       switch(ao_usb_setup.type) {
+
+       /* 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) {
        case AO_USB_TYPE_STANDARD:
-               switch(ao_usb_setup.recip) {
+               switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_RECIP_MASK) {
                case AO_USB_RECIP_DEVICE:
                        switch(ao_usb_setup.request) {
                        case AO_USB_REQ_GET_STATUS:
-                               ao_usb_send_two_bytes(0,0);
+                               ao_usb_ep0_queue_byte(0);
+                               ao_usb_ep0_queue_byte(0);
                                break;
                        case AO_USB_REQ_SET_ADDRESS:
                                ao_usb_set_address(ao_usb_setup.value);
                                break;
                        case AO_USB_REQ_GET_DESCRIPTOR:
-                               ao_usb_get_descriptor(ao_usb_setup.value,
-                                                     ao_usb_setup.index);
+                               ao_usb_get_descriptor(ao_usb_setup.value);
                                break;
                        case AO_USB_REQ_GET_CONFIGURATION:
-                               ao_usb_send_one_byte(ao_usb_configuration);
+                               ao_usb_ep0_queue_byte(ao_usb_configuration);
                                break;
                        case AO_USB_REQ_SET_CONFIGURATION:
                                ao_usb_configuration = ao_usb_setup.value;
@@ -350,20 +356,21 @@ ao_usb_ep0_setup(void)
                case AO_USB_RECIP_INTERFACE:
                        switch(ao_usb_setup.request) {
                        case AO_USB_REQ_GET_STATUS:
-                               ao_usb_send_two_bytes(0,0);
+                               ao_usb_ep0_queue_byte(0);
+                               ao_usb_ep0_queue_byte(0);
                                break;
                        case AO_USB_REQ_GET_INTERFACE:
-                               ao_usb_send_one_byte(0);
+                               ao_usb_ep0_queue_byte(0);
                                break;
                        case AO_USB_REQ_SET_INTERFACE:
-                               ao_usb_send_zero_bytes();
                                break;
                        }
                        break;
                case AO_USB_RECIP_ENDPOINT:
                        switch(ao_usb_setup.request) {
                        case AO_USB_REQ_GET_STATUS:
-                               ao_usb_send_two_bytes(0, 0);
+                               ao_usb_ep0_queue_byte(0);
+                               ao_usb_ep0_queue_byte(0);
                                break;
                        }
                        break;
@@ -374,19 +381,21 @@ ao_usb_ep0_setup(void)
                case SET_LINE_CODING:
                        ao_usb_ep0_out_len = 7;
                        ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_line_coding;
-                       ao_usb_ep0_state = AO_USB_EP0_DATA_OUT;
                        break;
                case GET_LINE_CODING:
                        ao_usb_ep0_in_len = 7;
                        ao_usb_ep0_in_data = (uint8_t *) &ao_usb_line_coding;
-                       ao_usb_ep0_state = AO_USB_EP0_DATA_IN;
                        break;
                case SET_CONTROL_LINE_STATE:
                        break;
                }
                break;
        }
-       ao_usb_ep0_flush();
+       if (ao_usb_ep0_state != AO_USB_EP0_DATA_OUT) {
+               if (ao_usb_setup.length < ao_usb_ep0_in_len)
+                       ao_usb_ep0_in_len = ao_usb_setup.length;
+               ao_usb_ep0_flush();
+       }
 }
 
 /* End point 0 receives all of the control messages. */
@@ -397,7 +406,15 @@ ao_usb_ep0(void)
 
        ao_usb_ep0_state = AO_USB_EP0_IDLE;
        for (;;) {
-               ao_sleep(&ao_usb_task);
+               ao_interrupt_disable();
+               for (;;) {
+                       if (ao_usb_iif & 1) {
+                               ao_usb_iif &= ~1;
+                               break;
+                       }
+                       ao_sleep(&ao_usb_task);
+               }
+               ao_interrupt_enable();
                USBINDEX = 0;
                cs0 = USBCS0;
                if (cs0 & USBCS0_SETUP_END) {
@@ -408,7 +425,9 @@ ao_usb_ep0(void)
                        ao_usb_ep0_state = AO_USB_EP0_IDLE;
                        USBCS0 &= ~USBCS0_SENT_STALL;
                }
-               if (cs0 & USBCS0_INPKT_RDY) {
+               if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN &&
+                   (cs0 & USBCS0_INPKT_RDY) == 0)
+               {
                        ao_usb_ep0_flush();
                }
                if (cs0 & USBCS0_OUTPKT_RDY) {
@@ -420,13 +439,13 @@ ao_usb_ep0(void)
                                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)
+                                       USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END;
+                               else
+                                       USBCS0 = USBCS0_CLR_OUTPKT_RDY;
                                break;
                        }
-                       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;
                }
        }
 }
@@ -504,6 +523,9 @@ ao_usb_init(void)
        /* Ignore control interrupts */
        USBCIE = 0;
        
+       /* enable USB interrupts */
+       IEN2 |= IEN2_USBIE;
+
        /* Clear any pending interrupts */
        USBCIF = 0;
        USBOIF = 0;
index cbd0f3a720d2c7ab021bb5d9eb7c9c7a5d2f9e27..84f92877950c95c8caeafbd8d570ca7ee6607fac 100644 (file)
--- a/ao_usb.h
+++ b/ao_usb.h
 #ifndef _AO_USB_H_
 #define _AO_USB_H_
 
+#define AO_USB_SETUP_DIR_MASK  (0x01 << 7)
+#define AO_USB_SETUP_TYPE_MASK (0x03 << 5)
+#define AO_USB_SETUP_RECIP_MASK        (0x1f)
+
 #define AO_USB_DIR_OUT                 0
-#define AO_USB_DIR_IN                  1
+#define AO_USB_DIR_IN                  (1 << 7)
 
 #define AO_USB_TYPE_STANDARD           0
-#define AO_USB_TYPE_CLASS              1
-#define AO_USB_TYPE_VENDOR             2
-#define AO_USB_TYPE_RESERVED           3
+#define AO_USB_TYPE_CLASS              (1 << 5)
+#define AO_USB_TYPE_VENDOR             (2 << 5)
+#define AO_USB_TYPE_RESERVED           (3 << 5)
 
 #define AO_USB_RECIP_DEVICE            0
 #define AO_USB_RECIP_INTERFACE         1