]> git.sur5r.net Git - u-boot/commitdiff
Various USB related patches
authorWolfgang Denk <wd@pollux.denx.de>
Wed, 14 Jun 2006 15:45:53 +0000 (17:45 +0200)
committerWolfgang Denk <wd@pollux.denx.de>
Wed, 14 Jun 2006 15:45:53 +0000 (17:45 +0200)
- Add support for mpc8xx USB device.
- Add support for Common Device Class - Abstract Control Model USB console.
- Add support for flow control in USB slave devices.
- Add support for switching between gserial and cdc_acm using environment.
- Minor changes to usbdcore_omap1510.c usbdcore_omap1510.h
- Update usbcore slightly to ease host enumeration.
- Fix non-portable endian problems in usbdcore and usbdcore_ep0.
- Add AdderUSB_config as a defconfig to enable usage of the USB console
  by default with the Adder87x U-Boot port.
Patches by Bryan O'Donoghue <bodonoghue@codehermit.ie>, 29 May 2006

15 files changed:
CHANGELOG
Makefile
README
drivers/Makefile
drivers/usbdcore_ep0.c
drivers/usbdcore_mpc8xx.c [new file with mode: 0644]
drivers/usbdcore_omap1510.c
drivers/usbtty.c
drivers/usbtty.h
include/configs/AdderUSB.h [new file with mode: 0644]
include/usb_cdc_acm.h [new file with mode: 0644]
include/usbdcore.h
include/usbdcore_mpc8xx.h [new file with mode: 0644]
include/usbdcore_omap1510.h
include/usbdescriptors.h

index 4aab6fc04ba76c8cc66df0d53ff084f6d502e38f..63d327ab18efd6b2006dab8e87059af01f997598 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,18 @@
 Changes since U-Boot 1.1.4:
 ======================================================================
 
+* Various USB related patches 
+  - Add support for mpc8xx USB device.
+  - Add support for Common Device Class - Abstract Control Model USB console.
+  - Add support for flow control in USB slave devices.
+  - Add support for switching between gserial and cdc_acm using environment.
+  - Minor changes to usbdcore_omap1510.c usbdcore_omap1510.h
+  - Update usbcore slightly to ease host enumeration.
+  - Fix non-portable endian problems in usbdcore and usbdcore_ep0.
+  - Add AdderUSB_config as a defconfig to enable usage of the USB console
+    by default with the Adder87x U-Boot port.
+  Patch by Bryan O'Donoghue <bodonoghue@codehermit.ie>, 29 May 2006
+
 * Fix PCI to memory window size problems on PM82x boards
   We use the "automatic" mode that was used for  the  MPC8266ADS  and
   MPC8272 boards. Eventually this should be used on all boards?]
index 41a3624ff583bf72f46f5bc0a9bc45ae50d3c631..45e850c5f625b3b105c318f30e04b03afde840a6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -58,7 +58,7 @@ ifeq ($(HOSTARCH),ppc)
 CROSS_COMPILE =
 else
 ifeq ($(ARCH),ppc)
-CROSS_COMPILE = powerpc-linux-
+CROSS_COMPILE = ppc_8xx-
 endif
 ifeq ($(ARCH),arm)
 CROSS_COMPILE = arm-linux-
@@ -437,6 +437,9 @@ AdderII_config  \
        @echo "#define CONFIG_MPC852T" > include/config.h)
        @./mkconfig -a Adder ppc mpc8xx adder
 
+AdderUSB_config:       unconfig
+       @./mkconfig -a AdderUSB ppc mpc8xx adder
+
 ADS860_config     \
 FADS823_config    \
 FADS850SAR_config \
diff --git a/README b/README
index 3ffef62538fe2612c1ba2379d982d5ac7e0a1565..25e8971bcaea01b7e4f6504dbb64ab224ce196c5 100644 (file)
--- a/README
+++ b/README
@@ -862,7 +862,69 @@ The following options need to be configured:
                                for differential drivers: 0x00001000
                                for single ended drivers: 0x00005000
 
-
+- USB Device:
+               Define the below if you wish to use the USB console.
+               Once firmware is rebuilt from a serial console issue the
+               command "setenv stdin usbtty; setenv stdout usbtty" and
+               attach your usb cable. The Unix command "dmesg" should print
+               it has found a new device. The environment variable usbtty
+               can be set to gserial or cdc_acm to enable your device to
+               appear to a USB host as a Linux gserial device or a 
+               Common Device Class Abstract Control Model serial device.
+               If you select usbtty = gserial you should be able to enumerate
+               a Linux host by
+               # modprobe usbserial vendor=0xVendorID product=0xProductID
+               else if using cdc_acm, simply setting the environment
+               variable usbtty to be cdc_acm should suffice. The following
+               might be defined in YourBoardName.h
+       
+                       CONFIG_USB_DEVICE
+                       Define this to build a UDC device
+
+                       CONFIG_USB_TTY
+                       Define this to have a tty type of device available to
+                       talk to the UDC device
+               
+                       CFG_CONSOLE_IS_IN_ENV
+                       Define this if you want stdin, stdout &/or stderr to
+                       be set to usbtty.
+
+                       mpc8xx:
+                               CFG_USB_EXTC_CLK 0xBLAH
+                               Derive USB clock from external clock "blah"
+                               - CFG_USB_EXTC_CLK 0x02 
+                               
+                               CFG_USB_BRG_CLK 0xBLAH
+                               Derive USB clock from brgclk
+                               - CFG_USB_BRG_CLK 0x04
+
+               If you have a USB-IF assigned VendorID then you may wish to 
+               define your own vendor specific values either in BoardName.h
+               or directly in usbd_vendor_info.h. If you don't define 
+               CONFIG_USBD_MANUFACTURER, CONFIG_USBD_PRODUCT_NAME,
+               CONFIG_USBD_VENDORID and CONFIG_USBD_PRODUCTID, then U-Boot
+               should pretend to be a Linux device to it's target host.
+
+                       CONFIG_USBD_MANUFACTURER
+                       Define this string as the name of your company for
+                       - CONFIG_USBD_MANUFACTURER "my company"
+                       
+                       CONFIG_USBD_PRODUCT_NAME
+                       Define this string as the name of your product
+                       - CONFIG_USBD_PRODUCT_NAME "acme usb device"
+
+                       CONFIG_USBD_VENDORID
+                       Define this as your assigned Vendor ID from the USB
+                       Implementors Forum. This *must* be a genuine Vendor ID
+                       to avoid polluting the USB namespace.
+                       - CONFIG_USBD_VENDORID 0xFFFF
+                                
+                       CONFIG_USBD_PRODUCTID
+                       Define this as the unique Product ID
+                       for your device
+                       - CONFIG_USBD_PRODUCTID 0xFFFF
+               
+                       
 - MMC Support:
                The MMC controller on the Intel PXA is supported. To
                enable this define CONFIG_MMC. The MMC can be
index d5b6811829eff2b3d00cb6d22af84f4134261f50..8732e1626228c53c845af9d7f1483b54ad7d7a99 100644 (file)
@@ -48,7 +48,7 @@ OBJS  = 3c589.o 5701rls.o ali512x.o \
          ti_pci1410a.o tigon3.o tsec.o \
          usb_ohci.o usbdcore.o usbdcore_ep0.o usbdcore_omap1510.o usbtty.o \
          videomodes.o w83c553f.o \
-         ks8695eth.o
+         ks8695eth.o usbdcore_mpc8xx.o
 
 all:   $(LIB)
 
index 260befe9786d6cb80a8fe290b931514344745c5c..5e7443be8fc0d9f795fdb178b5b1a4a2ca0bcf74 100644 (file)
@@ -2,6 +2,9 @@
  * (C) Copyright 2003
  * Gerry Hamel, geh@ti.com, Texas Instruments
  *
+ * (C) Copyright 2006
+ * Bryan O'Donoghue, deckard@CodeHermit.ie
+ *
  * Based on
  * linux/drivers/usbd/ep0.c
  *
  * function driver. This may need to change.
  *
  * XXX
+ *
+ * As alluded to above, a simple callback cdc_recv_setup has been implemented
+ * in the usb_device data structure to facilicate passing 
+ * Common Device Class packets to a function driver.
+ *
+ * XXX
  */
 
 #include <common.h>
 
-#if defined(CONFIG_OMAP1510) && defined(CONFIG_USB_DEVICE)
+#if defined(CONFIG_USB_DEVICE)
 #include "usbdcore.h"
 
 #if 0
@@ -69,7 +78,7 @@ static int ep0_get_status (struct usb_device_instance *device,
        char *cp;
 
        urb->actual_length = 2;
-       cp = urb->buffer;
+       cp = (char*)urb->buffer;
        cp[0] = cp[1] = 0;
 
        switch (requesttype) {
@@ -115,7 +124,7 @@ static int ep0_get_one (struct usb_device_instance *device, struct urb *urb,
  *
  * Copy configuration data to urb transfer buffer if there is room for it.
  */
-static void copy_config (struct urb *urb, void *data, int max_length,
+void copy_config (struct urb *urb, void *data, int max_length,
                         int max_buf)
 {
        int available;
@@ -128,10 +137,7 @@ static void copy_config (struct urb *urb, void *data, int max_length,
                dbg_ep0 (1, "data is NULL");
                return;
        }
-       if (!(length = *(unsigned char *) data)) {
-               dbg_ep0 (1, "length is zero");
-               return;
-       }
+       length = max_length;
 
        if (length > max_length) {
                dbg_ep0 (1, "length: %d >= max_length: %d", length,
@@ -192,7 +198,7 @@ static int ep0_get_descriptor (struct usb_device_instance *device,
 
        /* setup tx urb */
        urb->actual_length = 0;
-       cp = urb->buffer;
+       cp = (char*)urb->buffer;
 
        dbg_ep0 (2, "%s", USBD_DEVICE_DESCRIPTORS (descriptor_type));
 
@@ -200,7 +206,6 @@ static int ep0_get_descriptor (struct usb_device_instance *device,
        case USB_DESCRIPTOR_TYPE_DEVICE:
                {
                        struct usb_device_descriptor *device_descriptor;
-
                        if (!
                            (device_descriptor =
                             usbd_device_device_descriptor (device, port))) {
@@ -214,20 +219,16 @@ static int ep0_get_descriptor (struct usb_device_instance *device,
                        /* correct the correct control endpoint 0 max packet size into the descriptor */
                        device_descriptor =
                                (struct usb_device_descriptor *) urb->buffer;
-                       device_descriptor->bMaxPacketSize0 =
-                               urb->device->bus->maxpacketsize;
 
                }
-               /*dbg_ep0(3, "copied device configuration, actual_length: %x", urb->actual_length); */
+               dbg_ep0(3, "copied device configuration, actual_length: 0x%x", urb->actual_length); 
                break;
 
        case USB_DESCRIPTOR_TYPE_CONFIGURATION:
                {
-                       int bNumInterface;
                        struct usb_configuration_descriptor
                                *configuration_descriptor;
                        struct usb_device_descriptor *device_descriptor;
-
                        if (!
                            (device_descriptor =
                             usbd_device_device_descriptor (device, port))) {
@@ -251,130 +252,35 @@ static int ep0_get_descriptor (struct usb_device_instance *device,
                                         index);
                                return -1;
                        }
+                       dbg_ep0(0, "attempt to copy %d bytes to urb\n",cpu_to_le16(configuration_descriptor->wTotalLength));
                        copy_config (urb, configuration_descriptor,
-                                    sizeof (struct
-                                            usb_configuration_descriptor),
-                                    max);
-
-
-                       /* iterate across interfaces for specified configuration */
-                       dbg_ep0 (0, "bNumInterfaces: %d",
-                                configuration_descriptor->bNumInterfaces);
-                       for (bNumInterface = 0;
-                            bNumInterface <
-                            configuration_descriptor->bNumInterfaces;
-                            bNumInterface++) {
 
-                               int bAlternateSetting;
-                               struct usb_interface_instance
-                                       *interface_instance;
-
-                               dbg_ep0 (3, "[%d] bNumInterfaces: %d",
-                                        bNumInterface,
-                                        configuration_descriptor->bNumInterfaces);
-
-                               if (! (interface_instance = usbd_device_interface_instance (device,
-                                                                    port, index, bNumInterface)))
-                               {
-                                       dbg_ep0 (3, "[%d] interface_instance NULL",
-                                                bNumInterface);
-                                       return -1;
-                               }
-                               /* iterate across interface alternates */
-                               for (bAlternateSetting = 0;
-                                    bAlternateSetting < interface_instance->alternates;
-                                    bAlternateSetting++) {
-                                       /*int class; */
-                                       int bNumEndpoint;
-                                       struct usb_interface_descriptor *interface_descriptor;
-
-                                       struct usb_alternate_instance *alternate_instance;
-
-                                       dbg_ep0 (3, "[%d:%d] alternates: %d",
-                                                bNumInterface,
-                                                bAlternateSetting,
-                                                interface_instance->alternates);
-
-                                       if (! (alternate_instance = usbd_device_alternate_instance (device, port, index, bNumInterface, bAlternateSetting))) {
-                                               dbg_ep0 (3, "[%d] alternate_instance NULL",
-                                                        bNumInterface);
-                                               return -1;
-                                       }
-                                       /* copy descriptor for this interface */
-                                       copy_config (urb, alternate_instance->interface_descriptor,
-                                                    sizeof (struct usb_interface_descriptor),
-                                                    max);
-
-                                       /*dbg_ep0(3, "[%d:%d] classes: %d endpoints: %d", bNumInterface, bAlternateSetting, */
-                                       /*        alternate_instance->classes, alternate_instance->endpoints); */
-
-                                       /* iterate across classes for this alternate interface */
-#if 0
-                                       for (class = 0;
-                                            class < alternate_instance->classes;
-                                            class++) {
-                                               struct usb_class_descriptor *class_descriptor;
-                                               /*dbg_ep0(3, "[%d:%d:%d] classes: %d", bNumInterface, bAlternateSetting, */
-                                               /*        class, alternate_instance->classes); */
-                                               if (!(class_descriptor = usbd_device_class_descriptor_index (device, port, index, bNumInterface, bAlternateSetting, class))) {
-                                                       dbg_ep0 (3, "[%d] class NULL",
-                                                                class);
-                                                       return -1;
-                                               }
-                                               /* copy descriptor for this class */
-                                               copy_config (urb, class_descriptor,
-                                                       sizeof (struct usb_class_descriptor),
-                                                       max);
-                                       }
-#endif
-
-                                       /* iterate across endpoints for this alternate interface */
-                                       interface_descriptor = alternate_instance->interface_descriptor;
-                                       for (bNumEndpoint = 0;
-                                            bNumEndpoint < alternate_instance->endpoints;
-                                            bNumEndpoint++) {
-                                               struct usb_endpoint_descriptor *endpoint_descriptor;
-                                               dbg_ep0 (3, "[%d:%d:%d] endpoint: %d",
-                                                        bNumInterface,
-                                                        bAlternateSetting,
-                                                        bNumEndpoint,
-                                                        interface_descriptor->
-                                                        bNumEndpoints);
-                                               if (!(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, index, bNumInterface, bAlternateSetting, bNumEndpoint))) {
-                                                       dbg_ep0 (3, "[%d] endpoint NULL",
-                                                                bNumEndpoint);
-                                                       return -1;
-                                               }
-                                               /* copy descriptor for this endpoint */
-                                               copy_config (urb, endpoint_descriptor,
-                                                            sizeof (struct usb_endpoint_descriptor),
-                                                            max);
-                                       }
-                               }
-                       }
-                       dbg_ep0 (3, "lengths: %d %d",
-                                le16_to_cpu (configuration_descriptor->wTotalLength),
-                                urb->actual_length);
+                                       cpu_to_le16(configuration_descriptor->wTotalLength),
+                                    max);
                }
+
                break;
 
        case USB_DESCRIPTOR_TYPE_STRING:
                {
                        struct usb_string_descriptor *string_descriptor;
-
                        if (!(string_descriptor = usbd_get_string (index))) {
+                               serial_printf("Invalid string index %d\n", index);
                                return -1;
                        }
-                       /*dbg_ep0(3, "string_descriptor: %p", string_descriptor); */
+                       dbg_ep0(3, "string_descriptor: %p length %d", string_descriptor, string_descriptor->bLength); 
                        copy_config (urb, string_descriptor, string_descriptor->bLength, max);
                }
                break;
        case USB_DESCRIPTOR_TYPE_INTERFACE:
+       serial_printf("USB_DESCRIPTOR_TYPE_INTERFACE - error not implemented\n");
                return -1;
        case USB_DESCRIPTOR_TYPE_ENDPOINT:
+               serial_printf("USB_DESCRIPTOR_TYPE_ENDPOINT - error not implemented\n");
                return -1;
        case USB_DESCRIPTOR_TYPE_HID:
                {
+                       serial_printf("USB_DESCRIPTOR_TYPE_HID - error not implemented\n");
                        return -1;      /* unsupported at this time */
 #if 0
                        int bNumInterface =
@@ -403,6 +309,7 @@ static int ep0_get_descriptor (struct usb_device_instance *device,
                break;
        case USB_DESCRIPTOR_TYPE_REPORT:
                {
+                       serial_printf("USB_DESCRIPTOR_TYPE_REPORT - error not implemented\n");
                        return -1;      /* unsupported at this time */
 #if 0
                        int bNumInterface =
@@ -434,12 +341,19 @@ static int ep0_get_descriptor (struct usb_device_instance *device,
 #endif
                }
                break;
+       case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER:
+               {
+                       /* If a USB device supports both a full speed and low speed operation
+                        * we must send a Device_Qualifier descriptor here 
+                        */
+                       return -1;
+               }
        default:
                return -1;
        }
 
 
-       dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d packet size: %2d",
+       dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d tx_packetSize: %2d",
                 urb->buffer, urb->buffer_length, urb->actual_length,
                 device->bus->endpoint_array[0].tx_packetSize);
 /*
@@ -495,6 +409,12 @@ int ep0_recv_setup (struct urb *urb)
 
        /* handle USB Standard Request (c.f. USB Spec table 9-2) */
        if ((request->bmRequestType & USB_REQ_TYPE_MASK) != 0) {
+               if(device->device_state <= STATE_CONFIGURED){
+                       /*      Attempt to handle a CDC specific request if we are
+                        *      in the configured state.
+                        */
+                       return device->cdc_recv_setup(request,urb);
+               }
                dbg_ep0 (1, "non standard request: %x",
                         request->bmRequestType & USB_REQ_TYPE_MASK);
                return -1;      /* Stall here */
@@ -567,6 +487,7 @@ int ep0_recv_setup (struct urb *urb)
                                                   le16_to_cpu (request->wValue) & 0xff);
 
                case USB_REQ_GET_CONFIGURATION:
+                       serial_printf("get config %d\n", device->configuration);
                        return ep0_get_one (device, urb,
                                            device->configuration);
 
@@ -642,7 +563,6 @@ int ep0_recv_setup (struct urb *urb)
                        /*dbg_ep0(2, "address: %d %d %d", */
                        /*        request->wValue, le16_to_cpu(request->wValue), device->address); */
 
-                       serial_printf ("DEVICE_ADDRESS_ASSIGNED.. event?\n");
                        return 0;
 
                case USB_REQ_SET_DESCRIPTOR:    /* XXX should we support this? */
@@ -653,9 +573,10 @@ int ep0_recv_setup (struct urb *urb)
                        /* c.f. 9.4.7 - the top half of wValue is reserved */
                        /* */
                        if ((device->configuration =
-                            le16_to_cpu (request->wValue) & 0x7f) != 0) {
+                               le16_to_cpu (request->wValue) & 0xFF80) != 0) {
                                /* c.f. 9.4.7 - zero is the default or addressed state, in our case this */
                                /* is the same is configuration zero */
+                               serial_printf("error setting dev->config to zero!\n");
                                device->configuration = 0;      /* TBR - ?????? */
                        }
                        /* reset interface and alternate settings */
diff --git a/drivers/usbdcore_mpc8xx.c b/drivers/usbdcore_mpc8xx.c
new file mode 100644 (file)
index 0000000..9bd2c23
--- /dev/null
@@ -0,0 +1,1412 @@
+/*
+ * Copyright (C) 2006 by Bryan O'Donoghue, CodeHermit
+ * bodonoghue@CodeHermit.ie                                             
+ *
+ * References
+ * DasUBoot/drivers/usbdcore_omap1510.c, for design and implementation ideas.
+ *
+ * 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; 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+/*
+ * Notes :
+ * 1.  #define __SIMULATE_ERROR__ to inject a CRC error into every 2nd TX 
+ *             packet to force the USB re-transmit protocol.
+ *
+ * 2.  #define __DEBUG_UDC__ to switch on debug tracing to serial console
+ *     be careful that tracing doesn't create Hiesen-bugs with respect to
+ *     response timeouts to control requests.
+ *
+ * 3.  This driver should be able to support any higher level driver that
+ *     that wants to do either of the two standard UDC implementations
+ *     Control-Bulk-Interrupt or  Bulk-IN/Bulk-Out standards. Hence
+ *     gserial and cdc_acm should work with this code.
+ *
+ * 4.  NAK events never actually get raised at all, the documentation
+ *     is just wrong !
+ *
+ * 5.  For some reason, cbd_datlen is *always* +2 the value it should be.
+ *     this means that having an RX cbd of 16 bytes is not possible, since
+ *     the same size is reported for 14 bytes received as 16 bytes received
+ *     until we can find out why this happens, RX cbds must be limited to 8
+ *     bytes. TODO: check errata for this behaviour.
+ *
+ * 6.  Right now this code doesn't support properly powering up with the USB
+ *     cable attached to the USB host my development board the Adder87x doesn't
+ *     have a pull-up fitted to allow this, so it is necessary to power the
+ *     board and *then* attached the USB cable to the host. However somebody
+ *     with a different design in their board may be able to keep the cable
+ *     constantly connected and simply enable/disable a pull-up  re
+ *     figure 31.1 in MPC885RM.pdf instead of having to power up the board and
+ *     then attach the cable !
+ *
+ */
+#include <common.h>
+#include <config.h>
+
+#if defined(CONFIG_MPC885_FAMILY) && defined(CONFIG_USB_DEVICE)
+#include <commproc.h>
+#include "usbdcore.h"  
+#include "usbdcore_mpc8xx.h"
+#include "usbdcore_ep0.h"
+
+#define ERR(fmt, args...)\
+       serial_printf("ERROR : [%s] %s:%d: "fmt,\
+                               __FILE__,__FUNCTION__,__LINE__, ##args)
+#ifdef __DEBUG_UDC__
+       #define DBG(fmt,args...)\
+               serial_printf("[%s] %s:%d: "fmt,\
+                               __FILE__,__FUNCTION__,__LINE__, ##args)
+#else
+       #define DBG(fmt,args...)
+#endif
+
+/* Static Data */
+#ifdef __SIMULATE_ERROR__
+       static char err_poison_test = 0;
+#endif
+static struct mpc8xx_ep ep_ref[MAX_ENDPOINTS];
+static u32 address_base = STATE_NOT_READY;
+static mpc8xx_udc_state_t udc_state = 0;
+static struct usb_device_instance *udc_device = 0;
+static volatile usb_epb_t *endpoints[MAX_ENDPOINTS];           
+static volatile cbd_t * tx_cbd[TX_RING_SIZE];
+static volatile cbd_t * rx_cbd[RX_RING_SIZE];
+static volatile immap_t *immr = 0;
+static volatile cpm8xx_t *cp = 0;
+static volatile usb_pram_t *usb_paramp = 0;
+static volatile usb_t *usbp = 0;
+static int rx_ct = 0;
+static int tx_ct = 0;
+
+/* Static Function Declarations */
+static void mpc8xx_udc_state_transition_up (usb_device_state_t initial,
+                                            usb_device_state_t final);    
+static void mpc8xx_udc_state_transition_down (usb_device_state_t initial,
+                                              usb_device_state_t final);
+static void mpc8xx_udc_stall (unsigned int ep);
+static void mpc8xx_udc_flush_tx_fifo(int epid);
+static void mpc8xx_udc_flush_rx_fifo(void);
+static void mpc8xx_udc_clear_rxbd (volatile cbd_t * rx_cbdp);
+static void mpc8xx_udc_init_tx(struct usb_endpoint_instance *epi, 
+               struct urb * tx_urb);
+static void mpc8xx_udc_dump_request(struct usb_device_request *request);
+static void mpc8xx_udc_clock_init (volatile immap_t * immr, 
+               volatile cpm8xx_t * cp);
+static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi);
+static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp);
+static void mpc8xx_udc_ep0_rx(volatile cbd_t * rx_cbdp);
+static void mpc8xx_udc_cbd_init (void);
+static void mpc8xx_udc_endpoint_init (void);
+static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size);
+static u32 mpc8xx_udc_alloc (u32 data_size, u32 alignment);
+static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp);
+static void mpc8xx_udc_set_nak (unsigned int ep);
+static short mpc8xx_udc_handle_txerr(void);
+static void mpc8xx_udc_advance_rx(volatile cbd_t ** rx_cbdp, int epid);
+
+/******************************************************************************
+                               Global Linkage
+ *****************************************************************************/
+
+/* udc_init
+ *
+ * Do initial bus gluing
+ */
+int udc_init(void)
+{
+       /* Init various pointers */
+       immr = (immap_t *) CFG_IMMR;
+       cp = (cpm8xx_t *)&(immr->im_cpm);
+       usb_paramp = (usb_pram_t*)&(cp->cp_dparam[PROFF_USB]);
+       usbp = (usb_t *) &(cp->cp_scc[0]);
+
+       memset(ep_ref, 0x00, (sizeof(struct mpc8xx_ep) * MAX_ENDPOINTS));
+       
+       udc_device = 0;
+       udc_state = STATE_NOT_READY;
+       
+       usbp->usmod= 0x00;
+       usbp->uscom= 0;
+               
+       /* Set USB Frame #0, Respond at Address & Get a clock source  */
+       usbp->usaddr = 0x00;
+       mpc8xx_udc_clock_init (immr, cp);
+       
+       /* PA15, PA14 as perhiperal USBRXD and USBOE */
+       immr->im_ioport.iop_padir&= ~0x0003;
+       immr->im_ioport.iop_papar|= 0x0003;
+                               
+       /* PC11/PC10 as peripheral USBRXP USBRXN */
+       immr->im_ioport.iop_pcso|= 0x0030;
+       
+       /* PC7/PC6 as perhiperal USBTXP and USBTXN */
+       immr->im_ioport.iop_pcdir|= 0x0300;
+       immr->im_ioport.iop_pcpar|= 0x0300;
+       
+       /* Set the base address */
+       address_base = (u32)(cp->cp_dpmem + CPM_USB_BASE);
+
+       /* Initialise endpoints and circular buffers */
+       mpc8xx_udc_endpoint_init();     
+       mpc8xx_udc_cbd_init();          
+               
+       /* Assign allocated Dual Port Endpoint descriptors */
+       usb_paramp->ep0ptr = (u32)endpoints[0];
+       usb_paramp->ep1ptr = (u32)endpoints[1];
+       usb_paramp->ep2ptr = (u32)endpoints[2];
+       usb_paramp->ep3ptr = (u32)endpoints[3];
+       usb_paramp->frame_n = 0;
+
+       DBG("ep0ptr=0x%08x ep1ptr=0x%08x ep2ptr=0x%08x ep3ptr=0x%08x\n",
+               usb_paramp->ep0ptr, usb_paramp->ep1ptr, usb_paramp->ep2ptr,
+               usb_paramp->ep3ptr);
+       
+       return 0;
+}
+
+/* udc_irq
+ *
+ * Poll for whatever events may have occured
+ */
+void udc_irq(void)
+{
+       int epid = 0;
+       volatile cbd_t * rx_cbdp = 0;
+       volatile cbd_t * rx_cbdp_base = 0;
+
+       if(udc_state!=STATE_READY){
+               return;
+       }
+       
+       if(usbp->usber&USB_E_BSY){
+               /* This shouldn't happen. If it does then it's a bug ! */
+               usbp->usber|=USB_E_BSY; 
+               mpc8xx_udc_flush_rx_fifo();
+       }
+
+       
+       /* Scan all RX/Bidirectional Endpoints for RX data. */
+       for(epid = 0; epid<MAX_ENDPOINTS; epid++){
+                               
+               if(!ep_ref[epid].prx){
+                       continue;
+               }
+
+               rx_cbdp = rx_cbdp_base = ep_ref[epid].prx;
+               do{
+                       if(!(rx_cbdp->cbd_sc&RX_BD_E)){
+                               
+                               if(rx_cbdp->cbd_sc&0x1F){
+                                       /* Corrupt data discard it.
+                                        * Controller has NAK'd this packet. 
+                                        */
+                                       mpc8xx_udc_clear_rxbd(rx_cbdp);
+
+                               }else{
+                                       if(!epid){
+                                               mpc8xx_udc_ep0_rx(rx_cbdp);
+
+                                       }else{
+                                               /* Process data */
+                                               mpc8xx_udc_set_nak(epid);
+                                               mpc8xx_udc_epn_rx(epid,rx_cbdp);
+                                               mpc8xx_udc_clear_rxbd(rx_cbdp);
+                                       }       
+                               }
+                               
+                               /* Advance RX CBD pointer */
+                               mpc8xx_udc_advance_rx(&rx_cbdp, epid);
+                               ep_ref[epid].prx = rx_cbdp;
+                       }else{
+                               /* Advance RX CBD pointer */
+                               mpc8xx_udc_advance_rx(&rx_cbdp, epid);
+                       }
+
+               }while(rx_cbdp != rx_cbdp_base);
+       }
+
+       /* Handle TX events as appropiate, the correct place to do this is
+        * in a tx routine. Perhaps TX on epn was pre-empted by ep0
+        */
+
+       if(usbp->usber&USB_E_TXB){
+               usbp->usber|=USB_E_TXB;
+       }
+       
+       if(usbp->usber&(USB_TX_ERRMASK)){
+               mpc8xx_udc_handle_txerr();
+       }
+
+       /* Switch to the default state, respond at the default address */
+       if(usbp->usber&USB_E_RESET){
+               usbp->usber|=USB_E_RESET;
+               usbp->usaddr = 0x00;    
+               udc_device->device_state = STATE_DEFAULT;
+       }
+
+       /*if(usbp->usber&USB_E_IDLE){
+               We could suspend here !
+               usbp->usber|=USB_E_IDLE;
+               DBG("idle state change\n");             
+       }                       
+       if(usbp->usbs){
+               We could resume here when IDLE is deasserted !
+               Not worth doing, so long as we are self powered though.
+       }*/
+
+       return;
+}
+
+
+
+/* udc_endpoint_write
+ *
+ * Write some data to an endpoint
+ */
+int udc_endpoint_write(struct usb_endpoint_instance *epi)
+{
+       int ep = 0;
+       short epid = 1, unnak = 0, ret = 0;
+
+       if(udc_state != STATE_READY){
+               ERR("invalid udc_state != STATE_READY!\n");
+               return -1;
+       }
+
+       if(!udc_device || !epi){
+               return -1;
+       }
+       
+       if(udc_device->device_state!=STATE_CONFIGURED){
+               return -1;
+       }
+
+       ep = epi->endpoint_address & 0x03;
+       if(ep >= MAX_ENDPOINTS){
+               return -1;
+       }
+       
+       /* Set NAK for all RX endpoints during TX */
+       for(epid = 1; epid<MAX_ENDPOINTS; epid++){
+
+               /* Don't set NAK on DATA IN/CONTROL endpoints */
+               if(ep_ref[epid].sc & USB_DIR_IN){
+                       continue;
+               }
+
+               if(!(usbp->usep[epid]&( USEP_THS_NAK | USEP_RHS_NAK ))){
+                       unnak |= 1<<epid;
+               }
+
+               mpc8xx_udc_set_nak(epid);
+       }
+
+       mpc8xx_udc_init_tx(&udc_device->bus->endpoint_array[ep],epi->tx_urb);
+       ret = mpc8xx_udc_ep_tx(&udc_device->bus->endpoint_array[ep]);
+       
+       /* Remove temporary NAK */
+       for(epid = 1; epid<MAX_ENDPOINTS; epid++){
+               if(unnak&(1<<epid)){
+                       udc_unset_nak(epid);
+               }
+       }
+       
+       return ret;
+}
+
+/* mpc8xx_udc_assign_urb
+ *
+ * Associate a given urb to an endpoint TX or RX transmit/receive buffers
+ */
+static int mpc8xx_udc_assign_urb(int ep, char direction)
+{
+       struct usb_endpoint_instance *epi = 0;
+       
+       if(ep >= MAX_ENDPOINTS){
+               goto err;
+       }
+       epi = &udc_device->bus->endpoint_array[ep];
+       if(!epi){
+               goto err;
+       }
+
+       if(!ep_ref[ep].urb){
+               ep_ref[ep].urb = usbd_alloc_urb(udc_device, 
+                       udc_device->bus->endpoint_array);
+               if(!ep_ref[ep].urb){
+                       goto err;
+               }
+       }else{
+               ep_ref[ep].urb->actual_length = 0;
+       }
+
+       switch(direction){
+               case USB_DIR_IN:
+                       epi->tx_urb = ep_ref[ep].urb;
+                       break;
+               case USB_DIR_OUT:
+                       epi->rcv_urb = ep_ref[ep].urb;
+                       break;
+               default:
+                       goto err;
+       }
+       return 0;
+
+err:
+       udc_state = STATE_ERROR;
+       return -1;
+}
+
+/* udc_setup_ep
+ *
+ * Associate U-Boot software endpoints to mpc8xx endpoint parameter ram
+ * Isochronous endpoints aren't yet supported!
+ */
+void udc_setup_ep(struct usb_device_instance *device, unsigned int ep,
+                  struct usb_endpoint_instance *epi)
+{
+       uchar direction = 0;
+       int ep_attrib = 0;
+
+       if(epi && (ep < MAX_ENDPOINTS)){
+               
+               if(ep == 0){
+                       if (epi->rcv_attributes!=USB_ENDPOINT_XFER_CONTROL 
+                               ||epi->tx_attributes!= 
+                               USB_ENDPOINT_XFER_CONTROL){
+
+                               /* ep0 must be a control endpoint*/
+                               udc_state = STATE_ERROR;
+                               return;
+
+                       }
+                       if(!(ep_ref[ep].sc & EP_ATTACHED)){
+                               mpc8xx_udc_cbd_attach (ep, epi->tx_packetSize, 
+                                       epi->rcv_packetSize);
+                       }
+                       usbp->usep[ep] = 0x0000;
+                       return;
+               }
+               
+               if ((epi->endpoint_address & USB_ENDPOINT_DIR_MASK) 
+                       == USB_DIR_IN) {
+
+                       direction = 1;
+                       ep_attrib = epi->tx_attributes;
+                       epi->rcv_packetSize = 0;
+                       ep_ref[ep].sc |= USB_DIR_IN;            
+               } else {
+                       
+                       direction = 0;
+                       ep_attrib = epi->rcv_attributes;
+                       epi->tx_packetSize = 0; 
+                       ep_ref[ep].sc &= ~USB_DIR_IN;
+               }
+
+               if(mpc8xx_udc_assign_urb(ep, epi->endpoint_address
+                                       &USB_ENDPOINT_DIR_MASK)){
+                       return;
+               }
+
+               switch(ep_attrib){
+                       case USB_ENDPOINT_XFER_CONTROL:
+                               if(!(ep_ref[ep].sc & EP_ATTACHED)){
+                                       mpc8xx_udc_cbd_attach (ep,
+                                               epi->tx_packetSize, 
+                                               epi->rcv_packetSize);
+                               }
+                               usbp->usep[ep] = ep<<12;
+                               epi->rcv_urb = epi->tx_urb = ep_ref[ep].urb;
+
+                               break;
+                       case USB_ENDPOINT_XFER_BULK :
+                       case USB_ENDPOINT_XFER_INT:
+                               if(!(ep_ref[ep].sc & EP_ATTACHED)){
+                                       if(direction){
+                                               mpc8xx_udc_cbd_attach (ep, 
+                                                       epi->tx_packetSize, 0);
+                                       }else{
+                                               mpc8xx_udc_cbd_attach (ep, 
+                                                       0, epi->rcv_packetSize);
+                                       }
+                               }
+                               usbp->usep[ep]= (ep<<12)|((ep_attrib)<<8);
+                                       
+                               break;
+                       case USB_ENDPOINT_XFER_ISOC:
+                       default:
+                               serial_printf("Error endpoint attrib %d>3\n",
+                                               ep_attrib);
+                               udc_state = STATE_ERROR;
+                               break;
+               }
+       }
+
+}
+
+/* udc_connect
+ *
+ * Move state, switch on the USB
+ */
+void udc_connect(void)
+{
+       /* Enable pull-up resistor on D+ 
+        * TODO: fit a pull-up resistor to drive SE0 for > 2.5us
+        */
+       
+       if(udc_state!=STATE_ERROR){
+               udc_state = STATE_READY;
+               usbp->usmod|= USMOD_EN;
+       }
+}      
+
+/* udc_disconnect
+ *
+ * Disconnect is not used but, is included for completeness
+ */
+void udc_disconnect(void)
+{
+       /* Disable pull-up resistor on D-
+        * TODO: fix a pullup resistor to control this
+        */
+
+       if(udc_state!=STATE_ERROR){
+               udc_state = STATE_NOT_READY;
+       }
+       usbp->usmod&=~USMOD_EN;
+}
+
+/* udc_enable
+ * 
+ * Grab an EP0 URB, register interest in a subset of USB events
+ */
+void udc_enable(struct usb_device_instance *device)
+{
+       if(udc_state == STATE_ERROR){
+               return;
+       }
+
+       udc_device = device;
+       
+       if(!ep_ref[0].urb){
+               ep_ref[0].urb = usbd_alloc_urb(device, 
+                                       device->bus->endpoint_array);
+       }
+
+       /* Register interest in all events except SOF, enable transceiver */
+       usbp->usber= 0x03FF;
+       usbp->usbmr= 0x02F7;
+
+       return;
+}
+
+/* udc_disable
+ *
+ * disable the currently hooked device
+ */
+void udc_disable(void)
+{
+       int i = 0;
+
+       if(udc_state == STATE_ERROR){
+               DBG("Won't disable UDC. udc_state==STATE_ERROR !\n");
+               return;
+       }
+
+       udc_device = 0;
+
+       for(;i<MAX_ENDPOINTS; i++){
+               if(ep_ref[i].urb){
+                       usbd_dealloc_urb(ep_ref[i].urb);
+                       ep_ref[i].urb = 0;
+               }
+       }
+               
+       usbp->usbmr= 0x00;      
+       usbp->usmod= ~USMOD_EN;
+       udc_state = STATE_NOT_READY;
+}
+
+/* udc_startup_events
+ *
+ * Enable the specified device
+ */
+void udc_startup_events(struct usb_device_instance *device)
+{
+       udc_enable(device);
+       if(udc_state == STATE_READY){
+               usbd_device_event_irq (device, DEVICE_CREATE, 0);
+       }
+}
+
+/* udc_set_nak
+ * 
+ * Allow upper layers to signal lower layers should not accept more RX data
+ *
+ */
+void udc_set_nak(int epid)
+{
+       if(epid){
+               mpc8xx_udc_set_nak(epid);
+       }
+}
+
+/* udc_unset_nak 
+ * 
+ * Suspend sending of NAK tokens for DATA OUT tokens on a given endpoint.
+ * Switch off NAKing on this endpoint to accept more data output from host.
+ *
+ */
+void udc_unset_nak (int epid)
+{
+       if(epid > MAX_ENDPOINTS){
+               return;
+       }
+
+       if(usbp->usep[epid]&(USEP_THS_NAK | USEP_RHS_NAK)){
+               usbp->usep[epid]&= ~(USEP_THS_NAK | USEP_RHS_NAK);
+               __asm__ ("eieio");
+       }
+}
+
+/******************************************************************************
+                              Static Linkage
+******************************************************************************/
+
+/* udc_state_transition_up
+ * udc_state_transition_down
+ *
+ * Helper functions to implement device state changes. The device states and
+ * the events that transition between them are:
+ *
+ *                             STATE_ATTACHED
+ *                             ||      /\
+ *                             \/      ||
+ *     DEVICE_HUB_CONFIGURED                   DEVICE_HUB_RESET
+ *                             ||      /\
+ *                             \/      ||
+ *                             STATE_POWERED
+ *                             ||      /\
+ *                             \/      ||
+ *     DEVICE_RESET                            DEVICE_POWER_INTERRUPTION
+ *                             ||      /\
+ *                             \/      ||
+ *                             STATE_DEFAULT
+ *                             ||      /\
+ *                             \/      ||
+ *     DEVICE_ADDRESS_ASSIGNED                 DEVICE_RESET
+ *                             ||      /\
+ *                             \/      ||
+ *                             STATE_ADDRESSED
+ *                             ||      /\
+ *                             \/      ||
+ *     DEVICE_CONFIGURED                       DEVICE_DE_CONFIGURED
+ *                             ||      /\
+ *                             \/      ||
+ *                             STATE_CONFIGURED
+ *
+ * udc_state_transition_up transitions up (in the direction from STATE_ATTACHED
+ * to STATE_CONFIGURED) from the specified initial state to the specified final
+ * state, passing through each intermediate state on the way.  If the initial
+ * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then
+ * no state transitions will take place.
+ *
+ * udc_state_transition_down transitions down (in the direction from
+ * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the
+ * specified final state, passing through each intermediate state on the way.
+ * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final
+ * state, then no state transitions will take place.
+ *
+ */
+static void mpc8xx_udc_state_transition_up (usb_device_state_t initial,
+                                    usb_device_state_t final)
+{              
+       if (initial < final) {
+               switch (initial) {
+               case STATE_ATTACHED:
+                       usbd_device_event_irq (udc_device,
+                                              DEVICE_HUB_CONFIGURED, 0);
+                       if (final == STATE_POWERED)
+                               break;
+               case STATE_POWERED:
+                       usbd_device_event_irq (udc_device, DEVICE_RESET, 0);
+                       if (final == STATE_DEFAULT)
+                               break;
+               case STATE_DEFAULT:
+                       usbd_device_event_irq (udc_device,
+                                              DEVICE_ADDRESS_ASSIGNED, 0);
+                       if (final == STATE_ADDRESSED)
+                               break;
+               case STATE_ADDRESSED:
+                       usbd_device_event_irq (udc_device, DEVICE_CONFIGURED,
+                                              0);
+               case STATE_CONFIGURED:
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static void mpc8xx_udc_state_transition_down (usb_device_state_t initial,
+                                      usb_device_state_t final)
+{
+       if (initial > final) {
+               switch (initial) {
+               case STATE_CONFIGURED:
+                       usbd_device_event_irq (udc_device, 
+                                       DEVICE_DE_CONFIGURED, 0);
+                       if (final == STATE_ADDRESSED)
+                               break;
+               case STATE_ADDRESSED:
+                       usbd_device_event_irq (udc_device, DEVICE_RESET, 0);
+                       if (final == STATE_DEFAULT)
+                               break;
+               case STATE_DEFAULT:
+                       usbd_device_event_irq (udc_device, 
+                                       DEVICE_POWER_INTERRUPTION, 0);
+                       if (final == STATE_POWERED)
+                               break;
+               case STATE_POWERED:
+                       usbd_device_event_irq (udc_device, DEVICE_HUB_RESET,
+                                       0);
+               case STATE_ATTACHED:
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+/* mpc8xx_udc_stall
+ *
+ * Force returning of STALL tokens on the given endpoint. Protocol or function
+ * STALL conditions are permissable here
+ */
+static void mpc8xx_udc_stall (unsigned int ep)
+{
+       usbp->usep[ep] |= STALL_BITMASK;
+}
+
+/* mpc8xx_udc_set_nak
+ *
+ * Force returning of NAK responses for the given endpoint as a kind of very
+ * simple flow control
+ */ 
+static void mpc8xx_udc_set_nak (unsigned int ep)
+{
+       usbp->usep[ep] |= NAK_BITMASK;
+       __asm__ ("eieio");
+}
+
+/* mpc8xx_udc_handle_txerr
+ *
+ * Handle errors relevant to TX. Return a status code to allow calling
+ * indicative of what if anything happened
+ */
+static short mpc8xx_udc_handle_txerr()
+{
+       short ep = 0, ret = 0;
+       
+       for(; ep<TX_RING_SIZE; ep++){
+               if(usbp->usber&(0x10<<ep)){
+                       
+                       /* Timeout or underrun */
+                       if(tx_cbd[ep]->cbd_sc&0x06){
+                               ret = 1;
+                               mpc8xx_udc_flush_tx_fifo(ep);
+
+                       }else{
+                               if(usbp->usep[ep]&STALL_BITMASK){
+                                       if(!ep){
+                                               usbp->usep[ep]&=
+                                                       ~STALL_BITMASK;
+                                       }
+                               }/* else NAK */
+                       }
+                       usbp->usber|=(0x10<<ep);
+               }
+       }
+       return ret;
+}
+
+/* mpc8xx_udc_advance_rx
+ *
+ * Advance cbd rx
+ */
+static void mpc8xx_udc_advance_rx(volatile cbd_t ** rx_cbdp, int epid)
+{
+       if((*rx_cbdp)->cbd_sc & RX_BD_W){
+               *rx_cbdp  = (volatile cbd_t*)
+                       (endpoints[epid]->rbase + CFG_IMMR);
+                       
+       }else{
+               (*rx_cbdp)++;
+       }
+}
+
+
+/* mpc8xx_udc_flush_tx_fifo
+ *
+ * Flush a given TX fifo. Assumes one tx cbd per endpoint
+ */
+static void mpc8xx_udc_flush_tx_fifo(int epid)
+{      
+       volatile cbd_t * tx_cbdp = 0;
+
+       if(epid > MAX_ENDPOINTS){
+               return;
+       }
+
+       /* TX stop */
+       immr->im_cpm.cp_cpcr = ((epid<<2) | 0x1D01);
+       __asm__ ("eieio");
+       while(immr->im_cpm.cp_cpcr & 0x01);
+       
+       usbp->uscom = 0x40 | 0;
+       
+       /* reset ring */
+       tx_cbdp = (cbd_t*)(endpoints[epid]->tbptr + CFG_IMMR);
+       tx_cbdp->cbd_sc = (TX_BD_I | TX_BD_W);
+
+               
+       endpoints[epid]->tptr = endpoints[epid]->tbase;
+       endpoints[epid]->tstate = 0x00;
+       endpoints[epid]->tbcnt  = 0x00;
+
+       /* TX start */
+       immr->im_cpm.cp_cpcr = ((epid<<2) | 0x2D01);
+       __asm__ ("eieio");
+       while(immr->im_cpm.cp_cpcr & 0x01);
+
+       return;
+}
+
+/* mpc8xx_udc_flush_rx_fifo
+ *
+ * For the sake of completeness of the namespace, it seems like
+ * a good-design-decision (tm) to include mpc8xx_udc_flush_rx_fifo();
+ * If RX_BD_E is true => a driver bug either here or in an upper layer
+ * not polling frequently enough. If RX_BD_E is true we have told the host
+ * we have accepted data but, the CPM found it had no-where to put that data
+ * which needless to say would be a bad thing.
+ */
+static void mpc8xx_udc_flush_rx_fifo()
+{
+       int i = 0;
+       for(i = 0;i<RX_RING_SIZE; i++){
+               if(!(rx_cbd[i]->cbd_sc&RX_BD_E)){
+                       ERR("buf %p used rx data len = 0x%x sc=0x%x!\n",
+                               rx_cbd[i], rx_cbd[i]->cbd_datlen, 
+                               rx_cbd[i]->cbd_sc);
+
+               }
+       }
+       ERR("BUG : Input over-run\n");  
+}
+
+/* mpc8xx_udc_clear_rxbd
+ * 
+ * Release control of RX CBD to CP.
+ */
+static void mpc8xx_udc_clear_rxbd(volatile cbd_t * rx_cbdp)
+{
+       rx_cbdp->cbd_datlen = 0x0000;
+       rx_cbdp->cbd_sc= ((rx_cbdp->cbd_sc & RX_BD_W)|(RX_BD_E | RX_BD_I));
+       __asm__ ("eieio");
+}
+
+/* mpc8xx_udc_tx_irq
+ *
+ * Parse for tx timeout, control RX or USB reset/busy conditions
+ * Return -1 on timeout, -2 on fatal error, else return zero
+ */
+static int mpc8xx_udc_tx_irq(int ep)
+{
+       int i = 0;
+
+       if(usbp->usber&(USB_TX_ERRMASK)){
+               if(mpc8xx_udc_handle_txerr()){
+                       /* Timeout, controlling function must retry send */
+                       return -1;
+               }
+       }
+
+       if(usbp->usber & (USB_E_RESET|USB_E_BSY)){
+               /* Fatal, abandon TX transaction */
+               return -2;
+       }
+       
+       if(usbp->usber & USB_E_RXB){
+               for(i = 0;i<RX_RING_SIZE; i++){
+                       if(!(rx_cbd[i]->cbd_sc&RX_BD_E)){
+                               if((rx_cbd[i] == ep_ref[0].prx) || ep){
+                                       return -2;      
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/* mpc8xx_udc_ep_tx
+ *
+ * Transmit in a re-entrant fashion outbound USB packets.
+ * Implement retry/timeout mechanism described in USB specification
+ * Toggle DATA0/DATA1 pids as necessary
+ * Introduces non-standard tx_retry. The USB standard has no scope for slave
+ * devices to give up TX, however tx_retry stops us getting stuck in an endless
+ * TX loop.
+ */
+static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi) 
+{
+       struct urb *urb = epi->tx_urb;
+       volatile cbd_t * tx_cbdp = 0;
+       unsigned int ep = 0, pkt_len = 0, x = 0, tx_retry = 0;
+       int ret = 0;
+       
+       if(!epi || (epi->endpoint_address&0x03)>=MAX_ENDPOINTS || !urb){
+               return -1;
+       }
+
+       ep = epi->endpoint_address & 0x03;
+       tx_cbdp = (cbd_t*)(endpoints[ep]->tbptr + CFG_IMMR);
+               
+       if(tx_cbdp->cbd_sc&TX_BD_R || usbp->usber&USB_E_TXB){
+               mpc8xx_udc_flush_tx_fifo(ep);
+               usbp->usber |= USB_E_TXB;
+       };
+
+       while(tx_retry++ < 100){
+               ret = mpc8xx_udc_tx_irq(ep);
+               if(ret == -1){
+                       /* ignore timeout here */
+               }else if(ret == -2){
+                       /* Abandon TX */
+                       mpc8xx_udc_flush_tx_fifo(ep);   
+                       return -1;
+               }       
+
+               tx_cbdp = (cbd_t*)(endpoints[ep]->tbptr + CFG_IMMR);
+               while(tx_cbdp->cbd_sc&TX_BD_R){};
+               tx_cbdp->cbd_sc = (tx_cbdp->cbd_sc&TX_BD_W);
+       
+               pkt_len = urb->actual_length - epi->sent;
+
+               if(pkt_len> epi->tx_packetSize || pkt_len > EP_MAX_PKT){
+                       pkt_len = MIN(epi->tx_packetSize, EP_MAX_PKT);
+               }
+
+               for(x=0; x<pkt_len; x++){
+                       *((unsigned char*)(tx_cbdp->cbd_bufaddr+x)) = 
+                               urb->buffer[epi->sent + x];
+               }
+               tx_cbdp->cbd_datlen = pkt_len;
+               tx_cbdp->cbd_sc|=(CBD_TX_BITMASK | ep_ref[ep].pid);
+               __asm__ ("eieio");
+
+               #ifdef __SIMULATE_ERROR__
+                       if(++err_poison_test == 2){
+                               err_poison_test = 0;
+                               tx_cbdp->cbd_sc&=~TX_BD_TC;
+                       }
+               #endif
+
+               usbp->uscom = (USCOM_STR | ep); 
+
+               while(!(usbp->usber&USB_E_TXB)){
+                       ret = mpc8xx_udc_tx_irq(ep);
+                       if(ret == -1){
+                               /* TX timeout */
+                               break;
+                       }else if(ret == -2){
+                               if(usbp->usber & USB_E_TXB){
+                                       usbp->usber|=USB_E_TXB;
+                               }
+                               mpc8xx_udc_flush_tx_fifo(ep);   
+                               return -1;
+                       }
+               };
+
+               if(usbp->usber & USB_E_TXB){
+                       usbp->usber|=USB_E_TXB;
+               }
+
+               /* ACK must be present <= 18bit times from TX */
+               if(ret == -1){
+                       continue;
+               }
+       
+               /* TX ACK : USB 2.0 8.7.2, Toggle PID, Advance TX */
+               epi->sent += pkt_len;
+               epi->last = MIN (urb->actual_length - epi->sent, 
+                               epi->tx_packetSize);
+               TOGGLE_TX_PID(ep_ref[ep].pid);
+
+               if(epi->sent >= epi->tx_urb->actual_length){
+                       
+                       epi->tx_urb->actual_length = 0;
+                       epi->sent = 0;
+                       
+                       if(ep_ref[ep].sc & EP_SEND_ZLP){
+                               ep_ref[ep].sc &= ~EP_SEND_ZLP;
+                       }else{
+                               return 0;
+                       }
+               }
+       }
+       
+       ERR("TX fail, endpoint 0x%x tx bytes 0x%x/0x%x\n",ep, epi->sent,
+               epi->tx_urb->actual_length);
+
+       return -1;
+}
+
+/* mpc8xx_udc_dump_request
+ *
+ * Dump a control request to console
+ */
+static void mpc8xx_udc_dump_request(struct usb_device_request *request)
+{
+       DBG(
+       "bmRequestType:%02x bRequest:%02x wValue:%04x "
+       "wIndex:%04x wLength:%04x ?\n",
+               request->bmRequestType,
+               request->bRequest,
+               request->wValue,
+               request->wIndex,
+               request->wLength);
+
+       return;
+}
+
+/* mpc8xx_udc_ep0_rx_setup 
+ * 
+ * Decode received ep0 SETUP packet. return non-zero on error
+ */
+static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp)
+{
+       unsigned int x = 0;
+       struct urb * purb = ep_ref[0].urb;
+       struct usb_endpoint_instance *epi = 
+               &udc_device->bus->endpoint_array[0];
+
+       for(; x<rx_cbdp->cbd_datlen; x++){
+               *(((unsigned char*)&ep_ref[0].urb->device_request)+x) = 
+                       *((unsigned char*)(rx_cbdp->cbd_bufaddr+x));
+       }
+       
+       mpc8xx_udc_clear_rxbd(rx_cbdp); 
+
+       if (ep0_recv_setup(purb)) {
+               mpc8xx_udc_dump_request(&purb->device_request);
+               return -1;
+       }
+
+       if ((purb->device_request.bmRequestType&USB_REQ_DIRECTION_MASK)
+           == USB_REQ_HOST2DEVICE) {
+
+               switch (purb->device_request.bRequest){
+                       case USB_REQ_SET_ADDRESS:
+                               /* Send the Status OUT ZLP */
+                               ep_ref[0].pid = TX_BD_PID_DATA1;
+                               purb->actual_length = 0;
+                               mpc8xx_udc_init_tx(epi,purb);
+                               mpc8xx_udc_ep_tx(epi);
+                               
+                               /* Move to the addressed state */
+                               usbp->usaddr = udc_device->address;
+                               mpc8xx_udc_state_transition_up(udc_device->device_state,
+                                       STATE_ADDRESSED);
+                               return 0;
+
+                       case USB_REQ_SET_CONFIGURATION:
+                               if(!purb->device_request.wValue){
+                                       
+                                       /* Respond at default address */
+                                       usbp->usaddr = 0x00;    
+                                       mpc8xx_udc_state_transition_down(udc_device->device_state,
+                                               STATE_ADDRESSED);
+
+                               } else {
+                                       
+                                       /* TODO: Support multiple configurations */
+                                       mpc8xx_udc_state_transition_up(udc_device->device_state,STATE_CONFIGURED);
+                                       for(x=1; x<MAX_ENDPOINTS; x++){
+                                               if((udc_device->bus->endpoint_array[x].endpoint_address&USB_ENDPOINT_DIR_MASK) 
+                                                       == USB_DIR_IN){
+                                                       ep_ref[x].pid = TX_BD_PID_DATA0;
+                                               }else{
+                                                       ep_ref[x].pid = RX_BD_PID_DATA0;
+                                               }
+                                               /* Set configuration must unstall endpoints */
+                                               usbp->usep[x]&=~STALL_BITMASK;
+                                       }
+
+                               }
+                               break;
+                       default:
+                               /* CDC/Vendor specific */
+                               break;
+               }
+
+               /* Send ZLP as ACK in Status OUT phase */
+               ep_ref[0].pid = TX_BD_PID_DATA1;
+               purb->actual_length = 0;
+               mpc8xx_udc_init_tx(epi,purb);
+               mpc8xx_udc_ep_tx(epi);
+
+       }else{
+               if(purb->actual_length){
+                       ep_ref[0].pid = TX_BD_PID_DATA1;
+                       mpc8xx_udc_init_tx(epi,purb);
+
+                       if(!(purb->actual_length%EP0_MAX_PACKET_SIZE)){
+                               ep_ref[0].sc |= EP_SEND_ZLP;
+                       }
+
+                       if(purb->device_request.wValue==
+                                       USB_DESCRIPTOR_TYPE_DEVICE){
+                               if(le16_to_cpu(purb->device_request.wLength)>
+                                               purb->actual_length){
+                                       /* Send EP0_MAX_PACKET_SIZE bytes
+                                        * unless correct size requested.
+                                        */
+                                       if(purb->actual_length > 
+                                                       epi->tx_packetSize){
+                                               
+                                               purb->actual_length =
+                                                       epi->tx_packetSize;
+                                       }
+                                       
+                               }
+                       }
+                       mpc8xx_udc_ep_tx(epi);
+
+               }else{
+                       /* Corrupt SETUP packet? */
+                       ERR("Zero length data or SETUP with DATA-IN phase ?\n");
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/* mpc8xx_udc_init_tx
+ *
+ * Setup some basic parameters for a TX transaction
+ */
+static void mpc8xx_udc_init_tx(struct usb_endpoint_instance *epi, 
+               struct urb * tx_urb)
+{
+       epi->sent = 0;
+       epi->last = 0;
+       epi->tx_urb = tx_urb;
+}
+
+/* mpc8xx_udc_ep0_rx
+ *
+ * Receive ep0/control USB data. Parse and possibly send a response.
+ */
+static void mpc8xx_udc_ep0_rx(volatile cbd_t * rx_cbdp)
+{
+       if(rx_cbdp->cbd_sc&RX_BD_PID_SETUP){
+               
+               /* Unconditionally accept SETUP packets */
+               if(mpc8xx_udc_ep0_rx_setup(rx_cbdp)){
+                       mpc8xx_udc_stall (0);   
+               }
+               
+       } else {
+               
+               mpc8xx_udc_clear_rxbd(rx_cbdp);
+               
+               if((rx_cbdp->cbd_datlen-2)){
+                       /* SETUP with a DATA phase
+                        * outside of SETUP packet.
+                        * Reply with STALL.
+                        */
+                       mpc8xx_udc_stall (0);
+               }
+       }
+}
+
+/* mpc8xx_udc_epn_rx
+ *
+ * Receive some data from cbd into USB system urb data abstraction
+ * Upper layers should NAK if there is insufficient RX data space 
+ */
+static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp)
+{
+       struct usb_endpoint_instance *epi = 0;
+       struct urb *urb = 0;
+       unsigned int x = 0;
+
+       if(epid >= MAX_ENDPOINTS || !rx_cbdp->cbd_datlen){
+               return 0;
+       }
+       
+       /* USB 2.0 PDF section 8.6.4 
+        * Discard data with invalid PID it is a resend.
+        */
+       if(ep_ref[epid].pid!=(rx_cbdp->cbd_sc&0xC0)){
+               return 1;
+       }
+       TOGGLE_RX_PID(ep_ref[epid].pid);
+       
+       epi = &udc_device->bus->endpoint_array[epid];
+       urb = epi->rcv_urb;
+
+       for(; x<(rx_cbdp->cbd_datlen-2); x++){
+               *((unsigned char*)(urb->buffer + urb->actual_length +x)) =
+                       *((unsigned char*)(rx_cbdp->cbd_bufaddr+x));
+       }
+
+       if(x){
+               usbd_rcv_complete (epi, x, 0);
+               if(ep_ref[epid].urb->status == RECV_ERROR){
+                       DBG("RX error unset NAK\n");
+                       udc_unset_nak(epid);
+               }
+       }       
+       return x;
+}
+
+/* mpc8xx_udc_clock_init
+ *
+ * Obtain a clock reference for Full Speed Signaling 
+ */
+static void mpc8xx_udc_clock_init (volatile immap_t * immr, 
+                                   volatile cpm8xx_t * cp)
+{
+
+#if defined(CFG_USB_EXTC_CLK)
+
+       /* This has been tested with a 48MHz crystal on CLK6 */
+       switch(CFG_USB_EXTC_CLK){
+               case 1:
+                       immr->im_ioport.iop_papar|= 0x0100;
+                       immr->im_ioport.iop_padir&= ~0x0100;
+                       cp->cp_sicr|= 0x24;
+                       break;
+               case 2:
+                       immr->im_ioport.iop_papar|= 0x0200;
+                       immr->im_ioport.iop_padir&= ~0x0200;
+                       cp->cp_sicr|= 0x2D; 
+                       break;
+               case 3:
+                       immr->im_ioport.iop_papar|= 0x0400;
+                       immr->im_ioport.iop_padir&= ~0x0400;
+                       cp->cp_sicr|= 0x36; 
+                       break;
+               case 4:
+                       immr->im_ioport.iop_papar|= 0x0800;
+                       immr->im_ioport.iop_padir&= ~0x0800;
+                       cp->cp_sicr|= 0x3F; 
+                       break;
+               default:
+                       udc_state = STATE_ERROR;
+                       break;
+       }
+
+#elif defined(CFG_USB_BRGCLK)
+
+       /* This has been tested with brgclk == 50MHz */ 
+       DECLARE_GLOBAL_DATA_PTR;
+       int divisor = 0;
+
+       if(gd->cpu_clk<48000000L){
+               ERR("brgclk is too slow for full-speed USB!\n");
+               udc_state = STATE_ERROR;
+               return;
+       }
+
+       /* Assume the brgclk is 'good enough', we want !(gd->cpu_clk%48Mhz)
+        * but, can /probably/ live with close-ish alternative rates.
+        */     
+       divisor = (gd->cpu_clk/48000000L)-1;
+       cp->cp_sicr &= ~0x0000003F;
+               
+       switch(CFG_USB_BRGCLK){
+               case 1:
+                       cp->cp_brgc1 |= (divisor|CPM_BRG_EN);
+                       cp->cp_sicr &= ~0x2F;
+                       break;
+               case 2:
+                       cp->cp_brgc2 |= (divisor|CPM_BRG_EN);
+                       cp->cp_sicr  |= 0x00000009;
+                       break;
+               case 3:
+                       cp->cp_brgc3 |= (divisor|CPM_BRG_EN);
+                       cp->cp_sicr  |= 0x00000012;
+                       break;
+               case 4:
+                       cp->cp_brgc4 = (divisor|CPM_BRG_EN);
+                       cp->cp_sicr  |= 0x0000001B; 
+                       break;
+               default:
+                       udc_state = STATE_ERROR;
+                       break;
+       }
+
+#else
+       #error "CFG_USB_EXTC_CLK or CFG_USB_BRGCLK must be defined"
+#endif
+
+}
+
+/* mpc8xx_udc_cbd_attach
+ *
+ * attach a cbd to and endpoint
+ */
+static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size)
+{
+       
+       if (!tx_cbd[ep] || !rx_cbd[ep] || ep >= MAX_ENDPOINTS){
+               udc_state = STATE_ERROR;
+               return;
+       }
+
+       if (tx_size>USB_MAX_PKT || rx_size>USB_MAX_PKT ||
+               (!tx_size && !rx_size)){
+               udc_state = STATE_ERROR;
+               return;
+       }
+
+       /* Attach CBD to appropiate Parameter RAM Endpoint data structure */
+       if(rx_size){
+               endpoints[ep]->rbase = (u32)rx_cbd[rx_ct];
+               endpoints[ep]->rbptr = (u32)rx_cbd[rx_ct];
+               rx_ct++;
+
+               if(!ep){
+                       
+                       endpoints[ep]->rbptr = (u32)rx_cbd[rx_ct];      
+                       rx_cbd[rx_ct]->cbd_sc |= RX_BD_W;
+                       rx_ct++;
+
+               }else{
+                       rx_ct += 2;
+                       endpoints[ep]->rbptr = (u32)rx_cbd[rx_ct];      
+                       rx_cbd[rx_ct]->cbd_sc |= RX_BD_W;
+                       rx_ct++;
+               }
+
+               /* Where we expect to RX data on this endpoint */
+               ep_ref[ep].prx = rx_cbd[rx_ct-1];
+       }else{
+
+               ep_ref[ep].prx = 0;
+               endpoints[ep]->rbase = 0;
+               endpoints[ep]->rbptr = 0;
+       }
+
+       if(tx_size){
+               endpoints[ep]->tbase = (u32)tx_cbd[tx_ct];
+               endpoints[ep]->tbptr = (u32)tx_cbd[tx_ct];
+               tx_ct++;
+       }else{
+               endpoints[ep]->tbase = 0;
+               endpoints[ep]->tbptr = 0;
+       }
+
+       endpoints[ep]->tstate = 0;
+       endpoints[ep]->tbcnt = 0;
+       endpoints[ep]->mrblr = EP_MAX_PKT;
+       endpoints[ep]->rfcr = 0x18;     
+       endpoints[ep]->tfcr = 0x18;
+       ep_ref[ep].sc |= EP_ATTACHED;
+
+       DBG("ep %d rbase 0x%08x rbptr 0x%08x tbase 0x%08x tbptr 0x%08x prx = %p\n",
+               ep, endpoints[ep]->rbase, endpoints[ep]->rbptr, endpoints[ep]->tbase,
+                       endpoints[ep]->tbptr, ep_ref[ep].prx);
+
+       return;
+}
+
+/* mpc8xx_udc_cbd_init
+ *
+ * Allocate space for a cbd and allocate TX/RX data space
+ */
+static void mpc8xx_udc_cbd_init (void)
+{
+       int i = 0;
+
+       for(; i<TX_RING_SIZE; i++){
+               tx_cbd[i]= (cbd_t*)
+                       mpc8xx_udc_alloc(sizeof(cbd_t), sizeof(int));
+       }
+
+       for(i=0; i<RX_RING_SIZE; i++){
+               rx_cbd[i]= (cbd_t*)
+                       mpc8xx_udc_alloc(sizeof(cbd_t),sizeof(int));
+       }       
+
+       for(i=0; i< TX_RING_SIZE; i++){
+               tx_cbd[i]->cbd_bufaddr = 
+                       mpc8xx_udc_alloc(EP_MAX_PKT, sizeof(int));
+                       
+               tx_cbd[i]->cbd_sc = (TX_BD_I | TX_BD_W);        
+               tx_cbd[i]->cbd_datlen = 0x0000;
+       }
+
+
+       for(i=0; i< RX_RING_SIZE; i++){
+               rx_cbd[i]->cbd_bufaddr = 
+                       mpc8xx_udc_alloc(EP_MAX_PKT, sizeof(int));
+               rx_cbd[i]->cbd_sc = (RX_BD_I | RX_BD_E);
+               rx_cbd[i]->cbd_datlen = 0x0000;
+
+       }
+
+       return;
+}
+
+/* mpc8xx_udc_endpoint_init
+ *
+ * Attach an endpoint to some dpram
+ */
+static void mpc8xx_udc_endpoint_init (void)
+{
+       int i = 0;
+
+       for(; i<MAX_ENDPOINTS; i++){
+               endpoints[i]= (usb_epb_t*)
+                       mpc8xx_udc_alloc(sizeof(usb_epb_t) , 32);
+       }
+}
+
+/* mpc8xx_udc_alloc
+ *
+ * Grab the address of some dpram 
+ */
+static u32 mpc8xx_udc_alloc (u32 data_size, u32 alignment)
+{
+       u32 retaddr = address_base;
+       
+       while(retaddr%alignment){
+               retaddr++;
+       }       
+       address_base+= data_size;
+       
+       return retaddr;
+}
+
+#endif /* CONFIG_MPC885_FAMILY && CONFIG_USB_DEVICE) */
index 1d54a635755ad3185f0c79e1134c43ff8ef5329c..83d898f0de9cc7796953f68b22b4d1f8a495a3e1 100644 (file)
@@ -645,7 +645,7 @@ static void omap1510_udc_state_changed (void)
 static void omap1510_udc_setup (struct usb_endpoint_instance *endpoint)
 {
        UDCDBG ("-> Entering device setup");
-
+       
        do {
                const int setup_pktsize = 8;
                unsigned char *datap =
@@ -1517,4 +1517,31 @@ void udc_startup_events (struct usb_device_instance *device)
        udc_enable (device);
 }
 
+/**
+ * udc_irq - do pseudo interrupts 
+ */
+void udc_irq(void)
+{
+       /* Loop while we have interrupts.
+        * If we don't do this, the input chain
+        * polling delay is likely to miss
+        * host requests.
+        */
+       while (inw (UDC_IRQ_SRC) & ~UDC_SOF_Flg) {
+               /* Handle any new IRQs */
+               omap1510_udc_irq ();
+               omap1510_udc_noniso_irq ();
+       }
+}
+
+/* Flow control */
+void udc_set_nak(int epid)
+{
+       /* TODO: implement this functionality in omap1510 */
+}
+
+void udc_unset_nak (int epid)
+{
+       /* TODO: implement this functionality in omap1510 */
+}
 #endif
index ce4a12e16e0eb7e0eb307a086a1014c327db0f80..ed96999e82011cc52f2de9cceb32623a258c46d4 100644 (file)
@@ -1,6 +1,9 @@
 /*
  * (C) Copyright 2003
  * Gerry Hamel, geh@ti.com, Texas Instruments
+ * 
+ * (C) Copyright 2006
+ * Bryan O'Donoghue, bodonoghue@codehermit.ie
  *
  * 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
 #include <circbuf.h>
 #include <devices.h>
 #include "usbtty.h"
+#include "usb_cdc_acm.h"
+#include "usbdescriptors.h"
+#include <config.h>            /* If defined, override Linux identifiers with
+                                * vendor specific ones */         
 
 #if 0
-#define TTYDBG(fmt,args...) serial_printf("[%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args)
+#define TTYDBG(fmt,args...)\
+       serial_printf("[%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args)
 #else
 #define TTYDBG(fmt,args...) do{}while(0)
 #endif
 
-#if 0
-#define TTYERR(fmt,args...) serial_printf("ERROR![%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args)
+#if 1
+#define TTYERR(fmt,args...)\
+       serial_printf("ERROR![%s] %s %d: "fmt, __FILE__,__FUNCTION__,\
+       __LINE__,##args)
 #else
 #define TTYERR(fmt,args...) do{}while(0)
 #endif
 
+/*
+ * Defines
+ */
+#define NUM_CONFIGS    1
+#define MAX_INTERFACES 2
+#define NUM_ENDPOINTS  3
+#define ACM_TX_ENDPOINT 3
+#define ACM_RX_ENDPOINT 2
+#define GSERIAL_TX_ENDPOINT 2
+#define GSERIAL_RX_ENDPOINT 1
+#define NUM_ACM_INTERFACES 2
+#define NUM_GSERIAL_INTERFACES 1
+#define CONFIG_USBD_DATA_INTERFACE_STR "Bulk Data Interface"
+#define CONFIG_USBD_CTRL_INTERFACE_STR "Control Interface"
+
 /*
  * Buffers to hold input and output data
  */
@@ -50,157 +75,336 @@ static circbuf_t usbtty_output;
  * Instance variables
  */
 static device_t usbttydev;
-static struct usb_device_instance       device_instance[1];
-static struct usb_bus_instance          bus_instance[1];
+static struct usb_device_instance device_instance[1];
+static struct usb_bus_instance bus_instance[1];
 static struct usb_configuration_instance config_instance[NUM_CONFIGS];
-static struct usb_interface_instance    interface_instance[NUM_INTERFACES];
-static struct usb_alternate_instance    alternate_instance[NUM_INTERFACES];
-static struct usb_endpoint_instance     endpoint_instance[NUM_ENDPOINTS+1]; /* one extra for control endpoint */
-
-/*
- * Static allocation of urbs
- */
-#define RECV_ENDPOINT 1
-#define TX_ENDPOINT 2
+static struct usb_interface_instance interface_instance[MAX_INTERFACES];
+static struct usb_alternate_instance alternate_instance[MAX_INTERFACES];
+/* one extra for control endpoint */
+static struct usb_endpoint_instance endpoint_instance[NUM_ENDPOINTS+1];
 
 /*
  * Global flag
  */
 int usbtty_configured_flag = 0;
 
-
 /*
  * Serial number
  */
 static char serial_number[16];
 
+
 /*
- * Descriptors
+ * Descriptors, Strings, Local variables.
  */
+
+/* defined and used by usbdcore_ep0.c */
+extern struct usb_string_descriptor **usb_strings;
+
+/* Indicies, References */
+static unsigned short rx_endpoint = 0;
+static unsigned short tx_endpoint = 0;
+static unsigned short interface_count = 0;
+static struct usb_string_descriptor *usbtty_string_table[STR_COUNT];
+
+/* USB Descriptor Strings */
 static u8 wstrLang[4] = {4,USB_DT_STRING,0x9,0x4};
 static u8 wstrManufacturer[2 + 2*(sizeof(CONFIG_USBD_MANUFACTURER)-1)];
 static u8 wstrProduct[2 + 2*(sizeof(CONFIG_USBD_PRODUCT_NAME)-1)];
 static u8 wstrSerial[2 + 2*(sizeof(serial_number) - 1)];
 static u8 wstrConfiguration[2 + 2*(sizeof(CONFIG_USBD_CONFIGURATION_STR)-1)];
-static u8 wstrInterface[2 + 2*(sizeof(CONFIG_USBD_INTERFACE_STR)-1)];
-
-static struct usb_string_descriptor *usbtty_string_table[] = {
-  (struct usb_string_descriptor*)wstrLang,
-  (struct usb_string_descriptor*)wstrManufacturer,
-  (struct usb_string_descriptor*)wstrProduct,
-  (struct usb_string_descriptor*)wstrSerial,
-  (struct usb_string_descriptor*)wstrConfiguration,
-  (struct usb_string_descriptor*)wstrInterface
-};
-extern struct usb_string_descriptor **usb_strings; /* defined and used by omap1510_ep0.c */
+static u8 wstrDataInterface[2 + 2*(sizeof(CONFIG_USBD_DATA_INTERFACE_STR)-1)];
+static u8 wstrCtrlInterface[2 + 2*(sizeof(CONFIG_USBD_DATA_INTERFACE_STR)-1)];
 
+/* Standard USB Data Structures */
+static struct usb_interface_descriptor interface_descriptors[MAX_INTERFACES];
+static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS];
+static struct usb_configuration_descriptor     *configuration_descriptor = 0;
 static struct usb_device_descriptor device_descriptor = {
-  bLength:           sizeof(struct usb_device_descriptor),
-  bDescriptorType:    USB_DT_DEVICE,
-  bcdUSB:            USB_BCD_VERSION,
-  bDeviceClass:              USBTTY_DEVICE_CLASS,
-  bDeviceSubClass:    USBTTY_DEVICE_SUBCLASS,
-  bDeviceProtocol:    USBTTY_DEVICE_PROTOCOL,
-  bMaxPacketSize0:    EP0_MAX_PACKET_SIZE,
-  idVendor:          CONFIG_USBD_VENDORID,
-  idProduct:         CONFIG_USBD_PRODUCTID,
-  bcdDevice:         USBTTY_BCD_DEVICE,
-  iManufacturer:      STR_MANUFACTURER,
-  iProduct:          STR_PRODUCT,
-  iSerialNumber:      STR_SERIAL,
-  bNumConfigurations: NUM_CONFIGS
-  };
-static struct usb_configuration_descriptor config_descriptors[NUM_CONFIGS] = {
-  {
-    bLength:            sizeof(struct usb_configuration_descriptor),
-    bDescriptorType:    USB_DT_CONFIG,
-    wTotalLength:       (sizeof(struct usb_configuration_descriptor)*NUM_CONFIGS) +
-                        (sizeof(struct usb_interface_descriptor)*NUM_INTERFACES) +
-                        (sizeof(struct usb_endpoint_descriptor)*NUM_ENDPOINTS),
-    bNumInterfaces:     NUM_INTERFACES,
-    bConfigurationValue: 1,
-    iConfiguration:     STR_CONFIG,
-    bmAttributes:       BMATTRIBUTE_SELF_POWERED | BMATTRIBUTE_RESERVED,
-    bMaxPower:          USBTTY_MAXPOWER
-  },
-};
-static struct usb_interface_descriptor interface_descriptors[NUM_INTERFACES] = {
-  {
-    bLength:            sizeof(struct usb_interface_descriptor),
-    bDescriptorType:    USB_DT_INTERFACE,
-    bInterfaceNumber:   0,
-    bAlternateSetting:  0,
-    bNumEndpoints:      NUM_ENDPOINTS,
-    bInterfaceClass:    USBTTY_INTERFACE_CLASS,
-    bInterfaceSubClass:         USBTTY_INTERFACE_SUBCLASS,
-    bInterfaceProtocol:         USBTTY_INTERFACE_PROTOCOL,
-    iInterface:                 STR_INTERFACE
-  },
+       .bLength = sizeof(struct usb_device_descriptor),
+       .bDescriptorType =      USB_DT_DEVICE,
+       .bcdUSB =               cpu_to_le16(USB_BCD_VERSION),
+       .bDeviceSubClass =      0x00,
+       .bDeviceProtocol =      0x00,
+       .bMaxPacketSize0 =      EP0_MAX_PACKET_SIZE,
+       .idVendor =             cpu_to_le16(CONFIG_USBD_VENDORID),
+       .bcdDevice =            cpu_to_le16(USBTTY_BCD_DEVICE),
+       .iManufacturer =        STR_MANUFACTURER,
+       .iProduct =             STR_PRODUCT,
+       .iSerialNumber =        STR_SERIAL,
+       .bNumConfigurations =   NUM_CONFIGS
 };
-static struct usb_endpoint_descriptor ep_descriptors[NUM_ENDPOINTS] = {
-  {
-    bLength:            sizeof(struct usb_endpoint_descriptor),
-    bDescriptorType:    USB_DT_ENDPOINT,
-    bEndpointAddress:   CONFIG_USBD_SERIAL_OUT_ENDPOINT | USB_DIR_OUT,
-    bmAttributes:       USB_ENDPOINT_XFER_BULK,
-    wMaxPacketSize:     CONFIG_USBD_SERIAL_OUT_PKTSIZE,
-    bInterval:          0
-  },
-  {
-    bLength:            sizeof(struct usb_endpoint_descriptor),
-    bDescriptorType:    USB_DT_ENDPOINT,
-    bEndpointAddress:   CONFIG_USBD_SERIAL_IN_ENDPOINT | USB_DIR_IN,
-    bmAttributes:       USB_ENDPOINT_XFER_BULK,
-    wMaxPacketSize:     CONFIG_USBD_SERIAL_IN_PKTSIZE,
-    bInterval:          0
-  },
-  {
-    bLength:            sizeof(struct usb_endpoint_descriptor),
-    bDescriptorType:    USB_DT_ENDPOINT,
-    bEndpointAddress:   CONFIG_USBD_SERIAL_INT_ENDPOINT | USB_DIR_IN,
-    bmAttributes:       USB_ENDPOINT_XFER_INT,
-    wMaxPacketSize:     CONFIG_USBD_SERIAL_INT_PKTSIZE,
-    bInterval:          0
-  },
-};
-static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS] = {
-  &(ep_descriptors[0]),
-  &(ep_descriptors[1]),
-  &(ep_descriptors[2]),
+
+
+/*
+ * Static CDC ACM specific descriptors
+ */
+
+struct acm_config_desc {
+       struct usb_configuration_descriptor configuration_desc;
+       
+       /* Master Interface */
+       struct usb_interface_descriptor interface_desc;
+       
+       struct usb_class_header_function_descriptor usb_class_header;
+       struct usb_class_call_management_descriptor usb_class_call_mgt;
+       struct usb_class_abstract_control_descriptor usb_class_acm;
+       struct usb_class_union_function_descriptor usb_class_union;
+       struct usb_endpoint_descriptor notification_endpoint;
+
+       /* Slave Interface */
+       struct usb_interface_descriptor data_class_interface;
+       struct usb_endpoint_descriptor 
+               data_endpoints[NUM_ENDPOINTS-1] __attribute__((packed));
+} __attribute__((packed));
+
+static struct acm_config_desc acm_configuration_descriptors[NUM_CONFIGS] = {
+       {
+               .configuration_desc ={
+                       .bLength = 
+                               sizeof(struct usb_configuration_descriptor),
+                       .bDescriptorType = USB_DT_CONFIG,
+                       .wTotalLength =  
+                               cpu_to_le16(sizeof(struct acm_config_desc)),
+                       .bNumInterfaces = NUM_ACM_INTERFACES,
+                       .bConfigurationValue = 1,
+                       .iConfiguration = STR_CONFIG,
+                       .bmAttributes = 
+                               BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED,
+                       .bMaxPower = USBTTY_MAXPOWER
+               },
+               /* Interface 1 */
+               .interface_desc = {
+                       .bLength  = sizeof(struct usb_interface_descriptor),
+                       .bDescriptorType = USB_DT_INTERFACE,
+                       .bInterfaceNumber = 0,
+                       .bAlternateSetting = 0,
+                       .bNumEndpoints = 0x01,
+                       .bInterfaceClass = 
+                               COMMUNICATIONS_INTERFACE_CLASS_CONTROL,
+                       .bInterfaceSubClass = COMMUNICATIONS_ACM_SUBCLASS,
+                       .bInterfaceProtocol = COMMUNICATIONS_V25TER_PROTOCOL,
+                       .iInterface = STR_CTRL_INTERFACE,
+               },
+               .usb_class_header = {
+                       .bFunctionLength        = 
+                               sizeof(struct usb_class_header_function_descriptor),
+                       .bDescriptorType        = CS_INTERFACE, 
+                       .bDescriptorSubtype     = USB_ST_HEADER,
+                       .bcdCDC = cpu_to_le16(110),
+               },
+               .usb_class_call_mgt = {
+                       .bFunctionLength        = 
+                               sizeof(struct usb_class_call_management_descriptor),
+                       .bDescriptorType        = CS_INTERFACE,
+                       .bDescriptorSubtype     = USB_ST_CMF,
+                       .bmCapabilities         = 0x00, 
+                       .bDataInterface         = 0x01, 
+               },
+               .usb_class_acm = {
+                       .bFunctionLength        = 
+                               sizeof(struct usb_class_abstract_control_descriptor),
+                       .bDescriptorType        = CS_INTERFACE,
+                       .bDescriptorSubtype     = USB_ST_ACMF,  
+                       .bmCapabilities         = 0x00, 
+               },
+               .usb_class_union = {
+                       .bFunctionLength        =       
+                               sizeof(struct usb_class_union_function_descriptor),
+                       .bDescriptorType        = CS_INTERFACE,
+                       .bDescriptorSubtype     = USB_ST_UF,
+                       .bMasterInterface       = 0x00, 
+                       .bSlaveInterface0       = 0x01, 
+               },
+               .notification_endpoint = {
+                       .bLength =              
+                               sizeof(struct usb_endpoint_descriptor),
+                       .bDescriptorType        = USB_DT_ENDPOINT,
+                       .bEndpointAddress       = 0x01 | USB_DIR_IN,
+                       .bmAttributes           = USB_ENDPOINT_XFER_INT,
+                       .wMaxPacketSize         
+                               = cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE),
+                       .bInterval              = 0xFF,
+               },
+
+               /* Interface 2 */
+               .data_class_interface = {
+                       .bLength                = 
+                               sizeof(struct usb_interface_descriptor),
+                       .bDescriptorType        = USB_DT_INTERFACE,
+                       .bInterfaceNumber       = 0x01,
+                       .bAlternateSetting      = 0x00,
+                       .bNumEndpoints          = 0x02,
+                       .bInterfaceClass        = 
+                               COMMUNICATIONS_INTERFACE_CLASS_DATA,
+                       .bInterfaceSubClass     = DATA_INTERFACE_SUBCLASS_NONE,
+                       .bInterfaceProtocol     = DATA_INTERFACE_PROTOCOL_NONE,
+                       .iInterface             = STR_DATA_INTERFACE,
+               },
+               .data_endpoints = {
+                       {
+                               .bLength                = 
+                                       sizeof(struct usb_endpoint_descriptor),
+                               .bDescriptorType        = USB_DT_ENDPOINT,
+                               .bEndpointAddress       = 0x02 | USB_DIR_OUT,
+                               .bmAttributes           = 
+                                       USB_ENDPOINT_XFER_BULK,
+                               .wMaxPacketSize         = 
+                                       cpu_to_le16(CONFIG_USBD_SERIAL_BULK_PKTSIZE),
+                               .bInterval              = 0xFF,
+                       },
+                       {
+                               .bLength                = 
+                                       sizeof(struct usb_endpoint_descriptor),
+                               .bDescriptorType        = USB_DT_ENDPOINT,
+                               .bEndpointAddress       = 0x03 | USB_DIR_IN,
+                               .bmAttributes           = 
+                                       USB_ENDPOINT_XFER_BULK,
+                               .wMaxPacketSize         = 
+                                       cpu_to_le16(CONFIG_USBD_SERIAL_BULK_PKTSIZE),
+                               .bInterval              = 0xFF,
+                       },
+               },
+       },
+};     
+
+static struct rs232_emu rs232_desc={
+               .dter           =       115200,
+               .stop_bits      =       0x00,
+               .parity         =       0x00,
+               .data_bits      =       0x08
 };
 
-/* utility function for converting char* to wide string used by USB */
-static void str2wide (char *str, u16 * wide)
-{
-       int i;
 
-       for (i = 0; i < strlen (str) && str[i]; i++)
-               wide[i] = (u16) str[i];
-}
+/*
+ * Static Generic Serial specific data
+ */
+
+
+struct gserial_config_desc {
+       
+       struct usb_configuration_descriptor configuration_desc;
+       struct usb_interface_descriptor 
+               interface_desc[NUM_GSERIAL_INTERFACES] __attribute__((packed));
+       struct usb_endpoint_descriptor 
+               data_endpoints[NUM_ENDPOINTS] __attribute__((packed));
+
+} __attribute__((packed));
+
+static struct gserial_config_desc 
+gserial_configuration_descriptors[NUM_CONFIGS] ={
+       {
+               .configuration_desc ={
+                       .bLength = sizeof(struct usb_configuration_descriptor),
+                       .bDescriptorType = USB_DT_CONFIG,
+                       .wTotalLength =  
+                               cpu_to_le16(sizeof(struct gserial_config_desc)),
+                       .bNumInterfaces = NUM_GSERIAL_INTERFACES,
+                       .bConfigurationValue = 1,
+                       .iConfiguration = STR_CONFIG,
+                       .bmAttributes = 
+                               BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED,
+                       .bMaxPower = USBTTY_MAXPOWER
+               },
+               .interface_desc = {
+                       {
+                               .bLength  = 
+                                       sizeof(struct usb_interface_descriptor),
+                               .bDescriptorType = USB_DT_INTERFACE,
+                               .bInterfaceNumber = 0,
+                               .bAlternateSetting = 0,
+                               .bNumEndpoints = NUM_ENDPOINTS,
+                               .bInterfaceClass = 
+                                       COMMUNICATIONS_INTERFACE_CLASS_VENDOR,
+                               .bInterfaceSubClass = 
+                                       COMMUNICATIONS_NO_SUBCLASS,
+                               .bInterfaceProtocol = 
+                                       COMMUNICATIONS_NO_PROTOCOL,
+                               .iInterface = STR_DATA_INTERFACE
+                       },
+               },
+               .data_endpoints  = {
+                       {
+                               .bLength =              
+                                       sizeof(struct usb_endpoint_descriptor),
+                               .bDescriptorType =      USB_DT_ENDPOINT,
+                               .bEndpointAddress =     0x01 | USB_DIR_OUT,
+                               .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+                               .wMaxPacketSize =       
+                                       cpu_to_le16(CONFIG_USBD_SERIAL_OUT_PKTSIZE),
+                               .bInterval=             0xFF,
+                       },
+                       {
+                               .bLength =              
+                                       sizeof(struct usb_endpoint_descriptor),
+                               .bDescriptorType =      USB_DT_ENDPOINT,
+                               .bEndpointAddress =     0x02 | USB_DIR_IN,
+                               .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+                               .wMaxPacketSize =       
+                                       cpu_to_le16(CONFIG_USBD_SERIAL_IN_PKTSIZE),
+                               .bInterval =            0xFF,
+                       },
+                       {
+                               .bLength =              
+                                       sizeof(struct usb_endpoint_descriptor),
+                               .bDescriptorType =      USB_DT_ENDPOINT,
+                               .bEndpointAddress =     0x03 | USB_DIR_IN,
+                               .bmAttributes =         USB_ENDPOINT_XFER_INT,
+                               .wMaxPacketSize =       
+                                       cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE),
+                               .bInterval =            0xFF,
+                       },
+               },
+       },
+};
 
 /*
- * Prototypes
+ * Static Function Prototypes
  */
+
 static void usbtty_init_strings (void);
 static void usbtty_init_instances (void);
 static void usbtty_init_endpoints (void);
-
+static void usbtty_init_terminal_type(short type);
 static void usbtty_event_handler (struct usb_device_instance *device,
-                                 usb_device_event_t event, int data);
+                               usb_device_event_t event, int data);
+static int usbtty_cdc_setup(struct usb_device_request *request, 
+                               struct urb *urb);
 static int usbtty_configured (void);
-
 static int write_buffer (circbuf_t * buf);
 static int fill_buffer (circbuf_t * buf);
 
 void usbtty_poll (void);
-static void pretend_interrupts (void);
 
+/* utility function for converting char* to wide string used by USB */
+static void str2wide (char *str, u16 * wide)
+{
+       int i;
+       for (i = 0; i < strlen (str) && str[i]; i++){
+               #if defined(__LITTLE_ENDIAN__)
+                       wide[i] = (u16) str[i];
+               #elif defined(__BIG_ENDIAN__)
+                       wide[i] = ((u16)(str[i])<<8);
+               #else
+                       #error "__LITTLE_ENDIAN__ or __BIG_ENDIAN__ undefined"
+               #endif
+       }
+}
 
 /*
  * Test whether a character is in the RX buffer
  */
+
 int usbtty_tstc (void)
 {
+       struct usb_endpoint_instance *endpoint =
+               &endpoint_instance[rx_endpoint];
+
+       /* If no input data exists, allow more RX to be accepted */
+       if(usbtty_input.size <= 0){
+               udc_unset_nak(endpoint->endpoint_address&0x03);
+       }
+
        usbtty_poll ();
        return (usbtty_input.size > 0);
 }
@@ -210,15 +414,21 @@ int usbtty_tstc (void)
  * otherwise. When the function is succesfull, the character read is
  * written into its argument c.
  */
+
 int usbtty_getc (void)
 {
        char c;
+       struct usb_endpoint_instance *endpoint =
+               &endpoint_instance[rx_endpoint];
 
        while (usbtty_input.size <= 0) {
+               udc_unset_nak(endpoint->endpoint_address&0x03);
                usbtty_poll ();
        }
 
        buf_pop (&usbtty_input, &c, 1);
+       udc_set_nak(endpoint->endpoint_address&0x03);
+
        return c;
 }
 
@@ -238,7 +448,6 @@ void usbtty_putc (const char c)
        }
 }
 
-
 /* usbtty_puts() helper function for finding the next '\n' in a string */
 static int next_nl_pos (const char *s)
 {
@@ -252,8 +461,9 @@ static int next_nl_pos (const char *s)
 }
 
 /*
- * Output a string to the usb client port.
+ * Output a string to the usb client port - implementing flow control
  */
+
 static void __usbtty_puts (const char *str, int len)
 {
        int maxlen = usbtty_output.totalsize;
@@ -261,22 +471,19 @@ static void __usbtty_puts (const char *str, int len)
 
        /* break str into chunks < buffer size, if needed */
        while (len > 0) {
-               space = maxlen - usbtty_output.size;
+               usbtty_poll ();
 
+               space = maxlen - usbtty_output.size;
                /* Empty buffer here, if needed, to ensure space... */
-               if (space <= 0) {
+               if (space) {
                        write_buffer (&usbtty_output);
-                       space = maxlen - usbtty_output.size;
-                       if (space <= 0) {
-                               space = len;    /* allow old data to be overwritten. */
-                       }
-               }
-
-               n = MIN (space, MIN (len, maxlen));
-               buf_push (&usbtty_output, str, n);
+                       
+                       n = MIN (space, MIN (len, maxlen));
+                       buf_push (&usbtty_output, str, n);
 
-               str += n;
-               len -= n;
+                       str += n;
+                       len -= n;                       
+               }
        }
 }
 
@@ -313,8 +520,10 @@ int drv_usbtty_init (void)
 {
        int rc;
        char * sn;
+       char * tt;
        int snlen;
 
+       /* Ger seiral number */
        if (!(sn = getenv("serial#"))) {
                sn = "000000000000";
        }
@@ -327,6 +536,14 @@ int drv_usbtty_init (void)
        memcpy (serial_number, sn, snlen);
        serial_number[snlen] = '\0';
 
+       /* Decide on which type of UDC device to be.
+        */
+
+       if(!(tt = getenv("usbtty"))) {
+               tt = "generic";
+       }
+       usbtty_init_terminal_type(strcmp(tt,"cdc_acm"));
+       
        /* prepare buffers... */
        buf_init (&usbtty_input, USBTTY_BUFFER_SIZE);
        buf_init (&usbtty_output, USBTTY_BUFFER_SIZE);
@@ -337,7 +554,7 @@ int drv_usbtty_init (void)
        usbtty_init_strings ();
        usbtty_init_instances ();
 
-       udc_startup_events (device_instance);   /* Enable our device, initialize udc pointers */
+       udc_startup_events (device_instance);/* Enable dev, init udc pointers */
        udc_connect ();         /* Enable pullup for host detection */
 
        usbtty_init_endpoints ();
@@ -362,34 +579,52 @@ static void usbtty_init_strings (void)
 {
        struct usb_string_descriptor *string;
 
+       usbtty_string_table[STR_LANG] = 
+               (struct usb_string_descriptor*)wstrLang;
+
        string = (struct usb_string_descriptor *) wstrManufacturer;
-       string->bLength = sizeof (wstrManufacturer);
+       string->bLength = sizeof(wstrManufacturer);
        string->bDescriptorType = USB_DT_STRING;
        str2wide (CONFIG_USBD_MANUFACTURER, string->wData);
+       usbtty_string_table[STR_MANUFACTURER]=string;
+
 
        string = (struct usb_string_descriptor *) wstrProduct;
-       string->bLength = sizeof (wstrProduct);
+       string->bLength = sizeof(wstrProduct);
        string->bDescriptorType = USB_DT_STRING;
        str2wide (CONFIG_USBD_PRODUCT_NAME, string->wData);
+       usbtty_string_table[STR_PRODUCT]=string;
+
 
        string = (struct usb_string_descriptor *) wstrSerial;
-       string->bLength = 2 + 2*strlen(serial_number);
+       string->bLength = sizeof(serial_number);
        string->bDescriptorType = USB_DT_STRING;
        str2wide (serial_number, string->wData);
+       usbtty_string_table[STR_SERIAL]=string;
+
 
        string = (struct usb_string_descriptor *) wstrConfiguration;
-       string->bLength = sizeof (wstrConfiguration);
+       string->bLength = sizeof(wstrConfiguration);
        string->bDescriptorType = USB_DT_STRING;
        str2wide (CONFIG_USBD_CONFIGURATION_STR, string->wData);
+       usbtty_string_table[STR_CONFIG]=string;
+
+
+       string = (struct usb_string_descriptor *) wstrDataInterface;
+       string->bLength = sizeof(wstrDataInterface);
+       string->bDescriptorType = USB_DT_STRING;
+       str2wide (CONFIG_USBD_DATA_INTERFACE_STR, string->wData);
+       usbtty_string_table[STR_DATA_INTERFACE]=string;
 
-       string = (struct usb_string_descriptor *) wstrInterface;
-       string->bLength = sizeof (wstrInterface);
+       string = (struct usb_string_descriptor *) wstrCtrlInterface;
+       string->bLength = sizeof(wstrCtrlInterface);
        string->bDescriptorType = USB_DT_STRING;
-       str2wide (CONFIG_USBD_INTERFACE_STR, string->wData);
+       str2wide (CONFIG_USBD_CTRL_INTERFACE_STR, string->wData);
+       usbtty_string_table[STR_CTRL_INTERFACE]=string;
 
        /* Now, initialize the string table for ep0 handling */
        usb_strings = usbtty_string_table;
-}
+}      
 
 static void usbtty_init_instances (void)
 {
@@ -400,6 +635,7 @@ static void usbtty_init_instances (void)
        device_instance->device_state = STATE_INIT;
        device_instance->device_descriptor = &device_descriptor;
        device_instance->event = usbtty_event_handler;
+       device_instance->cdc_recv_setup = usbtty_cdc_setup;
        device_instance->bus = bus_instance;
        device_instance->configurations = NUM_CONFIGS;
        device_instance->configuration_instance_array = config_instance;
@@ -415,8 +651,8 @@ static void usbtty_init_instances (void)
        /* configuration instance */
        memset (config_instance, 0,
                sizeof (struct usb_configuration_instance));
-       config_instance->interfaces = NUM_INTERFACES;
-       config_instance->configuration_descriptor = config_descriptors;
+       config_instance->interfaces = interface_count;
+       config_instance->configuration_descriptor = configuration_descriptor;
        config_instance->interface_instance_array = interface_instance;
 
        /* interface instance */
@@ -447,17 +683,22 @@ static void usbtty_init_instances (void)
                        sizeof (struct usb_endpoint_instance));
 
                endpoint_instance[i].endpoint_address =
-                       ep_descriptors[i - 1].bEndpointAddress;
+                       ep_descriptor_ptrs[i - 1]->bEndpointAddress;
 
-               endpoint_instance[i].rcv_packetSize =
-                       ep_descriptors[i - 1].wMaxPacketSize;
                endpoint_instance[i].rcv_attributes =
-                       ep_descriptors[i - 1].bmAttributes;
+                       ep_descriptor_ptrs[i - 1]->bmAttributes;
+
+               endpoint_instance[i].rcv_packetSize =
+                       le16_to_cpu(ep_descriptor_ptrs[i - 1]->wMaxPacketSize);
+               
+               endpoint_instance[i].tx_attributes =
+                       ep_descriptor_ptrs[i - 1]->bmAttributes;
 
                endpoint_instance[i].tx_packetSize =
-                       ep_descriptors[i - 1].wMaxPacketSize;
+                       le16_to_cpu(ep_descriptor_ptrs[i - 1]->wMaxPacketSize);
+
                endpoint_instance[i].tx_attributes =
-                       ep_descriptors[i - 1].bmAttributes;
+                       ep_descriptor_ptrs[i - 1]->bmAttributes;
 
                urb_link_init (&endpoint_instance[i].rcv);
                urb_link_init (&endpoint_instance[i].rdy);
@@ -480,13 +721,79 @@ static void usbtty_init_endpoints (void)
        int i;
 
        bus_instance->max_endpoints = NUM_ENDPOINTS + 1;
-       for (i = 0; i <= NUM_ENDPOINTS; i++) {
+       for (i = 1; i <= NUM_ENDPOINTS; i++) {          
                udc_setup_ep (device_instance, i, &endpoint_instance[i]);
        }
 }
 
+/* usbtty_init_terminal_type
+ * 
+ * Do some late binding for our device type.
+ */
+static void usbtty_init_terminal_type(short type)
+{
+       switch(type){
+               /* CDC ACM */                   
+               case 0:
+                       /* Assign endpoint descriptors */
+                       ep_descriptor_ptrs[0] = 
+                               &acm_configuration_descriptors[0].notification_endpoint;
+                       ep_descriptor_ptrs[1] = 
+                               &acm_configuration_descriptors[0].data_endpoints[0];
+                       ep_descriptor_ptrs[2] = 
+                               &acm_configuration_descriptors[0].data_endpoints[1];
+
+                       /* Enumerate Device Descriptor */
+                       device_descriptor.bDeviceClass = 
+                               COMMUNICATIONS_DEVICE_CLASS;
+                       device_descriptor.idProduct =
+                               cpu_to_le16(CONFIG_USBD_PRODUCTID_CDCACM);
+
+                       /* Assign endpoint indices */
+                       tx_endpoint = ACM_TX_ENDPOINT;
+                       rx_endpoint = ACM_RX_ENDPOINT;
+                       
+                       /* Configuration Descriptor */
+                       configuration_descriptor =
+                               (struct usb_configuration_descriptor*)
+                               &acm_configuration_descriptors;
+
+                       /* Interface count */
+                       interface_count = NUM_ACM_INTERFACES;
+               break;
 
-/*********************************************************************************/
+               /* BULK IN/OUT & Default */
+               case 1:
+               default:
+                       /* Assign endpoint descriptors */
+                       ep_descriptor_ptrs[0] = 
+                               &gserial_configuration_descriptors[0].data_endpoints[0];
+                       ep_descriptor_ptrs[1] = 
+                               &gserial_configuration_descriptors[0].data_endpoints[1];
+                       ep_descriptor_ptrs[2] = 
+                               &gserial_configuration_descriptors[0].data_endpoints[2];
+
+                       /* Enumerate Device Descriptor */
+                       device_descriptor.bDeviceClass = 0xFF;
+                       device_descriptor.idProduct =
+                               cpu_to_le16(CONFIG_USBD_PRODUCTID_GSERIAL);
+
+                       /* Assign endpoint indices */
+                       tx_endpoint = GSERIAL_TX_ENDPOINT;
+                       rx_endpoint = GSERIAL_RX_ENDPOINT;
+
+                       /* Configuration Descriptor */
+                       configuration_descriptor = 
+                               (struct usb_configuration_descriptor*)
+                               &gserial_configuration_descriptors;
+
+                       /* Interface count */
+                       interface_count = NUM_GSERIAL_INTERFACES;
+               break;
+       }
+}
+
+/******************************************************************************/
 
 static struct urb *next_urb (struct usb_device_instance *device,
                             struct usb_endpoint_instance *endpoint)
@@ -525,28 +832,40 @@ static int write_buffer (circbuf_t * buf)
        if (!usbtty_configured ()) {
                return 0;
        }
+       
+       struct usb_endpoint_instance *endpoint =
+                       &endpoint_instance[tx_endpoint];
+       struct urb *current_urb = NULL;
 
-       if (buf->size) {
+       current_urb = next_urb (device_instance, endpoint);
+       /* TX data still exists - send it now 
+        */     
+       if(endpoint->sent < current_urb->actual_length){
+               if(udc_endpoint_write (endpoint)){
+                       /* Write pre-empted by RX */
+                       return -1;
+               }
+       }
 
-               struct usb_endpoint_instance *endpoint =
-                       &endpoint_instance[TX_ENDPOINT];
-               struct urb *current_urb = NULL;
+       if (buf->size) {
                char *dest;
 
                int space_avail;
                int popnum, popped;
                int total = 0;
 
-               /* Break buffer into urb sized pieces, and link each to the endpoint */
+               /* Break buffer into urb sized pieces, 
+                * and link each to the endpoint 
+                */
                while (buf->size > 0) {
-                       current_urb = next_urb (device_instance, endpoint);
+                       
                        if (!current_urb) {
                                TTYERR ("current_urb is NULL, buf->size %d\n",
                                        buf->size);
                                return total;
                        }
 
-                       dest = current_urb->buffer +
+                       dest = (char*)current_urb->buffer +
                                current_urb->actual_length;
 
                        space_avail =
@@ -562,14 +881,19 @@ static int write_buffer (circbuf_t * buf)
                        current_urb->actual_length += popped;
                        total += popped;
 
-                       /* If endpoint->last == 0, then transfers have not started on this endpoint */
+                       /* If endpoint->last == 0, then transfers have 
+                        * not started on this endpoint 
+                        */
                        if (endpoint->last == 0) {
-                               udc_endpoint_write (endpoint);
+                               if(udc_endpoint_write (endpoint)){
+                                       /* Write pre-empted by RX */
+                                       return -1;
+                               }
                        }
 
-               }               /* end while */
+               }/* end while */
                return total;
-       }                       /* end if tx_urb */
+       }
 
        return 0;
 }
@@ -577,18 +901,22 @@ static int write_buffer (circbuf_t * buf)
 static int fill_buffer (circbuf_t * buf)
 {
        struct usb_endpoint_instance *endpoint =
-               &endpoint_instance[RECV_ENDPOINT];
+               &endpoint_instance[rx_endpoint];
 
        if (endpoint->rcv_urb && endpoint->rcv_urb->actual_length) {
-               unsigned int nb = endpoint->rcv_urb->actual_length;
+               unsigned int nb = 0; 
                char *src = (char *) endpoint->rcv_urb->buffer;
+               unsigned int rx_avail = buf->totalsize - buf->size;
 
-               buf_push (buf, src, nb);
-               endpoint->rcv_urb->actual_length = 0;
+               if(rx_avail >= endpoint->rcv_urb->actual_length){
 
+                       nb = endpoint->rcv_urb->actual_length;
+                       buf_push (buf, src, nb);
+                       endpoint->rcv_urb->actual_length = 0;
+                       
+               }
                return nb;
        }
-
        return 0;
 }
 
@@ -597,7 +925,7 @@ static int usbtty_configured (void)
        return usbtty_configured_flag;
 }
 
-/*********************************************************************************/
+/******************************************************************************/
 
 static void usbtty_event_handler (struct usb_device_instance *device,
                                  usb_device_event_t event, int data)
@@ -619,8 +947,34 @@ static void usbtty_event_handler (struct usb_device_instance *device,
        }
 }
 
-/*********************************************************************************/
+/******************************************************************************/
+
+int usbtty_cdc_setup(struct usb_device_request *request, struct urb *urb)
+{
+       switch (request->bRequest){
 
+               case ACM_SET_CONTROL_LINE_STATE:        /* Implies DTE ready */
+                       break;
+               case ACM_SEND_ENCAPSULATED_COMMAND :    /* Required */
+                       break;
+               case ACM_SET_LINE_ENCODING :            /* DTE stop/parity bits
+                                                        * per character */             
+                       break;
+               case ACM_GET_ENCAPSULATED_RESPONSE :    /* request response */
+                       break;
+               case ACM_GET_LINE_ENCODING :            /* request DTE rate,
+                                                        * stop/parity bits */
+                       memcpy (urb->buffer , &rs232_desc, sizeof(rs232_desc));
+                       urb->actual_length = sizeof(rs232_desc);
+
+                       break;
+               default:
+                       return 1;
+       }
+       return 0;
+}
+
+/******************************************************************************/
 
 /*
  * Since interrupt handling has not yet been implemented, we use this function
@@ -630,36 +984,29 @@ static void usbtty_event_handler (struct usb_device_instance *device,
 void usbtty_poll (void)
 {
        /* New interrupts? */
-       pretend_interrupts ();
+       udc_irq();
 
-       /* Write any output data to host buffer (do this before checking interrupts to avoid missing one) */
+       /* Write any output data to host buffer 
+        * (do this before checking interrupts to avoid missing one) 
+        */
        if (usbtty_configured ()) {
                write_buffer (&usbtty_output);
        }
 
        /* New interrupts? */
-       pretend_interrupts ();
-
-       /* Check for new data from host.. (do this after checking interrupts to get latest data) */
+       udc_irq();
+       
+       /* Check for new data from host.. 
+        * (do this after checking interrupts to get latest data) 
+        */
        if (usbtty_configured ()) {
                fill_buffer (&usbtty_input);
        }
 
        /* New interrupts? */
-       pretend_interrupts ();
-}
+       udc_irq();
 
-static void pretend_interrupts (void)
-{
-       /* Loop while we have interrupts.
-        * If we don't do this, the input chain
-        * polling delay is likely to miss
-        * host requests.
-        */
-       while (inw (UDC_IRQ_SRC) & ~UDC_SOF_Flg) {
-               /* Handle any new IRQs */
-               omap1510_udc_irq ();
-               omap1510_udc_noniso_irq ();
-       }
 }
+
+
 #endif
index 79c2fe57d7adf4e22a1230bd4218c04623b363e2..731b76330d4c968ad862fc4de6c789f997670e93 100644 (file)
@@ -2,6 +2,9 @@
  * (C) Copyright 2003
  * Gerry Hamel, geh@ti.com, Texas Instruments
  *
+ * (C) Copyright 2006
+ * Bryan O'Donoghue, bodonoghue@codehermit.ie, CodeHermit
+ *
  * 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; either version 2 of the License, or
 #ifndef __USB_TTY_H__
 #define __USB_TTY_H__
 
-
 #include "usbdcore.h"
+#if defined(CONFIG_PPC)
+#include "usbdcore_mpc8xx.h"
+#elif defined(CONFIG_ARM)
 #include "usbdcore_omap1510.h"
+#endif
 
+#include <version_autogenerated.h>
 
-#define NUM_CONFIGS    1
-#define NUM_INTERFACES 1
-#define NUM_ENDPOINTS  3
+/* If no VendorID/ProductID is defined in config.h, pretend to be Linux 
+ * DO NOT Reuse this Vendor/Product setup with protocol incompatible devices */
 
-#define EP0_MAX_PACKET_SIZE 64
+#define CONFIG_USBD_VENDORID 0x0525    /* Linux/NetChip */
+#define CONFIG_USBD_PRODUCTID_GSERIAL 0xa4a6   /* gserial */
+#define CONFIG_USBD_PRODUCTID_CDCACM  0xa4a7   /* CDC ACM */
+#define CONFIG_USBD_MANUFACTURER "Das U-Boot"
+#define CONFIG_USBD_PRODUCT_NAME U_BOOT_VERSION
 
-#define CONFIG_USBD_CONFIGURATION_STR "TTY via USB"
-#define CONFIG_USBD_INTERFACE_STR     "Simple Serial Data Interface - Bulk Mode"
 
+#define CONFIG_USBD_CONFIGURATION_STR "TTY via USB"
 
-#define CONFIG_USBD_SERIAL_OUT_ENDPOINT 2
-#define CONFIG_USBD_SERIAL_OUT_PKTSIZE 64
-#define CONFIG_USBD_SERIAL_IN_ENDPOINT 1
-#define CONFIG_USBD_SERIAL_IN_PKTSIZE  64
-#define CONFIG_USBD_SERIAL_INT_ENDPOINT 5
-#define CONFIG_USBD_SERIAL_INT_PKTSIZE 16
-
+#define CONFIG_USBD_SERIAL_OUT_ENDPOINT UDC_OUT_ENDPOINT 
+#define CONFIG_USBD_SERIAL_OUT_PKTSIZE UDC_OUT_PACKET_SIZE
+#define CONFIG_USBD_SERIAL_IN_ENDPOINT UDC_IN_ENDPOINT
+#define CONFIG_USBD_SERIAL_IN_PKTSIZE  UDC_IN_PACKET_SIZE
+#define CONFIG_USBD_SERIAL_INT_ENDPOINT UDC_INT_ENDPOINT
+#define CONFIG_USBD_SERIAL_INT_PKTSIZE UDC_INT_PACKET_SIZE
+#define CONFIG_USBD_SERIAL_BULK_PKTSIZE        UDC_BULK_PACKET_SIZE
 
 #define USBTTY_DEVICE_CLASS    COMMUNICATIONS_DEVICE_CLASS
-#define USBTTY_DEVICE_SUBCLASS COMMUNICATIONS_NO_SUBCLASS
-#define USBTTY_DEVICE_PROTOCOL COMMUNICATIONS_NO_PROTOCOL
-
-#define USBTTY_INTERFACE_CLASS    0xFF /* Vendor Specific */
-#define USBTTY_INTERFACE_SUBCLASS  0x02
-#define USBTTY_INTERFACE_PROTOCOL  0x01
 
-#define USBTTY_BCD_DEVICE 0x0
-#define USBTTY_MAXPOWER          0x0
+#define USBTTY_BCD_DEVICE      0x00
+#define USBTTY_MAXPOWER                0x00
 
-#define STR_MANUFACTURER 1
-#define STR_PRODUCT     2
-#define STR_SERIAL      3
-#define STR_CONFIG      4
-#define STR_INTERFACE   5
+#define STR_LANG               0x00
+#define STR_MANUFACTURER       0x01
+#define STR_PRODUCT            0x02
+#define STR_SERIAL             0x03
+#define STR_CONFIG             0x04
+#define STR_DATA_INTERFACE     0x05
+#define STR_CTRL_INTERFACE     0x06
+#define STR_COUNT              0x07
 
 #endif
diff --git a/include/configs/AdderUSB.h b/include/configs/AdderUSB.h
new file mode 100644 (file)
index 0000000..2112e56
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2006 CodeHermit.
+ * Bryan O'Donoghue <bodonoghue@codehermit.ie>
+ *
+ * Provides support for USB console on the Analogue & Micro Adder87x
+ * 
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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; 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __ADDERUSB__
+#define __ADDERUSB__
+
+/* Include the board port */
+#include "Adder.h"
+
+#define CONFIG_USB_DEVICE              /* Include UDC driver */
+#define CONFIG_USB_TTY                 /* Bind the TTY driver to UDC */
+#define CFG_USB_EXTC_CLK 0x02          /* Oscillator on EXTC_CLK 2 */
+#define CFG_USB_BRG_CLK        0x04            /* or use Baud rate generator 0x04 */
+#define CFG_CONSOLE_IS_IN_ENV          /* Console is in env */
+
+/* If you have a USB-IF assigned VendorID then you may wish to define
+ * your own vendor specific values either in BoardName.h or directly in
+ * usbd_vendor_info.h 
+ */
+
+/* 
+#define CONFIG_USBD_MANUFACTURER       "CodeHermit.ie"
+#define CONFIG_USBD_PRODUCT_NAME       "Das U-Boot"
+#define CONFIG_USBD_VENDORID           0xFFFF 
+#define CONFIG_USBD_PRODUCTID_GSERIAL  0xFFFF
+#define CONFIG_USBD_PRODUCTID_CDCACM   0xFFFE
+*/
+
+#endif /* __ADDERUSB_H__ */
diff --git a/include/usb_cdc_acm.h b/include/usb_cdc_acm.h
new file mode 100644 (file)
index 0000000..8cb1654
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * (C) Copyright 2006
+ * Bryan O'Donoghue, deckard@codehermit.ie, CodeHermit
+ *
+ * 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; 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* ACM Control Requests */
+#define ACM_SEND_ENCAPSULATED_COMMAND  0x00
+#define ACM_GET_ENCAPSULATED_RESPONSE  0x01
+#define ACM_SET_COMM_FEATURE           0x02
+#define ACM_GET_COMM_FEATRUE           0x03
+#define ACM_CLEAR_COMM_FEATURE         0x04
+#define ACM_SET_LINE_ENCODING          0x20
+#define ACM_GET_LINE_ENCODING          0x21
+#define ACM_SET_CONTROL_LINE_STATE     0x22
+#define ACM_SEND_BREAK                 0x23
+
+/* ACM Notification Codes */
+#define ACM_NETWORK_CONNECTION         0x00
+#define ACM_RESPONSE_AVAILABLE         0x01
+#define ACM_SERIAL_STATE               0x20
+
+/* Format of response expected by a ACM_GET_LINE_ENCODING request */ 
+struct rs232_emu{
+               unsigned long dter;
+               unsigned char stop_bits;
+               unsigned char parity;
+               unsigned char data_bits;
+}__attribute__((packed));
index 6e92df13bd0edfe8f76e02c4c9e8776831869f68..cb2be72804a4f1ca6b3b83e2b63395353f61a6d0 100644 (file)
@@ -576,6 +576,9 @@ struct usb_device_instance {
 
        void (*event) (struct usb_device_instance *device, usb_device_event_t event, int data);
 
+       /* Do cdc device specific control requests */
+       int (*cdc_recv_setup)(struct usb_device_request *request, struct urb *urb);
+
        /* bus interface */
        struct usb_bus_instance *bus;   /* which bus interface driver */
 
diff --git a/include/usbdcore_mpc8xx.h b/include/usbdcore_mpc8xx.h
new file mode 100644 (file)
index 0000000..e54acd9
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2006 Bryan O'Donoghue, CodeHermit
+ * bodonoghue@codehermit.ie
+ *
+ *
+ * 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; 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include <commproc.h>
+
+/* Mode Register */
+#define USMOD_EN       0x01
+#define USMOD_HOST     0x02
+#define USMOD_TEST     0x04
+#define USMOD_SFTE     0x08
+#define USMOD_RESUME   0x40
+#define USMOD_LSS      0x80
+
+/* Endpoint Registers */
+#define USEP_RHS_NORM  0x00
+#define USEP_RHS_IGNORE        0x01
+#define USEP_RHS_NAK   0x02
+#define USEP_RHS_STALL 0x03
+
+#define USEP_THS_NORM  0x00
+#define USEP_THS_IGNORE        0x04
+#define USEP_THS_NAK   0x08
+#define USEP_THS_STALL 0x0C
+
+#define USEP_RTE       0x10
+#define USEP_MF                0x20
+
+#define USEP_TM_CONTROL        0x00
+#define USEP_TM_INT    0x100
+#define USEP_TM_BULK   0x200
+#define USEP_TM_ISO    0x300
+
+/* Command Register */
+#define USCOM_EP0      0x00
+#define USCOM_EP1      0x01
+#define USCOM_EP2      0x02
+#define USCOM_EP3      0x03
+
+#define USCOM_FLUSH    0x40
+#define USCOM_STR      0x80
+
+/* Event Register */
+#define USB_E_RXB      0x0001
+#define USB_E_TXB      0x0002
+#define USB_E_BSY      0x0004
+#define USB_E_SOF      0x0008
+#define USB_E_TXE1     0x0010
+#define USB_E_TXE2     0x0020
+#define USB_E_TXE3     0x0040
+#define USB_E_TXE4     0x0080
+#define USB_TX_ERRMASK (USB_E_TXE1|USB_E_TXE2|USB_E_TXE3|USB_E_TXE4)
+#define USB_E_IDLE     0x0100
+#define USB_E_RESET    0x0200
+
+/* Mask Register */
+#define USBS_IDLE      0x01
+
+/* RX Buffer Descriptor */
+#define RX_BD_OV       0x02
+#define RX_BD_CR       0x04
+#define RX_BD_AB       0x08
+#define RX_BD_NO       0x10
+#define RX_BD_PID_DATA0        0x00
+#define RX_BD_PID_DATA1        0x40
+#define RX_BD_PID_SETUP        0x80
+#define RX_BD_F                0x400
+#define RX_BD_L                0x800
+#define RX_BD_I                0x1000
+#define RX_BD_W                0x2000
+#define RX_BD_E                0x8000
+
+/* Useful masks */
+#define RX_BD_PID_BITMASK (RX_BD_PID_DATA1 | RX_BD_PID_SETUP)
+#define STALL_BITMASK (USEP_THS_STALL | USEP_RHS_STALL)
+#define NAK_BITMASK (USEP_THS_NAK | USEP_RHS_NAK)
+#define CBD_TX_BITMASK (TX_BD_R | TX_BD_L | TX_BD_TC | TX_BD_I | TX_BD_CNF)
+
+/* TX Buffer Descriptor */
+#define TX_BD_UN       0x02
+#define TX_BD_TO       0x04
+#define TX_BD_NO_PID   0x00
+#define TX_BD_PID_DATA0        0x80
+#define TX_BD_PID_DATA1        0xC0    
+#define TX_BD_CNF      0x200
+#define TX_BD_TC       0x400
+#define TX_BD_L                0x800
+#define TX_BD_I                0x1000
+#define TX_BD_W                0x2000
+#define TX_BD_R                0x8000
+
+/* Implementation specific defines */
+
+#define EP_MIN_PACKET_SIZE 0x08
+#define MAX_ENDPOINTS  0x04
+#define FIFO_SIZE      0x10
+#define EP_MAX_PKT     FIFO_SIZE
+#define TX_RING_SIZE   0x04
+#define RX_RING_SIZE   0x06
+#define USB_MAX_PKT    0x40
+#define TOGGLE_TX_PID(x) x= ((~x)&0x40)|0x80
+#define TOGGLE_RX_PID(x) x^= 0x40
+#define EP_ATTACHED    0x01    /* Endpoint has a urb attached or not */
+#define EP_SEND_ZLP    0x02    /* Send ZLP y/n ? */
+
+#define PROFF_USB      0x00000000
+#define CPM_USB_BASE   0x00000A00
+
+/* UDC device defines */
+#define EP0_MAX_PACKET_SIZE    EP_MAX_PKT
+#define UDC_OUT_ENDPOINT       0x02
+#define UDC_OUT_PACKET_SIZE    EP_MIN_PACKET_SIZE
+#define UDC_IN_ENDPOINT                0x03
+#define UDC_IN_PACKET_SIZE     EP_MIN_PACKET_SIZE
+#define UDC_INT_ENDPOINT       0x01
+#define UDC_INT_PACKET_SIZE    UDC_IN_PACKET_SIZE
+#define UDC_BULK_PACKET_SIZE   EP_MIN_PACKET_SIZE
+
+struct mpc8xx_ep {
+       struct urb * urb;
+       unsigned char pid;
+       unsigned char sc;
+       volatile cbd_t * prx;
+};
+
+typedef struct mpc8xx_usb{
+       char usmod;     /* Mode Register */
+       char usaddr;    /* Slave Address Register */
+       char uscom;     /* Command Register */
+       char res1;      /* Reserved */
+       ushort usep[4];
+       ulong res2;     /* Reserved */
+       ushort usber;   /* Event Register */
+       ushort res3;    /* Reserved */
+       ushort usbmr;   /* Mask Register */
+       char res4;      /* Reserved */ 
+       char usbs;      /* Status Register */
+       char res5[8];   /* Reserved */
+}usb_t;
+
+typedef struct mpc8xx_parameter_ram{
+       ushort ep0ptr;  /* Endpoint Pointer Register 0 */       
+       ushort ep1ptr;  /* Endpoint Pointer Register 1 */       
+       ushort ep2ptr;  /* Endpoint Pointer Register 2 */       
+       ushort ep3ptr;  /* Endpoint Pointer Register 3 */       
+       uint rstate;    /* Receive state */
+       uint rptr;      /* Receive internal data pointer */
+       ushort frame_n; /* Frame number */
+       ushort rbcnt;   /* Receive byte count */
+       uint rtemp;     /* Receive temp cp use only */
+       uint rxusb;     /* Rx Data Temp */
+       ushort rxuptr;  /* Rx microcode return address temp */
+}usb_pram_t;
+
+typedef struct endpoint_parameter_block_pointer{
+       ushort rbase;   /* RxBD base address */
+       ushort tbase;   /* TxBD base address */
+       char rfcr;      /* Rx Function code */
+       char tfcr;      /* Tx Function code */
+       ushort mrblr;   /* Maximum Receive Buffer Length */
+       ushort rbptr;   /* RxBD pointer Next Buffer Descriptor */
+       ushort tbptr;   /* TxBD pointer Next Buffer Descriptor  */
+       ulong tstate;   /* Transmit internal state */
+       ulong tptr;     /* Transmit internal data pointer */
+       ushort tcrc;    /* Transmit temp CRC */
+       ushort tbcnt;   /* Transmit internal bye count */
+       ulong ttemp;    /* Tx temp */
+       ushort txuptr;  /* Tx microcode return address */
+       ushort res1;    /* Reserved */
+}usb_epb_t;
+
+typedef enum mpc8xx_udc_state{
+       STATE_NOT_READY,
+       STATE_ERROR,
+       STATE_READY,
+}mpc8xx_udc_state_t;
+
+/* Declarations */
+int udc_init(void);
+void udc_irq(void);
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint);
+void udc_setup_ep(struct usb_device_instance *device, unsigned int ep,
+                  struct usb_endpoint_instance *endpoint);
+void udc_connect(void);
+void udc_disconnect(void);
+void udc_enable(struct usb_device_instance *device);
+void udc_disable(void);
+void udc_startup_events(struct usb_device_instance *device);
+
+/* Flow control */
+void udc_set_nak(int epid);
+void udc_unset_nak (int epid);
index 6ea333122fde66e314d383156df513931032381b..526fcd920db32fc1f8f6d1d77cbc0755462ec09c 100644 (file)
 #define UDC_VBUS_CTRL      (1 << 19)
 #define UDC_VBUS_MODE      (1 << 18)
 
-
-void omap1510_udc_irq(void);
-void omap1510_udc_noniso_irq(void);
-
+/* OMAP Endpoint parameters */
+#define EP0_MAX_PACKET_SIZE 64
+#define UDC_OUT_ENDPOINT 2
+#define UDC_OUT_PACKET_SIZE 64
+#define UDC_IN_ENDPOINT        1
+#define UDC_IN_PACKET_SIZE 64
+#define UDC_INT_ENDPOINT 5
+#define UDC_INT_PKTSIZE        16
+#define UDC_BULK_PKTSIZE 16
+
+void udc_irq (void);
+/* Flow control */
+void udc_set_nak(int epid);
+void udc_unset_nak (int epid);
 
 /* Higher level functions for abstracting away from specific device */
 void udc_endpoint_write(struct usb_endpoint_instance *endpoint);
index 2d9f739343e23176c77608d56c4090198781a8c3..8336c188c108c29890bb8a429db566e460c554c7 100644 (file)
 #define COMMUNICATIONS_DEVICE_CLASS    0x02
 
 /* c.f. CDC 4.2 Table 15 */
-#define COMMUNICATIONS_INTERFACE_CLASS 0x02
+#define COMMUNICATIONS_INTERFACE_CLASS_CONTROL 0x02
+#define COMMUNICATIONS_INTERFACE_CLASS_DATA            0x0A
+#define COMMUNICATIONS_INTERFACE_CLASS_VENDOR  0x0FF
 
 /* c.f. CDC 4.3 Table 16 */
-#define COMMUNICATIONS_NO_SUBCLASS     0x00
+#define COMMUNICATIONS_NO_SUBCLASS             0x00
 #define COMMUNICATIONS_DLCM_SUBCLASS   0x01
-#define COMMUNICATIONS_ACM_SUBCLASS    0x02
-#define COMMUNICATIONS_TCM_SUBCLASS    0x03
+#define COMMUNICATIONS_ACM_SUBCLASS            0x02
+#define COMMUNICATIONS_TCM_SUBCLASS            0x03
 #define COMMUNICATIONS_MCCM_SUBCLASS   0x04
-#define COMMUNICATIONS_CCM_SUBCLASS    0x05
+#define COMMUNICATIONS_CCM_SUBCLASS            0x05
 #define COMMUNICATIONS_ENCM_SUBCLASS   0x06
 #define COMMUNICATIONS_ANCM_SUBCLASS   0x07
 
 /* c.f. WMCD 5.1 */
 #define COMMUNICATIONS_WHCM_SUBCLASS   0x08
-#define COMMUNICATIONS_DMM_SUBCLASS    0x09
+#define COMMUNICATIONS_DMM_SUBCLASS            0x09
 #define COMMUNICATIONS_MDLM_SUBCLASS   0x0a
 #define COMMUNICATIONS_OBEX_SUBCLASS   0x0b
 
-/* c.f. CDC 4.6 Table 18 */
+/* c.f. CDC 4.4 Table 17 */
+#define COMMUNICATIONS_NO_PROTOCOL             0x00
+#define COMMUNICATIONS_V25TER_PROTOCOL 0x01    /*Common AT Hayes compatible*/
+
+/* c.f. CDC 4.5 Table 18 */
 #define DATA_INTERFACE_CLASS           0x0a
 
+/* c.f. CDC 4.6 No Table */
+#define DATA_INTERFACE_SUBCLASS_NONE   0x00    /* No subclass pertinent */
+
 /* c.f. CDC 4.7 Table 19 */
-#define COMMUNICATIONS_NO_PROTOCOL     0x00
+#define DATA_INTERFACE_PROTOCOL_NONE   0x00    /* No class protcol required */
 
 
 /* c.f. CDC 5.2.3 Table 24 */
-#define CS_INTERFACE                   0x24
+#define CS_INTERFACE           0x24
 #define CS_ENDPOINT                    0x25
 
 /*
  * c.f. WMCD 5.3 Table 5.3
  */
 
-#define USB_ST_HEADER                  0x00
+#define USB_ST_HEADER          0x00
 #define USB_ST_CMF                     0x01
 #define USB_ST_ACMF                    0x02
 #define USB_ST_DLMF                    0x03
 #define USB_ST_UF                      0x06
 #define USB_ST_CSF                     0x07
 #define USB_ST_TOMF                    0x08
-#define USB_ST_USBTF                   0x09
+#define USB_ST_USBTF           0x09
 #define USB_ST_NCT                     0x0a
 #define USB_ST_PUF                     0x0b
 #define USB_ST_EUF                     0x0c
 #define USB_ST_MCMF                    0x0d
 #define USB_ST_CCMF                    0x0e
 #define USB_ST_ENF                     0x0f
-#define USB_ST_ATMNF                   0x10
+#define USB_ST_ATMNF           0x10
 
 #define USB_ST_WHCM                    0x11
 #define USB_ST_MDLM                    0x12
-#define USB_ST_MDLMD                   0x13
+#define USB_ST_MDLMD           0x13
 #define USB_ST_DMM                     0x14
 #define USB_ST_OBEX                    0x15
 #define USB_ST_CS                      0x16
@@ -312,7 +321,8 @@ struct usb_class_union_function_descriptor {
        u8 bDescriptorType;
        u8 bDescriptorSubtype;  /* 0x06 */
        u8 bMasterInterface;
-       u8 bSlaveInterface0[0];
+       //u8 bSlaveInterface0[0];
+       u8 bSlaveInterface0;
 } __attribute__ ((packed));
 
 struct usb_class_country_selection_descriptor {