drivers/usb : move usb drivers to drivers/usb
authorJean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Sat, 24 Nov 2007 18:40:11 +0000 (19:40 +0100)
committerJean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Sun, 25 Nov 2007 22:27:38 +0000 (23:27 +0100)
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
23 files changed:
Makefile
drivers/Makefile
drivers/isp116x-hcd.c [deleted file]
drivers/isp116x.h [deleted file]
drivers/sl811.h [deleted file]
drivers/sl811_usb.c [deleted file]
drivers/usb/Makefile [new file with mode: 0644]
drivers/usb/isp116x-hcd.c [new file with mode: 0644]
drivers/usb/isp116x.h [new file with mode: 0644]
drivers/usb/sl811.h [new file with mode: 0644]
drivers/usb/sl811_usb.c [new file with mode: 0644]
drivers/usb/usb_ohci.c [new file with mode: 0644]
drivers/usb/usb_ohci.h [new file with mode: 0644]
drivers/usb/usbdcore.c [new file with mode: 0644]
drivers/usb/usbdcore_ep0.c [new file with mode: 0644]
drivers/usb/usbdcore_mpc8xx.c [new file with mode: 0644]
drivers/usb/usbdcore_omap1510.c [new file with mode: 0644]
drivers/usb_ohci.c [deleted file]
drivers/usb_ohci.h [deleted file]
drivers/usbdcore.c [deleted file]
drivers/usbdcore_ep0.c [deleted file]
drivers/usbdcore_mpc8xx.c [deleted file]
drivers/usbdcore_omap1510.c [deleted file]

index e68454a7bf410faf6b366bdc34723ac3e8bbcb65..24a351d61a240435572fa50ecd71db4ed2ab37ee 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -225,6 +225,7 @@ ifeq ($(CPU),mpc85xx)
 LIBS += drivers/qe/qe.a
 endif
 LIBS += drivers/serial/libserial.a
+LIBS += drivers/usb/libusb.a
 LIBS += post/libpost.a post/drivers/libpostdrivers.a
 LIBS += $(shell if [ -d post/lib_$(ARCH) ]; then echo \
        "post/lib_$(ARCH)/libpost$(ARCH).a"; fi)
index cf8b584c7247a5e74aa14aaa7c4306bd585e7733..666957dff70847e0977e5a1e55477878154bb123 100755 (executable)
@@ -54,17 +54,6 @@ COBJS-y += pc_keyb.o
 COBJS-y += ps2ser.o
 COBJS-y += ps2mult.o
 
-#
-# USB Drivers
-#
-COBJS-y += isp116x-hcd.o
-COBJS-y += sl811_usb.o
-COBJS-y += usb_ohci.o
-COBJS-y += usbdcore.o
-COBJS-y += usbdcore_ep0.o
-COBJS-y += usbdcore_mpc8xx.o
-COBJS-y += usbdcore_omap1510.o
-
 #
 # Miscellaneous Drivers
 #
diff --git a/drivers/isp116x-hcd.c b/drivers/isp116x-hcd.c
deleted file mode 100644 (file)
index b21af10..0000000
+++ /dev/null
@@ -1,1445 +0,0 @@
-/*
- * ISP116x HCD (Host Controller Driver) for u-boot.
- *
- * Copyright (C) 2006-2007 Rodolfo Giometti <giometti@linux.it>
- * Copyright (C) 2006-2007 Eurotech S.p.A. <info@eurotech.it>
- *
- * 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
- *
- *
- * Derived in part from the SL811 HCD driver "u-boot/drivers/sl811_usb.c"
- * (original copyright message follows):
- *
- *    (C) Copyright 2004
- *    Wolfgang Denk, DENX Software Engineering, wd@denx.de.
- *
- *    This code is based on linux driver for sl811hs chip, source at
- *    drivers/usb/host/sl811.c:
- *
- *    SL811 Host Controller Interface driver for USB.
- *
- *    Copyright (c) 2003/06, Courage Co., Ltd.
- *
- *    Based on:
- *         1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap,
- *           Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber,
- *           Adam Richter, Gregory P. Smith;
- *         2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com>
- *         3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn>
- *
- *    [[GNU/GPL disclaimer]]
- *
- * and in part from AU1x00 OHCI HCD driver "u-boot/cpu/mips/au1x00_usb_ohci.c"
- * (original copyright message follows):
- *
- *    URB OHCI HCD (Host Controller Driver) for USB on the AU1x00.
- *
- *    (C) Copyright 2003
- *    Gary Jennejohn, DENX Software Engineering <gj@denx.de>
- *
- *    [[GNU/GPL disclaimer]]
- *
- *    Note: Part of this code has been derived from linux
- */
-
-#include <common.h>
-
-#ifdef CONFIG_USB_ISP116X_HCD
-#include <asm/io.h>
-#include <usb.h>
-#include <malloc.h>
-#include <linux/list.h>
-
-/*
- * ISP116x chips require certain delays between accesses to its
- * registers. The following timing options exist.
- *
- * 1. Configure your memory controller (the best)
- * 2. Use ndelay (easiest, poorest). For that, enable the following macro.
- *
- * Value is in microseconds.
- */
-#ifdef ISP116X_HCD_USE_UDELAY
-#define UDELAY         1
-#endif
-
-/*
- * On some (slowly?) machines an extra delay after data packing into
- * controller's FIFOs is required, * otherwise you may get the following
- * error:
- *
- *   uboot> usb start
- *   (Re)start USB...
- *   USB:   scanning bus for devices... isp116x: isp116x_submit_job: CTL:TIMEOUT
- *   isp116x: isp116x_submit_job: ****** FIFO not ready! ******
- *
- *         USB device not responding, giving up (status=4)
- *         isp116x: isp116x_submit_job: ****** FIFO not empty! ******
- *         isp116x: isp116x_submit_job: ****** FIFO not empty! ******
- *         isp116x: isp116x_submit_job: ****** FIFO not empty! ******
- *         3 USB Device(s) found
- *                scanning bus for storage devices... 0 Storage Device(s) found
- *
- * Value is in milliseconds.
- */
-#ifdef ISP116X_HCD_USE_EXTRA_DELAY
-#define EXTRA_DELAY    2
-#endif
-
-/*
- * Enable the following defines if you wish enable debugging messages.
- */
-#undef DEBUG                   /* enable debugging messages */
-#undef TRACE                   /* enable tracing code */
-#undef VERBOSE                 /* verbose debugging messages */
-
-#include "isp116x.h"
-
-#define DRIVER_VERSION "08 Jan 2007"
-static const char hcd_name[] = "isp116x-hcd";
-
-struct isp116x isp116x_dev;
-struct isp116x_platform_data isp116x_board;
-static int got_rhsc;           /* root hub status change */
-struct usb_device *devgone;    /* device which was disconnected */
-static int rh_devnum;          /* address of Root Hub endpoint */
-
-/* ------------------------------------------------------------------------- */
-
-#define ALIGN(x,a)     (((x)+(a)-1UL)&~((a)-1UL))
-#define min_t(type,x,y)        \
-       ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; })
-
-/* ------------------------------------------------------------------------- */
-
-static int isp116x_reset(struct isp116x *isp116x);
-
-/* --- Debugging functions ------------------------------------------------- */
-
-#define isp116x_show_reg(d, r) {                               \
-       if ((r) < 0x20) {                                       \
-               DBG("%-12s[%02x]: %08x", #r,                    \
-                       r, isp116x_read_reg32(d, r));           \
-       } else {                                                \
-               DBG("%-12s[%02x]:     %04x", #r,                \
-                       r, isp116x_read_reg16(d, r));           \
-       }                                                       \
-}
-
-#define isp116x_show_regs(d) {                                 \
-       isp116x_show_reg(d, HCREVISION);                        \
-       isp116x_show_reg(d, HCCONTROL);                         \
-       isp116x_show_reg(d, HCCMDSTAT);                         \
-       isp116x_show_reg(d, HCINTSTAT);                         \
-       isp116x_show_reg(d, HCINTENB);                          \
-       isp116x_show_reg(d, HCFMINTVL);                         \
-       isp116x_show_reg(d, HCFMREM);                           \
-       isp116x_show_reg(d, HCFMNUM);                           \
-       isp116x_show_reg(d, HCLSTHRESH);                        \
-       isp116x_show_reg(d, HCRHDESCA);                         \
-       isp116x_show_reg(d, HCRHDESCB);                         \
-       isp116x_show_reg(d, HCRHSTATUS);                        \
-       isp116x_show_reg(d, HCRHPORT1);                         \
-       isp116x_show_reg(d, HCRHPORT2);                         \
-       isp116x_show_reg(d, HCHWCFG);                           \
-       isp116x_show_reg(d, HCDMACFG);                          \
-       isp116x_show_reg(d, HCXFERCTR);                         \
-       isp116x_show_reg(d, HCuPINT);                           \
-       isp116x_show_reg(d, HCuPINTENB);                        \
-       isp116x_show_reg(d, HCCHIPID);                          \
-       isp116x_show_reg(d, HCSCRATCH);                         \
-       isp116x_show_reg(d, HCITLBUFLEN);                       \
-       isp116x_show_reg(d, HCATLBUFLEN);                       \
-       isp116x_show_reg(d, HCBUFSTAT);                         \
-       isp116x_show_reg(d, HCRDITL0LEN);                       \
-       isp116x_show_reg(d, HCRDITL1LEN);                       \
-}
-
-#if defined(TRACE)
-
-static int isp116x_get_current_frame_number(struct usb_device *usb_dev)
-{
-       struct isp116x *isp116x = &isp116x_dev;
-
-       return isp116x_read_reg32(isp116x, HCFMNUM);
-}
-
-static void dump_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
-                    int len, char *str)
-{
-#if defined(VERBOSE)
-       int i;
-#endif
-
-       DBG("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d stat:%#lx",
-           str,
-           isp116x_get_current_frame_number(dev),
-           usb_pipedevice(pipe),
-           usb_pipeendpoint(pipe),
-           usb_pipeout(pipe) ? 'O' : 'I',
-           usb_pipetype(pipe) < 2 ?
-           (usb_pipeint(pipe) ?
-            "INTR" : "ISOC") :
-           (usb_pipecontrol(pipe) ? "CTRL" : "BULK"), len, dev->status);
-#if defined(VERBOSE)
-       if (len > 0 && buffer) {
-               printf(__FILE__ ": data(%d):", len);
-               for (i = 0; i < 16 && i < len; i++)
-                       printf(" %02x", ((__u8 *) buffer)[i]);
-               printf("%s\n", i < len ? "..." : "");
-       }
-#endif
-}
-
-#define PTD_DIR_STR(ptd)  ({char __c;          \
-       switch(PTD_GET_DIR(ptd)){               \
-       case 0:  __c = 's'; break;              \
-       case 1:  __c = 'o'; break;              \
-       default: __c = 'i'; break;              \
-       }; __c;})
-
-/*
-  Dump PTD info. The code documents the format
-  perfectly, right :)
-*/
-static inline void dump_ptd(struct ptd *ptd)
-{
-#if defined(VERBOSE)
-       int k;
-#endif
-
-       DBG("PTD(ext) : cc:%x %d%c%d %d,%d,%d t:%x %x%x%x",
-           PTD_GET_CC(ptd),
-           PTD_GET_FA(ptd), PTD_DIR_STR(ptd), PTD_GET_EP(ptd),
-           PTD_GET_COUNT(ptd), PTD_GET_LEN(ptd), PTD_GET_MPS(ptd),
-           PTD_GET_TOGGLE(ptd),
-           PTD_GET_ACTIVE(ptd), PTD_GET_SPD(ptd), PTD_GET_LAST(ptd));
-#if defined(VERBOSE)
-       printf("isp116x: %s: PTD(byte): ", __FUNCTION__);
-       for (k = 0; k < sizeof(struct ptd); ++k)
-               printf("%02x ", ((u8 *) ptd)[k]);
-       printf("\n");
-#endif
-}
-
-static inline void dump_ptd_data(struct ptd *ptd, u8 * buf, int type)
-{
-#if defined(VERBOSE)
-       int k;
-
-       if (type == 0 /* 0ut data */ ) {
-               printf("isp116x: %s: out data: ", __FUNCTION__);
-               for (k = 0; k < PTD_GET_LEN(ptd); ++k)
-                       printf("%02x ", ((u8 *) buf)[k]);
-               printf("\n");
-       }
-       if (type == 1 /* 1n data */ ) {
-               printf("isp116x: %s: in data: ", __FUNCTION__);
-               for (k = 0; k < PTD_GET_COUNT(ptd); ++k)
-                       printf("%02x ", ((u8 *) buf)[k]);
-               printf("\n");
-       }
-
-       if (PTD_GET_LAST(ptd))
-               DBG("--- last PTD ---");
-#endif
-}
-
-#else
-
-#define dump_msg(dev, pipe, buffer, len, str)                  do { } while (0)
-#define dump_pkt(dev, pipe, buffer, len, setup, str, small)    do {} while (0)
-
-#define dump_ptd(ptd)                  do {} while (0)
-#define dump_ptd_data(ptd, buf, type)  do {} while (0)
-
-#endif
-
-/* --- Virtual Root Hub ---------------------------------------------------- */
-
-/* Device descriptor */
-static __u8 root_hub_dev_des[] = {
-       0x12,                   /*  __u8  bLength; */
-       0x01,                   /*  __u8  bDescriptorType; Device */
-       0x10,                   /*  __u16 bcdUSB; v1.1 */
-       0x01,
-       0x09,                   /*  __u8  bDeviceClass; HUB_CLASSCODE */
-       0x00,                   /*  __u8  bDeviceSubClass; */
-       0x00,                   /*  __u8  bDeviceProtocol; */
-       0x08,                   /*  __u8  bMaxPacketSize0; 8 Bytes */
-       0x00,                   /*  __u16 idVendor; */
-       0x00,
-       0x00,                   /*  __u16 idProduct; */
-       0x00,
-       0x00,                   /*  __u16 bcdDevice; */
-       0x00,
-       0x00,                   /*  __u8  iManufacturer; */
-       0x01,                   /*  __u8  iProduct; */
-       0x00,                   /*  __u8  iSerialNumber; */
-       0x01                    /*  __u8  bNumConfigurations; */
-};
-
-/* Configuration descriptor */
-static __u8 root_hub_config_des[] = {
-       0x09,                   /*  __u8  bLength; */
-       0x02,                   /*  __u8  bDescriptorType; Configuration */
-       0x19,                   /*  __u16 wTotalLength; */
-       0x00,
-       0x01,                   /*  __u8  bNumInterfaces; */
-       0x01,                   /*  __u8  bConfigurationValue; */
-       0x00,                   /*  __u8  iConfiguration; */
-       0x40,                   /*  __u8  bmAttributes;
-                                  Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
-       0x00,                   /*  __u8  MaxPower; */
-
-       /* interface */
-       0x09,                   /*  __u8  if_bLength; */
-       0x04,                   /*  __u8  if_bDescriptorType; Interface */
-       0x00,                   /*  __u8  if_bInterfaceNumber; */
-       0x00,                   /*  __u8  if_bAlternateSetting; */
-       0x01,                   /*  __u8  if_bNumEndpoints; */
-       0x09,                   /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
-       0x00,                   /*  __u8  if_bInterfaceSubClass; */
-       0x00,                   /*  __u8  if_bInterfaceProtocol; */
-       0x00,                   /*  __u8  if_iInterface; */
-
-       /* endpoint */
-       0x07,                   /*  __u8  ep_bLength; */
-       0x05,                   /*  __u8  ep_bDescriptorType; Endpoint */
-       0x81,                   /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
-       0x03,                   /*  __u8  ep_bmAttributes; Interrupt */
-       0x00,                   /*  __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
-       0x02,
-       0xff                    /*  __u8  ep_bInterval; 255 ms */
-};
-
-static unsigned char root_hub_str_index0[] = {
-       0x04,                   /*  __u8  bLength; */
-       0x03,                   /*  __u8  bDescriptorType; String-descriptor */
-       0x09,                   /*  __u8  lang ID */
-       0x04,                   /*  __u8  lang ID */
-};
-
-static unsigned char root_hub_str_index1[] = {
-       0x22,                   /*  __u8  bLength; */
-       0x03,                   /*  __u8  bDescriptorType; String-descriptor */
-       'I',                    /*  __u8  Unicode */
-       0,                      /*  __u8  Unicode */
-       'S',                    /*  __u8  Unicode */
-       0,                      /*  __u8  Unicode */
-       'P',                    /*  __u8  Unicode */
-       0,                      /*  __u8  Unicode */
-       '1',                    /*  __u8  Unicode */
-       0,                      /*  __u8  Unicode */
-       '1',                    /*  __u8  Unicode */
-       0,                      /*  __u8  Unicode */
-       '6',                    /*  __u8  Unicode */
-       0,                      /*  __u8  Unicode */
-       'x',                    /*  __u8  Unicode */
-       0,                      /*  __u8  Unicode */
-       ' ',                    /*  __u8  Unicode */
-       0,                      /*  __u8  Unicode */
-       'R',                    /*  __u8  Unicode */
-       0,                      /*  __u8  Unicode */
-       'o',                    /*  __u8  Unicode */
-       0,                      /*  __u8  Unicode */
-       'o',                    /*  __u8  Unicode */
-       0,                      /*  __u8  Unicode */
-       't',                    /*  __u8  Unicode */
-       0,                      /*  __u8  Unicode */
-       ' ',                    /*  __u8  Unicode */
-       0,                      /*  __u8  Unicode */
-       'H',                    /*  __u8  Unicode */
-       0,                      /*  __u8  Unicode */
-       'u',                    /*  __u8  Unicode */
-       0,                      /*  __u8  Unicode */
-       'b',                    /*  __u8  Unicode */
-       0,                      /*  __u8  Unicode */
-};
-
-/*
- * Hub class-specific descriptor is constructed dynamically
- */
-
-/* --- Virtual root hub management functions ------------------------------- */
-
-static int rh_check_port_status(struct isp116x *isp116x)
-{
-       u32 temp, ndp, i;
-       int res;
-
-       res = -1;
-       temp = isp116x_read_reg32(isp116x, HCRHSTATUS);
-       ndp = (temp & RH_A_NDP);
-       for (i = 0; i < ndp; i++) {
-               temp = isp116x_read_reg32(isp116x, HCRHPORT1 + i);
-               /* check for a device disconnect */
-               if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
-                    (RH_PS_PESC | RH_PS_CSC)) && ((temp & RH_PS_CCS) == 0)) {
-                       res = i;
-                       break;
-               }
-       }
-       return res;
-}
-
-/* --- HC management functions --------------------------------------------- */
-
-/* Write len bytes to fifo, pad till 32-bit boundary
- */
-static void write_ptddata_to_fifo(struct isp116x *isp116x, void *buf, int len)
-{
-       u8 *dp = (u8 *) buf;
-       u16 *dp2 = (u16 *) buf;
-       u16 w;
-       int quot = len % 4;
-
-       if ((unsigned long)dp2 & 1) {
-               /* not aligned */
-               for (; len > 1; len -= 2) {
-                       w = *dp++;
-                       w |= *dp++ << 8;
-                       isp116x_raw_write_data16(isp116x, w);
-               }
-               if (len)
-                       isp116x_write_data16(isp116x, (u16) * dp);
-       } else {
-               /* aligned */
-               for (; len > 1; len -= 2)
-                       isp116x_raw_write_data16(isp116x, *dp2++);
-               if (len)
-                       isp116x_write_data16(isp116x, 0xff & *((u8 *) dp2));
-       }
-       if (quot == 1 || quot == 2)
-               isp116x_raw_write_data16(isp116x, 0);
-}
-
-/* Read len bytes from fifo and then read till 32-bit boundary
- */
-static void read_ptddata_from_fifo(struct isp116x *isp116x, void *buf, int len)
-{
-       u8 *dp = (u8 *) buf;
-       u16 *dp2 = (u16 *) buf;
-       u16 w;
-       int quot = len % 4;
-
-       if ((unsigned long)dp2 & 1) {
-               /* not aligned */
-               for (; len > 1; len -= 2) {
-                       w = isp116x_raw_read_data16(isp116x);
-                       *dp++ = w & 0xff;
-                       *dp++ = (w >> 8) & 0xff;
-               }
-               if (len)
-                       *dp = 0xff & isp116x_read_data16(isp116x);
-       } else {
-               /* aligned */
-               for (; len > 1; len -= 2)
-                       *dp2++ = isp116x_raw_read_data16(isp116x);
-               if (len)
-                       *(u8 *) dp2 = 0xff & isp116x_read_data16(isp116x);
-       }
-       if (quot == 1 || quot == 2)
-               isp116x_raw_read_data16(isp116x);
-}
-
-/* Write PTD's and data for scheduled transfers into the fifo ram.
- * Fifo must be empty and ready */
-static void pack_fifo(struct isp116x *isp116x, struct usb_device *dev,
-                     unsigned long pipe, struct ptd *ptd, int n, void *data,
-                     int len)
-{
-       int buflen = n * sizeof(struct ptd) + len;
-       int i, done;
-
-       DBG("--- pack buffer %p - %d bytes (fifo %d) ---", data, len, buflen);
-
-       isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);
-       isp116x_write_reg16(isp116x, HCXFERCTR, buflen);
-       isp116x_write_addr(isp116x, HCATLPORT | ISP116x_WRITE_OFFSET);
-
-       done = 0;
-       for (i = 0; i < n; i++) {
-               DBG("i=%d - done=%d - len=%d", i, done, PTD_GET_LEN(&ptd[i]));
-
-               dump_ptd(&ptd[i]);
-               isp116x_write_data16(isp116x, ptd[i].count);
-               isp116x_write_data16(isp116x, ptd[i].mps);
-               isp116x_write_data16(isp116x, ptd[i].len);
-               isp116x_write_data16(isp116x, ptd[i].faddr);
-
-               dump_ptd_data(&ptd[i], (__u8 *) data + done, 0);
-               write_ptddata_to_fifo(isp116x,
-                                     (__u8 *) data + done,
-                                     PTD_GET_LEN(&ptd[i]));
-
-               done += PTD_GET_LEN(&ptd[i]);
-       }
-}
-
-/* Read the processed PTD's and data from fifo ram back to URBs' buffers.
- * Fifo must be full and done */
-static int unpack_fifo(struct isp116x *isp116x, struct usb_device *dev,
-                      unsigned long pipe, struct ptd *ptd, int n, void *data,
-                      int len)
-{
-       int buflen = n * sizeof(struct ptd) + len;
-       int i, done, cc, ret;
-
-       isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);
-       isp116x_write_reg16(isp116x, HCXFERCTR, buflen);
-       isp116x_write_addr(isp116x, HCATLPORT);
-
-       ret = TD_CC_NOERROR;
-       done = 0;
-       for (i = 0; i < n; i++) {
-               DBG("i=%d - done=%d - len=%d", i, done, PTD_GET_LEN(&ptd[i]));
-
-               ptd[i].count = isp116x_read_data16(isp116x);
-               ptd[i].mps = isp116x_read_data16(isp116x);
-               ptd[i].len = isp116x_read_data16(isp116x);
-               ptd[i].faddr = isp116x_read_data16(isp116x);
-               dump_ptd(&ptd[i]);
-
-               read_ptddata_from_fifo(isp116x,
-                                      (__u8 *) data + done,
-                                      PTD_GET_LEN(&ptd[i]));
-               dump_ptd_data(&ptd[i], (__u8 *) data + done, 1);
-
-               done += PTD_GET_LEN(&ptd[i]);
-
-               cc = PTD_GET_CC(&ptd[i]);
-
-               /* Data underrun means basically that we had more buffer space than
-                * the function had data. It is perfectly normal but upper levels have
-                * to know how much we actually transferred.
-                */
-               if (cc == TD_NOTACCESSED ||
-                               (cc != TD_CC_NOERROR && (ret == TD_CC_NOERROR || ret == TD_DATAUNDERRUN)))
-                       ret = cc;
-       }
-
-       DBG("--- unpack buffer %p - %d bytes (fifo %d) ---", data, len, buflen);
-
-       return ret;
-}
-
-/* Interrupt handling
- */
-static int isp116x_interrupt(struct isp116x *isp116x)
-{
-       u16 irqstat;
-       u32 intstat;
-       int ret = 0;
-
-       isp116x_write_reg16(isp116x, HCuPINTENB, 0);
-       irqstat = isp116x_read_reg16(isp116x, HCuPINT);
-       isp116x_write_reg16(isp116x, HCuPINT, irqstat);
-       DBG(">>>>>> irqstat %x <<<<<<", irqstat);
-
-       if (irqstat & HCuPINT_ATL) {
-               DBG(">>>>>> HCuPINT_ATL <<<<<<");
-               udelay(500);
-               ret = 1;
-       }
-
-       if (irqstat & HCuPINT_OPR) {
-               intstat = isp116x_read_reg32(isp116x, HCINTSTAT);
-               isp116x_write_reg32(isp116x, HCINTSTAT, intstat);
-               DBG(">>>>>> HCuPINT_OPR %x <<<<<<", intstat);
-
-               if (intstat & HCINT_UE) {
-                       ERR("unrecoverable error, controller disabled");
-
-                       /* FIXME: be optimistic, hope that bug won't repeat
-                        * often. Make some non-interrupt context restart the
-                        * controller. Count and limit the retries though;
-                        * either hardware or software errors can go forever...
-                        */
-                       isp116x_reset(isp116x);
-                       ret = -1;
-                       return -1;
-               }
-
-               if (intstat & HCINT_RHSC) {
-                       got_rhsc = 1;
-                       ret = 1;
-                       /* When root hub or any of its ports is going
-                          to come out of suspend, it may take more
-                          than 10ms for status bits to stabilize. */
-                       wait_ms(20);
-               }
-
-               if (intstat & HCINT_SO) {
-                       ERR("schedule overrun");
-                       ret = -1;
-               }
-
-               irqstat &= ~HCuPINT_OPR;
-       }
-
-       return ret;
-}
-
-/* With one PTD we can transfer almost 1K in one go;
- * HC does the splitting into endpoint digestible transactions
- */
-struct ptd ptd[1];
-
-static inline int max_transfer_len(struct usb_device *dev, unsigned long pipe)
-{
-       unsigned mpck = usb_maxpacket(dev, pipe);
-
-       /* One PTD can transfer 1023 bytes but try to always
-        * transfer multiples of endpoint buffer size
-        */
-       return 1023 / mpck * mpck;
-}
-
-/* Do an USB transfer
- */
-static int isp116x_submit_job(struct usb_device *dev, unsigned long pipe,
-                             int dir, void *buffer, int len)
-{
-       struct isp116x *isp116x = &isp116x_dev;
-       int type = usb_pipetype(pipe);
-       int epnum = usb_pipeendpoint(pipe);
-       int max = usb_maxpacket(dev, pipe);
-       int dir_out = usb_pipeout(pipe);
-       int speed_low = usb_pipeslow(pipe);
-       int i, done = 0, stat, timeout, cc;
-
-       /* 500 frames or 0.5s timeout when function is busy and NAKs transactions for a while */
-       int retries = 500;
-
-       DBG("------------------------------------------------");
-       dump_msg(dev, pipe, buffer, len, "SUBMIT");
-       DBG("------------------------------------------------");
-
-       if (len >= 1024) {
-               ERR("Too big job");
-               dev->status = USB_ST_CRC_ERR;
-               return -1;
-       }
-
-       if (isp116x->disabled) {
-               ERR("EPIPE");
-               dev->status = USB_ST_CRC_ERR;
-               return -1;
-       }
-
-       /* device pulled? Shortcut the action. */
-       if (devgone == dev) {
-               ERR("ENODEV");
-               dev->status = USB_ST_CRC_ERR;
-               return USB_ST_CRC_ERR;
-       }
-
-       if (!max) {
-               ERR("pipesize for pipe %lx is zero", pipe);
-               dev->status = USB_ST_CRC_ERR;
-               return -1;
-       }
-
-       if (type == PIPE_ISOCHRONOUS) {
-               ERR("isochronous transfers not supported");
-               dev->status = USB_ST_CRC_ERR;
-               return -1;
-       }
-
-       /* FIFO not empty? */
-       if (isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_FULL) {
-               ERR("****** FIFO not empty! ******");
-               dev->status = USB_ST_BUF_ERR;
-               return -1;
-       }
-
-      retry:
-       isp116x_write_reg32(isp116x, HCINTSTAT, 0xff);
-
-       /* Prepare the PTD data */
-       ptd->count = PTD_CC_MSK | PTD_ACTIVE_MSK |
-               PTD_TOGGLE(usb_gettoggle(dev, epnum, dir_out));
-       ptd->mps = PTD_MPS(max) | PTD_SPD(speed_low) | PTD_EP(epnum) | PTD_LAST_MSK;
-       ptd->len = PTD_LEN(len) | PTD_DIR(dir);
-       ptd->faddr = PTD_FA(usb_pipedevice(pipe));
-
-retry_same:
-       /* Pack data into FIFO ram */
-       pack_fifo(isp116x, dev, pipe, ptd, 1, buffer, len);
-#ifdef EXTRA_DELAY
-       wait_ms(EXTRA_DELAY);
-#endif
-
-       /* Start the data transfer */
-
-       /* Allow more time for a BULK device to react - some are slow */
-       if (usb_pipetype(pipe) == PIPE_BULK)
-               timeout = 5000;
-       else
-               timeout = 100;
-
-       /* Wait for it to complete */
-       for (;;) {
-               /* Check whether the controller is done */
-               stat = isp116x_interrupt(isp116x);
-
-               if (stat < 0) {
-                       dev->status = USB_ST_CRC_ERR;
-                       break;
-               }
-               if (stat > 0)
-                       break;
-
-               /* Check the timeout */
-               if (--timeout)
-                       udelay(1);
-               else {
-                       ERR("CTL:TIMEOUT ");
-                       stat = USB_ST_CRC_ERR;
-                       break;
-               }
-       }
-
-       /* We got an Root Hub Status Change interrupt */
-       if (got_rhsc) {
-               isp116x_show_regs(isp116x);
-
-               got_rhsc = 0;
-
-               /* Abuse timeout */
-               timeout = rh_check_port_status(isp116x);
-               if (timeout >= 0) {
-                       /*
-                        * FIXME! NOTE! AAAARGH!
-                        * This is potentially dangerous because it assumes
-                        * that only one device is ever plugged in!
-                        */
-                       devgone = dev;
-               }
-       }
-
-       /* Ok, now we can read transfer status */
-
-       /* FIFO not ready? */
-       if (!(isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_DONE)) {
-               ERR("****** FIFO not ready! ******");
-               dev->status = USB_ST_BUF_ERR;
-               return -1;
-       }
-
-       /* Unpack data from FIFO ram */
-       cc = unpack_fifo(isp116x, dev, pipe, ptd, 1, buffer, len);
-
-       i = PTD_GET_COUNT(ptd);
-       done += i;
-       buffer += i;
-       len -= i;
-
-       /* There was some kind of real problem; Prepare the PTD again
-        * and retry from the failed transaction on
-        */
-       if (cc && cc != TD_NOTACCESSED && cc != TD_DATAUNDERRUN) {
-               if (retries >= 100) {
-                       retries -= 100;
-                       /* The chip will have toggled the toggle bit for the failed
-                        * transaction too. We have to toggle it back.
-                        */
-                       usb_settoggle(dev, epnum, dir_out, !PTD_GET_TOGGLE(ptd));
-                       goto retry;
-               }
-       }
-       /* "Normal" errors; TD_NOTACCESSED would mean in effect that the function have NAKed
-        * the transactions from the first on for the whole frame. It may be busy and we retry
-        * with the same PTD. PTD_ACTIVE (and not TD_NOTACCESSED) would mean that some of the
-        * PTD didn't make it because the function was busy or the frame ended before the PTD
-        * finished. We prepare the rest of the data and try again.
-        */
-       else if (cc == TD_NOTACCESSED || PTD_GET_ACTIVE(ptd) || (cc != TD_DATAUNDERRUN && PTD_GET_COUNT(ptd) < PTD_GET_LEN(ptd))) {
-               if (retries) {
-                       --retries;
-                       if (cc == TD_NOTACCESSED && PTD_GET_ACTIVE(ptd) && !PTD_GET_COUNT(ptd)) goto retry_same;
-                       usb_settoggle(dev, epnum, dir_out, PTD_GET_TOGGLE(ptd));
-                       goto retry;
-               }
-       }
-
-       if (cc != TD_CC_NOERROR && cc != TD_DATAUNDERRUN) {
-               DBG("****** completition code error %x ******", cc);
-               switch (cc) {
-               case TD_CC_BITSTUFFING:
-                       dev->status = USB_ST_BIT_ERR;
-                       break;
-               case TD_CC_STALL:
-                       dev->status = USB_ST_STALLED;
-                       break;
-               case TD_BUFFEROVERRUN:
-               case TD_BUFFERUNDERRUN:
-                       dev->status = USB_ST_BUF_ERR;
-                       break;
-               default:
-                       dev->status = USB_ST_CRC_ERR;
-               }
-               return -cc;
-       }
-       else usb_settoggle(dev, epnum, dir_out, PTD_GET_TOGGLE(ptd));
-
-       dump_msg(dev, pipe, buffer, len, "SUBMIT(ret)");
-
-       dev->status = 0;
-       return done;
-}
-
-/* Adapted from au1x00_usb_ohci.c
- */
-static int isp116x_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
-                                void *buffer, int transfer_len,
-                                struct devrequest *cmd)
-{
-       struct isp116x *isp116x = &isp116x_dev;
-       u32 tmp = 0;
-
-       int leni = transfer_len;
-       int len = 0;
-       int stat = 0;
-       u32 datab[4];
-       u8 *data_buf = (u8 *) datab;
-       u16 bmRType_bReq;
-       u16 wValue;
-       u16 wIndex;
-       u16 wLength;
-
-       if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
-               INFO("Root-Hub submit IRQ: NOT implemented");
-               return 0;
-       }
-
-       bmRType_bReq = cmd->requesttype | (cmd->request << 8);
-       wValue = swap_16(cmd->value);
-       wIndex = swap_16(cmd->index);
-       wLength = swap_16(cmd->length);
-
-       DBG("--- HUB ----------------------------------------");
-       DBG("submit rh urb, req=%x val=%#x index=%#x len=%d",
-           bmRType_bReq, wValue, wIndex, wLength);
-       dump_msg(dev, pipe, buffer, transfer_len, "RH");
-       DBG("------------------------------------------------");
-
-       switch (bmRType_bReq) {
-       case RH_GET_STATUS:
-               DBG("RH_GET_STATUS");
-
-               *(__u16 *) data_buf = swap_16(1);
-               len = 2;
-               break;
-
-       case RH_GET_STATUS | RH_INTERFACE:
-               DBG("RH_GET_STATUS | RH_INTERFACE");
-
-               *(__u16 *) data_buf = swap_16(0);
-               len = 2;
-               break;
-
-       case RH_GET_STATUS | RH_ENDPOINT:
-               DBG("RH_GET_STATUS | RH_ENDPOINT");
-
-               *(__u16 *) data_buf = swap_16(0);
-               len = 2;
-               break;
-
-       case RH_GET_STATUS | RH_CLASS:
-               DBG("RH_GET_STATUS | RH_CLASS");
-
-               tmp = isp116x_read_reg32(isp116x, HCRHSTATUS);
-
-               *(__u32 *) data_buf = swap_32(tmp & ~(RH_HS_CRWE | RH_HS_DRWE));
-               len = 4;
-               break;
-
-       case RH_GET_STATUS | RH_OTHER | RH_CLASS:
-               DBG("RH_GET_STATUS | RH_OTHER | RH_CLASS");
-
-               tmp = isp116x_read_reg32(isp116x, HCRHPORT1 + wIndex - 1);
-               *(__u32 *) data_buf = swap_32(tmp);
-               isp116x_show_regs(isp116x);
-               len = 4;
-               break;
-
-       case RH_CLEAR_FEATURE | RH_ENDPOINT:
-               DBG("RH_CLEAR_FEATURE | RH_ENDPOINT");
-
-               switch (wValue) {
-               case RH_ENDPOINT_STALL:
-                       DBG("C_HUB_ENDPOINT_STALL");
-                       len = 0;
-                       break;
-               }
-               break;
-
-       case RH_CLEAR_FEATURE | RH_CLASS:
-               DBG("RH_CLEAR_FEATURE | RH_CLASS");
-
-               switch (wValue) {
-               case RH_C_HUB_LOCAL_POWER:
-                       DBG("C_HUB_LOCAL_POWER");
-                       len = 0;
-                       break;
-
-               case RH_C_HUB_OVER_CURRENT:
-                       DBG("C_HUB_OVER_CURRENT");
-                       isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_OCIC);
-                       len = 0;
-                       break;
-               }
-               break;
-
-       case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
-               DBG("RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS");
-
-               switch (wValue) {
-               case RH_PORT_ENABLE:
-                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
-                                           RH_PS_CCS);
-                       len = 0;
-                       break;
-
-               case RH_PORT_SUSPEND:
-                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
-                                           RH_PS_POCI);
-                       len = 0;
-                       break;
-
-               case RH_PORT_POWER:
-                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
-                                           RH_PS_LSDA);
-                       len = 0;
-                       break;
-
-               case RH_C_PORT_CONNECTION:
-                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
-                                           RH_PS_CSC);
-                       len = 0;
-                       break;
-
-               case RH_C_PORT_ENABLE:
-                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
-                                           RH_PS_PESC);
-                       len = 0;
-                       break;
-
-               case RH_C_PORT_SUSPEND:
-                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
-                                           RH_PS_PSSC);
-                       len = 0;
-                       break;
-
-               case RH_C_PORT_OVER_CURRENT:
-                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
-                                           RH_PS_POCI);
-                       len = 0;
-                       break;
-
-               case RH_C_PORT_RESET:
-                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
-                                           RH_PS_PRSC);
-                       len = 0;
-                       break;
-
-               default:
-                       ERR("invalid wValue");
-                       stat = USB_ST_STALLED;
-               }
-
-               isp116x_show_regs(isp116x);
-
-               break;
-
-       case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
-               DBG("RH_SET_FEATURE | RH_OTHER | RH_CLASS");
-
-               switch (wValue) {
-               case RH_PORT_SUSPEND:
-                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
-                                           RH_PS_PSS);
-                       len = 0;
-                       break;
-
-               case RH_PORT_RESET:
-                       /* Spin until any current reset finishes */
-                       while (1) {
-                               tmp =
-                                   isp116x_read_reg32(isp116x,
-                                                      HCRHPORT1 + wIndex - 1);
-                               if (!(tmp & RH_PS_PRS))
-                                       break;
-                               wait_ms(1);
-                       }
-                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
-                                           RH_PS_PRS);
-                       wait_ms(10);
-
-                       len = 0;
-                       break;
-
-               case RH_PORT_POWER:
-                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
-                                           RH_PS_PPS);
-                       len = 0;
-                       break;
-
-               case RH_PORT_ENABLE:
-                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
-                                           RH_PS_PES);
-                       len = 0;
-                       break;
-
-               default:
-                       ERR("invalid wValue");
-                       stat = USB_ST_STALLED;
-               }
-
-               isp116x_show_regs(isp116x);
-
-               break;
-
-       case RH_SET_ADDRESS:
-               DBG("RH_SET_ADDRESS");
-
-               rh_devnum = wValue;
-               len = 0;
-               break;
-
-       case RH_GET_DESCRIPTOR:
-               DBG("RH_GET_DESCRIPTOR: %x, %d", wValue, wLength);
-
-               switch (wValue) {
-               case (USB_DT_DEVICE << 8):      /* device descriptor */
-                       len = min_t(unsigned int,
-                                   leni, min_t(unsigned int,
-                                               sizeof(root_hub_dev_des),
-                                               wLength));
-                       data_buf = root_hub_dev_des;
-                       break;
-
-               case (USB_DT_CONFIG << 8):      /* configuration descriptor */
-                       len = min_t(unsigned int,
-                                   leni, min_t(unsigned int,
-                                               sizeof(root_hub_config_des),
-                                               wLength));
-                       data_buf = root_hub_config_des;
-                       break;
-
-               case ((USB_DT_STRING << 8) | 0x00):     /* string 0 descriptors */
-                       len = min_t(unsigned int,
-                                   leni, min_t(unsigned int,
-                                               sizeof(root_hub_str_index0),
-                                               wLength));
-                       data_buf = root_hub_str_index0;
-                       break;
-
-               case ((USB_DT_STRING << 8) | 0x01):     /* string 1 descriptors */
-                       len = min_t(unsigned int,
-                                   leni, min_t(unsigned int,
-                                               sizeof(root_hub_str_index1),
-                                               wLength));
-                       data_buf = root_hub_str_index1;
-                       break;
-
-               default:
-                       ERR("invalid wValue");
-                       stat = USB_ST_STALLED;
-               }
-
-               break;
-
-       case RH_GET_DESCRIPTOR | RH_CLASS:
-               DBG("RH_GET_DESCRIPTOR | RH_CLASS");
-
-               tmp = isp116x_read_reg32(isp116x, HCRHDESCA);
-
-               data_buf[0] = 0x09;     /* min length; */
-               data_buf[1] = 0x29;
-               data_buf[2] = tmp & RH_A_NDP;
-               data_buf[3] = 0;
-               if (tmp & RH_A_PSM)     /* per-port power switching? */
-                       data_buf[3] |= 0x01;
-               if (tmp & RH_A_NOCP)    /* no overcurrent reporting? */
-                       data_buf[3] |= 0x10;
-               else if (tmp & RH_A_OCPM)       /* per-port overcurrent rep? */
-                       data_buf[3] |= 0x08;
-
-               /* Corresponds to data_buf[4-7] */
-               datab[1] = 0;
-               data_buf[5] = (tmp & RH_A_POTPGT) >> 24;
-
-               tmp = isp116x_read_reg32(isp116x, HCRHDESCB);
-
-               data_buf[7] = tmp & RH_B_DR;
-               if (data_buf[2] < 7)
-                       data_buf[8] = 0xff;
-               else {
-                       data_buf[0] += 2;
-                       data_buf[8] = (tmp & RH_B_DR) >> 8;
-                       data_buf[10] = data_buf[9] = 0xff;
-               }
-
-               len = min_t(unsigned int, leni,
-                           min_t(unsigned int, data_buf[0], wLength));
-               break;
-
-       case RH_GET_CONFIGURATION:
-               DBG("RH_GET_CONFIGURATION");
-
-               *(__u8 *) data_buf = 0x01;
-               len = 1;
-               break;
-
-       case RH_SET_CONFIGURATION:
-               DBG("RH_SET_CONFIGURATION");
-
-               isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPSC);
-               len = 0;
-               break;
-
-       default:
-               ERR("*** *** *** unsupported root hub command *** *** ***");
-               stat = USB_ST_STALLED;
-       }
-
-       len = min_t(int, len, leni);
-       if (buffer != data_buf)
-               memcpy(buffer, data_buf, len);
-
-       dev->act_len = len;
-       dev->status = stat;
-       DBG("dev act_len %d, status %d", dev->act_len, dev->status);
-
-       dump_msg(dev, pipe, buffer, transfer_len, "RH(ret)");
-
-       return stat;
-}
-
-/* --- Transfer functions -------------------------------------------------- */
-
-int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
-                  int len, int interval)
-{
-       DBG("dev=%p pipe=%#lx buf=%p size=%d int=%d",
-           dev, pipe, buffer, len, interval);
-
-       return -1;
-}
-
-int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
-                      int len, struct devrequest *setup)
-{
-       int devnum = usb_pipedevice(pipe);
-       int epnum = usb_pipeendpoint(pipe);
-       int max = max_transfer_len(dev, pipe);
-       int dir_in = usb_pipein(pipe);
-       int done, ret;
-
-       /* Control message is for the HUB? */
-       if (devnum == rh_devnum)
-               return isp116x_submit_rh_msg(dev, pipe, buffer, len, setup);
-
-       /* Ok, no HUB message so send the message to the device */
-
-       /* Setup phase */
-       DBG("--- SETUP PHASE --------------------------------");
-       usb_settoggle(dev, epnum, 1, 0);
-       ret = isp116x_submit_job(dev, pipe,
-                                PTD_DIR_SETUP,
-                                setup, sizeof(struct devrequest));
-       if (ret < 0) {
-               DBG("control setup phase error (ret = %d", ret);
-               return -1;
-       }
-
-       /* Data phase */
-       DBG("--- DATA PHASE ---------------------------------");
-       done = 0;
-       usb_settoggle(dev, epnum, !dir_in, 1);
-       while (done < len) {
-               ret = isp116x_submit_job(dev, pipe,
-                                        dir_in ? PTD_DIR_IN : PTD_DIR_OUT,
-                                        (__u8 *) buffer + done,
-                                        max > len - done ? len - done : max);
-               if (ret < 0) {
-                       DBG("control data phase error (ret = %d)", ret);
-                       return -1;
-               }
-               done += ret;
-
-               if (dir_in && ret < max)        /* short packet */
-                       break;
-       }
-
-       /* Status phase */
-       DBG("--- STATUS PHASE -------------------------------");
-       usb_settoggle(dev, epnum, !dir_in, 1);
-       ret = isp116x_submit_job(dev, pipe,
-                                !dir_in ? PTD_DIR_IN : PTD_DIR_OUT, NULL, 0);
-       if (ret < 0) {
-               DBG("control status phase error (ret = %d", ret);
-               return -1;
-       }
-
-       dev->act_len = done;
-
-       dump_msg(dev, pipe, buffer, len, "DEV(ret)");
-
-       return done;
-}
-
-int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
-                   int len)
-{
-       int dir_out = usb_pipeout(pipe);
-       int max = max_transfer_len(dev, pipe);
-       int done, ret;
-
-       DBG("--- BULK ---------------------------------------");
-       DBG("dev=%ld pipe=%ld buf=%p size=%d dir_out=%d",
-           usb_pipedevice(pipe), usb_pipeendpoint(pipe), buffer, len, dir_out);
-
-       done = 0;
-       while (done < len) {
-               ret = isp116x_submit_job(dev, pipe,
-                                        !dir_out ? PTD_DIR_IN : PTD_DIR_OUT,
-                                        (__u8 *) buffer + done,
-                                        max > len - done ? len - done : max);
-               if (ret < 0) {
-                       DBG("error on bulk message (ret = %d)", ret);
-                       return -1;
-               }
-
-               done += ret;
-
-               if (!dir_out && ret < max)      /* short packet */
-                       break;
-       }
-
-       dev->act_len = done;
-
-       return 0;
-}
-
-/* --- Basic functions ----------------------------------------------------- */
-
-static int isp116x_sw_reset(struct isp116x *isp116x)
-{
-       int retries = 15;
-       int ret = 0;
-
-       DBG("");
-
-       isp116x->disabled = 1;
-
-       isp116x_write_reg16(isp116x, HCSWRES, HCSWRES_MAGIC);
-       isp116x_write_reg32(isp116x, HCCMDSTAT, HCCMDSTAT_HCR);
-       while (--retries) {
-               /* It usually resets within 1 ms */
-               wait_ms(1);
-               if (!(isp116x_read_reg32(isp116x, HCCMDSTAT) & HCCMDSTAT_HCR))
-                       break;
-       }
-       if (!retries) {
-               ERR("software reset timeout");
-               ret = -1;
-       }
-       return ret;
-}
-
-static int isp116x_reset(struct isp116x *isp116x)
-{
-       unsigned long t;
-       u16 clkrdy = 0;
-       int ret, timeout = 15 /* ms */ ;
-
-       DBG("");
-
-       ret = isp116x_sw_reset(isp116x);
-       if (ret)
-               return ret;
-
-       for (t = 0; t < timeout; t++) {
-               clkrdy = isp116x_read_reg16(isp116x, HCuPINT) & HCuPINT_CLKRDY;
-               if (clkrdy)
-                       break;
-               wait_ms(1);
-       }
-       if (!clkrdy) {
-               ERR("clock not ready after %dms", timeout);
-               /* After sw_reset the clock won't report to be ready, if
-                  H_WAKEUP pin is high. */
-               ERR("please make sure that the H_WAKEUP pin is pulled low!");
-               ret = -1;
-       }
-       return ret;
-}
-
-static void isp116x_stop(struct isp116x *isp116x)
-{
-       u32 val;
-
-       DBG("");
-
-       isp116x_write_reg16(isp116x, HCuPINTENB, 0);
-
-       /* Switch off ports' power, some devices don't come up
-          after next 'start' without this */
-       val = isp116x_read_reg32(isp116x, HCRHDESCA);
-       val &= ~(RH_A_NPS | RH_A_PSM);
-       isp116x_write_reg32(isp116x, HCRHDESCA, val);
-       isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPS);
-
-       isp116x_sw_reset(isp116x);
-}
-
-/*
- *  Configure the chip. The chip must be successfully reset by now.
- */
-static int isp116x_start(struct isp116x *isp116x)
-{
-       struct isp116x_platform_data *board = isp116x->board;
-       u32 val;
-
-       DBG("");
-
-       /* Clear interrupt status and disable all interrupt sources */
-       isp116x_write_reg16(isp116x, HCuPINT, 0xff);
-       isp116x_write_reg16(isp116x, HCuPINTENB, 0);
-
-       isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE);
-       isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE);
-
-       /* Hardware configuration */
-       val = HCHWCFG_DBWIDTH(1);
-       if (board->sel15Kres)
-               val |= HCHWCFG_15KRSEL;
-       /* Remote wakeup won't work without working clock */
-       if (board->remote_wakeup_enable)
-               val |= HCHWCFG_CLKNOTSTOP;
-       if (board->oc_enable)
-               val |= HCHWCFG_ANALOG_OC;
-       isp116x_write_reg16(isp116x, HCHWCFG, val);
-
-       /* --- Root hub configuration */
-       val = (25 << 24) & RH_A_POTPGT;
-       /* AN10003_1.pdf recommends RH_A_NPS (no power switching) to
-          be always set. Yet, instead, we request individual port
-          power switching. */
-       val |= RH_A_PSM;
-       /* Report overcurrent per port */
-       val |= RH_A_OCPM;
-       isp116x_write_reg32(isp116x, HCRHDESCA, val);
-       isp116x->rhdesca = isp116x_read_reg32(isp116x, HCRHDESCA);
-
-       val = RH_B_PPCM;
-       isp116x_write_reg32(isp116x, HCRHDESCB, val);
-       isp116x->rhdescb = isp116x_read_reg32(isp116x, HCRHDESCB);
-
-       val = 0;
-       if (board->remote_wakeup_enable)
-               val |= RH_HS_DRWE;
-       isp116x_write_reg32(isp116x, HCRHSTATUS, val);
-       isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS);
-
-       isp116x_write_reg32(isp116x, HCFMINTVL, 0x27782edf);
-
-       /* Go operational */
-       val = HCCONTROL_USB_OPER;
-       if (board->remote_wakeup_enable)
-               val |= HCCONTROL_RWE;
-       isp116x_write_reg32(isp116x, HCCONTROL, val);
-
-       /* Disable ports to avoid race in device enumeration */
-       isp116x_write_reg32(isp116x, HCRHPORT1, RH_PS_CCS);
-       isp116x_write_reg32(isp116x, HCRHPORT2, RH_PS_CCS);
-
-       isp116x_show_regs(isp116x);
-
-       isp116x->disabled = 0;
-
-       return 0;
-}
-
-/* --- Init functions ------------------------------------------------------ */
-
-int isp116x_check_id(struct isp116x *isp116x)
-{
-       int val;
-
-       val = isp116x_read_reg16(isp116x, HCCHIPID);
-       if ((val & HCCHIPID_MASK) != HCCHIPID_MAGIC) {
-               ERR("invalid chip ID %04x", val);
-               return -1;
-       }
-
-       return 0;
-}
-
-int usb_lowlevel_init(void)
-{
-       struct isp116x *isp116x = &isp116x_dev;
-
-       DBG("");
-
-       got_rhsc = rh_devnum = 0;
-
-       /* Init device registers addr */
-       isp116x->addr_reg = (u16 *) ISP116X_HCD_ADDR;
-       isp116x->data_reg = (u16 *) ISP116X_HCD_DATA;
-
-       /* Setup specific board settings */
-#ifdef ISP116X_HCD_SEL15kRES
-       isp116x_board.sel15Kres = 1;
-#endif
-#ifdef ISP116X_HCD_OC_ENABLE
-       isp116x_board.oc_enable = 1;
-#endif
-#ifdef ISP116X_HCD_REMOTE_WAKEUP_ENABLE
-       isp116x_board.remote_wakeup_enable = 1;
-#endif
-       isp116x->board = &isp116x_board;
-
-       /* Try to get ISP116x silicon chip ID */
-       if (isp116x_check_id(isp116x) < 0)
-               return -1;
-
-       isp116x->disabled = 1;
-       isp116x->sleeping = 0;
-
-       isp116x_reset(isp116x);
-       isp116x_start(isp116x);
-
-       return 0;
-}
-
-int usb_lowlevel_stop(void)
-{
-       struct isp116x *isp116x = &isp116x_dev;
-
-       DBG("");
-
-       if (!isp116x->disabled)
-               isp116x_stop(isp116x);
-
-       return 0;
-}
-
-#endif                         /* CONFIG_USB_ISP116X_HCD */
diff --git a/drivers/isp116x.h b/drivers/isp116x.h
deleted file mode 100644 (file)
index a3ce3b5..0000000
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * ISP116x register declarations and HCD data structures
- *
- * Copyright (C) 2007 Rodolfo Giometti <giometti@linux.it>
- * Copyright (C) 2007 Eurotech S.p.A. <info@eurotech.it>
- * Copyright (C) 2005 Olav Kongas <ok@artecdesign.ee>
- * Portions:
- * Copyright (C) 2004 Lothar Wassmann
- * Copyright (C) 2004 Psion Teklogix
- * Copyright (C) 2004 David Brownell
- *
- * 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
- */
-
-#ifdef DEBUG
-#define DBG(fmt, args...)      \
-               printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args)
-#else
-#define DBG(fmt, args...)      do {} while (0)
-#endif
-
-#ifdef VERBOSE
-#    define VDBG               DBG
-#else
-#    define VDBG(fmt, args...) do {} while (0)
-#endif
-
-#define ERR(fmt, args...)      \
-               printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args)
-#define WARN(fmt, args...)     \
-               printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args)
-#define INFO(fmt, args...)     \
-               printf("isp116x: " fmt "\n" , ## args)
-
-/* ------------------------------------------------------------------------- */
-
-/* us of 1ms frame */
-#define  MAX_LOAD_LIMIT                850
-
-/* Full speed: max # of bytes to transfer for a single urb
-   at a time must be < 1024 && must be multiple of 64.
-   832 allows transfering 4kiB within 5 frames. */
-#define MAX_TRANSFER_SIZE_FULLSPEED    832
-
-/* Low speed: there is no reason to schedule in very big
-   chunks; often the requested long transfers are for
-   string descriptors containing short strings. */
-#define MAX_TRANSFER_SIZE_LOWSPEED     64
-
-/* Bytetime (us), a rough indication of how much time it
-   would take to transfer a byte of useful data over USB */
-#define BYTE_TIME_FULLSPEED    1
-#define BYTE_TIME_LOWSPEED     20
-
-/* Buffer sizes */
-#define ISP116x_BUF_SIZE       4096
-#define ISP116x_ITL_BUFSIZE    0
-#define ISP116x_ATL_BUFSIZE    ((ISP116x_BUF_SIZE) - 2*(ISP116x_ITL_BUFSIZE))
-
-#define ISP116x_WRITE_OFFSET   0x80
-
-/* --- ISP116x registers/bits ---------------------------------------------- */
-
-#define        HCREVISION      0x00
-#define        HCCONTROL       0x01
-#define                HCCONTROL_HCFS  (3 << 6)        /* host controller
-                                                  functional state */
-#define                HCCONTROL_USB_RESET     (0 << 6)
-#define                HCCONTROL_USB_RESUME    (1 << 6)
-#define                HCCONTROL_USB_OPER      (2 << 6)
-#define                HCCONTROL_USB_SUSPEND   (3 << 6)
-#define                HCCONTROL_RWC   (1 << 9)        /* remote wakeup connected */
-#define                HCCONTROL_RWE   (1 << 10)       /* remote wakeup enable */
-#define        HCCMDSTAT       0x02
-#define                HCCMDSTAT_HCR   (1 << 0)        /* host controller reset */
-#define                HCCMDSTAT_SOC   (3 << 16)       /* scheduling overrun count */
-#define        HCINTSTAT       0x03
-#define                HCINT_SO        (1 << 0)        /* scheduling overrun */
-#define                HCINT_WDH       (1 << 1)        /* writeback of done_head */
-#define                HCINT_SF        (1 << 2)        /* start frame */
-#define                HCINT_RD        (1 << 3)        /* resume detect */
-#define                HCINT_UE        (1 << 4)        /* unrecoverable error */
-#define                HCINT_FNO       (1 << 5)        /* frame number overflow */
-#define                HCINT_RHSC      (1 << 6)        /* root hub status change */
-#define                HCINT_OC        (1 << 30)       /* ownership change */
-#define                HCINT_MIE       (1 << 31)       /* master interrupt enable */
-#define        HCINTENB        0x04
-#define        HCINTDIS        0x05
-#define        HCFMINTVL       0x0d
-#define        HCFMREM         0x0e
-#define        HCFMNUM         0x0f
-#define        HCLSTHRESH      0x11
-#define        HCRHDESCA       0x12
-#define                RH_A_NDP        (0x3 << 0)      /* # downstream ports */
-#define                RH_A_PSM        (1 << 8)        /* power switching mode */
-#define                RH_A_NPS        (1 << 9)        /* no power switching */
-#define                RH_A_DT         (1 << 10)       /* device type (mbz) */
-#define                RH_A_OCPM       (1 << 11)       /* overcurrent protection
-                                                  mode */
-#define                RH_A_NOCP       (1 << 12)       /* no overcurrent protection */
-#define                RH_A_POTPGT     (0xff << 24)    /* power on -> power good
-                                                  time */
-#define        HCRHDESCB       0x13
-#define                RH_B_DR         (0xffff << 0)   /* device removable flags */
-#define                RH_B_PPCM       (0xffff << 16)  /* port power control mask */
-#define        HCRHSTATUS      0x14
-#define                RH_HS_LPS       (1 << 0)        /* local power status */
-#define                RH_HS_OCI       (1 << 1)        /* over current indicator */
-#define                RH_HS_DRWE      (1 << 15)       /* device remote wakeup
-                                                  enable */
-#define                RH_HS_LPSC      (1 << 16)       /* local power status change */
-#define                RH_HS_OCIC      (1 << 17)       /* over current indicator
-                                                  change */
-#define                RH_HS_CRWE      (1 << 31)       /* clear remote wakeup
-                                                  enable */
-#define        HCRHPORT1       0x15
-#define                RH_PS_CCS       (1 << 0)        /* current connect status */
-#define                RH_PS_PES       (1 << 1)        /* port enable status */
-#define                RH_PS_PSS       (1 << 2)        /* port suspend status */
-#define                RH_PS_POCI      (1 << 3)        /* port over current
-                                                  indicator */
-#define                RH_PS_PRS       (1 << 4)        /* port reset status */
-#define                RH_PS_PPS       (1 << 8)        /* port power status */
-#define                RH_PS_LSDA      (1 << 9)        /* low speed device attached */
-#define                RH_PS_CSC       (1 << 16)       /* connect status change */
-#define                RH_PS_PESC      (1 << 17)       /* port enable status change */
-#define                RH_PS_PSSC      (1 << 18)       /* port suspend status
-                                                  change */
-#define                RH_PS_OCIC      (1 << 19)       /* over current indicator
-                                                  change */
-#define                RH_PS_PRSC      (1 << 20)       /* port reset status change */
-#define                HCRHPORT_CLRMASK        (0x1f << 16)
-#define        HCRHPORT2       0x16
-#define        HCHWCFG         0x20
-#define                HCHWCFG_15KRSEL         (1 << 12)
-#define                HCHWCFG_CLKNOTSTOP      (1 << 11)
-#define                HCHWCFG_ANALOG_OC       (1 << 10)
-#define                HCHWCFG_DACK_MODE       (1 << 8)
-#define                HCHWCFG_EOT_POL         (1 << 7)
-#define                HCHWCFG_DACK_POL        (1 << 6)
-#define                HCHWCFG_DREQ_POL        (1 << 5)
-#define                HCHWCFG_DBWIDTH_MASK    (0x03 << 3)
-#define                HCHWCFG_DBWIDTH(n)      (((n) << 3) & HCHWCFG_DBWIDTH_MASK)
-#define                HCHWCFG_INT_POL         (1 << 2)
-#define                HCHWCFG_INT_TRIGGER     (1 << 1)
-#define                HCHWCFG_INT_ENABLE      (1 << 0)
-#define        HCDMACFG        0x21
-#define                HCDMACFG_BURST_LEN_MASK (0x03 << 5)
-#define                HCDMACFG_BURST_LEN(n)   (((n) << 5) & HCDMACFG_BURST_LEN_MASK)
-#define                HCDMACFG_BURST_LEN_1    HCDMACFG_BURST_LEN(0)
-#define                HCDMACFG_BURST_LEN_4    HCDMACFG_BURST_LEN(1)
-#define                HCDMACFG_BURST_LEN_8    HCDMACFG_BURST_LEN(2)
-#define                HCDMACFG_DMA_ENABLE     (1 << 4)
-#define                HCDMACFG_BUF_TYPE_MASK  (0x07 << 1)
-#define                HCDMACFG_CTR_SEL        (1 << 2)
-#define                HCDMACFG_ITLATL_SEL     (1 << 1)
-#define                HCDMACFG_DMA_RW_SELECT  (1 << 0)
-#define        HCXFERCTR       0x22
-#define        HCuPINT         0x24
-#define                HCuPINT_SOF             (1 << 0)
-#define                HCuPINT_ATL             (1 << 1)
-#define                HCuPINT_AIIEOT          (1 << 2)
-#define                HCuPINT_OPR             (1 << 4)
-#define                HCuPINT_SUSP            (1 << 5)
-#define                HCuPINT_CLKRDY          (1 << 6)
-#define        HCuPINTENB      0x25
-#define        HCCHIPID        0x27
-#define                HCCHIPID_MASK           0xff00
-#define                HCCHIPID_MAGIC          0x6100
-#define        HCSCRATCH       0x28
-#define        HCSWRES         0x29
-#define                HCSWRES_MAGIC           0x00f6
-#define        HCITLBUFLEN     0x2a
-#define        HCATLBUFLEN     0x2b
-#define        HCBUFSTAT       0x2c
-#define                HCBUFSTAT_ITL0_FULL     (1 << 0)
-#define                HCBUFSTAT_ITL1_FULL     (1 << 1)
-#define                HCBUFSTAT_ATL_FULL      (1 << 2)
-#define                HCBUFSTAT_ITL0_DONE     (1 << 3)
-#define                HCBUFSTAT_ITL1_DONE     (1 << 4)
-#define                HCBUFSTAT_ATL_DONE      (1 << 5)
-#define        HCRDITL0LEN     0x2d
-#define        HCRDITL1LEN     0x2e
-#define        HCITLPORT       0x40
-#define        HCATLPORT       0x41
-
-/* PTD accessor macros. */
-#define PTD_GET_COUNT(p)       (((p)->count & PTD_COUNT_MSK) >> 0)
-#define PTD_COUNT(v)           (((v) << 0) & PTD_COUNT_MSK)
-#define PTD_GET_TOGGLE(p)      (((p)->count & PTD_TOGGLE_MSK) >> 10)
-#define PTD_TOGGLE(v)          (((v) << 10) & PTD_TOGGLE_MSK)
-#define PTD_GET_ACTIVE(p)      (((p)->count & PTD_ACTIVE_MSK) >> 11)
-#define PTD_ACTIVE(v)          (((v) << 11) & PTD_ACTIVE_MSK)
-#define PTD_GET_CC(p)          (((p)->count & PTD_CC_MSK) >> 12)
-#define PTD_CC(v)              (((v) << 12) & PTD_CC_MSK)
-#define PTD_GET_MPS(p)         (((p)->mps & PTD_MPS_MSK) >> 0)
-#define PTD_MPS(v)             (((v) << 0) & PTD_MPS_MSK)
-#define PTD_GET_SPD(p)         (((p)->mps & PTD_SPD_MSK) >> 10)
-#define PTD_SPD(v)             (((v) << 10) & PTD_SPD_MSK)
-#define PTD_GET_LAST(p)                (((p)->mps & PTD_LAST_MSK) >> 11)
-#define PTD_LAST(v)            (((v) << 11) & PTD_LAST_MSK)
-#define PTD_GET_EP(p)          (((p)->mps & PTD_EP_MSK) >> 12)
-#define PTD_EP(v)              (((v) << 12) & PTD_EP_MSK)
-#define PTD_GET_LEN(p)         (((p)->len & PTD_LEN_MSK) >> 0)
-#define PTD_LEN(v)             (((v) << 0) & PTD_LEN_MSK)
-#define PTD_GET_DIR(p)         (((p)->len & PTD_DIR_MSK) >> 10)
-#define PTD_DIR(v)             (((v) << 10) & PTD_DIR_MSK)
-#define PTD_GET_B5_5(p)                (((p)->len & PTD_B5_5_MSK) >> 13)
-#define PTD_B5_5(v)            (((v) << 13) & PTD_B5_5_MSK)
-#define PTD_GET_FA(p)          (((p)->faddr & PTD_FA_MSK) >> 0)
-#define PTD_FA(v)              (((v) << 0) & PTD_FA_MSK)
-#define PTD_GET_FMT(p)         (((p)->faddr & PTD_FMT_MSK) >> 7)
-#define PTD_FMT(v)             (((v) << 7) & PTD_FMT_MSK)
-
-/*  Hardware transfer status codes -- CC from ptd->count */
-#define TD_CC_NOERROR      0x00
-#define TD_CC_CRC          0x01
-#define TD_CC_BITSTUFFING  0x02
-#define TD_CC_DATATOGGLEM  0x03
-#define TD_CC_STALL        0x04
-#define TD_DEVNOTRESP      0x05
-#define TD_PIDCHECKFAIL    0x06
-#define TD_UNEXPECTEDPID   0x07
-#define TD_DATAOVERRUN     0x08
-#define TD_DATAUNDERRUN    0x09
-    /* 0x0A, 0x0B reserved for hardware */
-#define TD_BUFFEROVERRUN   0x0C
-#define TD_BUFFERUNDERRUN  0x0D
-    /* 0x0E, 0x0F reserved for HCD */
-#define TD_NOTACCESSED     0x0F
-
-/* ------------------------------------------------------------------------- */
-
-#define        LOG2_PERIODIC_SIZE      5       /* arbitrary; this matches OHCI */
-#define        PERIODIC_SIZE           (1 << LOG2_PERIODIC_SIZE)
-
-/* Philips transfer descriptor */
-struct ptd {
-       u16 count;
-#define        PTD_COUNT_MSK   (0x3ff << 0)
-#define        PTD_TOGGLE_MSK  (1 << 10)
-#define        PTD_ACTIVE_MSK  (1 << 11)
-#define        PTD_CC_MSK      (0xf << 12)
-       u16 mps;
-#define        PTD_MPS_MSK     (0x3ff << 0)
-#define        PTD_SPD_MSK     (1 << 10)
-#define        PTD_LAST_MSK    (1 << 11)
-#define        PTD_EP_MSK      (0xf << 12)
-       u16 len;
-#define        PTD_LEN_MSK     (0x3ff << 0)
-#define        PTD_DIR_MSK     (3 << 10)
-#define        PTD_DIR_SETUP   (0)
-#define        PTD_DIR_OUT     (1)
-#define        PTD_DIR_IN      (2)
-#define        PTD_B5_5_MSK    (1 << 13)
-       u16 faddr;
-#define        PTD_FA_MSK      (0x7f << 0)
-#define        PTD_FMT_MSK     (1 << 7)
-} __attribute__ ((packed, aligned(2)));
-
-struct isp116x_ep {
-       struct usb_device *udev;
-       struct ptd ptd;
-
-       u8 maxpacket;
-       u8 epnum;
-       u8 nextpid;
-
-       u16 length;             /* of current packet */
-       unsigned char *data;    /* to databuf */
-
-       u16 error_count;
-};
-
-/* URB struct */
-#define N_URB_TD               48
-#define URB_DEL                        1
-typedef struct {
-       struct isp116x_ep *ed;
-       void *transfer_buffer;  /* (in) associated data buffer */
-       int actual_length;      /* (return) actual transfer length */
-       unsigned long pipe;     /* (in) pipe information */
-#if 0
-       int state;
-#endif
-} urb_priv_t;
-
-struct isp116x_platform_data {
-       /* Enable internal resistors on downstream ports */
-       unsigned sel15Kres:1;
-       /* On-chip overcurrent detection */
-       unsigned oc_enable:1;
-       /* Enable wakeup by devices on usb bus (e.g. wakeup
-          by attachment/detachment or by device activity
-          such as moving a mouse). When chosen, this option
-          prevents stopping internal clock, increasing
-          thereby power consumption in suspended state. */
-       unsigned remote_wakeup_enable:1;
-};
-
-struct isp116x {
-       u16 *addr_reg;
-       u16 *data_reg;
-
-       struct isp116x_platform_data *board;
-
-       struct dentry *dentry;
-       unsigned long stat1, stat2, stat4, stat8, stat16;
-
-       /* Status flags */
-       unsigned disabled:1;
-       unsigned sleeping:1;
-
-       /* Root hub registers */
-       u32 rhdesca;
-       u32 rhdescb;
-       u32 rhstatus;
-       u32 rhport[2];
-
-       /* Schedule for the current frame */
-       struct isp116x_ep *atl_active;
-       int atl_buflen;
-       int atl_bufshrt;
-       int atl_last_dir;
-       int atl_finishing;
-};
-
-/* ------------------------------------------------- */
-
-/* Inter-io delay (ns). The chip is picky about access timings; it
- * expects at least:
- * 150ns delay between consecutive accesses to DATA_REG,
- * 300ns delay between access to ADDR_REG and DATA_REG
- * OE, WE MUST NOT be changed during these intervals
- */
-#if defined(UDELAY)
-#define        isp116x_delay(h,d)      udelay(d)
-#else
-#define        isp116x_delay(h,d)      do {} while (0)
-#endif
-
-static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg)
-{
-       writew(reg & 0xff, isp116x->addr_reg);
-       isp116x_delay(isp116x, UDELAY);
-}
-
-static inline void isp116x_write_data16(struct isp116x *isp116x, u16 val)
-{
-       writew(val, isp116x->data_reg);
-       isp116x_delay(isp116x, UDELAY);
-}
-
-static inline void isp116x_raw_write_data16(struct isp116x *isp116x, u16 val)
-{
-       __raw_writew(val, isp116x->data_reg);
-       isp116x_delay(isp116x, UDELAY);
-}
-
-static inline u16 isp116x_read_data16(struct isp116x *isp116x)
-{
-       u16 val;
-
-       val = readw(isp116x->data_reg);
-       isp116x_delay(isp116x, UDELAY);
-       return val;
-}
-
-static inline u16 isp116x_raw_read_data16(struct isp116x *isp116x)
-{
-       u16 val;
-
-       val = __raw_readw(isp116x->data_reg);
-       isp116x_delay(isp116x, UDELAY);
-       return val;
-}
-
-static inline void isp116x_write_data32(struct isp116x *isp116x, u32 val)
-{
-       writew(val & 0xffff, isp116x->data_reg);
-       isp116x_delay(isp116x, UDELAY);
-       writew(val >> 16, isp116x->data_reg);
-       isp116x_delay(isp116x, UDELAY);
-}
-
-static inline u32 isp116x_read_data32(struct isp116x *isp116x)
-{
-       u32 val;
-
-       val = (u32) readw(isp116x->data_reg);
-       isp116x_delay(isp116x, UDELAY);
-       val |= ((u32) readw(isp116x->data_reg)) << 16;
-       isp116x_delay(isp116x, UDELAY);
-       return val;
-}
-
-/* Let's keep register access functions out of line. Hint:
-   we wait at least 150 ns at every access.
-*/
-static u16 isp116x_read_reg16(struct isp116x *isp116x, unsigned reg)
-{
-       isp116x_write_addr(isp116x, reg);
-       return isp116x_read_data16(isp116x);
-}
-
-static u32 isp116x_read_reg32(struct isp116x *isp116x, unsigned reg)
-{
-       isp116x_write_addr(isp116x, reg);
-       return isp116x_read_data32(isp116x);
-}
-
-static void isp116x_write_reg16(struct isp116x *isp116x, unsigned reg,
-                               unsigned val)
-{
-       isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
-       isp116x_write_data16(isp116x, (u16) (val & 0xffff));
-}
-
-static void isp116x_write_reg32(struct isp116x *isp116x, unsigned reg,
-                               unsigned val)
-{
-       isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
-       isp116x_write_data32(isp116x, (u32) val);
-}
-
-/* --- USB HUB constants (not OHCI-specific; see hub.h) -------------------- */
-
-/* destination of request */
-#define RH_INTERFACE               0x01
-#define RH_ENDPOINT                0x02
-#define RH_OTHER                   0x03
-
-#define RH_CLASS                   0x20
-#define RH_VENDOR                  0x40
-
-/* Requests: bRequest << 8 | bmRequestType */
-#define RH_GET_STATUS           0x0080
-#define RH_CLEAR_FEATURE        0x0100
-#define RH_SET_FEATURE          0x0300
-#define RH_SET_ADDRESS          0x0500
-#define RH_GET_DESCRIPTOR       0x0680
-#define RH_SET_DESCRIPTOR       0x0700
-#define RH_GET_CONFIGURATION    0x0880
-#define RH_SET_CONFIGURATION    0x0900
-#define RH_GET_STATE            0x0280
-#define RH_GET_INTERFACE        0x0A80
-#define RH_SET_INTERFACE        0x0B00
-#define RH_SYNC_FRAME           0x0C80
-/* Our Vendor Specific Request */
-#define RH_SET_EP               0x2000
-
-/* Hub port features */
-#define RH_PORT_CONNECTION         0x00
-#define RH_PORT_ENABLE             0x01
-#define RH_PORT_SUSPEND            0x02
-#define RH_PORT_OVER_CURRENT       0x03
-#define RH_PORT_RESET              0x04
-#define RH_PORT_POWER              0x08
-#define RH_PORT_LOW_SPEED          0x09
-
-#define RH_C_PORT_CONNECTION       0x10
-#define RH_C_PORT_ENABLE           0x11
-#define RH_C_PORT_SUSPEND          0x12
-#define RH_C_PORT_OVER_CURRENT     0x13
-#define RH_C_PORT_RESET            0x14
-
-/* Hub features */
-#define RH_C_HUB_LOCAL_POWER       0x00
-#define RH_C_HUB_OVER_CURRENT      0x01
-
-#define RH_DEVICE_REMOTE_WAKEUP    0x00
-#define RH_ENDPOINT_STALL          0x01
-
-#define RH_ACK                     0x01
-#define RH_REQ_ERR                 -1
-#define RH_NACK                    0x00
diff --git a/drivers/sl811.h b/drivers/sl811.h
deleted file mode 100644 (file)
index c1f9f01..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-#ifndef __UBOOT_SL811_H
-#define __UBOOT_SL811_H
-
-#undef SL811_DEBUG
-
-#ifdef SL811_DEBUG
-       #define PDEBUG(level, fmt, args...) \
-               if (debug >= (level)) printf("[%s:%d] " fmt, \
-               __PRETTY_FUNCTION__, __LINE__ , ## args)
-#else
-       #define PDEBUG(level, fmt, args...) do {} while(0)
-#endif
-
-/* Sl811 host control register */
-#define        SL811_CTRL_A            0x00
-#define        SL811_ADDR_A            0x01
-#define        SL811_LEN_A             0x02
-#define        SL811_STS_A             0x03    /* read */
-#define        SL811_PIDEP_A           0x03    /* write */
-#define        SL811_CNT_A             0x04    /* read */
-#define        SL811_DEV_A             0x04    /* write */
-#define        SL811_CTRL1             0x05
-#define        SL811_INTR              0x06
-#define        SL811_CTRL_B            0x08
-#define        SL811_ADDR_B            0x09
-#define        SL811_LEN_B             0x0A
-#define        SL811_STS_B             0x0B    /* read */
-#define        SL811_PIDEP_B           0x0B    /* write */
-#define        SL811_CNT_B             0x0C    /* read */
-#define        SL811_DEV_B             0x0C    /* write */
-#define        SL811_INTRSTS           0x0D    /* write clears bitwise */
-#define        SL811_HWREV             0x0E    /* read */
-#define        SL811_SOFLOW            0x0E    /* write */
-#define        SL811_SOFCNTDIV         0x0F    /* read */
-#define        SL811_CTRL2             0x0F    /* write */
-
-/* USB control register bits (addr 0x00 and addr 0x08) */
-#define        SL811_USB_CTRL_ARM      0x01
-#define        SL811_USB_CTRL_ENABLE   0x02
-#define        SL811_USB_CTRL_DIR_OUT  0x04
-#define        SL811_USB_CTRL_ISO      0x10
-#define        SL811_USB_CTRL_SOF      0x20
-#define        SL811_USB_CTRL_TOGGLE_1 0x40
-#define        SL811_USB_CTRL_PREAMBLE 0x80
-
-/* USB status register bits (addr 0x03 and addr 0x0B) */
-#define        SL811_USB_STS_ACK       0x01
-#define        SL811_USB_STS_ERROR     0x02
-#define        SL811_USB_STS_TIMEOUT   0x04
-#define        SL811_USB_STS_TOGGLE_1  0x08
-#define        SL811_USB_STS_SETUP     0x10
-#define        SL811_USB_STS_OVERFLOW  0x20
-#define        SL811_USB_STS_NAK       0x40
-#define        SL811_USB_STS_STALL     0x80
-
-/* Control register 1 bits (addr 0x05) */
-#define        SL811_CTRL1_SOF         0x01
-#define        SL811_CTRL1_RESET       0x08
-#define        SL811_CTRL1_JKSTATE     0x10
-#define        SL811_CTRL1_SPEED_LOW   0x20
-#define        SL811_CTRL1_SUSPEND     0x40
-
-/* Interrut enable (addr 0x06) and interrupt status register bits (addr 0x0D) */
-#define        SL811_INTR_DONE_A       0x01
-#define        SL811_INTR_DONE_B       0x02
-#define        SL811_INTR_SOF          0x10
-#define        SL811_INTR_INSRMV       0x20
-#define        SL811_INTR_DETECT       0x40
-#define        SL811_INTR_NOTPRESENT   0x40
-#define        SL811_INTR_SPEED_FULL   0x80    /* only in status reg */
-
-/* HW rev and SOF lo register bits (addr 0x0E) */
-#define        SL811_HWR_HWREV         0xF0
-
-/* SOF counter and control reg 2 (addr 0x0F) */
-#define        SL811_CTL2_SOFHI        0x3F
-#define        SL811_CTL2_DSWAP        0x40
-#define        SL811_CTL2_HOST         0x80
-
-/* Set up for 1-ms SOF time. */
-#define SL811_12M_LOW          0xE0
-#define SL811_12M_HI           0x2E
-
-#define SL811_DATA_START       0x10
-#define SL811_DATA_LIMIT       240
-
-/* Requests: bRequest << 8 | bmRequestType */
-#define RH_GET_STATUS           0x0080
-#define RH_CLEAR_FEATURE        0x0100
-#define RH_SET_FEATURE          0x0300
-#define RH_SET_ADDRESS         0x0500
-#define RH_GET_DESCRIPTOR      0x0680
-#define RH_SET_DESCRIPTOR       0x0700
-#define RH_GET_CONFIGURATION   0x0880
-#define RH_SET_CONFIGURATION   0x0900
-#define RH_GET_STATE            0x0280
-#define RH_GET_INTERFACE        0x0A80
-#define RH_SET_INTERFACE        0x0B00
-#define RH_SYNC_FRAME           0x0C80
-
-
-#define PIDEP(pid, ep) (((pid) & 0x0f) << 4 | (ep))
-
-#endif /* __UBOOT_SL811_H */
diff --git a/drivers/sl811_usb.c b/drivers/sl811_usb.c
deleted file mode 100644 (file)
index b0cdf0b..0000000
+++ /dev/null
@@ -1,737 +0,0 @@
-/*
- * (C) Copyright 2004
- * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
- *
- * This code is based on linux driver for sl811hs chip, source at
- * drivers/usb/host/sl811.c:
- *
- * SL811 Host Controller Interface driver for USB.
- *
- * Copyright (c) 2003/06, Courage Co., Ltd.
- *
- * Based on:
- *     1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap,
- *       Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber,
- *       Adam Richter, Gregory P. Smith;
- *     2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com>
- *     3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn>
- *
- * 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
- */
-
-#include <common.h>
-#ifdef CONFIG_USB_SL811HS
-#include <mpc8xx.h>
-#include <usb.h>
-#include "sl811.h"
-
-#include "../board/kup/common/kup.h"
-
-#ifdef __PPC__
-# define EIEIO         __asm__ volatile ("eieio")
-#else
-# define EIEIO         /* nothing */
-#endif
-
-#define         SL811_ADR (0x50000000)
-#define         SL811_DAT (0x50000001)
-
-#define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);})
-
-#ifdef SL811_DEBUG
-static int debug = 9;
-#endif
-
-static int root_hub_devnum = 0;
-static struct usb_port_status rh_status = { 0 };/* root hub port status */
-
-static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe,
-                              void *data, int buf_len, struct devrequest *cmd);
-
-static void sl811_write (__u8 index, __u8 data)
-{
-       *(volatile unsigned char *) (SL811_ADR) = index;
-       EIEIO;
-       *(volatile unsigned char *) (SL811_DAT) = data;
-       EIEIO;
-}
-
-static __u8 sl811_read (__u8 index)
-{
-       __u8 data;
-
-       *(volatile unsigned char *) (SL811_ADR) = index;
-       EIEIO;
-       data = *(volatile unsigned char *) (SL811_DAT);
-       EIEIO;
-       return (data);
-}
-
-/*
- * Read consecutive bytes of data from the SL811H/SL11H buffer
- */
-static void inline sl811_read_buf(__u8 offset, __u8 *buf, __u8 size)
-{
-       *(volatile unsigned char *) (SL811_ADR) = offset;
-       EIEIO;
-       while (size--) {
-               *buf++ = *(volatile unsigned char *) (SL811_DAT);
-               EIEIO;
-       }
-}
-
-/*
- * Write consecutive bytes of data to the SL811H/SL11H buffer
- */
-static void inline sl811_write_buf(__u8 offset, __u8 *buf, __u8 size)
-{
-       *(volatile unsigned char *) (SL811_ADR) = offset;
-       EIEIO;
-       while (size--) {
-               *(volatile unsigned char *) (SL811_DAT) = *buf++;
-               EIEIO;
-       }
-}
-
-int usb_init_kup4x (void)
-{
-       volatile immap_t *immap = (immap_t *) CFG_IMMR;
-       volatile memctl8xx_t *memctl = &immap->im_memctl;
-       int i;
-       unsigned char tmp;
-
-       memctl = &immap->im_memctl;
-       memctl->memc_or7 = 0xFFFF8726;
-       memctl->memc_br7 = 0x50000401;  /* start at 0x50000000 */
-       /* BP 14 low = USB ON */
-       immap->im_cpm.cp_pbdat &= ~(BP_USB_VCC);
-       /* PB 14 nomal port */
-       immap->im_cpm.cp_pbpar &= ~(BP_USB_VCC);
-       /* output */
-       immap->im_cpm.cp_pbdir |= (BP_USB_VCC);
-
-       puts ("USB:   ");
-
-       for (i = 0x10; i < 0xff; i++) {
-               sl811_write(i, i);
-               tmp = (sl811_read(i));
-               if (tmp != i) {
-                       printf ("SL811 compare error index=0x%02x read=0x%02x\n", i, tmp);
-                       return (-1);
-               }
-       }
-       printf ("SL811 ready\n");
-       return (0);
-}
-
-/*
- * This function resets SL811HS controller and detects the speed of
- * the connecting device
- *
- * Return: 0 = no device attached; 1 = USB device attached
- */
-static int sl811_hc_reset(void)
-{
-       int status ;
-
-       sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
-       sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
-
-       mdelay(20);
-
-       /* Disable hardware SOF generation, clear all irq status. */
-       sl811_write(SL811_CTRL1, 0);
-       mdelay(2);
-       sl811_write(SL811_INTRSTS, 0xff);
-       status = sl811_read(SL811_INTRSTS);
-
-       if (status & SL811_INTR_NOTPRESENT) {
-               /* Device is not present */
-               PDEBUG(0, "Device not present\n");
-               rh_status.wPortStatus &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE);
-               rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
-               sl811_write(SL811_INTR, SL811_INTR_INSRMV);
-               return 0;
-       }
-
-       /* Send SOF to address 0, endpoint 0. */
-       sl811_write(SL811_LEN_B, 0);
-       sl811_write(SL811_PIDEP_B, PIDEP(USB_PID_SOF, 0));
-       sl811_write(SL811_DEV_B, 0x00);
-       sl811_write(SL811_SOFLOW, SL811_12M_LOW);
-
-       if (status & SL811_INTR_SPEED_FULL) {
-               /* full speed device connect directly to root hub */
-               PDEBUG (0, "Full speed Device attached\n");
-
-               sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
-               mdelay(20);
-               sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
-               sl811_write(SL811_CTRL1, SL811_CTRL1_SOF);
-
-               /* start the SOF or EOP */
-               sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM);
-               rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION;
-               rh_status.wPortStatus &= ~USB_PORT_STAT_LOW_SPEED;
-               mdelay(2);
-               sl811_write(SL811_INTRSTS, 0xff);
-       } else {
-               /* slow speed device connect directly to root-hub */
-               PDEBUG(0, "Low speed Device attached\n");
-
-               sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
-               mdelay(20);
-               sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_CTL2_DSWAP | SL811_12M_HI);
-               sl811_write(SL811_CTRL1, SL811_CTRL1_SPEED_LOW | SL811_CTRL1_SOF);
-
-               /* start the SOF or EOP */
-               sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM);
-               rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION | USB_PORT_STAT_LOW_SPEED;
-               mdelay(2);
-               sl811_write(SL811_INTRSTS, 0xff);
-       }
-
-       rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
-       sl811_write(SL811_INTR, /*SL811_INTR_INSRMV*/SL811_INTR_DONE_A);
-
-       return 1;
-}
-
-int usb_lowlevel_init(void)
-{
-       root_hub_devnum = 0;
-       sl811_hc_reset();
-       return 0;
-}
-
-int usb_lowlevel_stop(void)
-{
-       sl811_hc_reset();
-       return 0;
-}
-
-static int calc_needed_buswidth(int bytes, int need_preamble)
-{
-       return !need_preamble ? bytes * 8 + 256 : 8 * 8 * bytes + 2048;
-}
-
-static int sl811_send_packet(struct usb_device *dev, unsigned long pipe, __u8 *buffer, int len)
-{
-       __u8 ctrl = SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE;
-       __u16 status = 0;
-       int err = 0, time_start = get_timer(0);
-       int need_preamble = !(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) &&
-               usb_pipeslow(pipe);
-
-       if (len > 239)
-               return -1;
-
-       if (usb_pipeout(pipe))
-               ctrl |= SL811_USB_CTRL_DIR_OUT;
-       if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)))
-               ctrl |= SL811_USB_CTRL_TOGGLE_1;
-       if (need_preamble)
-               ctrl |= SL811_USB_CTRL_PREAMBLE;
-
-       sl811_write(SL811_INTRSTS, 0xff);
-
-       while (err < 3) {
-               sl811_write(SL811_ADDR_A, 0x10);
-               sl811_write(SL811_LEN_A, len);
-               if (usb_pipeout(pipe) && len)
-                       sl811_write_buf(0x10, buffer, len);
-
-               if (!(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) &&
-                   sl811_read(SL811_SOFCNTDIV)*64 < calc_needed_buswidth(len, need_preamble))
-                       ctrl |= SL811_USB_CTRL_SOF;
-               else
-                       ctrl &= ~SL811_USB_CTRL_SOF;
-
-               sl811_write(SL811_CTRL_A, ctrl);
-               while (!(sl811_read(SL811_INTRSTS) & SL811_INTR_DONE_A)) {
-                       if (5*CFG_HZ < get_timer(time_start)) {
-                               printf("USB transmit timed out\n");
-                               return -USB_ST_CRC_ERR;
-                       }
-               }
-
-               sl811_write(SL811_INTRSTS, 0xff);
-               status = sl811_read(SL811_STS_A);
-
-               if (status & SL811_USB_STS_ACK) {
-                       int remainder = sl811_read(SL811_CNT_A);
-                       if (remainder) {
-                               PDEBUG(0, "usb transfer remainder = %d\n", remainder);
-                               len -= remainder;
-                       }
-                       if (usb_pipein(pipe) && len)
-                               sl811_read_buf(0x10, buffer, len);
-                       return len;
-               }
-
-               if ((status & SL811_USB_STS_NAK) == SL811_USB_STS_NAK)
-                       continue;
-
-               PDEBUG(0, "usb transfer error %#x\n", (int)status);
-               err++;
-       }
-
-       err = 0;
-
-       if (status & SL811_USB_STS_ERROR)
-               err |= USB_ST_BUF_ERR;
-       if (status & SL811_USB_STS_TIMEOUT)
-               err |= USB_ST_CRC_ERR;
-       if (status & SL811_USB_STS_STALL)
-               err |= USB_ST_STALLED;
-
-       return -err;
-}
-
-int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
-                   int len)
-{
-       int dir_out = usb_pipeout(pipe);
-       int ep = usb_pipeendpoint(pipe);
-       int max = usb_maxpacket(dev, pipe);
-       int done = 0;
-
-       PDEBUG(7, "dev = %ld pipe = %ld buf = %p size = %d dir_out = %d\n",
-              usb_pipedevice(pipe), usb_pipeendpoint(pipe), buffer, len, dir_out);
-
-       dev->status = 0;
-
-       sl811_write(SL811_DEV_A, usb_pipedevice(pipe));
-       sl811_write(SL811_PIDEP_A, PIDEP(!dir_out ? USB_PID_IN : USB_PID_OUT, ep));
-       while (done < len) {
-               int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done,
-                                           max > len - done ? len - done : max);
-               if (res < 0) {
-                       dev->status = -res;
-                       return res;
-               }
-
-               if (!dir_out && res < max) /* short packet */
-                       break;
-
-               done += res;
-               usb_dotoggle(dev, ep, dir_out);
-       }
-
-       dev->act_len = done;
-
-       return 0;
-}
-
-int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
-                      int len,struct devrequest *setup)
-{
-       int done = 0;
-       int devnum = usb_pipedevice(pipe);
-       int ep = usb_pipeendpoint(pipe);
-
-       dev->status = 0;
-
-       if (devnum == root_hub_devnum)
-               return sl811_rh_submit_urb(dev, pipe, buffer, len, setup);
-
-       PDEBUG(7, "dev = %d pipe = %ld buf = %p size = %d rt = %#x req = %#x bus = %i\n",
-              devnum, ep, buffer, len, (int)setup->requesttype,
-              (int)setup->request, sl811_read(SL811_SOFCNTDIV)*64);
-
-       sl811_write(SL811_DEV_A, devnum);
-       sl811_write(SL811_PIDEP_A, PIDEP(USB_PID_SETUP, ep));
-       /* setup phase */
-       usb_settoggle(dev, ep, 1, 0);
-       if (sl811_send_packet(dev, usb_sndctrlpipe(dev, ep),
-                             (__u8*)setup, sizeof(*setup)) == sizeof(*setup)) {
-               int dir_in = usb_pipein(pipe);
-               int max = usb_maxpacket(dev, pipe);
-
-               /* data phase */
-               sl811_write(SL811_PIDEP_A,
-                           PIDEP(dir_in ? USB_PID_IN : USB_PID_OUT, ep));
-               usb_settoggle(dev, ep, usb_pipeout(pipe), 1);
-               while (done < len) {
-                       int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done,
-                                                   max > len - done ? len - done : max);
-                       if (res < 0) {
-                               PDEBUG(0, "status data failed!\n");
-                               dev->status = -res;
-                               return 0;
-                       }
-                       done += res;
-                       usb_dotoggle(dev, ep, usb_pipeout(pipe));
-                       if (dir_in && res < max) /* short packet */
-                               break;
-               }
-
-               /* status phase */
-               sl811_write(SL811_PIDEP_A,
-                           PIDEP(!dir_in ? USB_PID_IN : USB_PID_OUT, ep));
-               usb_settoggle(dev, ep, !usb_pipeout(pipe), 1);
-               if (sl811_send_packet(dev,
-                                     !dir_in ? usb_rcvctrlpipe(dev, ep) :
-                                     usb_sndctrlpipe(dev, ep),
-                                     0, 0) < 0) {
-                       PDEBUG(0, "status phase failed!\n");
-                       dev->status = -1;
-               }
-       } else {
-               PDEBUG(0, "setup phase failed!\n");
-               dev->status = -1;
-       }
-
-       dev->act_len = done;
-
-       return done;
-}
-
-int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
-                  int len, int interval)
-{
-       PDEBUG(0, "dev = %p pipe = %#lx buf = %p size = %d int = %d\n", dev, pipe,
-              buffer, len, interval);
-       return -1;
-}
-
-/*
- * SL811 Virtual Root Hub
- */
-
-/* Device descriptor */
-static __u8 sl811_rh_dev_des[] =
-{
-       0x12,       /*  __u8  bLength; */
-       0x01,       /*  __u8  bDescriptorType; Device */
-       0x10,       /*  __u16 bcdUSB; v1.1 */
-       0x01,
-       0x09,       /*  __u8  bDeviceClass; HUB_CLASSCODE */
-       0x00,       /*  __u8  bDeviceSubClass; */
-       0x00,       /*  __u8  bDeviceProtocol; */
-       0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
-       0x00,       /*  __u16 idVendor; */
-       0x00,
-       0x00,       /*  __u16 idProduct; */
-       0x00,
-       0x00,       /*  __u16 bcdDevice; */
-       0x00,
-       0x00,       /*  __u8  iManufacturer; */
-       0x02,       /*  __u8  iProduct; */
-       0x01,       /*  __u8  iSerialNumber; */
-       0x01        /*  __u8  bNumConfigurations; */
-};
-
-/* Configuration descriptor */
-static __u8 sl811_rh_config_des[] =
-{
-       0x09,       /*  __u8  bLength; */
-       0x02,       /*  __u8  bDescriptorType; Configuration */
-       0x19,       /*  __u16 wTotalLength; */
-       0x00,
-       0x01,       /*  __u8  bNumInterfaces; */
-       0x01,       /*  __u8  bConfigurationValue; */
-       0x00,       /*  __u8  iConfiguration; */
-       0x40,       /*  __u8  bmAttributes;
-                   Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup,
-                   4..0: resvd */
-       0x00,       /*  __u8  MaxPower; */
-
-       /* interface */
-       0x09,       /*  __u8  if_bLength; */
-       0x04,       /*  __u8  if_bDescriptorType; Interface */
-       0x00,       /*  __u8  if_bInterfaceNumber; */
-       0x00,       /*  __u8  if_bAlternateSetting; */
-       0x01,       /*  __u8  if_bNumEndpoints; */
-       0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
-       0x00,       /*  __u8  if_bInterfaceSubClass; */
-       0x00,       /*  __u8  if_bInterfaceProtocol; */
-       0x00,       /*  __u8  if_iInterface; */
-
-       /* endpoint */
-       0x07,       /*  __u8  ep_bLength; */
-       0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
-       0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
-       0x03,       /*  __u8  ep_bmAttributes; Interrupt */
-       0x08,       /*  __u16 ep_wMaxPacketSize; */
-       0x00,
-       0xff        /*  __u8  ep_bInterval; 255 ms */
-};
-
-/* root hub class descriptor*/
-static __u8 sl811_rh_hub_des[] =
-{
-       0x09,                   /*  __u8  bLength; */
-       0x29,                   /*  __u8  bDescriptorType; Hub-descriptor */
-       0x01,                   /*  __u8  bNbrPorts; */
-       0x00,                   /* __u16  wHubCharacteristics; */
-       0x00,
-       0x50,                   /*  __u8  bPwrOn2pwrGood; 2ms */
-       0x00,                   /*  __u8  bHubContrCurrent; 0 mA */
-       0xfc,                   /*  __u8  DeviceRemovable; *** 7 Ports max *** */
-       0xff                    /*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
-};
-
-/*
- * helper routine for returning string descriptors in UTF-16LE
- * input can actually be ISO-8859-1; ASCII is its 7-bit subset
- */
-static int ascii2utf (char *s, u8 *utf, int utfmax)
-{
-       int retval;
-
-       for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) {
-               *utf++ = *s++;
-               *utf++ = 0;
-       }
-       return retval;
-}
-
-/*
- * root_hub_string is used by each host controller's root hub code,
- * so that they're identified consistently throughout the system.
- */
-static int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
-{
-       char buf [30];
-
-       /* assert (len > (2 * (sizeof (buf) + 1)));
-          assert (strlen (type) <= 8);*/
-
-       /* language ids */
-       if (id == 0) {
-               *data++ = 4; *data++ = 3;       /* 4 bytes data */
-               *data++ = 0; *data++ = 0;       /* some language id */
-               return 4;
-
-       /* serial number */
-       } else if (id == 1) {
-               sprintf (buf, "%#x", serial);
-
-       /* product description */
-       } else if (id == 2) {
-               sprintf (buf, "USB %s Root Hub", type);
-
-       /* id 3 == vendor description */
-
-       /* unsupported IDs --> "stall" */
-       } else
-           return 0;
-
-       ascii2utf (buf, data + 2, len - 2);
-       data [0] = 2 + strlen(buf) * 2;
-       data [1] = 3;
-       return data [0];
-}
-
-/* helper macro */
-#define OK(x)  len = (x); break
-
-/*
- * This function handles all USB request to the the virtual root hub
- */
-static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe,
-                              void *data, int buf_len, struct devrequest *cmd)
-{
-       __u8 data_buf[16];
-       __u8 *bufp = data_buf;
-       int len = 0;
-       int status = 0;
-
-       __u16 bmRType_bReq;
-       __u16 wValue;
-       __u16 wIndex;
-       __u16 wLength;
-
-       if (usb_pipeint(pipe)) {
-               PDEBUG(0, "interrupt transfer unimplemented!\n");
-               return 0;
-       }
-
-       bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
-       wValue        = le16_to_cpu (cmd->value);
-       wIndex        = le16_to_cpu (cmd->index);
-       wLength       = le16_to_cpu (cmd->length);
-
-       PDEBUG(5, "submit rh urb, req = %d(%x) val = %#x index = %#x len=%d\n",
-              bmRType_bReq, bmRType_bReq, wValue, wIndex, wLength);
-
-       /* Request Destination:
-                  without flags: Device,
-                  USB_RECIP_INTERFACE: interface,
-                  USB_RECIP_ENDPOINT: endpoint,
-                  USB_TYPE_CLASS means HUB here,
-                  USB_RECIP_OTHER | USB_TYPE_CLASS  almost ever means HUB_PORT here
-       */
-       switch (bmRType_bReq) {
-       case RH_GET_STATUS:
-               *(__u16 *)bufp = cpu_to_le16(1);
-               OK(2);
-
-       case RH_GET_STATUS | USB_RECIP_INTERFACE:
-               *(__u16 *)bufp = cpu_to_le16(0);
-               OK(2);
-
-       case RH_GET_STATUS | USB_RECIP_ENDPOINT:
-               *(__u16 *)bufp = cpu_to_le16(0);
-               OK(2);
-
-       case RH_GET_STATUS | USB_TYPE_CLASS:
-               *(__u32 *)bufp = cpu_to_le32(0);
-               OK(4);
-
-       case RH_GET_STATUS | USB_RECIP_OTHER | USB_TYPE_CLASS:
-               *(__u32 *)bufp = cpu_to_le32(rh_status.wPortChange<<16 | rh_status.wPortStatus);
-               OK(4);
-
-       case RH_CLEAR_FEATURE | USB_RECIP_ENDPOINT:
-               switch (wValue) {
-               case 1:
-                       OK(0);
-               }
-               break;
-
-       case RH_CLEAR_FEATURE | USB_TYPE_CLASS:
-               switch (wValue) {
-               case C_HUB_LOCAL_POWER:
-                       OK(0);
-
-               case C_HUB_OVER_CURRENT:
-                       OK(0);
-               }
-               break;
-
-       case RH_CLEAR_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
-               switch (wValue) {
-               case USB_PORT_FEAT_ENABLE:
-                       rh_status.wPortStatus &= ~USB_PORT_STAT_ENABLE;
-                       OK(0);
-
-               case USB_PORT_FEAT_SUSPEND:
-                       rh_status.wPortStatus &= ~USB_PORT_STAT_SUSPEND;
-                       OK(0);
-
-               case USB_PORT_FEAT_POWER:
-                       rh_status.wPortStatus &= ~USB_PORT_STAT_POWER;
-                       OK(0);
-
-               case USB_PORT_FEAT_C_CONNECTION:
-                       rh_status.wPortChange &= ~USB_PORT_STAT_C_CONNECTION;
-                       OK(0);
-
-               case USB_PORT_FEAT_C_ENABLE:
-                       rh_status.wPortChange &= ~USB_PORT_STAT_C_ENABLE;
-                       OK(0);
-
-               case USB_PORT_FEAT_C_SUSPEND:
-                       rh_status.wPortChange &= ~USB_PORT_STAT_C_SUSPEND;
-                       OK(0);
-
-               case USB_PORT_FEAT_C_OVER_CURRENT:
-                       rh_status.wPortChange &= ~USB_PORT_STAT_C_OVERCURRENT;
-                       OK(0);
-
-               case USB_PORT_FEAT_C_RESET:
-                       rh_status.wPortChange &= ~USB_PORT_STAT_C_RESET;
-                       OK(0);
-               }
-               break;
-
-       case RH_SET_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
-               switch (wValue) {
-               case USB_PORT_FEAT_SUSPEND:
-                       rh_status.wPortStatus |= USB_PORT_STAT_SUSPEND;
-                       OK(0);
-
-               case USB_PORT_FEAT_RESET:
-                       rh_status.wPortStatus |= USB_PORT_STAT_RESET;
-                       rh_status.wPortChange = 0;
-                       rh_status.wPortChange |= USB_PORT_STAT_C_RESET;
-                       rh_status.wPortStatus &= ~USB_PORT_STAT_RESET;
-                       rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
-                       OK(0);
-
-               case USB_PORT_FEAT_POWER:
-                       rh_status.wPortStatus |= USB_PORT_STAT_POWER;
-                       OK(0);
-
-               case USB_PORT_FEAT_ENABLE:
-                       rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
-                       OK(0);
-               }
-               break;
-
-       case RH_SET_ADDRESS:
-               root_hub_devnum = wValue;
-               OK(0);
-
-       case RH_GET_DESCRIPTOR:
-               switch ((wValue & 0xff00) >> 8) {
-               case USB_DT_DEVICE:
-                       len = sizeof(sl811_rh_dev_des);
-                       bufp = sl811_rh_dev_des;
-                       OK(len);
-
-               case USB_DT_CONFIG:
-                       len = sizeof(sl811_rh_config_des);
-                       bufp = sl811_rh_config_des;
-                       OK(len);
-
-               case USB_DT_STRING:
-                       len = usb_root_hub_string(wValue & 0xff, (int)(long)0,  "SL811HS", data, wLength);
-                       if (len > 0) {
-                               bufp = data;
-                               OK(len);
-                       }
-
-               default:
-                       status = -32;
-               }
-               break;
-
-       case RH_GET_DESCRIPTOR | USB_TYPE_CLASS:
-               len = sizeof(sl811_rh_hub_des);
-               bufp = sl811_rh_hub_des;
-               OK(len);
-
-       case RH_GET_CONFIGURATION:
-               bufp[0] = 0x01;
-               OK(1);
-
-       case RH_SET_CONFIGURATION:
-               OK(0);
-
-       default:
-               PDEBUG(1, "unsupported root hub command\n");
-               status = -32;
-       }
-
-       len = min(len, buf_len);
-       if (data != bufp)
-               memcpy(data, bufp, len);
-
-       PDEBUG(5, "len = %d, status = %d\n", len, status);
-
-       usb_dev->status = status;
-       usb_dev->act_len = len;
-
-       return status == 0 ? len : status;
-}
-
-#endif /* CONFIG_USB_SL811HS */
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
new file mode 100644 (file)
index 0000000..f8ea167
--- /dev/null
@@ -0,0 +1,52 @@
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB    := $(obj)libusb.a
+
+COBJS-y += isp116x-hcd.o
+COBJS-y += sl811_usb.o
+COBJS-y += usb_ohci.o
+COBJS-y += usbdcore.o
+COBJS-y += usbdcore_ep0.o
+COBJS-y += usbdcore_mpc8xx.o
+COBJS-y += usbdcore_omap1510.o
+
+COBJS  := $(COBJS-y)
+SRCS   := $(COBJS:.o=.c)
+OBJS   := $(addprefix $(obj),$(COBJS))
+
+all:   $(LIB)
+
+$(LIB):        $(obj).depend $(OBJS)
+       $(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/drivers/usb/isp116x-hcd.c b/drivers/usb/isp116x-hcd.c
new file mode 100644 (file)
index 0000000..b21af10
--- /dev/null
@@ -0,0 +1,1445 @@
+/*
+ * ISP116x HCD (Host Controller Driver) for u-boot.
+ *
+ * Copyright (C) 2006-2007 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (C) 2006-2007 Eurotech S.p.A. <info@eurotech.it>
+ *
+ * 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
+ *
+ *
+ * Derived in part from the SL811 HCD driver "u-boot/drivers/sl811_usb.c"
+ * (original copyright message follows):
+ *
+ *    (C) Copyright 2004
+ *    Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ *    This code is based on linux driver for sl811hs chip, source at
+ *    drivers/usb/host/sl811.c:
+ *
+ *    SL811 Host Controller Interface driver for USB.
+ *
+ *    Copyright (c) 2003/06, Courage Co., Ltd.
+ *
+ *    Based on:
+ *         1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap,
+ *           Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber,
+ *           Adam Richter, Gregory P. Smith;
+ *         2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com>
+ *         3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn>
+ *
+ *    [[GNU/GPL disclaimer]]
+ *
+ * and in part from AU1x00 OHCI HCD driver "u-boot/cpu/mips/au1x00_usb_ohci.c"
+ * (original copyright message follows):
+ *
+ *    URB OHCI HCD (Host Controller Driver) for USB on the AU1x00.
+ *
+ *    (C) Copyright 2003
+ *    Gary Jennejohn, DENX Software Engineering <gj@denx.de>
+ *
+ *    [[GNU/GPL disclaimer]]
+ *
+ *    Note: Part of this code has been derived from linux
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_USB_ISP116X_HCD
+#include <asm/io.h>
+#include <usb.h>
+#include <malloc.h>
+#include <linux/list.h>
+
+/*
+ * ISP116x chips require certain delays between accesses to its
+ * registers. The following timing options exist.
+ *
+ * 1. Configure your memory controller (the best)
+ * 2. Use ndelay (easiest, poorest). For that, enable the following macro.
+ *
+ * Value is in microseconds.
+ */
+#ifdef ISP116X_HCD_USE_UDELAY
+#define UDELAY         1
+#endif
+
+/*
+ * On some (slowly?) machines an extra delay after data packing into
+ * controller's FIFOs is required, * otherwise you may get the following
+ * error:
+ *
+ *   uboot> usb start
+ *   (Re)start USB...
+ *   USB:   scanning bus for devices... isp116x: isp116x_submit_job: CTL:TIMEOUT
+ *   isp116x: isp116x_submit_job: ****** FIFO not ready! ******
+ *
+ *         USB device not responding, giving up (status=4)
+ *         isp116x: isp116x_submit_job: ****** FIFO not empty! ******
+ *         isp116x: isp116x_submit_job: ****** FIFO not empty! ******
+ *         isp116x: isp116x_submit_job: ****** FIFO not empty! ******
+ *         3 USB Device(s) found
+ *                scanning bus for storage devices... 0 Storage Device(s) found
+ *
+ * Value is in milliseconds.
+ */
+#ifdef ISP116X_HCD_USE_EXTRA_DELAY
+#define EXTRA_DELAY    2
+#endif
+
+/*
+ * Enable the following defines if you wish enable debugging messages.
+ */
+#undef DEBUG                   /* enable debugging messages */
+#undef TRACE                   /* enable tracing code */
+#undef VERBOSE                 /* verbose debugging messages */
+
+#include "isp116x.h"
+
+#define DRIVER_VERSION "08 Jan 2007"
+static const char hcd_name[] = "isp116x-hcd";
+
+struct isp116x isp116x_dev;
+struct isp116x_platform_data isp116x_board;
+static int got_rhsc;           /* root hub status change */
+struct usb_device *devgone;    /* device which was disconnected */
+static int rh_devnum;          /* address of Root Hub endpoint */
+
+/* ------------------------------------------------------------------------- */
+
+#define ALIGN(x,a)     (((x)+(a)-1UL)&~((a)-1UL))
+#define min_t(type,x,y)        \
+       ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; })
+
+/* ------------------------------------------------------------------------- */
+
+static int isp116x_reset(struct isp116x *isp116x);
+
+/* --- Debugging functions ------------------------------------------------- */
+
+#define isp116x_show_reg(d, r) {                               \
+       if ((r) < 0x20) {                                       \
+               DBG("%-12s[%02x]: %08x", #r,                    \
+                       r, isp116x_read_reg32(d, r));           \
+       } else {                                                \
+               DBG("%-12s[%02x]:     %04x", #r,                \
+                       r, isp116x_read_reg16(d, r));           \
+       }                                                       \
+}
+
+#define isp116x_show_regs(d) {                                 \
+       isp116x_show_reg(d, HCREVISION);                        \
+       isp116x_show_reg(d, HCCONTROL);                         \
+       isp116x_show_reg(d, HCCMDSTAT);                         \
+       isp116x_show_reg(d, HCINTSTAT);                         \
+       isp116x_show_reg(d, HCINTENB);                          \
+       isp116x_show_reg(d, HCFMINTVL);                         \
+       isp116x_show_reg(d, HCFMREM);                           \
+       isp116x_show_reg(d, HCFMNUM);                           \
+       isp116x_show_reg(d, HCLSTHRESH);                        \
+       isp116x_show_reg(d, HCRHDESCA);                         \
+       isp116x_show_reg(d, HCRHDESCB);                         \
+       isp116x_show_reg(d, HCRHSTATUS);                        \
+       isp116x_show_reg(d, HCRHPORT1);                         \
+       isp116x_show_reg(d, HCRHPORT2);                         \
+       isp116x_show_reg(d, HCHWCFG);                           \
+       isp116x_show_reg(d, HCDMACFG);                          \
+       isp116x_show_reg(d, HCXFERCTR);                         \
+       isp116x_show_reg(d, HCuPINT);                           \
+       isp116x_show_reg(d, HCuPINTENB);                        \
+       isp116x_show_reg(d, HCCHIPID);                          \
+       isp116x_show_reg(d, HCSCRATCH);                         \
+       isp116x_show_reg(d, HCITLBUFLEN);                       \
+       isp116x_show_reg(d, HCATLBUFLEN);                       \
+       isp116x_show_reg(d, HCBUFSTAT);                         \
+       isp116x_show_reg(d, HCRDITL0LEN);                       \
+       isp116x_show_reg(d, HCRDITL1LEN);                       \
+}
+
+#if defined(TRACE)
+
+static int isp116x_get_current_frame_number(struct usb_device *usb_dev)
+{
+       struct isp116x *isp116x = &isp116x_dev;
+
+       return isp116x_read_reg32(isp116x, HCFMNUM);
+}
+
+static void dump_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+                    int len, char *str)
+{
+#if defined(VERBOSE)
+       int i;
+#endif
+
+       DBG("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d stat:%#lx",
+           str,
+           isp116x_get_current_frame_number(dev),
+           usb_pipedevice(pipe),
+           usb_pipeendpoint(pipe),
+           usb_pipeout(pipe) ? 'O' : 'I',
+           usb_pipetype(pipe) < 2 ?
+           (usb_pipeint(pipe) ?
+            "INTR" : "ISOC") :
+           (usb_pipecontrol(pipe) ? "CTRL" : "BULK"), len, dev->status);
+#if defined(VERBOSE)
+       if (len > 0 && buffer) {
+               printf(__FILE__ ": data(%d):", len);
+               for (i = 0; i < 16 && i < len; i++)
+                       printf(" %02x", ((__u8 *) buffer)[i]);
+               printf("%s\n", i < len ? "..." : "");
+       }
+#endif
+}
+
+#define PTD_DIR_STR(ptd)  ({char __c;          \
+       switch(PTD_GET_DIR(ptd)){               \
+       case 0:  __c = 's'; break;              \
+       case 1:  __c = 'o'; break;              \
+       default: __c = 'i'; break;              \
+       }; __c;})
+
+/*
+  Dump PTD info. The code documents the format
+  perfectly, right :)
+*/
+static inline void dump_ptd(struct ptd *ptd)
+{
+#if defined(VERBOSE)
+       int k;
+#endif
+
+       DBG("PTD(ext) : cc:%x %d%c%d %d,%d,%d t:%x %x%x%x",
+           PTD_GET_CC(ptd),
+           PTD_GET_FA(ptd), PTD_DIR_STR(ptd), PTD_GET_EP(ptd),
+           PTD_GET_COUNT(ptd), PTD_GET_LEN(ptd), PTD_GET_MPS(ptd),
+           PTD_GET_TOGGLE(ptd),
+           PTD_GET_ACTIVE(ptd), PTD_GET_SPD(ptd), PTD_GET_LAST(ptd));
+#if defined(VERBOSE)
+       printf("isp116x: %s: PTD(byte): ", __FUNCTION__);
+       for (k = 0; k < sizeof(struct ptd); ++k)
+               printf("%02x ", ((u8 *) ptd)[k]);
+       printf("\n");
+#endif
+}
+
+static inline void dump_ptd_data(struct ptd *ptd, u8 * buf, int type)
+{
+#if defined(VERBOSE)
+       int k;
+
+       if (type == 0 /* 0ut data */ ) {
+               printf("isp116x: %s: out data: ", __FUNCTION__);
+               for (k = 0; k < PTD_GET_LEN(ptd); ++k)
+                       printf("%02x ", ((u8 *) buf)[k]);
+               printf("\n");
+       }
+       if (type == 1 /* 1n data */ ) {
+               printf("isp116x: %s: in data: ", __FUNCTION__);
+               for (k = 0; k < PTD_GET_COUNT(ptd); ++k)
+                       printf("%02x ", ((u8 *) buf)[k]);
+               printf("\n");
+       }
+
+       if (PTD_GET_LAST(ptd))
+               DBG("--- last PTD ---");
+#endif
+}
+
+#else
+
+#define dump_msg(dev, pipe, buffer, len, str)                  do { } while (0)
+#define dump_pkt(dev, pipe, buffer, len, setup, str, small)    do {} while (0)
+
+#define dump_ptd(ptd)                  do {} while (0)
+#define dump_ptd_data(ptd, buf, type)  do {} while (0)
+
+#endif
+
+/* --- Virtual Root Hub ---------------------------------------------------- */
+
+/* Device descriptor */
+static __u8 root_hub_dev_des[] = {
+       0x12,                   /*  __u8  bLength; */
+       0x01,                   /*  __u8  bDescriptorType; Device */
+       0x10,                   /*  __u16 bcdUSB; v1.1 */
+       0x01,
+       0x09,                   /*  __u8  bDeviceClass; HUB_CLASSCODE */
+       0x00,                   /*  __u8  bDeviceSubClass; */
+       0x00,                   /*  __u8  bDeviceProtocol; */
+       0x08,                   /*  __u8  bMaxPacketSize0; 8 Bytes */
+       0x00,                   /*  __u16 idVendor; */
+       0x00,
+       0x00,                   /*  __u16 idProduct; */
+       0x00,
+       0x00,                   /*  __u16 bcdDevice; */
+       0x00,
+       0x00,                   /*  __u8  iManufacturer; */
+       0x01,                   /*  __u8  iProduct; */
+       0x00,                   /*  __u8  iSerialNumber; */
+       0x01                    /*  __u8  bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] = {
+       0x09,                   /*  __u8  bLength; */
+       0x02,                   /*  __u8  bDescriptorType; Configuration */
+       0x19,                   /*  __u16 wTotalLength; */
+       0x00,
+       0x01,                   /*  __u8  bNumInterfaces; */
+       0x01,                   /*  __u8  bConfigurationValue; */
+       0x00,                   /*  __u8  iConfiguration; */
+       0x40,                   /*  __u8  bmAttributes;
+                                  Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+       0x00,                   /*  __u8  MaxPower; */
+
+       /* interface */
+       0x09,                   /*  __u8  if_bLength; */
+       0x04,                   /*  __u8  if_bDescriptorType; Interface */
+       0x00,                   /*  __u8  if_bInterfaceNumber; */
+       0x00,                   /*  __u8  if_bAlternateSetting; */
+       0x01,                   /*  __u8  if_bNumEndpoints; */
+       0x09,                   /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+       0x00,                   /*  __u8  if_bInterfaceSubClass; */
+       0x00,                   /*  __u8  if_bInterfaceProtocol; */
+       0x00,                   /*  __u8  if_iInterface; */
+
+       /* endpoint */
+       0x07,                   /*  __u8  ep_bLength; */
+       0x05,                   /*  __u8  ep_bDescriptorType; Endpoint */
+       0x81,                   /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+       0x03,                   /*  __u8  ep_bmAttributes; Interrupt */
+       0x00,                   /*  __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+       0x02,
+       0xff                    /*  __u8  ep_bInterval; 255 ms */
+};
+
+static unsigned char root_hub_str_index0[] = {
+       0x04,                   /*  __u8  bLength; */
+       0x03,                   /*  __u8  bDescriptorType; String-descriptor */
+       0x09,                   /*  __u8  lang ID */
+       0x04,                   /*  __u8  lang ID */
+};
+
+static unsigned char root_hub_str_index1[] = {
+       0x22,                   /*  __u8  bLength; */
+       0x03,                   /*  __u8  bDescriptorType; String-descriptor */
+       'I',                    /*  __u8  Unicode */
+       0,                      /*  __u8  Unicode */
+       'S',                    /*  __u8  Unicode */
+       0,                      /*  __u8  Unicode */
+       'P',                    /*  __u8  Unicode */
+       0,                      /*  __u8  Unicode */
+       '1',                    /*  __u8  Unicode */
+       0,                      /*  __u8  Unicode */
+       '1',                    /*  __u8  Unicode */
+       0,                      /*  __u8  Unicode */
+       '6',                    /*  __u8  Unicode */
+       0,                      /*  __u8  Unicode */
+       'x',                    /*  __u8  Unicode */
+       0,                      /*  __u8  Unicode */
+       ' ',                    /*  __u8  Unicode */
+       0,                      /*  __u8  Unicode */
+       'R',                    /*  __u8  Unicode */
+       0,                      /*  __u8  Unicode */
+       'o',                    /*  __u8  Unicode */
+       0,                      /*  __u8  Unicode */
+       'o',                    /*  __u8  Unicode */
+       0,                      /*  __u8  Unicode */
+       't',                    /*  __u8  Unicode */
+       0,                      /*  __u8  Unicode */
+       ' ',                    /*  __u8  Unicode */
+       0,                      /*  __u8  Unicode */
+       'H',                    /*  __u8  Unicode */
+       0,                      /*  __u8  Unicode */
+       'u',                    /*  __u8  Unicode */
+       0,                      /*  __u8  Unicode */
+       'b',                    /*  __u8  Unicode */
+       0,                      /*  __u8  Unicode */
+};
+
+/*
+ * Hub class-specific descriptor is constructed dynamically
+ */
+
+/* --- Virtual root hub management functions ------------------------------- */
+
+static int rh_check_port_status(struct isp116x *isp116x)
+{
+       u32 temp, ndp, i;
+       int res;
+
+       res = -1;
+       temp = isp116x_read_reg32(isp116x, HCRHSTATUS);
+       ndp = (temp & RH_A_NDP);
+       for (i = 0; i < ndp; i++) {
+               temp = isp116x_read_reg32(isp116x, HCRHPORT1 + i);
+               /* check for a device disconnect */
+               if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
+                    (RH_PS_PESC | RH_PS_CSC)) && ((temp & RH_PS_CCS) == 0)) {
+                       res = i;
+                       break;
+               }
+       }
+       return res;
+}
+
+/* --- HC management functions --------------------------------------------- */
+
+/* Write len bytes to fifo, pad till 32-bit boundary
+ */
+static void write_ptddata_to_fifo(struct isp116x *isp116x, void *buf, int len)
+{
+       u8 *dp = (u8 *) buf;
+       u16 *dp2 = (u16 *) buf;
+       u16 w;
+       int quot = len % 4;
+
+       if ((unsigned long)dp2 & 1) {
+               /* not aligned */
+               for (; len > 1; len -= 2) {
+                       w = *dp++;
+                       w |= *dp++ << 8;
+                       isp116x_raw_write_data16(isp116x, w);
+               }
+               if (len)
+                       isp116x_write_data16(isp116x, (u16) * dp);
+       } else {
+               /* aligned */
+               for (; len > 1; len -= 2)
+                       isp116x_raw_write_data16(isp116x, *dp2++);
+               if (len)
+                       isp116x_write_data16(isp116x, 0xff & *((u8 *) dp2));
+       }
+       if (quot == 1 || quot == 2)
+               isp116x_raw_write_data16(isp116x, 0);
+}
+
+/* Read len bytes from fifo and then read till 32-bit boundary
+ */
+static void read_ptddata_from_fifo(struct isp116x *isp116x, void *buf, int len)
+{
+       u8 *dp = (u8 *) buf;
+       u16 *dp2 = (u16 *) buf;
+       u16 w;
+       int quot = len % 4;
+
+       if ((unsigned long)dp2 & 1) {
+               /* not aligned */
+               for (; len > 1; len -= 2) {
+                       w = isp116x_raw_read_data16(isp116x);
+                       *dp++ = w & 0xff;
+                       *dp++ = (w >> 8) & 0xff;
+               }
+               if (len)
+                       *dp = 0xff & isp116x_read_data16(isp116x);
+       } else {
+               /* aligned */
+               for (; len > 1; len -= 2)
+                       *dp2++ = isp116x_raw_read_data16(isp116x);
+               if (len)
+                       *(u8 *) dp2 = 0xff & isp116x_read_data16(isp116x);
+       }
+       if (quot == 1 || quot == 2)
+               isp116x_raw_read_data16(isp116x);
+}
+
+/* Write PTD's and data for scheduled transfers into the fifo ram.
+ * Fifo must be empty and ready */
+static void pack_fifo(struct isp116x *isp116x, struct usb_device *dev,
+                     unsigned long pipe, struct ptd *ptd, int n, void *data,
+                     int len)
+{
+       int buflen = n * sizeof(struct ptd) + len;
+       int i, done;
+
+       DBG("--- pack buffer %p - %d bytes (fifo %d) ---", data, len, buflen);
+
+       isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);
+       isp116x_write_reg16(isp116x, HCXFERCTR, buflen);
+       isp116x_write_addr(isp116x, HCATLPORT | ISP116x_WRITE_OFFSET);
+
+       done = 0;
+       for (i = 0; i < n; i++) {
+               DBG("i=%d - done=%d - len=%d", i, done, PTD_GET_LEN(&ptd[i]));
+
+               dump_ptd(&ptd[i]);
+               isp116x_write_data16(isp116x, ptd[i].count);
+               isp116x_write_data16(isp116x, ptd[i].mps);
+               isp116x_write_data16(isp116x, ptd[i].len);
+               isp116x_write_data16(isp116x, ptd[i].faddr);
+
+               dump_ptd_data(&ptd[i], (__u8 *) data + done, 0);
+               write_ptddata_to_fifo(isp116x,
+                                     (__u8 *) data + done,
+                                     PTD_GET_LEN(&ptd[i]));
+
+               done += PTD_GET_LEN(&ptd[i]);
+       }
+}
+
+/* Read the processed PTD's and data from fifo ram back to URBs' buffers.
+ * Fifo must be full and done */
+static int unpack_fifo(struct isp116x *isp116x, struct usb_device *dev,
+                      unsigned long pipe, struct ptd *ptd, int n, void *data,
+                      int len)
+{
+       int buflen = n * sizeof(struct ptd) + len;
+       int i, done, cc, ret;
+
+       isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);
+       isp116x_write_reg16(isp116x, HCXFERCTR, buflen);
+       isp116x_write_addr(isp116x, HCATLPORT);
+
+       ret = TD_CC_NOERROR;
+       done = 0;
+       for (i = 0; i < n; i++) {
+               DBG("i=%d - done=%d - len=%d", i, done, PTD_GET_LEN(&ptd[i]));
+
+               ptd[i].count = isp116x_read_data16(isp116x);
+               ptd[i].mps = isp116x_read_data16(isp116x);
+               ptd[i].len = isp116x_read_data16(isp116x);
+               ptd[i].faddr = isp116x_read_data16(isp116x);
+               dump_ptd(&ptd[i]);
+
+               read_ptddata_from_fifo(isp116x,
+                                      (__u8 *) data + done,
+                                      PTD_GET_LEN(&ptd[i]));
+               dump_ptd_data(&ptd[i], (__u8 *) data + done, 1);
+
+               done += PTD_GET_LEN(&ptd[i]);
+
+               cc = PTD_GET_CC(&ptd[i]);
+
+               /* Data underrun means basically that we had more buffer space than
+                * the function had data. It is perfectly normal but upper levels have
+                * to know how much we actually transferred.
+                */
+               if (cc == TD_NOTACCESSED ||
+                               (cc != TD_CC_NOERROR && (ret == TD_CC_NOERROR || ret == TD_DATAUNDERRUN)))
+                       ret = cc;
+       }
+
+       DBG("--- unpack buffer %p - %d bytes (fifo %d) ---", data, len, buflen);
+
+       return ret;
+}
+
+/* Interrupt handling
+ */
+static int isp116x_interrupt(struct isp116x *isp116x)
+{
+       u16 irqstat;
+       u32 intstat;
+       int ret = 0;
+
+       isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+       irqstat = isp116x_read_reg16(isp116x, HCuPINT);
+       isp116x_write_reg16(isp116x, HCuPINT, irqstat);
+       DBG(">>>>>> irqstat %x <<<<<<", irqstat);
+
+       if (irqstat & HCuPINT_ATL) {
+               DBG(">>>>>> HCuPINT_ATL <<<<<<");
+               udelay(500);
+               ret = 1;
+       }
+
+       if (irqstat & HCuPINT_OPR) {
+               intstat = isp116x_read_reg32(isp116x, HCINTSTAT);
+               isp116x_write_reg32(isp116x, HCINTSTAT, intstat);
+               DBG(">>>>>> HCuPINT_OPR %x <<<<<<", intstat);
+
+               if (intstat & HCINT_UE) {
+                       ERR("unrecoverable error, controller disabled");
+
+                       /* FIXME: be optimistic, hope that bug won't repeat
+                        * often. Make some non-interrupt context restart the
+                        * controller. Count and limit the retries though;
+                        * either hardware or software errors can go forever...
+                        */
+                       isp116x_reset(isp116x);
+                       ret = -1;
+                       return -1;
+               }
+
+               if (intstat & HCINT_RHSC) {
+                       got_rhsc = 1;
+                       ret = 1;
+                       /* When root hub or any of its ports is going
+                          to come out of suspend, it may take more
+                          than 10ms for status bits to stabilize. */
+                       wait_ms(20);
+               }
+
+               if (intstat & HCINT_SO) {
+                       ERR("schedule overrun");
+                       ret = -1;
+               }
+
+               irqstat &= ~HCuPINT_OPR;
+       }
+
+       return ret;
+}
+
+/* With one PTD we can transfer almost 1K in one go;
+ * HC does the splitting into endpoint digestible transactions
+ */
+struct ptd ptd[1];
+
+static inline int max_transfer_len(struct usb_device *dev, unsigned long pipe)
+{
+       unsigned mpck = usb_maxpacket(dev, pipe);
+
+       /* One PTD can transfer 1023 bytes but try to always
+        * transfer multiples of endpoint buffer size
+        */
+       return 1023 / mpck * mpck;
+}
+
+/* Do an USB transfer
+ */
+static int isp116x_submit_job(struct usb_device *dev, unsigned long pipe,
+                             int dir, void *buffer, int len)
+{
+       struct isp116x *isp116x = &isp116x_dev;
+       int type = usb_pipetype(pipe);
+       int epnum = usb_pipeendpoint(pipe);
+       int max = usb_maxpacket(dev, pipe);
+       int dir_out = usb_pipeout(pipe);
+       int speed_low = usb_pipeslow(pipe);
+       int i, done = 0, stat, timeout, cc;
+
+       /* 500 frames or 0.5s timeout when function is busy and NAKs transactions for a while */
+       int retries = 500;
+
+       DBG("------------------------------------------------");
+       dump_msg(dev, pipe, buffer, len, "SUBMIT");
+       DBG("------------------------------------------------");
+
+       if (len >= 1024) {
+               ERR("Too big job");
+               dev->status = USB_ST_CRC_ERR;
+               return -1;
+       }
+
+       if (isp116x->disabled) {
+               ERR("EPIPE");
+               dev->status = USB_ST_CRC_ERR;
+               return -1;
+       }
+
+       /* device pulled? Shortcut the action. */
+       if (devgone == dev) {
+               ERR("ENODEV");
+               dev->status = USB_ST_CRC_ERR;
+               return USB_ST_CRC_ERR;
+       }
+
+       if (!max) {
+               ERR("pipesize for pipe %lx is zero", pipe);
+               dev->status = USB_ST_CRC_ERR;
+               return -1;
+       }
+
+       if (type == PIPE_ISOCHRONOUS) {
+               ERR("isochronous transfers not supported");
+               dev->status = USB_ST_CRC_ERR;
+               return -1;
+       }
+
+       /* FIFO not empty? */
+       if (isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_FULL) {
+               ERR("****** FIFO not empty! ******");
+               dev->status = USB_ST_BUF_ERR;
+               return -1;
+       }
+
+      retry:
+       isp116x_write_reg32(isp116x, HCINTSTAT, 0xff);
+
+       /* Prepare the PTD data */
+       ptd->count = PTD_CC_MSK | PTD_ACTIVE_MSK |
+               PTD_TOGGLE(usb_gettoggle(dev, epnum, dir_out));
+       ptd->mps = PTD_MPS(max) | PTD_SPD(speed_low) | PTD_EP(epnum) | PTD_LAST_MSK;
+       ptd->len = PTD_LEN(len) | PTD_DIR(dir);
+       ptd->faddr = PTD_FA(usb_pipedevice(pipe));
+
+retry_same:
+       /* Pack data into FIFO ram */
+       pack_fifo(isp116x, dev, pipe, ptd, 1, buffer, len);
+#ifdef EXTRA_DELAY
+       wait_ms(EXTRA_DELAY);
+#endif
+
+       /* Start the data transfer */
+
+       /* Allow more time for a BULK device to react - some are slow */
+       if (usb_pipetype(pipe) == PIPE_BULK)
+               timeout = 5000;
+       else
+               timeout = 100;
+
+       /* Wait for it to complete */
+       for (;;) {
+               /* Check whether the controller is done */
+               stat = isp116x_interrupt(isp116x);
+
+               if (stat < 0) {
+                       dev->status = USB_ST_CRC_ERR;
+                       break;
+               }
+               if (stat > 0)
+                       break;
+
+               /* Check the timeout */
+               if (--timeout)
+                       udelay(1);
+               else {
+                       ERR("CTL:TIMEOUT ");
+                       stat = USB_ST_CRC_ERR;
+                       break;
+               }
+       }
+
+       /* We got an Root Hub Status Change interrupt */
+       if (got_rhsc) {
+               isp116x_show_regs(isp116x);
+
+               got_rhsc = 0;
+
+               /* Abuse timeout */
+               timeout = rh_check_port_status(isp116x);
+               if (timeout >= 0) {
+                       /*
+                        * FIXME! NOTE! AAAARGH!
+                        * This is potentially dangerous because it assumes
+                        * that only one device is ever plugged in!
+                        */
+                       devgone = dev;
+               }
+       }
+
+       /* Ok, now we can read transfer status */
+
+       /* FIFO not ready? */
+       if (!(isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_DONE)) {
+               ERR("****** FIFO not ready! ******");
+               dev->status = USB_ST_BUF_ERR;
+               return -1;
+       }
+
+       /* Unpack data from FIFO ram */
+       cc = unpack_fifo(isp116x, dev, pipe, ptd, 1, buffer, len);
+
+       i = PTD_GET_COUNT(ptd);
+       done += i;
+       buffer += i;
+       len -= i;
+
+       /* There was some kind of real problem; Prepare the PTD again
+        * and retry from the failed transaction on
+        */
+       if (cc && cc != TD_NOTACCESSED && cc != TD_DATAUNDERRUN) {
+               if (retries >= 100) {
+                       retries -= 100;
+                       /* The chip will have toggled the toggle bit for the failed
+                        * transaction too. We have to toggle it back.
+                        */
+                       usb_settoggle(dev, epnum, dir_out, !PTD_GET_TOGGLE(ptd));
+                       goto retry;
+               }
+       }
+       /* "Normal" errors; TD_NOTACCESSED would mean in effect that the function have NAKed
+        * the transactions from the first on for the whole frame. It may be busy and we retry
+        * with the same PTD. PTD_ACTIVE (and not TD_NOTACCESSED) would mean that some of the
+        * PTD didn't make it because the function was busy or the frame ended before the PTD
+        * finished. We prepare the rest of the data and try again.
+        */
+       else if (cc == TD_NOTACCESSED || PTD_GET_ACTIVE(ptd) || (cc != TD_DATAUNDERRUN && PTD_GET_COUNT(ptd) < PTD_GET_LEN(ptd))) {
+               if (retries) {
+                       --retries;
+                       if (cc == TD_NOTACCESSED && PTD_GET_ACTIVE(ptd) && !PTD_GET_COUNT(ptd)) goto retry_same;
+                       usb_settoggle(dev, epnum, dir_out, PTD_GET_TOGGLE(ptd));
+                       goto retry;
+               }
+       }
+
+       if (cc != TD_CC_NOERROR && cc != TD_DATAUNDERRUN) {
+               DBG("****** completition code error %x ******", cc);
+               switch (cc) {
+               case TD_CC_BITSTUFFING:
+                       dev->status = USB_ST_BIT_ERR;
+                       break;
+               case TD_CC_STALL:
+                       dev->status = USB_ST_STALLED;
+                       break;
+               case TD_BUFFEROVERRUN:
+               case TD_BUFFERUNDERRUN:
+                       dev->status = USB_ST_BUF_ERR;
+                       break;
+               default:
+                       dev->status = USB_ST_CRC_ERR;
+               }
+               return -cc;
+       }
+       else usb_settoggle(dev, epnum, dir_out, PTD_GET_TOGGLE(ptd));
+
+       dump_msg(dev, pipe, buffer, len, "SUBMIT(ret)");
+
+       dev->status = 0;
+       return done;
+}
+
+/* Adapted from au1x00_usb_ohci.c
+ */
+static int isp116x_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+                                void *buffer, int transfer_len,
+                                struct devrequest *cmd)
+{
+       struct isp116x *isp116x = &isp116x_dev;
+       u32 tmp = 0;
+
+       int leni = transfer_len;
+       int len = 0;
+       int stat = 0;
+       u32 datab[4];
+       u8 *data_buf = (u8 *) datab;
+       u16 bmRType_bReq;
+       u16 wValue;
+       u16 wIndex;
+       u16 wLength;
+
+       if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
+               INFO("Root-Hub submit IRQ: NOT implemented");
+               return 0;
+       }
+
+       bmRType_bReq = cmd->requesttype | (cmd->request << 8);
+       wValue = swap_16(cmd->value);
+       wIndex = swap_16(cmd->index);
+       wLength = swap_16(cmd->length);
+
+       DBG("--- HUB ----------------------------------------");
+       DBG("submit rh urb, req=%x val=%#x index=%#x len=%d",
+           bmRType_bReq, wValue, wIndex, wLength);
+       dump_msg(dev, pipe, buffer, transfer_len, "RH");
+       DBG("------------------------------------------------");
+
+       switch (bmRType_bReq) {
+       case RH_GET_STATUS:
+               DBG("RH_GET_STATUS");
+
+               *(__u16 *) data_buf = swap_16(1);
+               len = 2;
+               break;
+
+       case RH_GET_STATUS | RH_INTERFACE:
+               DBG("RH_GET_STATUS | RH_INTERFACE");
+
+               *(__u16 *) data_buf = swap_16(0);
+               len = 2;
+               break;
+
+       case RH_GET_STATUS | RH_ENDPOINT:
+               DBG("RH_GET_STATUS | RH_ENDPOINT");
+
+               *(__u16 *) data_buf = swap_16(0);
+               len = 2;
+               break;
+
+       case RH_GET_STATUS | RH_CLASS:
+               DBG("RH_GET_STATUS | RH_CLASS");
+
+               tmp = isp116x_read_reg32(isp116x, HCRHSTATUS);
+
+               *(__u32 *) data_buf = swap_32(tmp & ~(RH_HS_CRWE | RH_HS_DRWE));
+               len = 4;
+               break;
+
+       case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+               DBG("RH_GET_STATUS | RH_OTHER | RH_CLASS");
+
+               tmp = isp116x_read_reg32(isp116x, HCRHPORT1 + wIndex - 1);
+               *(__u32 *) data_buf = swap_32(tmp);
+               isp116x_show_regs(isp116x);
+               len = 4;
+               break;
+
+       case RH_CLEAR_FEATURE | RH_ENDPOINT:
+               DBG("RH_CLEAR_FEATURE | RH_ENDPOINT");
+
+               switch (wValue) {
+               case RH_ENDPOINT_STALL:
+                       DBG("C_HUB_ENDPOINT_STALL");
+                       len = 0;
+                       break;
+               }
+               break;
+
+       case RH_CLEAR_FEATURE | RH_CLASS:
+               DBG("RH_CLEAR_FEATURE | RH_CLASS");
+
+               switch (wValue) {
+               case RH_C_HUB_LOCAL_POWER:
+                       DBG("C_HUB_LOCAL_POWER");
+                       len = 0;
+                       break;
+
+               case RH_C_HUB_OVER_CURRENT:
+                       DBG("C_HUB_OVER_CURRENT");
+                       isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_OCIC);
+                       len = 0;
+                       break;
+               }
+               break;
+
+       case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+               DBG("RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS");
+
+               switch (wValue) {
+               case RH_PORT_ENABLE:
+                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+                                           RH_PS_CCS);
+                       len = 0;
+                       break;
+
+               case RH_PORT_SUSPEND:
+                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+                                           RH_PS_POCI);
+                       len = 0;
+                       break;
+
+               case RH_PORT_POWER:
+                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+                                           RH_PS_LSDA);
+                       len = 0;
+                       break;
+
+               case RH_C_PORT_CONNECTION:
+                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+                                           RH_PS_CSC);
+                       len = 0;
+                       break;
+
+               case RH_C_PORT_ENABLE:
+                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+                                           RH_PS_PESC);
+                       len = 0;
+                       break;
+
+               case RH_C_PORT_SUSPEND:
+                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+                                           RH_PS_PSSC);
+                       len = 0;
+                       break;
+
+               case RH_C_PORT_OVER_CURRENT:
+                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+                                           RH_PS_POCI);
+                       len = 0;
+                       break;
+
+               case RH_C_PORT_RESET:
+                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+                                           RH_PS_PRSC);
+                       len = 0;
+                       break;
+
+               default:
+                       ERR("invalid wValue");
+                       stat = USB_ST_STALLED;
+               }
+
+               isp116x_show_regs(isp116x);
+
+               break;
+
+       case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+               DBG("RH_SET_FEATURE | RH_OTHER | RH_CLASS");
+
+               switch (wValue) {
+               case RH_PORT_SUSPEND:
+                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+                                           RH_PS_PSS);
+                       len = 0;
+                       break;
+
+               case RH_PORT_RESET:
+                       /* Spin until any current reset finishes */
+                       while (1) {
+                               tmp =
+                                   isp116x_read_reg32(isp116x,
+                                                      HCRHPORT1 + wIndex - 1);
+                               if (!(tmp & RH_PS_PRS))
+                                       break;
+                               wait_ms(1);
+                       }
+                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+                                           RH_PS_PRS);
+                       wait_ms(10);
+
+                       len = 0;
+                       break;
+
+               case RH_PORT_POWER:
+                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+                                           RH_PS_PPS);
+                       len = 0;
+                       break;
+
+               case RH_PORT_ENABLE:
+                       isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+                                           RH_PS_PES);
+                       len = 0;
+                       break;
+
+               default:
+                       ERR("invalid wValue");
+                       stat = USB_ST_STALLED;
+               }
+
+               isp116x_show_regs(isp116x);
+
+               break;
+
+       case RH_SET_ADDRESS:
+               DBG("RH_SET_ADDRESS");
+
+               rh_devnum = wValue;
+               len = 0;
+               break;
+
+       case RH_GET_DESCRIPTOR:
+               DBG("RH_GET_DESCRIPTOR: %x, %d", wValue, wLength);
+
+               switch (wValue) {
+               case (USB_DT_DEVICE << 8):      /* device descriptor */
+                       len = min_t(unsigned int,
+                                   leni, min_t(unsigned int,
+                                               sizeof(root_hub_dev_des),
+                                               wLength));
+                       data_buf = root_hub_dev_des;
+                       break;
+
+               case (USB_DT_CONFIG << 8):      /* configuration descriptor */
+                       len = min_t(unsigned int,
+                                   leni, min_t(unsigned int,
+                                               sizeof(root_hub_config_des),
+                                               wLength));
+                       data_buf = root_hub_config_des;
+                       break;
+
+               case ((USB_DT_STRING << 8) | 0x00):     /* string 0 descriptors */
+                       len = min_t(unsigned int,
+                                   leni, min_t(unsigned int,
+                                               sizeof(root_hub_str_index0),
+                                               wLength));
+                       data_buf = root_hub_str_index0;
+                       break;
+
+               case ((USB_DT_STRING << 8) | 0x01):     /* string 1 descriptors */
+                       len = min_t(unsigned int,
+                                   leni, min_t(unsigned int,
+                                               sizeof(root_hub_str_index1),
+                                               wLength));
+                       data_buf = root_hub_str_index1;
+                       break;
+
+               default:
+                       ERR("invalid wValue");
+                       stat = USB_ST_STALLED;
+               }
+
+               break;
+
+       case RH_GET_DESCRIPTOR | RH_CLASS:
+               DBG("RH_GET_DESCRIPTOR | RH_CLASS");
+
+               tmp = isp116x_read_reg32(isp116x, HCRHDESCA);
+
+               data_buf[0] = 0x09;     /* min length; */
+               data_buf[1] = 0x29;
+               data_buf[2] = tmp & RH_A_NDP;
+               data_buf[3] = 0;
+               if (tmp & RH_A_PSM)     /* per-port power switching? */
+                       data_buf[3] |= 0x01;
+               if (tmp & RH_A_NOCP)    /* no overcurrent reporting? */
+                       data_buf[3] |= 0x10;
+               else if (tmp & RH_A_OCPM)       /* per-port overcurrent rep? */
+                       data_buf[3] |= 0x08;
+
+               /* Corresponds to data_buf[4-7] */
+               datab[1] = 0;
+               data_buf[5] = (tmp & RH_A_POTPGT) >> 24;
+
+               tmp = isp116x_read_reg32(isp116x, HCRHDESCB);
+
+               data_buf[7] = tmp & RH_B_DR;
+               if (data_buf[2] < 7)
+                       data_buf[8] = 0xff;
+               else {
+                       data_buf[0] += 2;
+                       data_buf[8] = (tmp & RH_B_DR) >> 8;
+                       data_buf[10] = data_buf[9] = 0xff;
+               }
+
+               len = min_t(unsigned int, leni,
+                           min_t(unsigned int, data_buf[0], wLength));
+               break;
+
+       case RH_GET_CONFIGURATION:
+               DBG("RH_GET_CONFIGURATION");
+
+               *(__u8 *) data_buf = 0x01;
+               len = 1;
+               break;
+
+       case RH_SET_CONFIGURATION:
+               DBG("RH_SET_CONFIGURATION");
+
+               isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPSC);
+               len = 0;
+               break;
+
+       default:
+               ERR("*** *** *** unsupported root hub command *** *** ***");
+               stat = USB_ST_STALLED;
+       }
+
+       len = min_t(int, len, leni);
+       if (buffer != data_buf)
+               memcpy(buffer, data_buf, len);
+
+       dev->act_len = len;
+       dev->status = stat;
+       DBG("dev act_len %d, status %d", dev->act_len, dev->status);
+
+       dump_msg(dev, pipe, buffer, transfer_len, "RH(ret)");
+
+       return stat;
+}
+
+/* --- Transfer functions -------------------------------------------------- */
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+                  int len, int interval)
+{
+       DBG("dev=%p pipe=%#lx buf=%p size=%d int=%d",
+           dev, pipe, buffer, len, interval);
+
+       return -1;
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+                      int len, struct devrequest *setup)
+{
+       int devnum = usb_pipedevice(pipe);
+       int epnum = usb_pipeendpoint(pipe);
+       int max = max_transfer_len(dev, pipe);
+       int dir_in = usb_pipein(pipe);
+       int done, ret;
+
+       /* Control message is for the HUB? */
+       if (devnum == rh_devnum)
+               return isp116x_submit_rh_msg(dev, pipe, buffer, len, setup);
+
+       /* Ok, no HUB message so send the message to the device */
+
+       /* Setup phase */
+       DBG("--- SETUP PHASE --------------------------------");
+       usb_settoggle(dev, epnum, 1, 0);
+       ret = isp116x_submit_job(dev, pipe,
+                                PTD_DIR_SETUP,
+                                setup, sizeof(struct devrequest));
+       if (ret < 0) {
+               DBG("control setup phase error (ret = %d", ret);
+               return -1;
+       }
+
+       /* Data phase */
+       DBG("--- DATA PHASE ---------------------------------");
+       done = 0;
+       usb_settoggle(dev, epnum, !dir_in, 1);
+       while (done < len) {
+               ret = isp116x_submit_job(dev, pipe,
+                                        dir_in ? PTD_DIR_IN : PTD_DIR_OUT,
+                                        (__u8 *) buffer + done,
+                                        max > len - done ? len - done : max);
+               if (ret < 0) {
+                       DBG("control data phase error (ret = %d)", ret);
+                       return -1;
+               }
+               done += ret;
+
+               if (dir_in && ret < max)        /* short packet */
+                       break;
+       }
+
+       /* Status phase */
+       DBG("--- STATUS PHASE -------------------------------");
+       usb_settoggle(dev, epnum, !dir_in, 1);
+       ret = isp116x_submit_job(dev, pipe,
+                                !dir_in ? PTD_DIR_IN : PTD_DIR_OUT, NULL, 0);
+       if (ret < 0) {
+               DBG("control status phase error (ret = %d", ret);
+               return -1;
+       }
+
+       dev->act_len = done;
+
+       dump_msg(dev, pipe, buffer, len, "DEV(ret)");
+
+       return done;
+}
+
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+                   int len)
+{
+       int dir_out = usb_pipeout(pipe);
+       int max = max_transfer_len(dev, pipe);
+       int done, ret;
+
+       DBG("--- BULK ---------------------------------------");
+       DBG("dev=%ld pipe=%ld buf=%p size=%d dir_out=%d",
+           usb_pipedevice(pipe), usb_pipeendpoint(pipe), buffer, len, dir_out);
+
+       done = 0;
+       while (done < len) {
+               ret = isp116x_submit_job(dev, pipe,
+                                        !dir_out ? PTD_DIR_IN : PTD_DIR_OUT,
+                                        (__u8 *) buffer + done,
+                                        max > len - done ? len - done : max);
+               if (ret < 0) {
+                       DBG("error on bulk message (ret = %d)", ret);
+                       return -1;
+               }
+
+               done += ret;
+
+               if (!dir_out && ret < max)      /* short packet */
+                       break;
+       }
+
+       dev->act_len = done;
+
+       return 0;
+}
+
+/* --- Basic functions ----------------------------------------------------- */
+
+static int isp116x_sw_reset(struct isp116x *isp116x)
+{
+       int retries = 15;
+       int ret = 0;
+
+       DBG("");
+
+       isp116x->disabled = 1;
+
+       isp116x_write_reg16(isp116x, HCSWRES, HCSWRES_MAGIC);
+       isp116x_write_reg32(isp116x, HCCMDSTAT, HCCMDSTAT_HCR);
+       while (--retries) {
+               /* It usually resets within 1 ms */
+               wait_ms(1);
+               if (!(isp116x_read_reg32(isp116x, HCCMDSTAT) & HCCMDSTAT_HCR))
+                       break;
+       }
+       if (!retries) {
+               ERR("software reset timeout");
+               ret = -1;
+       }
+       return ret;
+}
+
+static int isp116x_reset(struct isp116x *isp116x)
+{
+       unsigned long t;
+       u16 clkrdy = 0;
+       int ret, timeout = 15 /* ms */ ;
+
+       DBG("");
+
+       ret = isp116x_sw_reset(isp116x);
+       if (ret)
+               return ret;
+
+       for (t = 0; t < timeout; t++) {
+               clkrdy = isp116x_read_reg16(isp116x, HCuPINT) & HCuPINT_CLKRDY;
+               if (clkrdy)
+                       break;
+               wait_ms(1);
+       }
+       if (!clkrdy) {
+               ERR("clock not ready after %dms", timeout);
+               /* After sw_reset the clock won't report to be ready, if
+                  H_WAKEUP pin is high. */
+               ERR("please make sure that the H_WAKEUP pin is pulled low!");
+               ret = -1;
+       }
+       return ret;
+}
+
+static void isp116x_stop(struct isp116x *isp116x)
+{
+       u32 val;
+
+       DBG("");
+
+       isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+
+       /* Switch off ports' power, some devices don't come up
+          after next 'start' without this */
+       val = isp116x_read_reg32(isp116x, HCRHDESCA);
+       val &= ~(RH_A_NPS | RH_A_PSM);
+       isp116x_write_reg32(isp116x, HCRHDESCA, val);
+       isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPS);
+
+       isp116x_sw_reset(isp116x);
+}
+
+/*
+ *  Configure the chip. The chip must be successfully reset by now.
+ */
+static int isp116x_start(struct isp116x *isp116x)
+{
+       struct isp116x_platform_data *board = isp116x->board;
+       u32 val;
+
+       DBG("");
+
+       /* Clear interrupt status and disable all interrupt sources */
+       isp116x_write_reg16(isp116x, HCuPINT, 0xff);
+       isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+
+       isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE);
+       isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE);
+
+       /* Hardware configuration */
+       val = HCHWCFG_DBWIDTH(1);
+       if (board->sel15Kres)
+               val |= HCHWCFG_15KRSEL;
+       /* Remote wakeup won't work without working clock */
+       if (board->remote_wakeup_enable)
+               val |= HCHWCFG_CLKNOTSTOP;
+       if (board->oc_enable)
+               val |= HCHWCFG_ANALOG_OC;
+       isp116x_write_reg16(isp116x, HCHWCFG, val);
+
+       /* --- Root hub configuration */
+       val = (25 << 24) & RH_A_POTPGT;
+       /* AN10003_1.pdf recommends RH_A_NPS (no power switching) to
+          be always set. Yet, instead, we request individual port
+          power switching. */
+       val |= RH_A_PSM;
+       /* Report overcurrent per port */
+       val |= RH_A_OCPM;
+       isp116x_write_reg32(isp116x, HCRHDESCA, val);
+       isp116x->rhdesca = isp116x_read_reg32(isp116x, HCRHDESCA);
+
+       val = RH_B_PPCM;
+       isp116x_write_reg32(isp116x, HCRHDESCB, val);
+       isp116x->rhdescb = isp116x_read_reg32(isp116x, HCRHDESCB);
+
+       val = 0;
+       if (board->remote_wakeup_enable)
+               val |= RH_HS_DRWE;
+       isp116x_write_reg32(isp116x, HCRHSTATUS, val);
+       isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS);
+
+       isp116x_write_reg32(isp116x, HCFMINTVL, 0x27782edf);
+
+       /* Go operational */
+       val = HCCONTROL_USB_OPER;
+       if (board->remote_wakeup_enable)
+               val |= HCCONTROL_RWE;
+       isp116x_write_reg32(isp116x, HCCONTROL, val);
+
+       /* Disable ports to avoid race in device enumeration */
+       isp116x_write_reg32(isp116x, HCRHPORT1, RH_PS_CCS);
+       isp116x_write_reg32(isp116x, HCRHPORT2, RH_PS_CCS);
+
+       isp116x_show_regs(isp116x);
+
+       isp116x->disabled = 0;
+
+       return 0;
+}
+
+/* --- Init functions ------------------------------------------------------ */
+
+int isp116x_check_id(struct isp116x *isp116x)
+{
+       int val;
+
+       val = isp116x_read_reg16(isp116x, HCCHIPID);
+       if ((val & HCCHIPID_MASK) != HCCHIPID_MAGIC) {
+               ERR("invalid chip ID %04x", val);
+               return -1;
+       }
+
+       return 0;
+}
+
+int usb_lowlevel_init(void)
+{
+       struct isp116x *isp116x = &isp116x_dev;
+
+       DBG("");
+
+       got_rhsc = rh_devnum = 0;
+
+       /* Init device registers addr */
+       isp116x->addr_reg = (u16 *) ISP116X_HCD_ADDR;
+       isp116x->data_reg = (u16 *) ISP116X_HCD_DATA;
+
+       /* Setup specific board settings */
+#ifdef ISP116X_HCD_SEL15kRES
+       isp116x_board.sel15Kres = 1;
+#endif
+#ifdef ISP116X_HCD_OC_ENABLE
+       isp116x_board.oc_enable = 1;
+#endif
+#ifdef ISP116X_HCD_REMOTE_WAKEUP_ENABLE
+       isp116x_board.remote_wakeup_enable = 1;
+#endif
+       isp116x->board = &isp116x_board;
+
+       /* Try to get ISP116x silicon chip ID */
+       if (isp116x_check_id(isp116x) < 0)
+               return -1;
+
+       isp116x->disabled = 1;
+       isp116x->sleeping = 0;
+
+       isp116x_reset(isp116x);
+       isp116x_start(isp116x);
+
+       return 0;
+}
+
+int usb_lowlevel_stop(void)
+{
+       struct isp116x *isp116x = &isp116x_dev;
+
+       DBG("");
+
+       if (!isp116x->disabled)
+               isp116x_stop(isp116x);
+
+       return 0;
+}
+
+#endif                         /* CONFIG_USB_ISP116X_HCD */
diff --git a/drivers/usb/isp116x.h b/drivers/usb/isp116x.h
new file mode 100644 (file)
index 0000000..a3ce3b5
--- /dev/null
@@ -0,0 +1,489 @@
+/*
+ * ISP116x register declarations and HCD data structures
+ *
+ * Copyright (C) 2007 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (C) 2007 Eurotech S.p.A. <info@eurotech.it>
+ * Copyright (C) 2005 Olav Kongas <ok@artecdesign.ee>
+ * Portions:
+ * Copyright (C) 2004 Lothar Wassmann
+ * Copyright (C) 2004 Psion Teklogix
+ * Copyright (C) 2004 David Brownell
+ *
+ * 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
+ */
+
+#ifdef DEBUG
+#define DBG(fmt, args...)      \
+               printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args)
+#else
+#define DBG(fmt, args...)      do {} while (0)
+#endif
+
+#ifdef VERBOSE
+#    define VDBG               DBG
+#else
+#    define VDBG(fmt, args...) do {} while (0)
+#endif
+
+#define ERR(fmt, args...)      \
+               printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args)
+#define WARN(fmt, args...)     \
+               printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args)
+#define INFO(fmt, args...)     \
+               printf("isp116x: " fmt "\n" , ## args)
+
+/* ------------------------------------------------------------------------- */
+
+/* us of 1ms frame */
+#define  MAX_LOAD_LIMIT                850
+
+/* Full speed: max # of bytes to transfer for a single urb
+   at a time must be < 1024 && must be multiple of 64.
+   832 allows transfering 4kiB within 5 frames. */
+#define MAX_TRANSFER_SIZE_FULLSPEED    832
+
+/* Low speed: there is no reason to schedule in very big
+   chunks; often the requested long transfers are for
+   string descriptors containing short strings. */
+#define MAX_TRANSFER_SIZE_LOWSPEED     64
+
+/* Bytetime (us), a rough indication of how much time it
+   would take to transfer a byte of useful data over USB */
+#define BYTE_TIME_FULLSPEED    1
+#define BYTE_TIME_LOWSPEED     20
+
+/* Buffer sizes */
+#define ISP116x_BUF_SIZE       4096
+#define ISP116x_ITL_BUFSIZE    0
+#define ISP116x_ATL_BUFSIZE    ((ISP116x_BUF_SIZE) - 2*(ISP116x_ITL_BUFSIZE))
+
+#define ISP116x_WRITE_OFFSET   0x80
+
+/* --- ISP116x registers/bits ---------------------------------------------- */
+
+#define        HCREVISION      0x00
+#define        HCCONTROL       0x01
+#define                HCCONTROL_HCFS  (3 << 6)        /* host controller
+                                                  functional state */
+#define                HCCONTROL_USB_RESET     (0 << 6)
+#define                HCCONTROL_USB_RESUME    (1 << 6)
+#define                HCCONTROL_USB_OPER      (2 << 6)
+#define                HCCONTROL_USB_SUSPEND   (3 << 6)
+#define                HCCONTROL_RWC   (1 << 9)        /* remote wakeup connected */
+#define                HCCONTROL_RWE   (1 << 10)       /* remote wakeup enable */
+#define        HCCMDSTAT       0x02
+#define                HCCMDSTAT_HCR   (1 << 0)        /* host controller reset */
+#define                HCCMDSTAT_SOC   (3 << 16)       /* scheduling overrun count */
+#define        HCINTSTAT       0x03
+#define                HCINT_SO        (1 << 0)        /* scheduling overrun */
+#define                HCINT_WDH       (1 << 1)        /* writeback of done_head */
+#define                HCINT_SF        (1 << 2)        /* start frame */
+#define                HCINT_RD        (1 << 3)        /* resume detect */
+#define                HCINT_UE        (1 << 4)        /* unrecoverable error */
+#define                HCINT_FNO       (1 << 5)        /* frame number overflow */
+#define                HCINT_RHSC      (1 << 6)        /* root hub status change */
+#define                HCINT_OC        (1 << 30)       /* ownership change */
+#define                HCINT_MIE       (1 << 31)       /* master interrupt enable */
+#define        HCINTENB        0x04
+#define        HCINTDIS        0x05
+#define        HCFMINTVL       0x0d
+#define        HCFMREM         0x0e
+#define        HCFMNUM         0x0f
+#define        HCLSTHRESH      0x11
+#define        HCRHDESCA       0x12
+#define                RH_A_NDP        (0x3 << 0)      /* # downstream ports */
+#define                RH_A_PSM        (1 << 8)        /* power switching mode */
+#define                RH_A_NPS        (1 << 9)        /* no power switching */
+#define                RH_A_DT         (1 << 10)       /* device type (mbz) */
+#define                RH_A_OCPM       (1 << 11)       /* overcurrent protection
+                                                  mode */
+#define                RH_A_NOCP       (1 << 12)       /* no overcurrent protection */
+#define                RH_A_POTPGT     (0xff << 24)    /* power on -> power good
+                                                  time */
+#define        HCRHDESCB       0x13
+#define                RH_B_DR         (0xffff << 0)   /* device removable flags */
+#define                RH_B_PPCM       (0xffff << 16)  /* port power control mask */
+#define        HCRHSTATUS      0x14
+#define                RH_HS_LPS       (1 << 0)        /* local power status */
+#define                RH_HS_OCI       (1 << 1)        /* over current indicator */
+#define                RH_HS_DRWE      (1 << 15)       /* device remote wakeup
+                                                  enable */
+#define                RH_HS_LPSC      (1 << 16)       /* local power status change */
+#define                RH_HS_OCIC      (1 << 17)       /* over current indicator
+                                                  change */
+#define                RH_HS_CRWE      (1 << 31)       /* clear remote wakeup
+                                                  enable */
+#define        HCRHPORT1       0x15
+#define                RH_PS_CCS       (1 << 0)        /* current connect status */
+#define                RH_PS_PES       (1 << 1)        /* port enable status */
+#define                RH_PS_PSS       (1 << 2)        /* port suspend status */
+#define                RH_PS_POCI      (1 << 3)        /* port over current
+                                                  indicator */
+#define                RH_PS_PRS       (1 << 4)        /* port reset status */
+#define                RH_PS_PPS       (1 << 8)        /* port power status */
+#define                RH_PS_LSDA      (1 << 9)        /* low speed device attached */
+#define                RH_PS_CSC       (1 << 16)       /* connect status change */
+#define                RH_PS_PESC      (1 << 17)       /* port enable status change */
+#define                RH_PS_PSSC      (1 << 18)       /* port suspend status
+                                                  change */
+#define                RH_PS_OCIC      (1 << 19)       /* over current indicator
+                                                  change */
+#define                RH_PS_PRSC      (1 << 20)       /* port reset status change */
+#define                HCRHPORT_CLRMASK        (0x1f << 16)
+#define        HCRHPORT2       0x16
+#define        HCHWCFG         0x20
+#define                HCHWCFG_15KRSEL         (1 << 12)
+#define                HCHWCFG_CLKNOTSTOP      (1 << 11)
+#define                HCHWCFG_ANALOG_OC       (1 << 10)
+#define                HCHWCFG_DACK_MODE       (1 << 8)
+#define                HCHWCFG_EOT_POL         (1 << 7)
+#define                HCHWCFG_DACK_POL        (1 << 6)
+#define                HCHWCFG_DREQ_POL        (1 << 5)
+#define                HCHWCFG_DBWIDTH_MASK    (0x03 << 3)
+#define                HCHWCFG_DBWIDTH(n)      (((n) << 3) & HCHWCFG_DBWIDTH_MASK)
+#define                HCHWCFG_INT_POL         (1 << 2)
+#define                HCHWCFG_INT_TRIGGER     (1 << 1)
+#define                HCHWCFG_INT_ENABLE      (1 << 0)
+#define        HCDMACFG        0x21
+#define                HCDMACFG_BURST_LEN_MASK (0x03 << 5)
+#define                HCDMACFG_BURST_LEN(n)   (((n) << 5) & HCDMACFG_BURST_LEN_MASK)
+#define                HCDMACFG_BURST_LEN_1    HCDMACFG_BURST_LEN(0)
+#define                HCDMACFG_BURST_LEN_4    HCDMACFG_BURST_LEN(1)
+#define                HCDMACFG_BURST_LEN_8    HCDMACFG_BURST_LEN(2)
+#define                HCDMACFG_DMA_ENABLE     (1 << 4)
+#define                HCDMACFG_BUF_TYPE_MASK  (0x07 << 1)
+#define                HCDMACFG_CTR_SEL        (1 << 2)
+#define                HCDMACFG_ITLATL_SEL     (1 << 1)
+#define                HCDMACFG_DMA_RW_SELECT  (1 << 0)
+#define        HCXFERCTR       0x22
+#define        HCuPINT         0x24
+#define                HCuPINT_SOF             (1 << 0)
+#define                HCuPINT_ATL             (1 << 1)
+#define                HCuPINT_AIIEOT          (1 << 2)
+#define                HCuPINT_OPR             (1 << 4)
+#define                HCuPINT_SUSP            (1 << 5)
+#define                HCuPINT_CLKRDY          (1 << 6)
+#define        HCuPINTENB      0x25
+#define        HCCHIPID        0x27
+#define                HCCHIPID_MASK           0xff00
+#define                HCCHIPID_MAGIC          0x6100
+#define        HCSCRATCH       0x28
+#define        HCSWRES         0x29
+#define                HCSWRES_MAGIC           0x00f6
+#define        HCITLBUFLEN     0x2a
+#define        HCATLBUFLEN     0x2b
+#define        HCBUFSTAT       0x2c
+#define                HCBUFSTAT_ITL0_FULL     (1 << 0)
+#define                HCBUFSTAT_ITL1_FULL     (1 << 1)
+#define                HCBUFSTAT_ATL_FULL      (1 << 2)
+#define                HCBUFSTAT_ITL0_DONE     (1 << 3)
+#define                HCBUFSTAT_ITL1_DONE     (1 << 4)
+#define                HCBUFSTAT_ATL_DONE      (1 << 5)
+#define        HCRDITL0LEN     0x2d
+#define        HCRDITL1LEN     0x2e
+#define        HCITLPORT       0x40
+#define        HCATLPORT       0x41
+
+/* PTD accessor macros. */
+#define PTD_GET_COUNT(p)       (((p)->count & PTD_COUNT_MSK) >> 0)
+#define PTD_COUNT(v)           (((v) << 0) & PTD_COUNT_MSK)
+#define PTD_GET_TOGGLE(p)      (((p)->count & PTD_TOGGLE_MSK) >> 10)
+#define PTD_TOGGLE(v)          (((v) << 10) & PTD_TOGGLE_MSK)
+#define PTD_GET_ACTIVE(p)      (((p)->count & PTD_ACTIVE_MSK) >> 11)
+#define PTD_ACTIVE(v)          (((v) << 11) & PTD_ACTIVE_MSK)
+#define PTD_GET_CC(p)          (((p)->count & PTD_CC_MSK) >> 12)
+#define PTD_CC(v)              (((v) << 12) & PTD_CC_MSK)
+#define PTD_GET_MPS(p)         (((p)->mps & PTD_MPS_MSK) >> 0)
+#define PTD_MPS(v)             (((v) << 0) & PTD_MPS_MSK)
+#define PTD_GET_SPD(p)         (((p)->mps & PTD_SPD_MSK) >> 10)
+#define PTD_SPD(v)             (((v) << 10) & PTD_SPD_MSK)
+#define PTD_GET_LAST(p)                (((p)->mps & PTD_LAST_MSK) >> 11)
+#define PTD_LAST(v)            (((v) << 11) & PTD_LAST_MSK)
+#define PTD_GET_EP(p)          (((p)->mps & PTD_EP_MSK) >> 12)
+#define PTD_EP(v)              (((v) << 12) & PTD_EP_MSK)
+#define PTD_GET_LEN(p)         (((p)->len & PTD_LEN_MSK) >> 0)
+#define PTD_LEN(v)             (((v) << 0) & PTD_LEN_MSK)
+#define PTD_GET_DIR(p)         (((p)->len & PTD_DIR_MSK) >> 10)
+#define PTD_DIR(v)             (((v) << 10) & PTD_DIR_MSK)
+#define PTD_GET_B5_5(p)                (((p)->len & PTD_B5_5_MSK) >> 13)
+#define PTD_B5_5(v)            (((v) << 13) & PTD_B5_5_MSK)
+#define PTD_GET_FA(p)          (((p)->faddr & PTD_FA_MSK) >> 0)
+#define PTD_FA(v)              (((v) << 0) & PTD_FA_MSK)
+#define PTD_GET_FMT(p)         (((p)->faddr & PTD_FMT_MSK) >> 7)
+#define PTD_FMT(v)             (((v) << 7) & PTD_FMT_MSK)
+
+/*  Hardware transfer status codes -- CC from ptd->count */
+#define TD_CC_NOERROR      0x00
+#define TD_CC_CRC          0x01
+#define TD_CC_BITSTUFFING  0x02
+#define TD_CC_DATATOGGLEM  0x03
+#define TD_CC_STALL        0x04
+#define TD_DEVNOTRESP      0x05
+#define TD_PIDCHECKFAIL    0x06
+#define TD_UNEXPECTEDPID   0x07
+#define TD_DATAOVERRUN     0x08
+#define TD_DATAUNDERRUN    0x09
+    /* 0x0A, 0x0B reserved for hardware */
+#define TD_BUFFEROVERRUN   0x0C
+#define TD_BUFFERUNDERRUN  0x0D
+    /* 0x0E, 0x0F reserved for HCD */
+#define TD_NOTACCESSED     0x0F
+
+/* ------------------------------------------------------------------------- */
+
+#define        LOG2_PERIODIC_SIZE      5       /* arbitrary; this matches OHCI */
+#define        PERIODIC_SIZE           (1 << LOG2_PERIODIC_SIZE)
+
+/* Philips transfer descriptor */
+struct ptd {
+       u16 count;
+#define        PTD_COUNT_MSK   (0x3ff << 0)
+#define        PTD_TOGGLE_MSK  (1 << 10)
+#define        PTD_ACTIVE_MSK  (1 << 11)
+#define        PTD_CC_MSK      (0xf << 12)
+       u16 mps;
+#define        PTD_MPS_MSK     (0x3ff << 0)
+#define        PTD_SPD_MSK     (1 << 10)
+#define        PTD_LAST_MSK    (1 << 11)
+#define        PTD_EP_MSK      (0xf << 12)
+       u16 len;
+#define        PTD_LEN_MSK     (0x3ff << 0)
+#define        PTD_DIR_MSK     (3 << 10)
+#define        PTD_DIR_SETUP   (0)
+#define        PTD_DIR_OUT     (1)
+#define        PTD_DIR_IN      (2)
+#define        PTD_B5_5_MSK    (1 << 13)
+       u16 faddr;
+#define        PTD_FA_MSK      (0x7f << 0)
+#define        PTD_FMT_MSK     (1 << 7)
+} __attribute__ ((packed, aligned(2)));
+
+struct isp116x_ep {
+       struct usb_device *udev;
+       struct ptd ptd;
+
+       u8 maxpacket;
+       u8 epnum;
+       u8 nextpid;
+
+       u16 length;             /* of current packet */
+       unsigned char *data;    /* to databuf */
+
+       u16 error_count;
+};
+
+/* URB struct */
+#define N_URB_TD               48
+#define URB_DEL                        1
+typedef struct {
+       struct isp116x_ep *ed;
+       void *transfer_buffer;  /* (in) associated data buffer */
+       int actual_length;      /* (return) actual transfer length */
+       unsigned long pipe;     /* (in) pipe information */
+#if 0
+       int state;
+#endif
+} urb_priv_t;
+
+struct isp116x_platform_data {
+       /* Enable internal resistors on downstream ports */
+       unsigned sel15Kres:1;
+       /* On-chip overcurrent detection */
+       unsigned oc_enable:1;
+       /* Enable wakeup by devices on usb bus (e.g. wakeup
+          by attachment/detachment or by device activity
+          such as moving a mouse). When chosen, this option
+          prevents stopping internal clock, increasing
+          thereby power consumption in suspended state. */
+       unsigned remote_wakeup_enable:1;
+};
+
+struct isp116x {
+       u16 *addr_reg;
+       u16 *data_reg;
+
+       struct isp116x_platform_data *board;
+
+       struct dentry *dentry;
+       unsigned long stat1, stat2, stat4, stat8, stat16;
+
+       /* Status flags */
+       unsigned disabled:1;
+       unsigned sleeping:1;
+
+       /* Root hub registers */
+       u32 rhdesca;
+       u32 rhdescb;
+       u32 rhstatus;
+       u32 rhport[2];
+
+       /* Schedule for the current frame */
+       struct isp116x_ep *atl_active;
+       int atl_buflen;
+       int atl_bufshrt;
+       int atl_last_dir;
+       int atl_finishing;
+};
+
+/* ------------------------------------------------- */
+
+/* Inter-io delay (ns). The chip is picky about access timings; it
+ * expects at least:
+ * 150ns delay between consecutive accesses to DATA_REG,
+ * 300ns delay between access to ADDR_REG and DATA_REG
+ * OE, WE MUST NOT be changed during these intervals
+ */
+#if defined(UDELAY)
+#define        isp116x_delay(h,d)      udelay(d)
+#else
+#define        isp116x_delay(h,d)      do {} while (0)
+#endif
+
+static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg)
+{
+       writew(reg & 0xff, isp116x->addr_reg);
+       isp116x_delay(isp116x, UDELAY);
+}
+
+static inline void isp116x_write_data16(struct isp116x *isp116x, u16 val)
+{
+       writew(val, isp116x->data_reg);
+       isp116x_delay(isp116x, UDELAY);
+}
+
+static inline void isp116x_raw_write_data16(struct isp116x *isp116x, u16 val)
+{
+       __raw_writew(val, isp116x->data_reg);
+       isp116x_delay(isp116x, UDELAY);
+}
+
+static inline u16 isp116x_read_data16(struct isp116x *isp116x)
+{
+       u16 val;
+
+       val = readw(isp116x->data_reg);
+       isp116x_delay(isp116x, UDELAY);
+       return val;
+}
+
+static inline u16 isp116x_raw_read_data16(struct isp116x *isp116x)
+{
+       u16 val;
+
+       val = __raw_readw(isp116x->data_reg);
+       isp116x_delay(isp116x, UDELAY);
+       return val;
+}
+
+static inline void isp116x_write_data32(struct isp116x *isp116x, u32 val)
+{
+       writew(val & 0xffff, isp116x->data_reg);
+       isp116x_delay(isp116x, UDELAY);
+       writew(val >> 16, isp116x->data_reg);
+       isp116x_delay(isp116x, UDELAY);
+}
+
+static inline u32 isp116x_read_data32(struct isp116x *isp116x)
+{
+       u32 val;
+
+       val = (u32) readw(isp116x->data_reg);
+       isp116x_delay(isp116x, UDELAY);
+       val |= ((u32) readw(isp116x->data_reg)) << 16;
+       isp116x_delay(isp116x, UDELAY);
+       return val;
+}
+
+/* Let's keep register access functions out of line. Hint:
+   we wait at least 150 ns at every access.
+*/
+static u16 isp116x_read_reg16(struct isp116x *isp116x, unsigned reg)
+{
+       isp116x_write_addr(isp116x, reg);
+       return isp116x_read_data16(isp116x);
+}
+
+static u32 isp116x_read_reg32(struct isp116x *isp116x, unsigned reg)
+{
+       isp116x_write_addr(isp116x, reg);
+       return isp116x_read_data32(isp116x);
+}
+
+static void isp116x_write_reg16(struct isp116x *isp116x, unsigned reg,
+                               unsigned val)
+{
+       isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
+       isp116x_write_data16(isp116x, (u16) (val & 0xffff));
+}
+
+static void isp116x_write_reg32(struct isp116x *isp116x, unsigned reg,
+                               unsigned val)
+{
+       isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
+       isp116x_write_data32(isp116x, (u32) val);
+}
+
+/* --- USB HUB constants (not OHCI-specific; see hub.h) -------------------- */
+
+/* destination of request */
+#define RH_INTERFACE               0x01
+#define RH_ENDPOINT                0x02
+#define RH_OTHER                   0x03
+
+#define RH_CLASS                   0x20
+#define RH_VENDOR                  0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS           0x0080
+#define RH_CLEAR_FEATURE        0x0100
+#define RH_SET_FEATURE          0x0300
+#define RH_SET_ADDRESS          0x0500
+#define RH_GET_DESCRIPTOR       0x0680
+#define RH_SET_DESCRIPTOR       0x0700
+#define RH_GET_CONFIGURATION    0x0880
+#define RH_SET_CONFIGURATION    0x0900
+#define RH_GET_STATE            0x0280
+#define RH_GET_INTERFACE        0x0A80
+#define RH_SET_INTERFACE        0x0B00
+#define RH_SYNC_FRAME           0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP               0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION         0x00
+#define RH_PORT_ENABLE             0x01
+#define RH_PORT_SUSPEND            0x02
+#define RH_PORT_OVER_CURRENT       0x03
+#define RH_PORT_RESET              0x04
+#define RH_PORT_POWER              0x08
+#define RH_PORT_LOW_SPEED          0x09
+
+#define RH_C_PORT_CONNECTION       0x10
+#define RH_C_PORT_ENABLE           0x11
+#define RH_C_PORT_SUSPEND          0x12
+#define RH_C_PORT_OVER_CURRENT     0x13
+#define RH_C_PORT_RESET            0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER       0x00
+#define RH_C_HUB_OVER_CURRENT      0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP    0x00
+#define RH_ENDPOINT_STALL          0x01
+
+#define RH_ACK                     0x01
+#define RH_REQ_ERR                 -1
+#define RH_NACK                    0x00
diff --git a/drivers/usb/sl811.h b/drivers/usb/sl811.h
new file mode 100644 (file)
index 0000000..c1f9f01
--- /dev/null
@@ -0,0 +1,104 @@
+#ifndef __UBOOT_SL811_H
+#define __UBOOT_SL811_H
+
+#undef SL811_DEBUG
+
+#ifdef SL811_DEBUG
+       #define PDEBUG(level, fmt, args...) \
+               if (debug >= (level)) printf("[%s:%d] " fmt, \
+               __PRETTY_FUNCTION__, __LINE__ , ## args)
+#else
+       #define PDEBUG(level, fmt, args...) do {} while(0)
+#endif
+
+/* Sl811 host control register */
+#define        SL811_CTRL_A            0x00
+#define        SL811_ADDR_A            0x01
+#define        SL811_LEN_A             0x02
+#define        SL811_STS_A             0x03    /* read */
+#define        SL811_PIDEP_A           0x03    /* write */
+#define        SL811_CNT_A             0x04    /* read */
+#define        SL811_DEV_A             0x04    /* write */
+#define        SL811_CTRL1             0x05
+#define        SL811_INTR              0x06
+#define        SL811_CTRL_B            0x08
+#define        SL811_ADDR_B            0x09
+#define        SL811_LEN_B             0x0A
+#define        SL811_STS_B             0x0B    /* read */
+#define        SL811_PIDEP_B           0x0B    /* write */
+#define        SL811_CNT_B             0x0C    /* read */
+#define        SL811_DEV_B             0x0C    /* write */
+#define        SL811_INTRSTS           0x0D    /* write clears bitwise */
+#define        SL811_HWREV             0x0E    /* read */
+#define        SL811_SOFLOW            0x0E    /* write */
+#define        SL811_SOFCNTDIV         0x0F    /* read */
+#define        SL811_CTRL2             0x0F    /* write */
+
+/* USB control register bits (addr 0x00 and addr 0x08) */
+#define        SL811_USB_CTRL_ARM      0x01
+#define        SL811_USB_CTRL_ENABLE   0x02
+#define        SL811_USB_CTRL_DIR_OUT  0x04
+#define        SL811_USB_CTRL_ISO      0x10
+#define        SL811_USB_CTRL_SOF      0x20
+#define        SL811_USB_CTRL_TOGGLE_1 0x40
+#define        SL811_USB_CTRL_PREAMBLE 0x80
+
+/* USB status register bits (addr 0x03 and addr 0x0B) */
+#define        SL811_USB_STS_ACK       0x01
+#define        SL811_USB_STS_ERROR     0x02
+#define        SL811_USB_STS_TIMEOUT   0x04
+#define        SL811_USB_STS_TOGGLE_1  0x08
+#define        SL811_USB_STS_SETUP     0x10
+#define        SL811_USB_STS_OVERFLOW  0x20
+#define        SL811_USB_STS_NAK       0x40
+#define        SL811_USB_STS_STALL     0x80
+
+/* Control register 1 bits (addr 0x05) */
+#define        SL811_CTRL1_SOF         0x01
+#define        SL811_CTRL1_RESET       0x08
+#define        SL811_CTRL1_JKSTATE     0x10
+#define        SL811_CTRL1_SPEED_LOW   0x20
+#define        SL811_CTRL1_SUSPEND     0x40
+
+/* Interrut enable (addr 0x06) and interrupt status register bits (addr 0x0D) */
+#define        SL811_INTR_DONE_A       0x01
+#define        SL811_INTR_DONE_B       0x02
+#define        SL811_INTR_SOF          0x10
+#define        SL811_INTR_INSRMV       0x20
+#define        SL811_INTR_DETECT       0x40
+#define        SL811_INTR_NOTPRESENT   0x40
+#define        SL811_INTR_SPEED_FULL   0x80    /* only in status reg */
+
+/* HW rev and SOF lo register bits (addr 0x0E) */
+#define        SL811_HWR_HWREV         0xF0
+
+/* SOF counter and control reg 2 (addr 0x0F) */
+#define        SL811_CTL2_SOFHI        0x3F
+#define        SL811_CTL2_DSWAP        0x40
+#define        SL811_CTL2_HOST         0x80
+
+/* Set up for 1-ms SOF time. */
+#define SL811_12M_LOW          0xE0
+#define SL811_12M_HI           0x2E
+
+#define SL811_DATA_START       0x10
+#define SL811_DATA_LIMIT       240
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS           0x0080
+#define RH_CLEAR_FEATURE        0x0100
+#define RH_SET_FEATURE          0x0300
+#define RH_SET_ADDRESS         0x0500
+#define RH_GET_DESCRIPTOR      0x0680
+#define RH_SET_DESCRIPTOR       0x0700
+#define RH_GET_CONFIGURATION   0x0880
+#define RH_SET_CONFIGURATION   0x0900
+#define RH_GET_STATE            0x0280
+#define RH_GET_INTERFACE        0x0A80
+#define RH_SET_INTERFACE        0x0B00
+#define RH_SYNC_FRAME           0x0C80
+
+
+#define PIDEP(pid, ep) (((pid) & 0x0f) << 4 | (ep))
+
+#endif /* __UBOOT_SL811_H */
diff --git a/drivers/usb/sl811_usb.c b/drivers/usb/sl811_usb.c
new file mode 100644 (file)
index 0000000..c1f8427
--- /dev/null
@@ -0,0 +1,737 @@
+/*
+ * (C) Copyright 2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This code is based on linux driver for sl811hs chip, source at
+ * drivers/usb/host/sl811.c:
+ *
+ * SL811 Host Controller Interface driver for USB.
+ *
+ * Copyright (c) 2003/06, Courage Co., Ltd.
+ *
+ * Based on:
+ *     1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap,
+ *       Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber,
+ *       Adam Richter, Gregory P. Smith;
+ *     2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com>
+ *     3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn>
+ *
+ * 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
+ */
+
+#include <common.h>
+#ifdef CONFIG_USB_SL811HS
+#include <mpc8xx.h>
+#include <usb.h>
+#include "sl811.h"
+
+#include "../../board/kup/common/kup.h"
+
+#ifdef __PPC__
+# define EIEIO         __asm__ volatile ("eieio")
+#else
+# define EIEIO         /* nothing */
+#endif
+
+#define         SL811_ADR (0x50000000)
+#define         SL811_DAT (0x50000001)
+
+#define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);})
+
+#ifdef SL811_DEBUG
+static int debug = 9;
+#endif
+
+static int root_hub_devnum = 0;
+static struct usb_port_status rh_status = { 0 };/* root hub port status */
+
+static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe,
+                              void *data, int buf_len, struct devrequest *cmd);
+
+static void sl811_write (__u8 index, __u8 data)
+{
+       *(volatile unsigned char *) (SL811_ADR) = index;
+       EIEIO;
+       *(volatile unsigned char *) (SL811_DAT) = data;
+       EIEIO;
+}
+
+static __u8 sl811_read (__u8 index)
+{
+       __u8 data;
+
+       *(volatile unsigned char *) (SL811_ADR) = index;
+       EIEIO;
+       data = *(volatile unsigned char *) (SL811_DAT);
+       EIEIO;
+       return (data);
+}
+
+/*
+ * Read consecutive bytes of data from the SL811H/SL11H buffer
+ */
+static void inline sl811_read_buf(__u8 offset, __u8 *buf, __u8 size)
+{
+       *(volatile unsigned char *) (SL811_ADR) = offset;
+       EIEIO;
+       while (size--) {
+               *buf++ = *(volatile unsigned char *) (SL811_DAT);
+               EIEIO;
+       }
+}
+
+/*
+ * Write consecutive bytes of data to the SL811H/SL11H buffer
+ */
+static void inline sl811_write_buf(__u8 offset, __u8 *buf, __u8 size)
+{
+       *(volatile unsigned char *) (SL811_ADR) = offset;
+       EIEIO;
+       while (size--) {
+               *(volatile unsigned char *) (SL811_DAT) = *buf++;
+               EIEIO;
+       }
+}
+
+int usb_init_kup4x (void)
+{
+       volatile immap_t *immap = (immap_t *) CFG_IMMR;
+       volatile memctl8xx_t *memctl = &immap->im_memctl;
+       int i;
+       unsigned char tmp;
+
+       memctl = &immap->im_memctl;
+       memctl->memc_or7 = 0xFFFF8726;
+       memctl->memc_br7 = 0x50000401;  /* start at 0x50000000 */
+       /* BP 14 low = USB ON */
+       immap->im_cpm.cp_pbdat &= ~(BP_USB_VCC);
+       /* PB 14 nomal port */
+       immap->im_cpm.cp_pbpar &= ~(BP_USB_VCC);
+       /* output */
+       immap->im_cpm.cp_pbdir |= (BP_USB_VCC);
+
+       puts ("USB:   ");
+
+       for (i = 0x10; i < 0xff; i++) {
+               sl811_write(i, i);
+               tmp = (sl811_read(i));
+               if (tmp != i) {
+                       printf ("SL811 compare error index=0x%02x read=0x%02x\n", i, tmp);
+                       return (-1);
+               }
+       }
+       printf ("SL811 ready\n");
+       return (0);
+}
+
+/*
+ * This function resets SL811HS controller and detects the speed of
+ * the connecting device
+ *
+ * Return: 0 = no device attached; 1 = USB device attached
+ */
+static int sl811_hc_reset(void)
+{
+       int status ;
+
+       sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
+       sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
+
+       mdelay(20);
+
+       /* Disable hardware SOF generation, clear all irq status. */
+       sl811_write(SL811_CTRL1, 0);
+       mdelay(2);
+       sl811_write(SL811_INTRSTS, 0xff);
+       status = sl811_read(SL811_INTRSTS);
+
+       if (status & SL811_INTR_NOTPRESENT) {
+               /* Device is not present */
+               PDEBUG(0, "Device not present\n");
+               rh_status.wPortStatus &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE);
+               rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
+               sl811_write(SL811_INTR, SL811_INTR_INSRMV);
+               return 0;
+       }
+
+       /* Send SOF to address 0, endpoint 0. */
+       sl811_write(SL811_LEN_B, 0);
+       sl811_write(SL811_PIDEP_B, PIDEP(USB_PID_SOF, 0));
+       sl811_write(SL811_DEV_B, 0x00);
+       sl811_write(SL811_SOFLOW, SL811_12M_LOW);
+
+       if (status & SL811_INTR_SPEED_FULL) {
+               /* full speed device connect directly to root hub */
+               PDEBUG (0, "Full speed Device attached\n");
+
+               sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
+               mdelay(20);
+               sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
+               sl811_write(SL811_CTRL1, SL811_CTRL1_SOF);
+
+               /* start the SOF or EOP */
+               sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM);
+               rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION;
+               rh_status.wPortStatus &= ~USB_PORT_STAT_LOW_SPEED;
+               mdelay(2);
+               sl811_write(SL811_INTRSTS, 0xff);
+       } else {
+               /* slow speed device connect directly to root-hub */
+               PDEBUG(0, "Low speed Device attached\n");
+
+               sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
+               mdelay(20);
+               sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_CTL2_DSWAP | SL811_12M_HI);
+               sl811_write(SL811_CTRL1, SL811_CTRL1_SPEED_LOW | SL811_CTRL1_SOF);
+
+               /* start the SOF or EOP */
+               sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM);
+               rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION | USB_PORT_STAT_LOW_SPEED;
+               mdelay(2);
+               sl811_write(SL811_INTRSTS, 0xff);
+       }
+
+       rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
+       sl811_write(SL811_INTR, /*SL811_INTR_INSRMV*/SL811_INTR_DONE_A);
+
+       return 1;
+}
+
+int usb_lowlevel_init(void)
+{
+       root_hub_devnum = 0;
+       sl811_hc_reset();
+       return 0;
+}
+
+int usb_lowlevel_stop(void)
+{
+       sl811_hc_reset();
+       return 0;
+}
+
+static int calc_needed_buswidth(int bytes, int need_preamble)
+{
+       return !need_preamble ? bytes * 8 + 256 : 8 * 8 * bytes + 2048;
+}
+
+static int sl811_send_packet(struct usb_device *dev, unsigned long pipe, __u8 *buffer, int len)
+{
+       __u8 ctrl = SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE;
+       __u16 status = 0;
+       int err = 0, time_start = get_timer(0);
+       int need_preamble = !(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) &&
+               usb_pipeslow(pipe);
+
+       if (len > 239)
+               return -1;
+
+       if (usb_pipeout(pipe))
+               ctrl |= SL811_USB_CTRL_DIR_OUT;
+       if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)))
+               ctrl |= SL811_USB_CTRL_TOGGLE_1;
+       if (need_preamble)
+               ctrl |= SL811_USB_CTRL_PREAMBLE;
+
+       sl811_write(SL811_INTRSTS, 0xff);
+
+       while (err < 3) {
+               sl811_write(SL811_ADDR_A, 0x10);
+               sl811_write(SL811_LEN_A, len);
+               if (usb_pipeout(pipe) && len)
+                       sl811_write_buf(0x10, buffer, len);
+
+               if (!(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) &&
+                   sl811_read(SL811_SOFCNTDIV)*64 < calc_needed_buswidth(len, need_preamble))
+                       ctrl |= SL811_USB_CTRL_SOF;
+               else
+                       ctrl &= ~SL811_USB_CTRL_SOF;
+
+               sl811_write(SL811_CTRL_A, ctrl);
+               while (!(sl811_read(SL811_INTRSTS) & SL811_INTR_DONE_A)) {
+                       if (5*CFG_HZ < get_timer(time_start)) {
+                               printf("USB transmit timed out\n");
+                               return -USB_ST_CRC_ERR;
+                       }
+               }
+
+               sl811_write(SL811_INTRSTS, 0xff);
+               status = sl811_read(SL811_STS_A);
+
+               if (status & SL811_USB_STS_ACK) {
+                       int remainder = sl811_read(SL811_CNT_A);
+                       if (remainder) {
+                               PDEBUG(0, "usb transfer remainder = %d\n", remainder);
+                               len -= remainder;
+                       }
+                       if (usb_pipein(pipe) && len)
+                               sl811_read_buf(0x10, buffer, len);
+                       return len;
+               }
+
+               if ((status & SL811_USB_STS_NAK) == SL811_USB_STS_NAK)
+                       continue;
+
+               PDEBUG(0, "usb transfer error %#x\n", (int)status);
+               err++;
+       }
+
+       err = 0;
+
+       if (status & SL811_USB_STS_ERROR)
+               err |= USB_ST_BUF_ERR;
+       if (status & SL811_USB_STS_TIMEOUT)
+               err |= USB_ST_CRC_ERR;
+       if (status & SL811_USB_STS_STALL)
+               err |= USB_ST_STALLED;
+
+       return -err;
+}
+
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+                   int len)
+{
+       int dir_out = usb_pipeout(pipe);
+       int ep = usb_pipeendpoint(pipe);
+       int max = usb_maxpacket(dev, pipe);
+       int done = 0;
+
+       PDEBUG(7, "dev = %ld pipe = %ld buf = %p size = %d dir_out = %d\n",
+              usb_pipedevice(pipe), usb_pipeendpoint(pipe), buffer, len, dir_out);
+
+       dev->status = 0;
+
+       sl811_write(SL811_DEV_A, usb_pipedevice(pipe));
+       sl811_write(SL811_PIDEP_A, PIDEP(!dir_out ? USB_PID_IN : USB_PID_OUT, ep));
+       while (done < len) {
+               int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done,
+                                           max > len - done ? len - done : max);
+               if (res < 0) {
+                       dev->status = -res;
+                       return res;
+               }
+
+               if (!dir_out && res < max) /* short packet */
+                       break;
+
+               done += res;
+               usb_dotoggle(dev, ep, dir_out);
+       }
+
+       dev->act_len = done;
+
+       return 0;
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+                      int len,struct devrequest *setup)
+{
+       int done = 0;
+       int devnum = usb_pipedevice(pipe);
+       int ep = usb_pipeendpoint(pipe);
+
+       dev->status = 0;
+
+       if (devnum == root_hub_devnum)
+               return sl811_rh_submit_urb(dev, pipe, buffer, len, setup);
+
+       PDEBUG(7, "dev = %d pipe = %ld buf = %p size = %d rt = %#x req = %#x bus = %i\n",
+              devnum, ep, buffer, len, (int)setup->requesttype,
+              (int)setup->request, sl811_read(SL811_SOFCNTDIV)*64);
+
+       sl811_write(SL811_DEV_A, devnum);
+       sl811_write(SL811_PIDEP_A, PIDEP(USB_PID_SETUP, ep));
+       /* setup phase */
+       usb_settoggle(dev, ep, 1, 0);
+       if (sl811_send_packet(dev, usb_sndctrlpipe(dev, ep),
+                             (__u8*)setup, sizeof(*setup)) == sizeof(*setup)) {
+               int dir_in = usb_pipein(pipe);
+               int max = usb_maxpacket(dev, pipe);
+
+               /* data phase */
+               sl811_write(SL811_PIDEP_A,
+                           PIDEP(dir_in ? USB_PID_IN : USB_PID_OUT, ep));
+               usb_settoggle(dev, ep, usb_pipeout(pipe), 1);
+               while (done < len) {
+                       int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done,
+                                                   max > len - done ? len - done : max);
+                       if (res < 0) {
+                               PDEBUG(0, "status data failed!\n");
+                               dev->status = -res;
+                               return 0;
+                       }
+                       done += res;
+                       usb_dotoggle(dev, ep, usb_pipeout(pipe));
+                       if (dir_in && res < max) /* short packet */
+                               break;
+               }
+
+               /* status phase */
+               sl811_write(SL811_PIDEP_A,
+                           PIDEP(!dir_in ? USB_PID_IN : USB_PID_OUT, ep));
+               usb_settoggle(dev, ep, !usb_pipeout(pipe), 1);
+               if (sl811_send_packet(dev,
+                                     !dir_in ? usb_rcvctrlpipe(dev, ep) :
+                                     usb_sndctrlpipe(dev, ep),
+                                     0, 0) < 0) {
+                       PDEBUG(0, "status phase failed!\n");
+                       dev->status = -1;
+               }
+       } else {
+               PDEBUG(0, "setup phase failed!\n");
+               dev->status = -1;
+       }
+
+       dev->act_len = done;
+
+       return done;
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+                  int len, int interval)
+{
+       PDEBUG(0, "dev = %p pipe = %#lx buf = %p size = %d int = %d\n", dev, pipe,
+              buffer, len, interval);
+       return -1;
+}
+
+/*
+ * SL811 Virtual Root Hub
+ */
+
+/* Device descriptor */
+static __u8 sl811_rh_dev_des[] =
+{
+       0x12,       /*  __u8  bLength; */
+       0x01,       /*  __u8  bDescriptorType; Device */
+       0x10,       /*  __u16 bcdUSB; v1.1 */
+       0x01,
+       0x09,       /*  __u8  bDeviceClass; HUB_CLASSCODE */
+       0x00,       /*  __u8  bDeviceSubClass; */
+       0x00,       /*  __u8  bDeviceProtocol; */
+       0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
+       0x00,       /*  __u16 idVendor; */
+       0x00,
+       0x00,       /*  __u16 idProduct; */
+       0x00,
+       0x00,       /*  __u16 bcdDevice; */
+       0x00,
+       0x00,       /*  __u8  iManufacturer; */
+       0x02,       /*  __u8  iProduct; */
+       0x01,       /*  __u8  iSerialNumber; */
+       0x01        /*  __u8  bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 sl811_rh_config_des[] =
+{
+       0x09,       /*  __u8  bLength; */
+       0x02,       /*  __u8  bDescriptorType; Configuration */
+       0x19,       /*  __u16 wTotalLength; */
+       0x00,
+       0x01,       /*  __u8  bNumInterfaces; */
+       0x01,       /*  __u8  bConfigurationValue; */
+       0x00,       /*  __u8  iConfiguration; */
+       0x40,       /*  __u8  bmAttributes;
+                   Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup,
+                   4..0: resvd */
+       0x00,       /*  __u8  MaxPower; */
+
+       /* interface */
+       0x09,       /*  __u8  if_bLength; */
+       0x04,       /*  __u8  if_bDescriptorType; Interface */
+       0x00,       /*  __u8  if_bInterfaceNumber; */
+       0x00,       /*  __u8  if_bAlternateSetting; */
+       0x01,       /*  __u8  if_bNumEndpoints; */
+       0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+       0x00,       /*  __u8  if_bInterfaceSubClass; */
+       0x00,       /*  __u8  if_bInterfaceProtocol; */
+       0x00,       /*  __u8  if_iInterface; */
+
+       /* endpoint */
+       0x07,       /*  __u8  ep_bLength; */
+       0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
+       0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+       0x03,       /*  __u8  ep_bmAttributes; Interrupt */
+       0x08,       /*  __u16 ep_wMaxPacketSize; */
+       0x00,
+       0xff        /*  __u8  ep_bInterval; 255 ms */
+};
+
+/* root hub class descriptor*/
+static __u8 sl811_rh_hub_des[] =
+{
+       0x09,                   /*  __u8  bLength; */
+       0x29,                   /*  __u8  bDescriptorType; Hub-descriptor */
+       0x01,                   /*  __u8  bNbrPorts; */
+       0x00,                   /* __u16  wHubCharacteristics; */
+       0x00,
+       0x50,                   /*  __u8  bPwrOn2pwrGood; 2ms */
+       0x00,                   /*  __u8  bHubContrCurrent; 0 mA */
+       0xfc,                   /*  __u8  DeviceRemovable; *** 7 Ports max *** */
+       0xff                    /*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+/*
+ * helper routine for returning string descriptors in UTF-16LE
+ * input can actually be ISO-8859-1; ASCII is its 7-bit subset
+ */
+static int ascii2utf (char *s, u8 *utf, int utfmax)
+{
+       int retval;
+
+       for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) {
+               *utf++ = *s++;
+               *utf++ = 0;
+       }
+       return retval;
+}
+
+/*
+ * root_hub_string is used by each host controller's root hub code,
+ * so that they're identified consistently throughout the system.
+ */
+static int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
+{
+       char buf [30];
+
+       /* assert (len > (2 * (sizeof (buf) + 1)));
+          assert (strlen (type) <= 8);*/
+
+       /* language ids */
+       if (id == 0) {
+               *data++ = 4; *data++ = 3;       /* 4 bytes data */
+               *data++ = 0; *data++ = 0;       /* some language id */
+               return 4;
+
+       /* serial number */
+       } else if (id == 1) {
+               sprintf (buf, "%#x", serial);
+
+       /* product description */
+       } else if (id == 2) {
+               sprintf (buf, "USB %s Root Hub", type);
+
+       /* id 3 == vendor description */
+
+       /* unsupported IDs --> "stall" */
+       } else
+           return 0;
+
+       ascii2utf (buf, data + 2, len - 2);
+       data [0] = 2 + strlen(buf) * 2;
+       data [1] = 3;
+       return data [0];
+}
+
+/* helper macro */
+#define OK(x)  len = (x); break
+
+/*
+ * This function handles all USB request to the the virtual root hub
+ */
+static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe,
+                              void *data, int buf_len, struct devrequest *cmd)
+{
+       __u8 data_buf[16];
+       __u8 *bufp = data_buf;
+       int len = 0;
+       int status = 0;
+
+       __u16 bmRType_bReq;
+       __u16 wValue;
+       __u16 wIndex;
+       __u16 wLength;
+
+       if (usb_pipeint(pipe)) {
+               PDEBUG(0, "interrupt transfer unimplemented!\n");
+               return 0;
+       }
+
+       bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
+       wValue        = le16_to_cpu (cmd->value);
+       wIndex        = le16_to_cpu (cmd->index);
+       wLength       = le16_to_cpu (cmd->length);
+
+       PDEBUG(5, "submit rh urb, req = %d(%x) val = %#x index = %#x len=%d\n",
+              bmRType_bReq, bmRType_bReq, wValue, wIndex, wLength);
+
+       /* Request Destination:
+                  without flags: Device,
+                  USB_RECIP_INTERFACE: interface,
+                  USB_RECIP_ENDPOINT: endpoint,
+                  USB_TYPE_CLASS means HUB here,
+                  USB_RECIP_OTHER | USB_TYPE_CLASS  almost ever means HUB_PORT here
+       */
+       switch (bmRType_bReq) {
+       case RH_GET_STATUS:
+               *(__u16 *)bufp = cpu_to_le16(1);
+               OK(2);
+
+       case RH_GET_STATUS | USB_RECIP_INTERFACE:
+               *(__u16 *)bufp = cpu_to_le16(0);
+               OK(2);
+
+       case RH_GET_STATUS | USB_RECIP_ENDPOINT:
+               *(__u16 *)bufp = cpu_to_le16(0);
+               OK(2);
+
+       case RH_GET_STATUS | USB_TYPE_CLASS:
+               *(__u32 *)bufp = cpu_to_le32(0);
+               OK(4);
+
+       case RH_GET_STATUS | USB_RECIP_OTHER | USB_TYPE_CLASS:
+               *(__u32 *)bufp = cpu_to_le32(rh_status.wPortChange<<16 | rh_status.wPortStatus);
+               OK(4);
+
+       case RH_CLEAR_FEATURE | USB_RECIP_ENDPOINT:
+               switch (wValue) {
+               case 1:
+                       OK(0);
+               }
+               break;
+
+       case RH_CLEAR_FEATURE | USB_TYPE_CLASS:
+               switch (wValue) {
+               case C_HUB_LOCAL_POWER:
+                       OK(0);
+
+               case C_HUB_OVER_CURRENT:
+                       OK(0);
+               }
+               break;
+
+       case RH_CLEAR_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
+               switch (wValue) {
+               case USB_PORT_FEAT_ENABLE:
+                       rh_status.wPortStatus &= ~USB_PORT_STAT_ENABLE;
+                       OK(0);
+
+               case USB_PORT_FEAT_SUSPEND:
+                       rh_status.wPortStatus &= ~USB_PORT_STAT_SUSPEND;
+                       OK(0);
+
+               case USB_PORT_FEAT_POWER:
+                       rh_status.wPortStatus &= ~USB_PORT_STAT_POWER;
+                       OK(0);
+
+               case USB_PORT_FEAT_C_CONNECTION:
+                       rh_status.wPortChange &= ~USB_PORT_STAT_C_CONNECTION;
+                       OK(0);
+
+               case USB_PORT_FEAT_C_ENABLE:
+                       rh_status.wPortChange &= ~USB_PORT_STAT_C_ENABLE;
+                       OK(0);
+
+               case USB_PORT_FEAT_C_SUSPEND:
+                       rh_status.wPortChange &= ~USB_PORT_STAT_C_SUSPEND;
+                       OK(0);
+
+               case USB_PORT_FEAT_C_OVER_CURRENT:
+                       rh_status.wPortChange &= ~USB_PORT_STAT_C_OVERCURRENT;
+                       OK(0);
+
+               case USB_PORT_FEAT_C_RESET:
+                       rh_status.wPortChange &= ~USB_PORT_STAT_C_RESET;
+                       OK(0);
+               }
+               break;
+
+       case RH_SET_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
+               switch (wValue) {
+               case USB_PORT_FEAT_SUSPEND:
+                       rh_status.wPortStatus |= USB_PORT_STAT_SUSPEND;
+                       OK(0);
+
+               case USB_PORT_FEAT_RESET:
+                       rh_status.wPortStatus |= USB_PORT_STAT_RESET;
+                       rh_status.wPortChange = 0;
+                       rh_status.wPortChange |= USB_PORT_STAT_C_RESET;
+                       rh_status.wPortStatus &= ~USB_PORT_STAT_RESET;
+                       rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
+                       OK(0);
+
+               case USB_PORT_FEAT_POWER:
+                       rh_status.wPortStatus |= USB_PORT_STAT_POWER;
+                       OK(0);
+
+               case USB_PORT_FEAT_ENABLE:
+                       rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
+                       OK(0);
+               }
+               break;
+
+       case RH_SET_ADDRESS:
+               root_hub_devnum = wValue;
+               OK(0);
+
+       case RH_GET_DESCRIPTOR:
+               switch ((wValue & 0xff00) >> 8) {
+               case USB_DT_DEVICE:
+                       len = sizeof(sl811_rh_dev_des);
+                       bufp = sl811_rh_dev_des;
+                       OK(len);
+
+               case USB_DT_CONFIG:
+                       len = sizeof(sl811_rh_config_des);
+                       bufp = sl811_rh_config_des;
+                       OK(len);
+
+               case USB_DT_STRING:
+                       len = usb_root_hub_string(wValue & 0xff, (int)(long)0,  "SL811HS", data, wLength);
+                       if (len > 0) {
+                               bufp = data;
+                               OK(len);
+                       }
+
+               default:
+                       status = -32;
+               }
+               break;
+
+       case RH_GET_DESCRIPTOR | USB_TYPE_CLASS:
+               len = sizeof(sl811_rh_hub_des);
+               bufp = sl811_rh_hub_des;
+               OK(len);
+
+       case RH_GET_CONFIGURATION:
+               bufp[0] = 0x01;
+               OK(1);
+
+       case RH_SET_CONFIGURATION:
+               OK(0);
+
+       default:
+               PDEBUG(1, "unsupported root hub command\n");
+               status = -32;
+       }
+
+       len = min(len, buf_len);
+       if (data != bufp)
+               memcpy(data, bufp, len);
+
+       PDEBUG(5, "len = %d, status = %d\n", len, status);
+
+       usb_dev->status = status;
+       usb_dev->act_len = len;
+
+       return status == 0 ? len : status;
+}
+
+#endif /* CONFIG_USB_SL811HS */
diff --git a/drivers/usb/usb_ohci.c b/drivers/usb/usb_ohci.c
new file mode 100644 (file)
index 0000000..cfa384e
--- /dev/null
@@ -0,0 +1,1923 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB on the AT91RM9200 and PCI bus.
+ *
+ * Interrupt support is added. Now, it has been tested
+ * on ULI1575 chip and works well with USB keyboard.
+ *
+ * (C) Copyright 2007
+ * Zhang Wei, Freescale Semiconductor, Inc. <wei.zhang@freescale.com>
+ *
+ * (C) Copyright 2003
+ * Gary Jennejohn, DENX Software Engineering <gj@denx.de>
+ *
+ * Note: Much of this code has been derived from Linux 2.4
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell
+ *
+ * Modified for the MP2USB by (C) Copyright 2005 Eric Benard
+ * ebenard@eukrea.com - based on s3c24x0's driver
+ *
+ * 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
+ *
+ */
+/*
+ * IMPORTANT NOTES
+ * 1 - Read doc/README.generic_usb_ohci
+ * 2 - this driver is intended for use with USB Mass Storage Devices
+ *     (BBB) and USB keyboard. There is NO support for Isochronous pipes!
+ * 2 - when running on a PQFP208 AT91RM9200, define CONFIG_AT91C_PQFP_UHPBUG
+ *     to activate workaround for bug #41 or this driver will NOT work!
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_USB_OHCI_NEW
+
+#include <asm/byteorder.h>
+
+#if defined(CONFIG_PCI_OHCI)
+# include <pci.h>
+#endif
+
+#include <malloc.h>
+#include <usb.h>
+#include "usb_ohci.h"
+
+#ifdef CONFIG_AT91RM9200
+#include <asm/arch/hardware.h> /* needed for AT91_USB_HOST_BASE */
+#endif
+
+#if defined(CONFIG_ARM920T) || \
+    defined(CONFIG_S3C2400) || \
+    defined(CONFIG_S3C2410) || \
+    defined(CONFIG_440EP) || \
+    defined(CONFIG_PCI_OHCI) || \
+    defined(CONFIG_MPC5200)
+# define OHCI_USE_NPS          /* force NoPowerSwitching mode */
+#endif
+
+#undef OHCI_VERBOSE_DEBUG      /* not always helpful */
+#undef DEBUG
+#undef SHOW_INFO
+#undef OHCI_FILL_TRACE
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define OHCI_CONTROL_INIT \
+       (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
+
+/*
+ * e.g. PCI controllers need this
+ */
+#ifdef CFG_OHCI_SWAP_REG_ACCESS
+# define readl(a) __swap_32(*((vu_long *)(a)))
+# define writel(a, b) (*((vu_long *)(b)) = __swap_32((vu_long)a))
+#else
+# define readl(a) (*((vu_long *)(a)))
+# define writel(a, b) (*((vu_long *)(b)) = ((vu_long)a))
+#endif /* CFG_OHCI_SWAP_REG_ACCESS */
+
+#define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+
+#ifdef CONFIG_PCI_OHCI
+static struct pci_device_id ohci_pci_ids[] = {
+       {0x10b9, 0x5237},       /* ULI1575 PCI OHCI module ids */
+       {0x1033, 0x0035},       /* NEC PCI OHCI module ids */
+       /* Please add supported PCI OHCI controller ids here */
+       {0, 0}
+};
+#endif
+
+#ifdef DEBUG
+#define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg)
+#else
+#define dbg(format, arg...) do {} while(0)
+#endif /* DEBUG */
+#define err(format, arg...) printf("ERROR: " format "\n", ## arg)
+#undef SHOW_INFO
+#ifdef SHOW_INFO
+#define info(format, arg...) printf("INFO: " format "\n", ## arg)
+#else
+#define info(format, arg...) do {} while(0)
+#endif
+
+#ifdef CFG_OHCI_BE_CONTROLLER
+# define m16_swap(x) cpu_to_be16(x)
+# define m32_swap(x) cpu_to_be32(x)
+#else
+# define m16_swap(x) cpu_to_le16(x)
+# define m32_swap(x) cpu_to_le32(x)
+#endif /* CFG_OHCI_BE_CONTROLLER */
+
+/* global ohci_t */
+static ohci_t gohci;
+/* this must be aligned to a 256 byte boundary */
+struct ohci_hcca ghcca[1];
+/* a pointer to the aligned storage */
+struct ohci_hcca *phcca;
+/* this allocates EDs for all possible endpoints */
+struct ohci_device ohci_dev;
+/* RHSC flag */
+int got_rhsc;
+/* device which was disconnected */
+struct usb_device *devgone;
+
+/*-------------------------------------------------------------------------*/
+
+/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
+ * The erratum (#4) description is incorrect.  AMD's workaround waits
+ * till some bits (mostly reserved) are clear; ok for all revs.
+ */
+#define OHCI_QUIRK_AMD756 0xabcd
+#define read_roothub(hc, register, mask) ({ \
+       u32 temp = readl (&hc->regs->roothub.register); \
+       if (hc->flags & OHCI_QUIRK_AMD756) \
+               while (temp & mask) \
+                       temp = readl (&hc->regs->roothub.register); \
+       temp; })
+
+static u32 roothub_a (struct ohci *hc)
+       { return read_roothub (hc, a, 0xfc0fe000); }
+static inline u32 roothub_b (struct ohci *hc)
+       { return readl (&hc->regs->roothub.b); }
+static inline u32 roothub_status (struct ohci *hc)
+       { return readl (&hc->regs->roothub.status); }
+static u32 roothub_portstatus (struct ohci *hc, int i)
+       { return read_roothub (hc, portstatus [i], 0xffe0fce0); }
+
+/* forward declaration */
+static int hc_interrupt (void);
+static void
+td_submit_job (struct usb_device * dev, unsigned long pipe, void * buffer,
+       int transfer_len, struct devrequest * setup, urb_priv_t * urb, int interval);
+
+/*-------------------------------------------------------------------------*
+ * URB support functions
+ *-------------------------------------------------------------------------*/
+
+/* free HCD-private data associated with this URB */
+
+static void urb_free_priv (urb_priv_t * urb)
+{
+       int             i;
+       int             last;
+       struct td       * td;
+
+       last = urb->length - 1;
+       if (last >= 0) {
+               for (i = 0; i <= last; i++) {
+                       td = urb->td[i];
+                       if (td) {
+                               td->usb_dev = NULL;
+                               urb->td[i] = NULL;
+                       }
+               }
+       }
+       free(urb);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+static int sohci_get_current_frame_number (struct usb_device * dev);
+
+/* debug| print the main components of an URB
+ * small: 0) header + data packets 1) just header */
+
+static void pkt_print (urb_priv_t *purb, struct usb_device * dev,
+       unsigned long pipe, void * buffer,
+       int transfer_len, struct devrequest * setup, char * str, int small)
+{
+       dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d/%d stat:%#lx",
+                       str,
+                       sohci_get_current_frame_number (dev),
+                       usb_pipedevice (pipe),
+                       usb_pipeendpoint (pipe),
+                       usb_pipeout (pipe)? 'O': 'I',
+                       usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):
+                               (usb_pipecontrol (pipe)? "CTRL": "BULK"),
+                       (purb ? purb->actual_length : 0),
+                       transfer_len, dev->status);
+#ifdef OHCI_VERBOSE_DEBUG
+       if (!small) {
+               int i, len;
+
+               if (usb_pipecontrol (pipe)) {
+                       printf (__FILE__ ": cmd(8):");
+                       for (i = 0; i < 8 ; i++)
+                               printf (" %02x", ((__u8 *) setup) [i]);
+                       printf ("\n");
+               }
+               if (transfer_len > 0 && buffer) {
+                       printf (__FILE__ ": data(%d/%d):",
+                               (purb ? purb->actual_length : 0),
+                               transfer_len);
+                       len = usb_pipeout (pipe)?
+                                       transfer_len:
+                                       (purb ? purb->actual_length : 0);
+                       for (i = 0; i < 16 && i < len; i++)
+                               printf (" %02x", ((__u8 *) buffer) [i]);
+                       printf ("%s\n", i < len? "...": "");
+               }
+       }
+#endif
+}
+
+/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
+void ep_print_int_eds (ohci_t *ohci, char * str) {
+       int i, j;
+        __u32 * ed_p;
+       for (i= 0; i < 32; i++) {
+               j = 5;
+               ed_p = &(ohci->hcca->int_table [i]);
+               if (*ed_p == 0)
+                   continue;
+               printf (__FILE__ ": %s branch int %2d(%2x):", str, i, i);
+               while (*ed_p != 0 && j--) {
+                       ed_t *ed = (ed_t *)m32_swap(ed_p);
+                       printf (" ed: %4x;", ed->hwINFO);
+                       ed_p = &ed->hwNextED;
+               }
+               printf ("\n");
+       }
+}
+
+static void ohci_dump_intr_mask (char *label, __u32 mask)
+{
+       dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+               label,
+               mask,
+               (mask & OHCI_INTR_MIE) ? " MIE" : "",
+               (mask & OHCI_INTR_OC) ? " OC" : "",
+               (mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+               (mask & OHCI_INTR_FNO) ? " FNO" : "",
+               (mask & OHCI_INTR_UE) ? " UE" : "",
+               (mask & OHCI_INTR_RD) ? " RD" : "",
+               (mask & OHCI_INTR_SF) ? " SF" : "",
+               (mask & OHCI_INTR_WDH) ? " WDH" : "",
+               (mask & OHCI_INTR_SO) ? " SO" : ""
+               );
+}
+
+static void maybe_print_eds (char *label, __u32 value)
+{
+       ed_t *edp = (ed_t *)value;
+
+       if (value) {
+               dbg ("%s %08x", label, value);
+               dbg ("%08x", edp->hwINFO);
+               dbg ("%08x", edp->hwTailP);
+               dbg ("%08x", edp->hwHeadP);
+               dbg ("%08x", edp->hwNextED);
+       }
+}
+
+static char * hcfs2string (int state)
+{
+       switch (state) {
+               case OHCI_USB_RESET:    return "reset";
+               case OHCI_USB_RESUME:   return "resume";
+               case OHCI_USB_OPER:     return "operational";
+               case OHCI_USB_SUSPEND:  return "suspend";
+       }
+       return "?";
+}
+
+/* dump control and status registers */
+static void ohci_dump_status (ohci_t *controller)
+{
+       struct ohci_regs        *regs = controller->regs;
+       __u32                   temp;
+
+       temp = readl (&regs->revision) & 0xff;
+       if (temp != 0x10)
+               dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+       temp = readl (&regs->control);
+       dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+               (temp & OHCI_CTRL_RWE) ? " RWE" : "",
+               (temp & OHCI_CTRL_RWC) ? " RWC" : "",
+               (temp & OHCI_CTRL_IR) ? " IR" : "",
+               hcfs2string (temp & OHCI_CTRL_HCFS),
+               (temp & OHCI_CTRL_BLE) ? " BLE" : "",
+               (temp & OHCI_CTRL_CLE) ? " CLE" : "",
+               (temp & OHCI_CTRL_IE) ? " IE" : "",
+               (temp & OHCI_CTRL_PLE) ? " PLE" : "",
+               temp & OHCI_CTRL_CBSR
+               );
+
+       temp = readl (&regs->cmdstatus);
+       dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+               (temp & OHCI_SOC) >> 16,
+               (temp & OHCI_OCR) ? " OCR" : "",
+               (temp & OHCI_BLF) ? " BLF" : "",
+               (temp & OHCI_CLF) ? " CLF" : "",
+               (temp & OHCI_HCR) ? " HCR" : ""
+               );
+
+       ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
+       ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
+
+       maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
+
+       maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
+       maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
+
+       maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
+       maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
+
+       maybe_print_eds ("donehead", readl (&regs->donehead));
+}
+
+static void ohci_dump_roothub (ohci_t *controller, int verbose)
+{
+       __u32                   temp, ndp, i;
+
+       temp = roothub_a (controller);
+       ndp = (temp & RH_A_NDP);
+#ifdef CONFIG_AT91C_PQFP_UHPBUG
+       ndp = (ndp == 2) ? 1:0;
+#endif
+       if (verbose) {
+               dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+                       ((temp & RH_A_POTPGT) >> 24) & 0xff,
+                       (temp & RH_A_NOCP) ? " NOCP" : "",
+                       (temp & RH_A_OCPM) ? " OCPM" : "",
+                       (temp & RH_A_DT) ? " DT" : "",
+                       (temp & RH_A_NPS) ? " NPS" : "",
+                       (temp & RH_A_PSM) ? " PSM" : "",
+                       ndp
+                       );
+               temp = roothub_b (controller);
+               dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
+                       temp,
+                       (temp & RH_B_PPCM) >> 16,
+                       (temp & RH_B_DR)
+                       );
+               temp = roothub_status (controller);
+               dbg ("roothub.status: %08x%s%s%s%s%s%s",
+                       temp,
+                       (temp & RH_HS_CRWE) ? " CRWE" : "",
+                       (temp & RH_HS_OCIC) ? " OCIC" : "",
+                       (temp & RH_HS_LPSC) ? " LPSC" : "",
+                       (temp & RH_HS_DRWE) ? " DRWE" : "",
+                       (temp & RH_HS_OCI) ? " OCI" : "",
+                       (temp & RH_HS_LPS) ? " LPS" : ""
+                       );
+       }
+
+       for (i = 0; i < ndp; i++) {
+               temp = roothub_portstatus (controller, i);
+               dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
+                       i,
+                       temp,
+                       (temp & RH_PS_PRSC) ? " PRSC" : "",
+                       (temp & RH_PS_OCIC) ? " OCIC" : "",
+                       (temp & RH_PS_PSSC) ? " PSSC" : "",
+                       (temp & RH_PS_PESC) ? " PESC" : "",
+                       (temp & RH_PS_CSC) ? " CSC" : "",
+
+                       (temp & RH_PS_LSDA) ? " LSDA" : "",
+                       (temp & RH_PS_PPS) ? " PPS" : "",
+                       (temp & RH_PS_PRS) ? " PRS" : "",
+                       (temp & RH_PS_POCI) ? " POCI" : "",
+                       (temp & RH_PS_PSS) ? " PSS" : "",
+
+                       (temp & RH_PS_PES) ? " PES" : "",
+                       (temp & RH_PS_CCS) ? " CCS" : ""
+                       );
+       }
+}
+
+static void ohci_dump (ohci_t *controller, int verbose)
+{
+       dbg ("OHCI controller usb-%s state", controller->slot_name);
+
+       /* dumps some of the state we know about */
+       ohci_dump_status (controller);
+       if (verbose)
+               ep_print_int_eds (controller, "hcca");
+       dbg ("hcca frame #%04x", controller->hcca->frame_no);
+       ohci_dump_roothub (controller, 1);
+
+#endif /* DEBUG */
+
+/*-------------------------------------------------------------------------*
+ * Interface functions (URB)
+ *-------------------------------------------------------------------------*/
+
+/* get a transfer request */
+
+int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
+{
+       ohci_t *ohci;
+       ed_t * ed;
+       urb_priv_t *purb_priv = urb;
+       int i, size = 0;
+       struct usb_device *dev = urb->dev;
+       unsigned long pipe = urb->pipe;
+       void *buffer = urb->transfer_buffer;
+       int transfer_len = urb->transfer_buffer_length;
+       int interval = urb->interval;
+
+       ohci = &gohci;
+
+       /* when controller's hung, permit only roothub cleanup attempts
+        * such as powering down ports */
+       if (ohci->disabled) {
+               err("sohci_submit_job: EPIPE");
+               return -1;
+       }
+
+       /* we're about to begin a new transaction here so mark the URB unfinished */
+       urb->finished = 0;
+
+       /* every endpoint has a ed, locate and fill it */
+       if (!(ed = ep_add_ed (dev, pipe, interval, 1))) {
+               err("sohci_submit_job: ENOMEM");
+               return -1;
+       }
+
+       /* for the private part of the URB we need the number of TDs (size) */
+       switch (usb_pipetype (pipe)) {
+               case PIPE_BULK: /* one TD for every 4096 Byte */
+                       size = (transfer_len - 1) / 4096 + 1;
+                       break;
+               case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
+                       size = (transfer_len == 0)? 2:
+                                               (transfer_len - 1) / 4096 + 3;
+                       break;
+               case PIPE_INTERRUPT: /* 1 TD */
+                       size = 1;
+                       break;
+       }
+
+       ed->purb = urb;
+
+       if (size >= (N_URB_TD - 1)) {
+               err("need %d TDs, only have %d", size, N_URB_TD);
+               return -1;
+       }
+       purb_priv->pipe = pipe;
+
+       /* fill the private part of the URB */
+       purb_priv->length = size;
+       purb_priv->ed = ed;
+       purb_priv->actual_length = 0;
+
+       /* allocate the TDs */
+       /* note that td[0] was allocated in ep_add_ed */
+       for (i = 0; i < size; i++) {
+               purb_priv->td[i] = td_alloc (dev);
+               if (!purb_priv->td[i]) {
+                       purb_priv->length = i;
+                       urb_free_priv (purb_priv);
+                       err("sohci_submit_job: ENOMEM");
+                       return -1;
+               }
+       }
+
+       if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
+               urb_free_priv (purb_priv);
+               err("sohci_submit_job: EINVAL");
+               return -1;
+       }
+
+       /* link the ed into a chain if is not already */
+       if (ed->state != ED_OPER)
+               ep_link (ohci, ed);
+
+       /* fill the TDs and link it to the ed */
+       td_submit_job(dev, pipe, buffer, transfer_len, setup, purb_priv, interval);
+
+       return 0;
+}
+
+static inline int sohci_return_job(struct ohci *hc, urb_priv_t *urb)
+{
+       struct ohci_regs *regs = hc->regs;
+
+       switch (usb_pipetype (urb->pipe)) {
+       case PIPE_INTERRUPT:
+               /* implicitly requeued */
+               if (urb->dev->irq_handle &&
+                               (urb->dev->irq_act_len = urb->actual_length)) {
+                       writel (OHCI_INTR_WDH, &regs->intrenable);
+                       readl (&regs->intrenable); /* PCI posting flush */
+                       urb->dev->irq_handle(urb->dev);
+                       writel (OHCI_INTR_WDH, &regs->intrdisable);
+                       readl (&regs->intrdisable); /* PCI posting flush */
+               }
+               urb->actual_length = 0;
+               td_submit_job (
+                               urb->dev,
+                               urb->pipe,
+                               urb->transfer_buffer,
+                               urb->transfer_buffer_length,
+                               NULL,
+                               urb,
+                               urb->interval);
+               break;
+       case PIPE_CONTROL:
+       case PIPE_BULK:
+               break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+/* tell us the current USB frame number */
+
+static int sohci_get_current_frame_number (struct usb_device *usb_dev)
+{
+       ohci_t *ohci = &gohci;
+
+       return m16_swap (ohci->hcca->frame_no);
+}
+#endif
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/
+
+/* search for the right branch to insert an interrupt ed into the int tree
+ * do some load ballancing;
+ * returns the branch and
+ * sets the interval to interval = 2^integer (ld (interval)) */
+
+static int ep_int_ballance (ohci_t * ohci, int interval, int load)
+{
+       int i, branch = 0;
+
+       /* search for the least loaded interrupt endpoint
+        * branch of all 32 branches
+        */
+       for (i = 0; i < 32; i++)
+               if (ohci->ohci_int_load [branch] > ohci->ohci_int_load [i])
+                       branch = i;
+
+       branch = branch % interval;
+       for (i = branch; i < 32; i += interval)
+               ohci->ohci_int_load [i] += load;
+
+       return branch;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*  2^int( ld (inter)) */
+
+static int ep_2_n_interval (int inter)
+{
+       int i;
+       for (i = 0; ((inter >> i) > 1 ) && (i < 5); i++);
+       return 1 << i;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* the int tree is a binary tree
+ * in order to process it sequentially the indexes of the branches have to be mapped
+ * the mapping reverses the bits of a word of num_bits length */
+
+static int ep_rev (int num_bits, int word)
+{
+       int i, wout = 0;
+
+       for (i = 0; i < num_bits; i++)
+               wout |= (((word >> i) & 1) << (num_bits - i - 1));
+       return wout;
+}
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/
+
+/* link an ed into one of the HC chains */
+
+static int ep_link (ohci_t *ohci, ed_t *edi)
+{
+       volatile ed_t *ed = edi;
+       int int_branch;
+       int i;
+       int inter;
+       int interval;
+       int load;
+       __u32 * ed_p;
+
+       ed->state = ED_OPER;
+       ed->int_interval = 0;
+
+       switch (ed->type) {
+       case PIPE_CONTROL:
+               ed->hwNextED = 0;
+               if (ohci->ed_controltail == NULL) {
+                       writel (ed, &ohci->regs->ed_controlhead);
+               } else {
+                       ohci->ed_controltail->hwNextED = m32_swap ((unsigned long)ed);
+               }
+               ed->ed_prev = ohci->ed_controltail;
+               if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
+                       !ohci->ed_rm_list[1] && !ohci->sleeping) {
+                       ohci->hc_control |= OHCI_CTRL_CLE;
+                       writel (ohci->hc_control, &ohci->regs->control);
+               }
+               ohci->ed_controltail = edi;
+               break;
+
+       case PIPE_BULK:
+               ed->hwNextED = 0;
+               if (ohci->ed_bulktail == NULL) {
+                       writel (ed, &ohci->regs->ed_bulkhead);
+               } else {
+                       ohci->ed_bulktail->hwNextED = m32_swap ((unsigned long)ed);
+               }
+               ed->ed_prev = ohci->ed_bulktail;
+               if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
+                       !ohci->ed_rm_list[1] && !ohci->sleeping) {
+                       ohci->hc_control |= OHCI_CTRL_BLE;
+                       writel (ohci->hc_control, &ohci->regs->control);
+               }
+               ohci->ed_bulktail = edi;
+               break;
+
+       case PIPE_INTERRUPT:
+               load = ed->int_load;
+               interval = ep_2_n_interval (ed->int_period);
+               ed->int_interval = interval;
+               int_branch = ep_int_ballance (ohci, interval, load);
+               ed->int_branch = int_branch;
+
+               for (i = 0; i < ep_rev (6, interval); i += inter) {
+                       inter = 1;
+                       for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) + int_branch]);
+                               (*ed_p != 0) && (((ed_t *)ed_p)->int_interval >= interval);
+                               ed_p = &(((ed_t *)ed_p)->hwNextED))
+                                       inter = ep_rev (6, ((ed_t *)ed_p)->int_interval);
+                       ed->hwNextED = *ed_p;
+                       *ed_p = m32_swap((unsigned long)ed);
+               }
+               break;
+       }
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* scan the periodic table to find and unlink this ED */
+static void periodic_unlink ( struct ohci *ohci, volatile struct ed *ed,
+               unsigned index, unsigned period)
+{
+       for (; index < NUM_INTS; index += period) {
+               __u32   *ed_p = &ohci->hcca->int_table [index];
+
+               /* ED might have been unlinked through another path */
+               while (*ed_p != 0) {
+                       if (((struct ed *)m32_swap ((unsigned long)ed_p)) == ed) {
+                               *ed_p = ed->hwNextED;
+                               break;
+                       }
+                       ed_p = & (((struct ed *)m32_swap ((unsigned long)ed_p))->hwNextED);
+               }
+       }
+}
+
+/* unlink an ed from one of the HC chains.
+ * just the link to the ed is unlinked.
+ * the link from the ed still points to another operational ed or 0
+ * so the HC can eventually finish the processing of the unlinked ed */
+
+static int ep_unlink (ohci_t *ohci, ed_t *edi)
+{
+       volatile ed_t *ed = edi;
+       int i;
+
+       ed->hwINFO |= m32_swap (OHCI_ED_SKIP);
+
+       switch (ed->type) {
+       case PIPE_CONTROL:
+               if (ed->ed_prev == NULL) {
+                       if (!ed->hwNextED) {
+                               ohci->hc_control &= ~OHCI_CTRL_CLE;
+                               writel (ohci->hc_control, &ohci->regs->control);
+                       }
+                       writel (m32_swap (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_controlhead);
+               } else {
+                       ed->ed_prev->hwNextED = ed->hwNextED;
+               }
+               if (ohci->ed_controltail == ed) {
+                       ohci->ed_controltail = ed->ed_prev;
+               } else {
+                       ((ed_t *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+               }
+               break;
+
+       case PIPE_BULK:
+               if (ed->ed_prev == NULL) {
+                       if (!ed->hwNextED) {
+                               ohci->hc_control &= ~OHCI_CTRL_BLE;
+                               writel (ohci->hc_control, &ohci->regs->control);
+                       }
+                       writel (m32_swap (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_bulkhead);
+               } else {
+                       ed->ed_prev->hwNextED = ed->hwNextED;
+               }
+               if (ohci->ed_bulktail == ed) {
+                       ohci->ed_bulktail = ed->ed_prev;
+               } else {
+                       ((ed_t *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+               }
+               break;
+
+       case PIPE_INTERRUPT:
+               periodic_unlink (ohci, ed, 0, 1);
+               for (i = ed->int_branch; i < 32; i += ed->int_interval)
+                   ohci->ohci_int_load[i] -= ed->int_load;
+               break;
+       }
+       ed->state = ED_UNLINK;
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* add/reinit an endpoint; this should be done once at the
+ * usb_set_configuration command, but the USB stack is a little bit
+ * stateless so we do it at every transaction if the state of the ed
+ * is ED_NEW then a dummy td is added and the state is changed to
+ * ED_UNLINK in all other cases the state is left unchanged the ed
+ * info fields are setted anyway even though most of them should not
+ * change
+ */
+static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe,
+               int interval, int load)
+{
+       td_t *td;
+       ed_t *ed_ret;
+       volatile ed_t *ed;
+
+       ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint (pipe) << 1) |
+                       (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))];
+
+       if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
+               err("ep_add_ed: pending delete");
+               /* pending delete request */
+               return NULL;
+       }
+
+       if (ed->state == ED_NEW) {
+               ed->hwINFO = m32_swap (OHCI_ED_SKIP); /* skip ed */
+               /* dummy td; end of td list for ed */
+               td = td_alloc (usb_dev);
+               ed->hwTailP = m32_swap ((unsigned long)td);
+               ed->hwHeadP = ed->hwTailP;
+               ed->state = ED_UNLINK;
+               ed->type = usb_pipetype (pipe);
+               ohci_dev.ed_cnt++;
+       }
+
+       ed->hwINFO = m32_swap (usb_pipedevice (pipe)
+                       | usb_pipeendpoint (pipe) << 7
+                       | (usb_pipeisoc (pipe)? 0x8000: 0)
+                       | (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000))
+                       | usb_pipeslow (pipe) << 13
+                       | usb_maxpacket (usb_dev, pipe) << 16);
+
+       if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
+               ed->int_period = interval;
+               ed->int_load = load;
+       }
+
+       return ed_ret;
+}
+
+/*-------------------------------------------------------------------------*
+ * TD handling functions
+ *-------------------------------------------------------------------------*/
+
+/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
+
+static void td_fill (ohci_t *ohci, unsigned int info,
+       void *data, int len,
+       struct usb_device *dev, int index, urb_priv_t *urb_priv)
+{
+       volatile td_t  *td, *td_pt;
+#ifdef OHCI_FILL_TRACE
+       int i;
+#endif
+
+       if (index > urb_priv->length) {
+               err("index > length");
+               return;
+       }
+       /* use this td as the next dummy */
+       td_pt = urb_priv->td [index];
+       td_pt->hwNextTD = 0;
+
+       /* fill the old dummy TD */
+       td = urb_priv->td [index] = (td_t *)(m32_swap (urb_priv->ed->hwTailP) & ~0xf);
+
+       td->ed = urb_priv->ed;
+       td->next_dl_td = NULL;
+       td->index = index;
+       td->data = (__u32)data;
+#ifdef OHCI_FILL_TRACE
+       if ((usb_pipetype(urb_priv->pipe) == PIPE_BULK) && usb_pipeout(urb_priv->pipe)) {
+               for (i = 0; i < len; i++)
+               printf("td->data[%d] %#2x ",i, ((unsigned char *)td->data)[i]);
+               printf("\n");
+       }
+#endif
+       if (!len)
+               data = 0;
+
+       td->hwINFO = m32_swap (info);
+       td->hwCBP = m32_swap ((unsigned long)data);
+       if (data)
+               td->hwBE = m32_swap ((unsigned long)(data + len - 1));
+       else
+               td->hwBE = 0;
+       td->hwNextTD = m32_swap ((unsigned long)td_pt);
+
+       /* append to queue */
+       td->ed->hwTailP = td->hwNextTD;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* prepare all TDs of a transfer */
+
+static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buffer,
+       int transfer_len, struct devrequest *setup, urb_priv_t *urb, int interval)
+{
+       ohci_t *ohci = &gohci;
+       int data_len = transfer_len;
+       void *data;
+       int cnt = 0;
+       __u32 info = 0;
+       unsigned int toggle = 0;
+
+       /* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
+       if(usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
+               toggle = TD_T_TOGGLE;
+       } else {
+               toggle = TD_T_DATA0;
+               usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 1);
+       }
+       urb->td_cnt = 0;
+       if (data_len)
+               data = buffer;
+       else
+               data = 0;
+
+       switch (usb_pipetype (pipe)) {
+       case PIPE_BULK:
+               info = usb_pipeout (pipe)?
+                       TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
+               while(data_len > 4096) {
+                       td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, dev, cnt, urb);
+                       data += 4096; data_len -= 4096; cnt++;
+               }
+               info = usb_pipeout (pipe)?
+                       TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
+               td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, dev, cnt, urb);
+               cnt++;
+
+               if (!ohci->sleeping)
+                       writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+               break;
+
+       case PIPE_CONTROL:
+               info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+               td_fill (ohci, info, setup, 8, dev, cnt++, urb);
+               if (data_len > 0) {
+                       info = usb_pipeout (pipe)?
+                               TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
+                       /* NOTE:  mishandles transfers >8K, some >4K */
+                       td_fill (ohci, info, data, data_len, dev, cnt++, urb);
+               }
+               info = usb_pipeout (pipe)?
+                       TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
+               td_fill (ohci, info, data, 0, dev, cnt++, urb);
+               if (!ohci->sleeping)
+                       writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+               break;
+
+       case PIPE_INTERRUPT:
+               info = usb_pipeout (urb->pipe)?
+                       TD_CC | TD_DP_OUT | toggle:
+                       TD_CC | TD_R | TD_DP_IN | toggle;
+               td_fill (ohci, info, data, data_len, dev, cnt++, urb);
+               break;
+       }
+       if (urb->length != cnt)
+               dbg("TD LENGTH %d != CNT %d", urb->length, cnt);
+}
+
+/*-------------------------------------------------------------------------*
+ * Done List handling functions
+ *-------------------------------------------------------------------------*/
+
+/* calculate the transfer length and update the urb */
+
+static void dl_transfer_length(td_t * td)
+{
+       __u32 tdINFO, tdBE, tdCBP;
+       urb_priv_t *lurb_priv = td->ed->purb;
+
+       tdINFO = m32_swap (td->hwINFO);
+       tdBE   = m32_swap (td->hwBE);
+       tdCBP  = m32_swap (td->hwCBP);
+
+       if (!(usb_pipetype (lurb_priv->pipe) == PIPE_CONTROL &&
+           ((td->index == 0) || (td->index == lurb_priv->length - 1)))) {
+               if (tdBE != 0) {
+                       if (td->hwCBP == 0)
+                               lurb_priv->actual_length += tdBE - td->data + 1;
+                       else
+                               lurb_priv->actual_length += tdCBP - td->data;
+               }
+       }
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* replies to the request have to be on a FIFO basis so
+ * we reverse the reversed done-list */
+
+static td_t * dl_reverse_done_list (ohci_t *ohci)
+{
+       __u32 td_list_hc;
+       td_t *td_rev = NULL;
+       td_t *td_list = NULL;
+       urb_priv_t *lurb_priv = NULL;
+
+       td_list_hc = m32_swap (ohci->hcca->done_head) & 0xfffffff0;
+       ohci->hcca->done_head = 0;
+
+       while (td_list_hc) {
+               td_list = (td_t *)td_list_hc;
+
+               if (TD_CC_GET (m32_swap (td_list->hwINFO))) {
+                       lurb_priv = td_list->ed->purb;
+                       dbg(" USB-error/status: %x : %p",
+                                       TD_CC_GET (m32_swap (td_list->hwINFO)), td_list);
+                       if (td_list->ed->hwHeadP & m32_swap (0x1)) {
+                               if (lurb_priv && ((td_list->index + 1) < lurb_priv->length)) {
+                                       td_list->ed->hwHeadP =
+                                               (lurb_priv->td[lurb_priv->length - 1]->hwNextTD & m32_swap (0xfffffff0)) |
+                                                                       (td_list->ed->hwHeadP & m32_swap (0x2));
+                                       lurb_priv->td_cnt += lurb_priv->length - td_list->index - 1;
+                               } else
+                                       td_list->ed->hwHeadP &= m32_swap (0xfffffff2);
+                       }
+#ifdef CONFIG_MPC5200
+                       td_list->hwNextTD = 0;
+#endif
+               }
+
+               td_list->next_dl_td = td_rev;
+               td_rev = td_list;
+               td_list_hc = m32_swap (td_list->hwNextTD) & 0xfffffff0;
+       }
+       return td_list;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* td done list */
+static int dl_done_list (ohci_t *ohci, td_t *td_list)
+{
+       td_t *td_list_next = NULL;
+       ed_t *ed;
+       int cc = 0;
+       int stat = 0;
+       /* urb_t *urb; */
+       urb_priv_t *lurb_priv;
+       __u32 tdINFO, edHeadP, edTailP;
+
+       while (td_list) {
+               td_list_next = td_list->next_dl_td;
+
+               tdINFO = m32_swap (td_list->hwINFO);
+
+               ed = td_list->ed;
+               lurb_priv = ed->purb;
+
+               dl_transfer_length(td_list);
+
+               /* error code of transfer */
+               cc = TD_CC_GET (tdINFO);
+               if (cc != 0) {
+                       dbg("ConditionCode %#x", cc);
+                       stat = cc_to_error[cc];
+               }
+
+               /* see if this done list makes for all TD's of current URB,
+                * and mark the URB finished if so */
+               if (++(lurb_priv->td_cnt) == lurb_priv->length) {
+#if 1
+                       if ((ed->state & (ED_OPER | ED_UNLINK)) &&
+                           (lurb_priv->state != URB_DEL))
+#else
+                       if ((ed->state & (ED_OPER | ED_UNLINK)))
+#endif
+                               lurb_priv->finished = sohci_return_job(ohci,
+                                               lurb_priv);
+                       else
+                               dbg("dl_done_list: strange.., ED state %x, ed->state\n");
+               } else
+                       dbg("dl_done_list: processing TD %x, len %x\n", lurb_priv->td_cnt,
+                               lurb_priv->length);
+               if (ed->state != ED_NEW &&
+                         (usb_pipetype (lurb_priv->pipe) != PIPE_INTERRUPT)) {
+                       edHeadP = m32_swap (ed->hwHeadP) & 0xfffffff0;
+                       edTailP = m32_swap (ed->hwTailP);
+
+                       /* unlink eds if they are not busy */
+                       if ((edHeadP == edTailP) && (ed->state == ED_OPER))
+                               ep_unlink (ohci, ed);
+               }
+
+               td_list = td_list_next;
+       }
+       return stat;
+}
+
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub
+ *-------------------------------------------------------------------------*/
+
+/* Device descriptor */
+static __u8 root_hub_dev_des[] =
+{
+       0x12,       /*  __u8  bLength; */
+       0x01,       /*  __u8  bDescriptorType; Device */
+       0x10,       /*  __u16 bcdUSB; v1.1 */
+       0x01,
+       0x09,       /*  __u8  bDeviceClass; HUB_CLASSCODE */
+       0x00,       /*  __u8  bDeviceSubClass; */
+       0x00,       /*  __u8  bDeviceProtocol; */
+       0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
+       0x00,       /*  __u16 idVendor; */
+       0x00,
+       0x00,       /*  __u16 idProduct; */
+       0x00,
+       0x00,       /*  __u16 bcdDevice; */
+       0x00,
+       0x00,       /*  __u8  iManufacturer; */
+       0x01,       /*  __u8  iProduct; */
+       0x00,       /*  __u8  iSerialNumber; */
+       0x01        /*  __u8  bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+       0x09,       /*  __u8  bLength; */
+       0x02,       /*  __u8  bDescriptorType; Configuration */
+       0x19,       /*  __u16 wTotalLength; */
+       0x00,
+       0x01,       /*  __u8  bNumInterfaces; */
+       0x01,       /*  __u8  bConfigurationValue; */
+       0x00,       /*  __u8  iConfiguration; */
+       0x40,       /*  __u8  bmAttributes;
+                Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+       0x00,       /*  __u8  MaxPower; */
+
+       /* interface */
+       0x09,       /*  __u8  if_bLength; */
+       0x04,       /*  __u8  if_bDescriptorType; Interface */
+       0x00,       /*  __u8  if_bInterfaceNumber; */
+       0x00,       /*  __u8  if_bAlternateSetting; */
+       0x01,       /*  __u8  if_bNumEndpoints; */
+       0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+       0x00,       /*  __u8  if_bInterfaceSubClass; */
+       0x00,       /*  __u8  if_bInterfaceProtocol; */
+       0x00,       /*  __u8  if_iInterface; */
+
+       /* endpoint */
+       0x07,       /*  __u8  ep_bLength; */
+       0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
+       0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+       0x03,       /*  __u8  ep_bmAttributes; Interrupt */
+       0x02,       /*  __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+       0x00,
+       0xff        /*  __u8  ep_bInterval; 255 ms */
+};
+
+static unsigned char root_hub_str_index0[] =
+{
+       0x04,                   /*  __u8  bLength; */
+       0x03,                   /*  __u8  bDescriptorType; String-descriptor */
+       0x09,                   /*  __u8  lang ID */
+       0x04,                   /*  __u8  lang ID */
+};
+
+static unsigned char root_hub_str_index1[] =
+{
+       28,                     /*  __u8  bLength; */
+       0x03,                   /*  __u8  bDescriptorType; String-descriptor */
+       'O',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       'H',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       'C',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       'I',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       ' ',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       'R',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       'o',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       'o',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       't',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       ' ',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       'H',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       'u',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       'b',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+};
+
+/* Hub class-specific descriptor is constructed dynamically */
+
+/*-------------------------------------------------------------------------*/
+
+#define OK(x)                  len = (x); break
+#ifdef DEBUG
+#define WR_RH_STAT(x)          {info("WR:status %#8x", (x));writel((x), &gohci.regs->roothub.status);}
+#define WR_RH_PORTSTAT(x)      {info("WR:portstatus[%d] %#8x", wIndex-1, (x));writel((x), &gohci.regs->roothub.portstatus[wIndex-1]);}
+#else
+#define WR_RH_STAT(x)          writel((x), &gohci.regs->roothub.status)
+#define WR_RH_PORTSTAT(x)      writel((x), &gohci.regs->roothub.portstatus[wIndex-1])
+#endif
+#define RD_RH_STAT             roothub_status(&gohci)
+#define RD_RH_PORTSTAT         roothub_portstatus(&gohci,wIndex-1)
+
+/* request to virtual root hub */
+
+int rh_check_port_status(ohci_t *controller)
+{
+       __u32 temp, ndp, i;
+       int res;
+
+       res = -1;
+       temp = roothub_a (controller);
+       ndp = (temp & RH_A_NDP);
+#ifdef CONFIG_AT91C_PQFP_UHPBUG
+       ndp = (ndp == 2) ? 1:0;
+#endif
+       for (i = 0; i < ndp; i++) {
+               temp = roothub_portstatus (controller, i);
+               /* check for a device disconnect */
+               if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
+                       (RH_PS_PESC | RH_PS_CSC)) &&
+                       ((temp & RH_PS_CCS) == 0)) {
+                       res = i;
+                       break;
+               }
+       }
+       return res;
+}
+
+static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+               void *buffer, int transfer_len, struct devrequest *cmd)
+{
+       void * data = buffer;
+       int leni = transfer_len;
+       int len = 0;
+       int stat = 0;
+       __u32 datab[4];
+       __u8 *data_buf = (__u8 *)datab;
+       __u16 bmRType_bReq;
+       __u16 wValue;
+       __u16 wIndex;
+       __u16 wLength;
+
+#ifdef DEBUG
+pkt_print(NULL, dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe));
+#else
+       wait_ms(1);
+#endif
+       if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
+               info("Root-Hub submit IRQ: NOT implemented");
+               return 0;
+       }
+
+       bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
+       wValue        = cpu_to_le16 (cmd->value);
+       wIndex        = cpu_to_le16 (cmd->index);
+       wLength       = cpu_to_le16 (cmd->length);
+
+       info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x",
+               dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
+
+       switch (bmRType_bReq) {
+       /* Request Destination:
+          without flags: Device,
+          RH_INTERFACE: interface,
+          RH_ENDPOINT: endpoint,
+          RH_CLASS means HUB here,
+          RH_OTHER | RH_CLASS  almost ever means HUB_PORT here
+       */
+
+       case RH_GET_STATUS:
+                       *(__u16 *) data_buf = cpu_to_le16 (1); OK (2);
+       case RH_GET_STATUS | RH_INTERFACE:
+                       *(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
+       case RH_GET_STATUS | RH_ENDPOINT:
+                       *(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
+       case RH_GET_STATUS | RH_CLASS:
+                       *(__u32 *) data_buf = cpu_to_le32 (
+                               RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
+                       OK (4);
+       case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+                       *(__u32 *) data_buf = cpu_to_le32 (RD_RH_PORTSTAT); OK (4);
+
+       case RH_CLEAR_FEATURE | RH_ENDPOINT:
+               switch (wValue) {
+                       case (RH_ENDPOINT_STALL): OK (0);
+               }
+               break;
+
+       case RH_CLEAR_FEATURE | RH_CLASS:
+               switch (wValue) {
+                       case RH_C_HUB_LOCAL_POWER:
+                               OK(0);
+                       case (RH_C_HUB_OVER_CURRENT):
+                                       WR_RH_STAT(RH_HS_OCIC); OK (0);
+               }
+               break;
+
+       case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+               switch (wValue) {
+                       case (RH_PORT_ENABLE):
+                                       WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
+                       case (RH_PORT_SUSPEND):
+                                       WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
+                       case (RH_PORT_POWER):
+                                       WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
+                       case (RH_C_PORT_CONNECTION):
+                                       WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
+                       case (RH_C_PORT_ENABLE):
+                                       WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
+                       case (RH_C_PORT_SUSPEND):
+                                       WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
+                       case (RH_C_PORT_OVER_CURRENT):
+                                       WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
+                       case (RH_C_PORT_RESET):
+                                       WR_RH_PORTSTAT (RH_PS_PRSC); OK (0);
+               }
+               break;
+
+       case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+               switch (wValue) {
+                       case (RH_PORT_SUSPEND):
+                                       WR_RH_PORTSTAT (RH_PS_PSS ); OK (0);
+                       case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
+                                       if (RD_RH_PORTSTAT & RH_PS_CCS)
+                                           WR_RH_PORTSTAT (RH_PS_PRS);
+                                       OK (0);
+                       case (RH_PORT_POWER):
+                                       WR_RH_PORTSTAT (RH_PS_PPS );
+                                       wait_ms(100);
+                                       OK (0);
+                       case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
+                                       if (RD_RH_PORTSTAT & RH_PS_CCS)
+                                           WR_RH_PORTSTAT (RH_PS_PES );
+                                       OK (0);
+               }
+               break;
+
+       case RH_SET_ADDRESS: gohci.rh.devnum = wValue; OK(0);
+
+       case RH_GET_DESCRIPTOR:
+               switch ((wValue & 0xff00) >> 8) {
+                       case (0x01): /* device descriptor */
+                               len = min_t(unsigned int,
+                                         leni,
+                                         min_t(unsigned int,
+                                             sizeof (root_hub_dev_des),
+                                             wLength));
+                               data_buf = root_hub_dev_des; OK(len);
+                       case (0x02): /* configuration descriptor */
+                               len = min_t(unsigned int,
+                                         leni,
+                                         min_t(unsigned int,
+                                             sizeof (root_hub_config_des),
+                                             wLength));
+                               data_buf = root_hub_config_des; OK(len);
+                       case (0x03): /* string descriptors */
+                               if(wValue==0x0300) {
+                                       len = min_t(unsigned int,
+                                                 leni,
+                                                 min_t(unsigned int,
+                                                     sizeof (root_hub_str_index0),
+                                                     wLength));
+                                       data_buf = root_hub_str_index0;
+                                       OK(len);
+                               }
+                               if(wValue==0x0301) {
+                                       len = min_t(unsigned int,
+                                                 leni,
+                                                 min_t(unsigned int,
+                                                     sizeof (root_hub_str_index1),
+                                                     wLength));
+                                       data_buf = root_hub_str_index1;
+                                       OK(len);
+                       }
+                       default:
+                               stat = USB_ST_STALLED;
+               }
+               break;
+
+       case RH_GET_DESCRIPTOR | RH_CLASS:
+       {
+               __u32 temp = roothub_a (&gohci);
+
+               data_buf [0] = 9;               /* min length; */
+               data_buf [1] = 0x29;
+               data_buf [2] = temp & RH_A_NDP;
+#ifdef CONFIG_AT91C_PQFP_UHPBUG
+               data_buf [2] = (data_buf [2] == 2) ? 1:0;
+#endif
+               data_buf [3] = 0;
+               if (temp & RH_A_PSM)    /* per-port power switching? */
+                       data_buf [3] |= 0x1;
+               if (temp & RH_A_NOCP)   /* no overcurrent reporting? */
+                       data_buf [3] |= 0x10;
+               else if (temp & RH_A_OCPM)      /* per-port overcurrent reporting? */
+                       data_buf [3] |= 0x8;
+
+               /* corresponds to data_buf[4-7] */
+               datab [1] = 0;
+               data_buf [5] = (temp & RH_A_POTPGT) >> 24;
+               temp = roothub_b (&gohci);
+               data_buf [7] = temp & RH_B_DR;
+               if (data_buf [2] < 7) {
+                       data_buf [8] = 0xff;
+               } else {
+                       data_buf [0] += 2;
+                       data_buf [8] = (temp & RH_B_DR) >> 8;
+                       data_buf [10] = data_buf [9] = 0xff;
+               }
+
+               len = min_t(unsigned int, leni,
+                           min_t(unsigned int, data_buf [0], wLength));
+               OK (len);
+       }
+
+       case RH_GET_CONFIGURATION:      *(__u8 *) data_buf = 0x01; OK (1);
+
+       case RH_SET_CONFIGURATION:      WR_RH_STAT (0x10000); OK (0);
+
+       default:
+               dbg ("unsupported root hub command");
+               stat = USB_ST_STALLED;
+       }
+
+#ifdef DEBUG
+       ohci_dump_roothub (&gohci, 1);
+#else
+       wait_ms(1);
+#endif
+
+       len = min_t(int, len, leni);
+       if (data != data_buf)
+           memcpy (data, data_buf, len);
+       dev->act_len = len;
+       dev->status = stat;
+
+#ifdef DEBUG
+       pkt_print(NULL, dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
+#else
+       wait_ms(1);
+#endif
+
+       return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* common code for handling submit messages - used for all but root hub */
+/* accesses. */
+int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+               int transfer_len, struct devrequest *setup, int interval)
+{
+       int stat = 0;
+       int maxsize = usb_maxpacket(dev, pipe);
+       int timeout;
+       urb_priv_t *urb;
+
+       urb = malloc(sizeof(urb_priv_t));
+       memset(urb, 0, sizeof(urb_priv_t));
+
+       urb->dev = dev;
+       urb->pipe = pipe;
+       urb->transfer_buffer = buffer;
+       urb->transfer_buffer_length = transfer_len;
+       urb->interval = interval;
+
+       /* device pulled? Shortcut the action. */
+       if (devgone == dev) {
+               dev->status = USB_ST_CRC_ERR;
+               return 0;
+       }
+
+#ifdef DEBUG
+       urb->actual_length = 0;
+       pkt_print(urb, dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
+#else
+       wait_ms(1);
+#endif
+       if (!maxsize) {
+               err("submit_common_message: pipesize for pipe %lx is zero",
+                       pipe);
+               return -1;
+       }
+
+       if (sohci_submit_job(urb, setup) < 0) {
+               err("sohci_submit_job failed");
+               return -1;
+       }
+
+#if 0
+       wait_ms(10);
+       /* ohci_dump_status(&gohci); */
+#endif
+
+       /* allow more time for a BULK device to react - some are slow */
+#define BULK_TO         5000   /* timeout in milliseconds */
+       if (usb_pipetype (pipe) == PIPE_BULK)
+               timeout = BULK_TO;
+       else
+               timeout = 100;
+
+       /* wait for it to complete */
+       for (;;) {
+               /* check whether the controller is done */
+               stat = hc_interrupt();
+               if (stat < 0) {
+                       stat = USB_ST_CRC_ERR;
+                       break;
+               }
+
+               /* NOTE: since we are not interrupt driven in U-Boot and always
+                * handle only one URB at a time, we cannot assume the
+                * transaction finished on the first successful return from
+                * hc_interrupt().. unless the flag for current URB is set,
+                * meaning that all TD's to/from device got actually
+                * transferred and processed. If the current URB is not
+                * finished we need to re-iterate this loop so as
+                * hc_interrupt() gets called again as there needs to be some
+                * more TD's to process still */
+               if ((stat >= 0) && (stat != 0xff) && (urb->finished)) {
+                       /* 0xff is returned for an SF-interrupt */
+                       break;
+               }
+
+               if (--timeout) {
+                       wait_ms(1);
+                       if (!urb->finished)
+                               dbg("\%");
+
+               } else {
+                       err("CTL:TIMEOUT ");
+                       dbg("submit_common_msg: TO status %x\n", stat);
+                       urb->finished = 1;
+                       stat = USB_ST_CRC_ERR;
+                       break;
+               }
+       }
+
+       dev->status = stat;
+       dev->act_len = transfer_len;
+
+#ifdef DEBUG
+       pkt_print(urb, dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe));
+#else
+       wait_ms(1);
+#endif
+
+       /* free TDs in urb_priv */
+       if (usb_pipetype (pipe) != PIPE_INTERRUPT)
+               urb_free_priv (urb);
+       return 0;
+}
+
+/* submit routines called from usb.c */
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+               int transfer_len)
+{
+       info("submit_bulk_msg");
+       return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0);
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+               int transfer_len, struct devrequest *setup)
+{
+       int maxsize = usb_maxpacket(dev, pipe);
+
+       info("submit_control_msg");
+#ifdef DEBUG
+       pkt_print(NULL, dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
+#else
+       wait_ms(1);
+#endif
+       if (!maxsize) {
+               err("submit_control_message: pipesize for pipe %lx is zero",
+                       pipe);
+               return -1;
+       }
+       if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) {
+               gohci.rh.dev = dev;
+               /* root hub - redirect */
+               return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len,
+                       setup);
+       }
+
+       return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0);
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+               int transfer_len, int interval)
+{
+       info("submit_int_msg");
+       return submit_common_msg(dev, pipe, buffer, transfer_len, NULL,
+                       interval);
+}
+
+/*-------------------------------------------------------------------------*
+ * HC functions
+ *-------------------------------------------------------------------------*/
+
+/* reset the HC and BUS */
+
+static int hc_reset (ohci_t *ohci)
+{
+       int timeout = 30;
+       int smm_timeout = 50; /* 0,5 sec */
+
+       dbg("%s\n", __FUNCTION__);
+
+       if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
+               writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
+               info("USB HC TakeOver from SMM");
+               while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
+                       wait_ms (10);
+                       if (--smm_timeout == 0) {
+                               err("USB HC TakeOver failed!");
+                               return -1;
+                       }
+               }
+       }
+
+       /* Disable HC interrupts */
+       writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
+
+       dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;\n",
+               ohci->slot_name,
+               readl(&ohci->regs->control));
+
+       /* Reset USB (needed by some controllers) */
+       ohci->hc_control = 0;
+       writel (ohci->hc_control, &ohci->regs->control);
+
+       /* HC Reset requires max 10 us delay */
+       writel (OHCI_HCR,  &ohci->regs->cmdstatus);
+       while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+               if (--timeout == 0) {
+                       err("USB HC reset timed out!");
+                       return -1;
+               }
+               udelay (1);
+       }
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Start an OHCI controller, set the BUS operational
+ * enable interrupts
+ * connect the virtual root hub */
+
+static int hc_start (ohci_t * ohci)
+{
+       __u32 mask;
+       unsigned int fminterval;
+
+       ohci->disabled = 1;
+
+       /* Tell the controller where the control and bulk lists are
+        * The lists are empty now. */
+
+       writel (0, &ohci->regs->ed_controlhead);
+       writel (0, &ohci->regs->ed_bulkhead);
+
+       writel ((__u32)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */
+
+       fminterval = 0x2edf;
+       writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
+       fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
+       writel (fminterval, &ohci->regs->fminterval);
+       writel (0x628, &ohci->regs->lsthresh);
+
+       /* start controller operations */
+       ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+       ohci->disabled = 0;
+       writel (ohci->hc_control, &ohci->regs->control);
+
+       /* disable all interrupts */
+       mask = (OHCI_INTR_SO | OHCI_INTR_WDH | OHCI_INTR_SF | OHCI_INTR_RD |
+                       OHCI_INTR_UE | OHCI_INTR_FNO | OHCI_INTR_RHSC |
+                       OHCI_INTR_OC | OHCI_INTR_MIE);
+       writel (mask, &ohci->regs->intrdisable);
+       /* clear all interrupts */
+       mask &= ~OHCI_INTR_MIE;
+       writel (mask, &ohci->regs->intrstatus);
+       /* Choose the interrupts we care about now  - but w/o MIE */
+       mask = OHCI_INTR_RHSC | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
+       writel (mask, &ohci->regs->intrenable);
+
+#ifdef OHCI_USE_NPS
+       /* required for AMD-756 and some Mac platforms */
+       writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
+               &ohci->regs->roothub.a);
+       writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+#endif /* OHCI_USE_NPS */
+
+#define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);})
+       /* POTPGT delay is bits 24-31, in 2 ms units. */
+       mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
+
+       /* connect the virtual root hub */
+       ohci->rh.devnum = 0;
+
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Poll USB interrupt. */
+void usb_event_poll(void)
+{
+       hc_interrupt();
+}
+
+/* an interrupt happens */
+
+static int hc_interrupt (void)
+{
+       ohci_t *ohci = &gohci;
+       struct ohci_regs *regs = ohci->regs;
+       int ints;
+       int stat = -1;
+
+       if ((ohci->hcca->done_head != 0) &&
+           !(m32_swap (ohci->hcca->done_head) & 0x01)) {
+               ints =  OHCI_INTR_WDH;
+       } else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
+               ohci->disabled++;
+               err ("%s device removed!", ohci->slot_name);
+               return -1;
+       } else if ((ints &= readl (&regs->intrenable)) == 0) {
+               dbg("hc_interrupt: returning..\n");
+               return 0xff;
+       }
+
+       /* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */
+
+       if (ints & OHCI_INTR_RHSC) {
+               got_rhsc = 1;
+               stat = 0xff;
+       }
+
+       if (ints & OHCI_INTR_UE) {
+               ohci->disabled++;
+               err ("OHCI Unrecoverable Error, controller usb-%s disabled",
+                       ohci->slot_name);
+               /* e.g. due to PCI Master/Target Abort */
+
+#ifdef DEBUG
+               ohci_dump (ohci, 1);
+#else
+       wait_ms(1);
+#endif
+               /* FIXME: be optimistic, hope that bug won't repeat often. */
+               /* Make some non-interrupt context restart the controller. */
+               /* Count and limit the retries though; either hardware or */
+               /* software errors can go forever... */
+               hc_reset (ohci);
+               return -1;
+       }
+
+       if (ints & OHCI_INTR_WDH) {
+               wait_ms(1);
+               writel (OHCI_INTR_WDH, &regs->intrdisable);
+               (void)readl (&regs->intrdisable); /* flush */
+               stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci));
+               writel (OHCI_INTR_WDH, &regs->intrenable);
+               (void)readl (&regs->intrdisable); /* flush */
+       }
+
+       if (ints & OHCI_INTR_SO) {
+               dbg("USB Schedule overrun\n");
+               writel (OHCI_INTR_SO, &regs->intrenable);
+               stat = -1;
+       }
+
+       /* FIXME:  this assumes SOF (1/ms) interrupts don't get lost... */
+       if (ints & OHCI_INTR_SF) {
+               unsigned int frame = m16_swap (ohci->hcca->frame_no) & 1;
+               wait_ms(1);
+               writel (OHCI_INTR_SF, &regs->intrdisable);
+               if (ohci->ed_rm_list[frame] != NULL)
+                       writel (OHCI_INTR_SF, &regs->intrenable);
+               stat = 0xff;
+       }
+
+       writel (ints, &regs->intrstatus);
+       return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+
+/* De-allocate all resources.. */
+
+static void hc_release_ohci (ohci_t *ohci)
+{
+       dbg ("USB HC release ohci usb-%s", ohci->slot_name);
+
+       if (!ohci->disabled)
+               hc_reset (ohci);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * low level initalisation routine, called from usb.c
+ */
+static char ohci_inited = 0;
+
+int usb_lowlevel_init(void)
+{
+#ifdef CONFIG_PCI_OHCI
+       pci_dev_t pdev;
+#endif
+
+#ifdef CFG_USB_OHCI_CPU_INIT
+       /* cpu dependant init */
+       if(usb_cpu_init())
+               return -1;
+#endif
+
+#ifdef CFG_USB_OHCI_BOARD_INIT
+       /*  board dependant init */
+       if(usb_board_init())
+               return -1;
+#endif
+       memset (&gohci, 0, sizeof (ohci_t));
+
+       /* align the storage */
+       if ((__u32)&ghcca[0] & 0xff) {
+               err("HCCA not aligned!!");
+               return -1;
+       }
+       phcca = &ghcca[0];
+       info("aligned ghcca %p", phcca);
+       memset(&ohci_dev, 0, sizeof(struct ohci_device));
+       if ((__u32)&ohci_dev.ed[0] & 0x7) {
+               err("EDs not aligned!!");
+               return -1;
+       }
+       memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1));
+       if ((__u32)gtd & 0x7) {
+               err("TDs not aligned!!");
+               return -1;
+       }
+       ptd = gtd;
+       gohci.hcca = phcca;
+       memset (phcca, 0, sizeof (struct ohci_hcca));
+
+       gohci.disabled = 1;
+       gohci.sleeping = 0;
+       gohci.irq = -1;
+#ifdef CONFIG_PCI_OHCI
+       pdev = pci_find_devices(ohci_pci_ids, 0);
+
+       if (pdev != -1) {
+               u16 vid, did;
+               u32 base;
+               pci_read_config_word(pdev, PCI_VENDOR_ID, &vid);
+               pci_read_config_word(pdev, PCI_DEVICE_ID, &did);
+               printf("OHCI pci controller (%04x, %04x) found @(%d:%d:%d)\n",
+                               vid, did, (pdev >> 16) & 0xff,
+                               (pdev >> 11) & 0x1f, (pdev >> 8) & 0x7);
+               pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &base);
+               printf("OHCI regs address 0x%08x\n", base);
+               gohci.regs = (struct ohci_regs *)base;
+       } else
+               return -1;
+#else
+       gohci.regs = (struct ohci_regs *)CFG_USB_OHCI_REGS_BASE;
+#endif
+
+       gohci.flags = 0;
+       gohci.slot_name = CFG_USB_OHCI_SLOT_NAME;
+
+       if (hc_reset (&gohci) < 0) {
+               hc_release_ohci (&gohci);
+               err ("can't reset usb-%s", gohci.slot_name);
+#ifdef CFG_USB_OHCI_BOARD_INIT
+               /* board dependant cleanup */
+               usb_board_init_fail();
+#endif
+
+#ifdef CFG_USB_OHCI_CPU_INIT
+               /* cpu dependant cleanup */
+               usb_cpu_init_fail();
+#endif
+               return -1;
+       }
+
+       /* FIXME this is a second HC reset; why?? */
+       /* writel(gohci.hc_control = OHCI_USB_RESET, &gohci.regs->control);
+          wait_ms(10); */
+       if (hc_start (&gohci) < 0) {
+               err ("can't start usb-%s", gohci.slot_name);
+               hc_release_ohci (&gohci);
+               /* Initialization failed */
+#ifdef CFG_USB_OHCI_BOARD_INIT
+               /* board dependant cleanup */
+               usb_board_stop();
+#endif
+
+#ifdef CFG_USB_OHCI_CPU_INIT
+               /* cpu dependant cleanup */
+               usb_cpu_stop();
+#endif
+               return -1;
+       }
+
+#ifdef DEBUG
+       ohci_dump (&gohci, 1);
+#else
+       wait_ms(1);
+#endif
+       ohci_inited = 1;
+       return 0;
+}
+
+int usb_lowlevel_stop(void)
+{
+       /* this gets called really early - before the controller has */
+       /* even been initialized! */
+       if (!ohci_inited)
+               return 0;
+       /* TODO release any interrupts, etc. */
+       /* call hc_release_ohci() here ? */
+       hc_reset (&gohci);
+
+#ifdef CFG_USB_OHCI_BOARD_INIT
+       /* board dependant cleanup */
+       if(usb_board_stop())
+               return -1;
+#endif
+
+#ifdef CFG_USB_OHCI_CPU_INIT
+       /* cpu dependant cleanup */
+       if(usb_cpu_stop())
+               return -1;
+#endif
+
+       return 0;
+}
+#endif /* CONFIG_USB_OHCI_NEW */
diff --git a/drivers/usb/usb_ohci.h b/drivers/usb/usb_ohci.h
new file mode 100644 (file)
index 0000000..380cb4c
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * usb-ohci.h
+ */
+
+/* functions for doing board or CPU specific setup/cleanup */
+extern int usb_board_init(void);
+extern int usb_board_stop(void);
+extern int usb_board_init_fail(void);
+
+extern int usb_cpu_init(void);
+extern int usb_cpu_stop(void);
+extern int usb_cpu_init_fail(void);
+
+
+static int cc_to_error[16] = {
+
+/* mapping of the OHCI CC status to error codes */
+       /* No  Error  */               0,
+       /* CRC Error  */               USB_ST_CRC_ERR,
+       /* Bit Stuff  */               USB_ST_BIT_ERR,
+       /* Data Togg  */               USB_ST_CRC_ERR,
+       /* Stall      */               USB_ST_STALLED,
+       /* DevNotResp */               -1,
+       /* PIDCheck   */               USB_ST_BIT_ERR,
+       /* UnExpPID   */               USB_ST_BIT_ERR,
+       /* DataOver   */               USB_ST_BUF_ERR,
+       /* DataUnder  */               USB_ST_BUF_ERR,
+       /* reservd    */               -1,
+       /* reservd    */               -1,
+       /* BufferOver */               USB_ST_BUF_ERR,
+       /* BuffUnder  */               USB_ST_BUF_ERR,
+       /* Not Access */               -1,
+       /* Not Access */               -1
+};
+
+/* ED States */
+
+#define ED_NEW         0x00
+#define ED_UNLINK      0x01
+#define ED_OPER                0x02
+#define ED_DEL         0x04
+#define ED_URB_DEL     0x08
+
+/* usb_ohci_ed */
+struct ed {
+       __u32 hwINFO;
+       __u32 hwTailP;
+       __u32 hwHeadP;
+       __u32 hwNextED;
+
+       struct ed *ed_prev;
+       __u8 int_period;
+       __u8 int_branch;
+       __u8 int_load;
+       __u8 int_interval;
+       __u8 state;
+       __u8 type;
+       __u16 last_iso;
+       struct ed *ed_rm_list;
+
+       struct usb_device *usb_dev;
+       void *purb;
+       __u32 unused[2];
+} __attribute((aligned(16)));
+typedef struct ed ed_t;
+
+
+/* TD info field */
+#define TD_CC      0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_EC      0x0C000000
+#define TD_T       0x03000000
+#define TD_T_DATA0  0x02000000
+#define TD_T_DATA1  0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_R       0x00040000
+#define TD_DI      0x00E00000
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP      0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN    0x00100000
+#define TD_DP_OUT   0x00080000
+
+#define TD_ISO     0x00010000
+#define TD_DEL     0x00020000
+
+/* CC Codes */
+#define TD_CC_NOERROR     0x00
+#define TD_CC_CRC         0x01
+#define TD_CC_BITSTUFFING  0x02
+#define TD_CC_DATATOGGLEM  0x03
+#define TD_CC_STALL       0x04
+#define TD_DEVNOTRESP     0x05
+#define TD_PIDCHECKFAIL           0x06
+#define TD_UNEXPECTEDPID   0x07
+#define TD_DATAOVERRUN    0x08
+#define TD_DATAUNDERRUN           0x09
+#define TD_BUFFEROVERRUN   0x0C
+#define TD_BUFFERUNDERRUN  0x0D
+#define TD_NOTACCESSED    0x0F
+
+
+#define MAXPSW 1
+
+struct td {
+       __u32 hwINFO;
+       __u32 hwCBP;            /* Current Buffer Pointer */
+       __u32 hwNextTD;         /* Next TD Pointer */
+       __u32 hwBE;             /* Memory Buffer End Pointer */
+
+/* #ifndef CONFIG_MPC5200 /\* this seems wrong *\/ */
+       __u16 hwPSW[MAXPSW];
+/* #endif */
+       __u8 unused;
+       __u8 index;
+       struct ed *ed;
+       struct td *next_dl_td;
+       struct usb_device *usb_dev;
+       int transfer_len;
+       __u32 data;
+
+       __u32 unused2[2];
+} __attribute((aligned(32)));
+typedef struct td td_t;
+
+#define OHCI_ED_SKIP   (1 << 14)
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of.  It must be 256-byte aligned.
+ */
+
+#define NUM_INTS 32    /* part of the OHCI standard */
+struct ohci_hcca {
+       __u32   int_table[NUM_INTS];    /* Interrupt ED table */
+#if defined(CONFIG_MPC5200)
+       __u16   pad1;                   /* set to 0 on each frame_no change */
+       __u16   frame_no;               /* current frame number */
+#else
+       __u16   frame_no;               /* current frame number */
+       __u16   pad1;                   /* set to 0 on each frame_no change */
+#endif
+       __u32   done_head;              /* info returned for an interrupt */
+       u8              reserved_for_hc[116];
+} __attribute((aligned(256)));
+
+
+/*
+ * Maximum number of root hub ports.
+ */
+#ifndef CFG_USB_OHCI_MAX_ROOT_PORTS
+# error "CFG_USB_OHCI_MAX_ROOT_PORTS undefined!"
+#endif
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region.  This is Memory Mapped I/O. You must use the readl() and
+ * writel() macros defined in asm/io.h to access these!!
+ */
+struct ohci_regs {
+       /* control and status registers */
+       __u32   revision;
+       __u32   control;
+       __u32   cmdstatus;
+       __u32   intrstatus;
+       __u32   intrenable;
+       __u32   intrdisable;
+       /* memory pointers */
+       __u32   hcca;
+       __u32   ed_periodcurrent;
+       __u32   ed_controlhead;
+       __u32   ed_controlcurrent;
+       __u32   ed_bulkhead;
+       __u32   ed_bulkcurrent;
+       __u32   donehead;
+       /* frame counters */
+       __u32   fminterval;
+       __u32   fmremaining;
+       __u32   fmnumber;
+       __u32   periodicstart;
+       __u32   lsthresh;
+       /* Root hub ports */
+       struct  ohci_roothub_regs {
+               __u32   a;
+               __u32   b;
+               __u32   status;
+               __u32   portstatus[CFG_USB_OHCI_MAX_ROOT_PORTS];
+       } roothub;
+} __attribute((aligned(32)));
+
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_CBSR (3 << 0)        /* control/bulk service ratio */
+#define OHCI_CTRL_PLE  (1 << 2)        /* periodic list enable */
+#define OHCI_CTRL_IE   (1 << 3)        /* isochronous enable */
+#define OHCI_CTRL_CLE  (1 << 4)        /* control list enable */
+#define OHCI_CTRL_BLE  (1 << 5)        /* bulk list enable */
+#define OHCI_CTRL_HCFS (3 << 6)        /* host controller functional state */
+#define OHCI_CTRL_IR   (1 << 8)        /* interrupt routing */
+#define OHCI_CTRL_RWC  (1 << 9)        /* remote wakeup connected */
+#define OHCI_CTRL_RWE  (1 << 10)       /* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+#      define OHCI_USB_RESET   (0 << 6)
+#      define OHCI_USB_RESUME  (1 << 6)
+#      define OHCI_USB_OPER    (2 << 6)
+#      define OHCI_USB_SUSPEND (3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR       (1 << 0)        /* host controller reset */
+#define OHCI_CLF       (1 << 1)        /* control list filled */
+#define OHCI_BLF       (1 << 2)        /* bulk list filled */
+#define OHCI_OCR       (1 << 3)        /* ownership change request */
+#define OHCI_SOC       (3 << 16)       /* scheduling overrun count */
+
+/*
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */
+#define OHCI_INTR_SO   (1 << 0)        /* scheduling overrun */
+#define OHCI_INTR_WDH  (1 << 1)        /* writeback of done_head */
+#define OHCI_INTR_SF   (1 << 2)        /* start frame */
+#define OHCI_INTR_RD   (1 << 3)        /* resume detect */
+#define OHCI_INTR_UE   (1 << 4)        /* unrecoverable error */
+#define OHCI_INTR_FNO  (1 << 5)        /* frame number overflow */
+#define OHCI_INTR_RHSC (1 << 6)        /* root hub status change */
+#define OHCI_INTR_OC   (1 << 30)       /* ownership change */
+#define OHCI_INTR_MIE  (1 << 31)       /* master interrupt enable */
+
+
+/* Virtual Root HUB */
+struct virt_root_hub {
+       int devnum; /* Address of Root Hub endpoint */
+       void *dev;  /* was urb */
+       void *int_addr;
+       int send;
+       int interval;
+};
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
+
+/* destination of request */
+#define RH_INTERFACE              0x01
+#define RH_ENDPOINT               0x02
+#define RH_OTHER                  0x03
+
+#define RH_CLASS                  0x20
+#define RH_VENDOR                 0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS          0x0080
+#define RH_CLEAR_FEATURE       0x0100
+#define RH_SET_FEATURE         0x0300
+#define RH_SET_ADDRESS         0x0500
+#define RH_GET_DESCRIPTOR      0x0680
+#define RH_SET_DESCRIPTOR      0x0700
+#define RH_GET_CONFIGURATION   0x0880
+#define RH_SET_CONFIGURATION   0x0900
+#define RH_GET_STATE           0x0280
+#define RH_GET_INTERFACE       0x0A80
+#define RH_SET_INTERFACE       0x0B00
+#define RH_SYNC_FRAME          0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP              0x2000
+
+
+/* Hub port features */
+#define RH_PORT_CONNECTION        0x00
+#define RH_PORT_ENABLE            0x01
+#define RH_PORT_SUSPEND                   0x02
+#define RH_PORT_OVER_CURRENT      0x03
+#define RH_PORT_RESET             0x04
+#define RH_PORT_POWER             0x08
+#define RH_PORT_LOW_SPEED         0x09
+
+#define RH_C_PORT_CONNECTION      0x10
+#define RH_C_PORT_ENABLE          0x11
+#define RH_C_PORT_SUSPEND         0x12
+#define RH_C_PORT_OVER_CURRENT    0x13
+#define RH_C_PORT_RESET                   0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER      0x00
+#define RH_C_HUB_OVER_CURRENT     0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP           0x00
+#define RH_ENDPOINT_STALL         0x01
+
+#define RH_ACK                    0x01
+#define RH_REQ_ERR                -1
+#define RH_NACK                           0x00
+
+
+/* OHCI ROOT HUB REGISTER MASKS */
+
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS           0x00000001         /* current connect status */
+#define RH_PS_PES           0x00000002         /* port enable status*/
+#define RH_PS_PSS           0x00000004         /* port suspend status */
+#define RH_PS_POCI          0x00000008         /* port over current indicator */
+#define RH_PS_PRS           0x00000010         /* port reset status */
+#define RH_PS_PPS           0x00000100         /* port power status */
+#define RH_PS_LSDA          0x00000200         /* low speed device attached */
+#define RH_PS_CSC           0x00010000         /* connect status change */
+#define RH_PS_PESC          0x00020000         /* port enable status change */
+#define RH_PS_PSSC          0x00040000         /* port suspend status change */
+#define RH_PS_OCIC          0x00080000         /* over current indicator change */
+#define RH_PS_PRSC          0x00100000         /* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS           0x00000001         /* local power status */
+#define RH_HS_OCI           0x00000002         /* over current indicator */
+#define RH_HS_DRWE          0x00008000         /* device remote wakeup enable */
+#define RH_HS_LPSC          0x00010000         /* local power status change */
+#define RH_HS_OCIC          0x00020000         /* over current indicator change */
+#define RH_HS_CRWE          0x80000000         /* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR                0x0000ffff              /* device removable flags */
+#define RH_B_PPCM      0xffff0000              /* port power control mask */
+
+/* roothub.a masks */
+#define RH_A_NDP       (0xff << 0)             /* number of downstream ports */
+#define RH_A_PSM       (1 << 8)                /* power switching mode */
+#define RH_A_NPS       (1 << 9)                /* no power switching */
+#define RH_A_DT                (1 << 10)               /* device type (mbz) */
+#define RH_A_OCPM      (1 << 11)               /* over current protection mode */
+#define RH_A_NOCP      (1 << 12)               /* no over current protection */
+#define RH_A_POTPGT    (0xff << 24)            /* power on to power good time */
+
+/* urb */
+#define N_URB_TD 48
+typedef struct
+{
+       ed_t *ed;
+       __u16 length;   /* number of tds associated with this request */
+       __u16 td_cnt;   /* number of tds already serviced */
+       struct usb_device *dev;
+       int   state;
+       unsigned long pipe;
+       void *transfer_buffer;
+       int transfer_buffer_length;
+       int interval;
+       int actual_length;
+       int finished;
+       td_t *td[N_URB_TD];     /* list pointer to all corresponding TDs associated with this request */
+} urb_priv_t;
+#define URB_DEL 1
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+
+typedef struct ohci {
+       struct ohci_hcca *hcca;         /* hcca */
+       /*dma_addr_t hcca_dma;*/
+
+       int irq;
+       int disabled;                   /* e.g. got a UE, we're hung */
+       int sleeping;
+       unsigned long flags;            /* for HC bugs */
+
+       struct ohci_regs *regs; /* OHCI controller's memory */
+
+       int ohci_int_load[32];   /* load of the 32 Interrupt Chains (for load balancing)*/
+       ed_t *ed_rm_list[2];     /* lists of all endpoints to be removed */
+       ed_t *ed_bulktail;       /* last endpoint of bulk list */
+       ed_t *ed_controltail;    /* last endpoint of control list */
+       int intrstatus;
+       __u32 hc_control;               /* copy of the hc control reg */
+       struct usb_device *dev[32];
+       struct virt_root_hub rh;
+
+       const char      *slot_name;
+} ohci_t;
+
+#define NUM_EDS 8              /* num of preallocated endpoint descriptors */
+
+struct ohci_device {
+       ed_t    ed[NUM_EDS];
+       int ed_cnt;
+};
+
+/* hcd */
+/* endpoint */
+static int ep_link(ohci_t * ohci, ed_t * ed);
+static int ep_unlink(ohci_t * ohci, ed_t * ed);
+static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned long pipe,
+               int interval, int load);
+
+/*-------------------------------------------------------------------------*/
+
+/* we need more TDs than EDs */
+#define NUM_TD 64
+
+/* +1 so we can align the storage */
+td_t gtd[NUM_TD+1];
+/* pointers to aligned storage */
+td_t *ptd;
+
+/* TDs ... */
+static inline struct td *
+td_alloc (struct usb_device *usb_dev)
+{
+       int i;
+       struct td       *td;
+
+       td = NULL;
+       for (i = 0; i < NUM_TD; i++)
+       {
+               if (ptd[i].usb_dev == NULL)
+               {
+                       td = &ptd[i];
+                       td->usb_dev = usb_dev;
+                       break;
+               }
+       }
+
+       return td;
+}
+
+static inline void
+ed_free (struct ed *ed)
+{
+       ed->usb_dev = NULL;
+}
diff --git a/drivers/usb/usbdcore.c b/drivers/usb/usbdcore.c
new file mode 100644 (file)
index 0000000..308c7ce
--- /dev/null
@@ -0,0 +1,684 @@
+/*
+ * (C) Copyright 2003
+ * Gerry Hamel, geh@ti.com, Texas Instruments
+ *
+ * Based on
+ * linux/drivers/usbd/usbd.c.c - USB Device Core Layer
+ *
+ * Copyright (c) 2000, 2001, 2002 Lineo
+ * Copyright (c) 2001 Hewlett Packard
+ *
+ * By:
+ *     Stuart Lynne <sl@lineo.com>,
+ *     Tom Rushworth <tbr@lineo.com>,
+ *     Bruce Balden <balden@lineo.com>
+ *
+ * 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.
+ *
+ */
+
+#include <malloc.h>
+#include "usbdcore.h"
+
+#define MAX_INTERFACES 2
+
+
+int maxstrings = 20;
+
+/* Global variables ************************************************************************** */
+
+struct usb_string_descriptor **usb_strings;
+
+int usb_devices;
+
+extern struct usb_function_driver ep0_driver;
+
+int registered_functions;
+int registered_devices;
+
+char *usbd_device_events[] = {
+       "DEVICE_UNKNOWN",
+       "DEVICE_INIT",
+       "DEVICE_CREATE",
+       "DEVICE_HUB_CONFIGURED",
+       "DEVICE_RESET",
+       "DEVICE_ADDRESS_ASSIGNED",
+       "DEVICE_CONFIGURED",
+       "DEVICE_SET_INTERFACE",
+       "DEVICE_SET_FEATURE",
+       "DEVICE_CLEAR_FEATURE",
+       "DEVICE_DE_CONFIGURED",
+       "DEVICE_BUS_INACTIVE",
+       "DEVICE_BUS_ACTIVITY",
+       "DEVICE_POWER_INTERRUPTION",
+       "DEVICE_HUB_RESET",
+       "DEVICE_DESTROY",
+       "DEVICE_FUNCTION_PRIVATE",
+};
+
+char *usbd_device_states[] = {
+       "STATE_INIT",
+       "STATE_CREATED",
+       "STATE_ATTACHED",
+       "STATE_POWERED",
+       "STATE_DEFAULT",
+       "STATE_ADDRESSED",
+       "STATE_CONFIGURED",
+       "STATE_UNKNOWN",
+};
+
+char *usbd_device_requests[] = {
+       "GET STATUS",           /* 0 */
+       "CLEAR FEATURE",        /* 1 */
+       "RESERVED",             /* 2 */
+       "SET FEATURE",          /* 3 */
+       "RESERVED",             /* 4 */
+       "SET ADDRESS",          /* 5 */
+       "GET DESCRIPTOR",       /* 6 */
+       "SET DESCRIPTOR",       /* 7 */
+       "GET CONFIGURATION",    /* 8 */
+       "SET CONFIGURATION",    /* 9 */
+       "GET INTERFACE",        /* 10 */
+       "SET INTERFACE",        /* 11 */
+       "SYNC FRAME",           /* 12 */
+};
+
+char *usbd_device_descriptors[] = {
+       "UNKNOWN",              /* 0 */
+       "DEVICE",               /* 1 */
+       "CONFIG",               /* 2 */
+       "STRING",               /* 3 */
+       "INTERFACE",            /* 4 */
+       "ENDPOINT",             /* 5 */
+       "DEVICE QUALIFIER",     /* 6 */
+       "OTHER SPEED",          /* 7 */
+       "INTERFACE POWER",      /* 8 */
+};
+
+char *usbd_device_status[] = {
+       "USBD_OPENING",
+       "USBD_OK",
+       "USBD_SUSPENDED",
+       "USBD_CLOSING",
+};
+
+
+/* Descriptor support functions ************************************************************** */
+
+
+/**
+ * usbd_get_string - find and return a string descriptor
+ * @index: string index to return
+ *
+ * Find an indexed string and return a pointer to a it.
+ */
+struct usb_string_descriptor *usbd_get_string (__u8 index)
+{
+       if (index >= maxstrings) {
+               return NULL;
+       }
+       return usb_strings[index];
+}
+
+
+/* Access to device descriptor functions ***************************************************** */
+
+
+/* *
+ * usbd_device_configuration_instance - find a configuration instance for this device
+ * @device:
+ * @configuration: index to configuration, 0 - N-1
+ *
+ * Get specifed device configuration. Index should be bConfigurationValue-1.
+ */
+static struct usb_configuration_instance *usbd_device_configuration_instance (struct usb_device_instance *device,
+               unsigned int port, unsigned int configuration)
+{
+       /* XXX */
+       configuration = configuration ? configuration - 1 : 0;
+
+       if (configuration >= device->configurations) {
+               return NULL;
+       }
+       return device->configuration_instance_array + configuration;
+}
+
+
+/* *
+ * usbd_device_interface_instance
+ * @device:
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ *
+ * Return the specified interface descriptor for the specified device.
+ */
+struct usb_interface_instance *usbd_device_interface_instance (struct usb_device_instance *device, int port, int configuration, int interface)
+{
+       struct usb_configuration_instance *configuration_instance;
+
+       if ((configuration_instance = usbd_device_configuration_instance (device, port, configuration)) == NULL) {
+               return NULL;
+       }
+       if (interface >= configuration_instance->interfaces) {
+               return NULL;
+       }
+       return configuration_instance->interface_instance_array + interface;
+}
+
+/* *
+ * usbd_device_alternate_descriptor_list
+ * @device:
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @alternate: alternate setting
+ *
+ * Return the specified alternate descriptor for the specified device.
+ */
+struct usb_alternate_instance *usbd_device_alternate_instance (struct usb_device_instance *device, int port, int configuration, int interface, int alternate)
+{
+       struct usb_interface_instance *interface_instance;
+
+       if ((interface_instance = usbd_device_interface_instance (device, port, configuration, interface)) == NULL) {
+               return NULL;
+       }
+
+       if (alternate >= interface_instance->alternates) {
+               return NULL;
+       }
+
+       return interface_instance->alternates_instance_array + alternate;
+}
+
+
+/* *
+ * usbd_device_device_descriptor
+ * @device: which device
+ * @configuration: index to configuration, 0 - N-1
+ * @port: which port
+ *
+ * Return the specified configuration descriptor for the specified device.
+ */
+struct usb_device_descriptor *usbd_device_device_descriptor (struct usb_device_instance *device, int port)
+{
+       return (device->device_descriptor);
+}
+
+
+/**
+ * usbd_device_configuration_descriptor
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ *
+ * Return the specified configuration descriptor for the specified device.
+ */
+struct usb_configuration_descriptor *usbd_device_configuration_descriptor (struct
+                                                                          usb_device_instance
+                                                                          *device, int port, int configuration)
+{
+       struct usb_configuration_instance *configuration_instance;
+       if (!(configuration_instance = usbd_device_configuration_instance (device, port, configuration))) {
+               return NULL;
+       }
+       return (configuration_instance->configuration_descriptor);
+}
+
+
+/**
+ * usbd_device_interface_descriptor
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @alternate: alternate setting
+ *
+ * Return the specified interface descriptor for the specified device.
+ */
+struct usb_interface_descriptor *usbd_device_interface_descriptor (struct usb_device_instance
+                                                                  *device, int port, int configuration, int interface, int alternate)
+{
+       struct usb_interface_instance *interface_instance;
+       if (!(interface_instance = usbd_device_interface_instance (device, port, configuration, interface))) {
+               return NULL;
+       }
+       if ((alternate < 0) || (alternate >= interface_instance->alternates)) {
+               return NULL;
+       }
+       return (interface_instance->alternates_instance_array[alternate].interface_descriptor);
+}
+
+/**
+ * usbd_device_endpoint_descriptor_index
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @alternate: index setting
+ * @index: which index
+ *
+ * Return the specified endpoint descriptor for the specified device.
+ */
+struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor_index (struct usb_device_instance
+                                                                      *device, int port, int configuration, int interface, int alternate, int index)
+{
+       struct usb_alternate_instance *alternate_instance;
+
+       if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
+               return NULL;
+       }
+       if (index >= alternate_instance->endpoints) {
+               return NULL;
+       }
+       return *(alternate_instance->endpoints_descriptor_array + index);
+}
+
+
+/**
+ * usbd_device_endpoint_transfersize
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @index: which index
+ *
+ * Return the specified endpoint transfer size;
+ */
+int usbd_device_endpoint_transfersize (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int index)
+{
+       struct usb_alternate_instance *alternate_instance;
+
+       if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
+               return 0;
+       }
+       if (index >= alternate_instance->endpoints) {
+               return 0;
+       }
+       return *(alternate_instance->endpoint_transfersize_array + index);
+}
+
+
+/**
+ * usbd_device_endpoint_descriptor
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @alternate: alternate setting
+ * @endpoint: which endpoint
+ *
+ * Return the specified endpoint descriptor for the specified device.
+ */
+struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int endpoint)
+{
+       struct usb_endpoint_descriptor *endpoint_descriptor;
+       int i;
+
+       for (i = 0; !(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, configuration, interface, alternate, i)); i++) {
+               if (endpoint_descriptor->bEndpointAddress == endpoint) {
+                       return endpoint_descriptor;
+               }
+       }
+       return NULL;
+}
+
+/**
+ * usbd_endpoint_halted
+ * @device: point to struct usb_device_instance
+ * @endpoint: endpoint to check
+ *
+ * Return non-zero if endpoint is halted.
+ */
+int usbd_endpoint_halted (struct usb_device_instance *device, int endpoint)
+{
+       return (device->status == USB_STATUS_HALT);
+}
+
+
+/**
+ * usbd_rcv_complete - complete a receive
+ * @endpoint:
+ * @len:
+ * @urb_bad:
+ *
+ * Called from rcv interrupt to complete.
+ */
+void usbd_rcv_complete(struct usb_endpoint_instance *endpoint, int len, int urb_bad)
+{
+       if (endpoint) {
+               struct urb *rcv_urb;
+
+               /*usbdbg("len: %d urb: %p\n", len, endpoint->rcv_urb); */
+
+               /* if we had an urb then update actual_length, dispatch if neccessary */
+               if ((rcv_urb = endpoint->rcv_urb)) {
+
+                       /*usbdbg("actual: %d buffer: %d\n", */
+                       /*rcv_urb->actual_length, rcv_urb->buffer_length); */
+
+                       /* check the urb is ok, are we adding data less than the packetsize */
+                       if (!urb_bad && (len <= endpoint->rcv_packetSize)) {
+                         /*usbdbg("updating actual_length by %d\n",len); */
+
+                               /* increment the received data size */
+                               rcv_urb->actual_length += len;
+
+                       } else {
+                               usberr(" RECV_ERROR actual: %d buffer: %d urb_bad: %d\n",
+                                      rcv_urb->actual_length, rcv_urb->buffer_length, urb_bad);
+
+                               rcv_urb->actual_length = 0;
+                               rcv_urb->status = RECV_ERROR;
+                       }
+               } else {
+                       usberr("no rcv_urb!");
+               }
+       } else {
+               usberr("no endpoint!");
+       }
+
+}
+
+/**
+ * usbd_tx_complete - complete a transmit
+ * @endpoint:
+ * @resetart:
+ *
+ * Called from tx interrupt to complete.
+ */
+void usbd_tx_complete (struct usb_endpoint_instance *endpoint)
+{
+       if (endpoint) {
+               struct urb *tx_urb;
+
+               /* if we have a tx_urb advance or reset, finish if complete */
+               if ((tx_urb = endpoint->tx_urb)) {
+                       int sent = endpoint->last;
+                       endpoint->sent += sent;
+                       endpoint->last -= sent;
+
+                       if( (endpoint->tx_urb->actual_length - endpoint->sent) <= 0 ) {
+                               tx_urb->actual_length = 0;
+                               endpoint->sent = 0;
+                               endpoint->last = 0;
+
+                               /* Remove from active, save for re-use */
+                               urb_detach(tx_urb);
+                               urb_append(&endpoint->done, tx_urb);
+                               /*usbdbg("done->next %p, tx_urb %p, done %p", */
+                               /*       endpoint->done.next, tx_urb, &endpoint->done); */
+
+                               endpoint->tx_urb = first_urb_detached(&endpoint->tx);
+                               if( endpoint->tx_urb ) {
+                                       endpoint->tx_queue--;
+                                       usbdbg("got urb from tx list");
+                               }
+                               if( !endpoint->tx_urb ) {
+                                       /*usbdbg("taking urb from done list"); */
+                                       endpoint->tx_urb = first_urb_detached(&endpoint->done);
+                               }
+                               if( !endpoint->tx_urb ) {
+                                       usbdbg("allocating new urb for tx_urb");
+                                       endpoint->tx_urb = usbd_alloc_urb(tx_urb->device, endpoint);
+                               }
+                       }
+               }
+       }
+}
+
+/* URB linked list functions ***************************************************** */
+
+/*
+ * Initialize an urb_link to be a single element list.
+ * If the urb_link is being used as a distinguished list head
+ * the list is empty when the head is the only link in the list.
+ */
+void urb_link_init (urb_link * ul)
+{
+       if (ul) {
+               ul->prev = ul->next = ul;
+       }
+}
+
+/*
+ * Detach an urb_link from a list, and set it
+ * up as a single element list, so no dangling
+ * pointers can be followed, and so it can be
+ * joined to another list if so desired.
+ */
+void urb_detach (struct urb *urb)
+{
+       if (urb) {
+               urb_link *ul = &urb->link;
+               ul->next->prev = ul->prev;
+               ul->prev->next = ul->next;
+               urb_link_init (ul);
+       }
+}
+
+/*
+ * Return the first urb_link in a list with a distinguished
+ * head "hd", or NULL if the list is empty.  This will also
+ * work as a predicate, returning NULL if empty, and non-NULL
+ * otherwise.
+ */
+urb_link *first_urb_link (urb_link * hd)
+{
+       urb_link *nx;
+       if (NULL != hd && NULL != (nx = hd->next) && nx != hd) {
+               /* There is at least one element in the list */
+               /* (besides the distinguished head). */
+               return (nx);
+       }
+       /* The list is empty */
+       return (NULL);
+}
+
+/*
+ * Return the first urb in a list with a distinguished
+ * head "hd", or NULL if the list is empty.
+ */
+struct urb *first_urb (urb_link * hd)
+{
+       urb_link *nx;
+       if (NULL == (nx = first_urb_link (hd))) {
+               /* The list is empty */
+               return (NULL);
+       }
+       return (p2surround (struct urb, link, nx));
+}
+
+/*
+ * Detach and return the first urb in a list with a distinguished
+ * head "hd", or NULL if the list is empty.
+ *
+ */
+struct urb *first_urb_detached (urb_link * hd)
+{
+       struct urb *urb;
+       if ((urb = first_urb (hd))) {
+               urb_detach (urb);
+       }
+       return urb;
+}
+
+
+/*
+ * Append an urb_link (or a whole list of
+ * urb_links) to the tail of another list
+ * of urb_links.
+ */
+void urb_append (urb_link * hd, struct urb *urb)
+{
+       if (hd && urb) {
+               urb_link *new = &urb->link;
+
+               /* This allows the new urb to be a list of urbs, */
+               /* with new pointing at the first, but the link */
+               /* must be initialized. */
+               /* Order is important here... */
+               urb_link *pul = hd->prev;
+               new->prev->next = hd;
+               hd->prev = new->prev;
+               new->prev = pul;
+               pul->next = new;
+       }
+}
+
+/* URB create/destroy functions ***************************************************** */
+
+/**
+ * usbd_alloc_urb - allocate an URB appropriate for specified endpoint
+ * @device: device instance
+ * @endpoint: endpoint
+ *
+ * Allocate an urb structure. The usb device urb structure is used to
+ * contain all data associated with a transfer, including a setup packet for
+ * control transfers.
+ *
+ * NOTE: endpoint_address MUST contain a direction flag.
+ */
+struct urb *usbd_alloc_urb (struct usb_device_instance *device, struct usb_endpoint_instance *endpoint)
+{
+       struct urb *urb;
+
+       if( !(urb = (struct urb*)malloc(sizeof(struct urb))) ) {
+         usberr(" F A T A L:  malloc(%u) FAILED!!!!", sizeof(struct urb));
+         return NULL;
+       }
+
+       /* Fill in known fields */
+       memset(urb, 0, sizeof(struct urb));
+       urb->endpoint = endpoint;
+       urb->device = device;
+       urb->buffer = (u8*)urb->buffer_data;
+       urb->buffer_length = sizeof(urb->buffer_data);
+
+       urb_link_init (&urb->link);
+
+       return urb;
+}
+
+/**
+ * usbd_dealloc_urb - deallocate an URB and associated buffer
+ * @urb: pointer to an urb structure
+ *
+ * Deallocate an urb structure and associated data.
+ */
+void usbd_dealloc_urb (struct urb *urb)
+{
+       if (urb) {
+               free (urb);
+       }
+}
+
+/* Event signaling functions ***************************************************** */
+
+/**
+ * usbd_device_event - called to respond to various usb events
+ * @device: pointer to struct device
+ * @event: event to respond to
+ *
+ * Used by a Bus driver to indicate an event.
+ */
+void usbd_device_event_irq (struct usb_device_instance *device, usb_device_event_t event, int data)
+{
+       usb_device_state_t state;
+
+       if (!device || !device->bus) {
+               usberr("(%p,%d) NULL device or device->bus", device, event);
+               return;
+       }
+
+       state = device->device_state;
+
+       usbinfo("%s", usbd_device_events[event]);
+
+       switch (event) {
+       case DEVICE_UNKNOWN:
+               break;
+       case DEVICE_INIT:
+               device->device_state = STATE_INIT;
+               break;
+
+       case DEVICE_CREATE:
+               device->device_state = STATE_ATTACHED;
+               break;
+
+       case DEVICE_HUB_CONFIGURED:
+               device->device_state = STATE_POWERED;
+               break;
+
+       case DEVICE_RESET:
+               device->device_state = STATE_DEFAULT;
+               device->address = 0;
+               break;
+
+       case DEVICE_ADDRESS_ASSIGNED:
+               device->device_state = STATE_ADDRESSED;
+               break;
+
+       case DEVICE_CONFIGURED:
+               device->device_state = STATE_CONFIGURED;
+               break;
+
+       case DEVICE_DE_CONFIGURED:
+               device->device_state = STATE_ADDRESSED;
+               break;
+
+       case DEVICE_BUS_INACTIVE:
+               if (device->status != USBD_CLOSING) {
+                       device->status = USBD_SUSPENDED;
+               }
+               break;
+       case DEVICE_BUS_ACTIVITY:
+               if (device->status != USBD_CLOSING) {
+                       device->status = USBD_OK;
+               }
+               break;
+
+       case DEVICE_SET_INTERFACE:
+               break;
+       case DEVICE_SET_FEATURE:
+               break;
+       case DEVICE_CLEAR_FEATURE:
+               break;
+
+       case DEVICE_POWER_INTERRUPTION:
+               device->device_state = STATE_POWERED;
+               break;
+       case DEVICE_HUB_RESET:
+               device->device_state = STATE_ATTACHED;
+               break;
+       case DEVICE_DESTROY:
+               device->device_state = STATE_UNKNOWN;
+               break;
+
+       case DEVICE_FUNCTION_PRIVATE:
+               break;
+
+       default:
+               usbdbg("event %d - not handled",event);
+               break;
+       }
+       /*usbdbg("%s event: %d oldstate: %d newstate: %d status: %d address: %d",
+               device->name, event, state,
+               device->device_state, device->status, device->address); */
+
+       /* tell the bus interface driver */
+       if( device->event ) {
+               /* usbdbg("calling device->event"); */
+               device->event(device, event, data);
+       }
+}
diff --git a/drivers/usb/usbdcore_ep0.c b/drivers/usb/usbdcore_ep0.c
new file mode 100644 (file)
index 0000000..1e44f32
--- /dev/null
@@ -0,0 +1,607 @@
+/*
+ * (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
+ *
+ * Copyright (c) 2000, 2001, 2002 Lineo
+ * Copyright (c) 2001 Hewlett Packard
+ *
+ * By:
+ *     Stuart Lynne <sl@lineo.com>,
+ *     Tom Rushworth <tbr@lineo.com>,
+ *     Bruce Balden <balden@lineo.com>
+ *
+ * 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.
+ *
+ */
+
+/*
+ * This is the builtin ep0 control function. It implements all required functionality
+ * for responding to control requests (SETUP packets).
+ *
+ * XXX
+ *
+ * Currently we do not pass any SETUP packets (or other) to the configured
+ * 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_USB_DEVICE)
+#include "usbdcore.h"
+
+#if 0
+#define dbg_ep0(lvl,fmt,args...) serial_printf("[%s] %s:%d: "fmt"\n",__FILE__,__FUNCTION__,__LINE__,##args)
+#else
+#define dbg_ep0(lvl,fmt,args...)
+#endif
+
+/* EP0 Configuration Set ********************************************************************* */
+
+
+/**
+ * ep0_get_status - fill in URB data with appropriate status
+ * @device:
+ * @urb:
+ * @index:
+ * @requesttype:
+ *
+ */
+static int ep0_get_status (struct usb_device_instance *device,
+                          struct urb *urb, int index, int requesttype)
+{
+       char *cp;
+
+       urb->actual_length = 2;
+       cp = (char*)urb->buffer;
+       cp[0] = cp[1] = 0;
+
+       switch (requesttype) {
+       case USB_REQ_RECIPIENT_DEVICE:
+               cp[0] = USB_STATUS_SELFPOWERED;
+               break;
+       case USB_REQ_RECIPIENT_INTERFACE:
+               break;
+       case USB_REQ_RECIPIENT_ENDPOINT:
+               cp[0] = usbd_endpoint_halted (device, index);
+               break;
+       case USB_REQ_RECIPIENT_OTHER:
+               urb->actual_length = 0;
+       default:
+               break;
+       }
+       dbg_ep0 (2, "%02x %02x", cp[0], cp[1]);
+       return 0;
+}
+
+/**
+ * ep0_get_one
+ * @device:
+ * @urb:
+ * @result:
+ *
+ * Set a single byte value in the urb send buffer. Return non-zero to signal
+ * a request error.
+ */
+static int ep0_get_one (struct usb_device_instance *device, struct urb *urb,
+                       __u8 result)
+{
+       urb->actual_length = 1; /* XXX 2? */
+       ((char *) urb->buffer)[0] = result;
+       return 0;
+}
+
+/**
+ * copy_config
+ * @urb: pointer to urb
+ * @data: pointer to configuration data
+ * @length: length of data
+ *
+ * Copy configuration data to urb transfer buffer if there is room for it.
+ */
+void copy_config (struct urb *urb, void *data, int max_length,
+                        int max_buf)
+{
+       int available;
+       int length;
+
+       /*dbg_ep0(3, "-> actual: %d buf: %d max_buf: %d max_length: %d data: %p", */
+       /*        urb->actual_length, urb->buffer_length, max_buf, max_length, data); */
+
+       if (!data) {
+               dbg_ep0 (1, "data is NULL");
+               return;
+       }
+       length = max_length;
+
+       if (length > max_length) {
+               dbg_ep0 (1, "length: %d >= max_length: %d", length,
+                        max_length);
+               return;
+       }
+       /*dbg_ep0(1, "   actual: %d buf: %d max_buf: %d max_length: %d length: %d", */
+       /*        urb->actual_length, urb->buffer_length, max_buf, max_length, length); */
+
+       if ((available =
+            /*urb->buffer_length */ max_buf - urb->actual_length) <= 0) {
+               return;
+       }
+       /*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */
+       /*        urb->actual_length, urb->buffer_length, max_buf, length, available); */
+
+       if (length > available) {
+               length = available;
+       }
+       /*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */
+       /*        urb->actual_length, urb->buffer_length, max_buf, length, available); */
+
+       memcpy (urb->buffer + urb->actual_length, data, length);
+       urb->actual_length += length;
+
+       dbg_ep0 (3,
+                "copy_config: <- actual: %d buf: %d max_buf: %d max_length: %d available: %d",
+                urb->actual_length, urb->buffer_length, max_buf, max_length,
+                available);
+}
+
+/**
+ * ep0_get_descriptor
+ * @device:
+ * @urb:
+ * @max:
+ * @descriptor_type:
+ * @index:
+ *
+ * Called by ep0_rx_process for a get descriptor device command. Determine what
+ * descriptor is being requested, copy to send buffer. Return zero if ok to send,
+ * return non-zero to signal a request error.
+ */
+static int ep0_get_descriptor (struct usb_device_instance *device,
+                              struct urb *urb, int max, int descriptor_type,
+                              int index)
+{
+       int port = 0;           /* XXX compound device */
+       char *cp;
+
+       /*dbg_ep0(3, "max: %x type: %x index: %x", max, descriptor_type, index); */
+
+       if (!urb || !urb->buffer || !urb->buffer_length
+           || (urb->buffer_length < 255)) {
+               dbg_ep0 (2, "invalid urb %p", urb);
+               return -1L;
+       }
+
+       /* setup tx urb */
+       urb->actual_length = 0;
+       cp = (char*)urb->buffer;
+
+       dbg_ep0 (2, "%s", USBD_DEVICE_DESCRIPTORS (descriptor_type));
+
+       switch (descriptor_type) {
+       case USB_DESCRIPTOR_TYPE_DEVICE:
+               {
+                       struct usb_device_descriptor *device_descriptor;
+                       if (!
+                           (device_descriptor =
+                            usbd_device_device_descriptor (device, port))) {
+                               return -1;
+                       }
+                       /* copy descriptor for this device */
+                       copy_config (urb, device_descriptor,
+                                    sizeof (struct usb_device_descriptor),
+                                    max);
+
+                       /* correct the correct control endpoint 0 max packet size into the descriptor */
+                       device_descriptor =
+                               (struct usb_device_descriptor *) urb->buffer;
+
+               }
+               dbg_ep0(3, "copied device configuration, actual_length: 0x%x", urb->actual_length);
+               break;
+
+       case USB_DESCRIPTOR_TYPE_CONFIGURATION:
+               {
+                       struct usb_configuration_descriptor
+                               *configuration_descriptor;
+                       struct usb_device_descriptor *device_descriptor;
+                       if (!
+                           (device_descriptor =
+                            usbd_device_device_descriptor (device, port))) {
+                               return -1;
+                       }
+                       /*dbg_ep0(2, "%d %d", index, device_descriptor->bNumConfigurations); */
+                       if (index > device_descriptor->bNumConfigurations) {
+                               dbg_ep0 (0, "index too large: %d > %d", index,
+                                        device_descriptor->
+                                        bNumConfigurations);
+                               return -1;
+                       }
+
+                       if (!
+                           (configuration_descriptor =
+                            usbd_device_configuration_descriptor (device,
+                                                                  port,
+                                                                  index))) {
+                               dbg_ep0 (0,
+                                        "usbd_device_configuration_descriptor failed: %d",
+                                        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,
+
+                                       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 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 =
+                               le16_to_cpu (urb->device_request.wIndex);
+                       int bAlternateSetting = 0;
+                       int class = 0;
+                       struct usb_class_descriptor *class_descriptor;
+
+                       if (!(class_descriptor =
+                             usbd_device_class_descriptor_index (device,
+                                                                 port, 0,
+                                                                 bNumInterface,
+                                                                 bAlternateSetting,
+                                                                 class))
+                           || class_descriptor->descriptor.hid.bDescriptorType != USB_DT_HID) {
+                               dbg_ep0 (3, "[%d] interface is not HID",
+                                        bNumInterface);
+                               return -1;
+                       }
+                       /* copy descriptor for this class */
+                       copy_config (urb, class_descriptor,
+                                    class_descriptor->descriptor.hid.bLength,
+                                    max);
+#endif
+               }
+               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 =
+                               le16_to_cpu (urb->device_request.wIndex);
+                       int bAlternateSetting = 0;
+                       int class = 0;
+                       struct usb_class_report_descriptor *report_descriptor;
+
+                       if (!(report_descriptor =
+                             usbd_device_class_report_descriptor_index
+                             (device, port, 0, bNumInterface,
+                              bAlternateSetting, class))
+                           || report_descriptor->bDescriptorType !=
+                           USB_DT_REPORT) {
+                               dbg_ep0 (3, "[%d] descriptor is not REPORT",
+                                        bNumInterface);
+                               return -1;
+                       }
+                       /* copy report descriptor for this class */
+                       /*copy_config(urb, &report_descriptor->bData[0], report_descriptor->wLength, max); */
+                       if (max - urb->actual_length > 0) {
+                               int length =
+                                       MIN (report_descriptor->wLength,
+                                            max - urb->actual_length);
+                               memcpy (urb->buffer + urb->actual_length,
+                                       &report_descriptor->bData[0], length);
+                               urb->actual_length += length;
+                       }
+#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 tx_packetSize: %2d",
+                urb->buffer, urb->buffer_length, urb->actual_length,
+                device->bus->endpoint_array[0].tx_packetSize);
+/*
+    if ((urb->actual_length < max) && !(urb->actual_length % device->bus->endpoint_array[0].tx_packetSize)) {
+       dbg_ep0(0, "adding null byte");
+       urb->buffer[urb->actual_length++] = 0;
+       dbg_ep0(0, "urb: buffer_length: %2d actual_length: %2d packet size: %2d",
+               urb->buffer_length, urb->actual_length device->bus->endpoint_array[0].tx_packetSize);
+    }
+*/
+       return 0;
+
+}
+
+/**
+ * ep0_recv_setup - called to indicate URB has been received
+ * @urb: pointer to struct urb
+ *
+ * Check if this is a setup packet, process the device request, put results
+ * back into the urb and return zero or non-zero to indicate success (DATA)
+ * or failure (STALL).
+ *
+ */
+int ep0_recv_setup (struct urb *urb)
+{
+       /*struct usb_device_request *request = urb->buffer; */
+       /*struct usb_device_instance *device = urb->device; */
+
+       struct usb_device_request *request;
+       struct usb_device_instance *device;
+       int address;
+
+       dbg_ep0 (0, "entering ep0_recv_setup()");
+       if (!urb || !urb->device) {
+               dbg_ep0 (3, "invalid URB %p", urb);
+               return -1;
+       }
+
+       request = &urb->device_request;
+       device = urb->device;
+
+       dbg_ep0 (3, "urb: %p device: %p", urb, urb->device);
+
+
+       /*dbg_ep0(2, "-       -       -       -       -       -       -       -       -       -"); */
+
+       dbg_ep0 (2,
+                "bmRequestType:%02x bRequest:%02x wValue:%04x wIndex:%04x wLength:%04x %s",
+                request->bmRequestType, request->bRequest,
+                le16_to_cpu (request->wValue), le16_to_cpu (request->wIndex),
+                le16_to_cpu (request->wLength),
+                USBD_DEVICE_REQUESTS (request->bRequest));
+
+       /* 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 */
+       }
+
+       switch (device->device_state) {
+       case STATE_CREATED:
+       case STATE_ATTACHED:
+       case STATE_POWERED:
+               /* It actually is important to allow requests in these states,
+                * Windows will request descriptors before assigning an
+                * address to the client.
+                */
+
+               /*dbg_ep0 (1, "request %s not allowed in this state: %s", */
+               /*                USBD_DEVICE_REQUESTS(request->bRequest), */
+               /*                usbd_device_states[device->device_state]); */
+               /*return -1; */
+               break;
+
+       case STATE_INIT:
+       case STATE_DEFAULT:
+               switch (request->bRequest) {
+               case USB_REQ_GET_STATUS:
+               case USB_REQ_GET_INTERFACE:
+               case USB_REQ_SYNCH_FRAME:       /* XXX should never see this (?) */
+               case USB_REQ_CLEAR_FEATURE:
+               case USB_REQ_SET_FEATURE:
+               case USB_REQ_SET_DESCRIPTOR:
+                       /* case USB_REQ_SET_CONFIGURATION: */
+               case USB_REQ_SET_INTERFACE:
+                       dbg_ep0 (1,
+                                "request %s not allowed in DEFAULT state: %s",
+                                USBD_DEVICE_REQUESTS (request->bRequest),
+                                usbd_device_states[device->device_state]);
+                       return -1;
+
+               case USB_REQ_SET_CONFIGURATION:
+               case USB_REQ_SET_ADDRESS:
+               case USB_REQ_GET_DESCRIPTOR:
+               case USB_REQ_GET_CONFIGURATION:
+                       break;
+               }
+       case STATE_ADDRESSED:
+       case STATE_CONFIGURED:
+               break;
+       case STATE_UNKNOWN:
+               dbg_ep0 (1, "request %s not allowed in UNKNOWN state: %s",
+                        USBD_DEVICE_REQUESTS (request->bRequest),
+                        usbd_device_states[device->device_state]);
+               return -1;
+       }
+
+       /* handle all requests that return data (direction bit set on bm RequestType) */
+       if ((request->bmRequestType & USB_REQ_DIRECTION_MASK)) {
+
+               dbg_ep0 (3, "Device-to-Host");
+
+               switch (request->bRequest) {
+
+               case USB_REQ_GET_STATUS:
+                       return ep0_get_status (device, urb, request->wIndex,
+                                              request->bmRequestType &
+                                              USB_REQ_RECIPIENT_MASK);
+
+               case USB_REQ_GET_DESCRIPTOR:
+                       return ep0_get_descriptor (device, urb,
+                                                  le16_to_cpu (request->wLength),
+                                                  le16_to_cpu (request->wValue) >> 8,
+                                                  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);
+
+               case USB_REQ_GET_INTERFACE:
+                       return ep0_get_one (device, urb, device->alternate);
+
+               case USB_REQ_SYNCH_FRAME:       /* XXX should never see this (?) */
+                       return -1;
+
+               case USB_REQ_CLEAR_FEATURE:
+               case USB_REQ_SET_FEATURE:
+               case USB_REQ_SET_ADDRESS:
+               case USB_REQ_SET_DESCRIPTOR:
+               case USB_REQ_SET_CONFIGURATION:
+               case USB_REQ_SET_INTERFACE:
+                       return -1;
+               }
+       }
+       /* handle the requests that do not return data */
+       else {
+
+
+               /*dbg_ep0(3, "Host-to-Device"); */
+               switch (request->bRequest) {
+
+               case USB_REQ_CLEAR_FEATURE:
+               case USB_REQ_SET_FEATURE:
+                       dbg_ep0 (0, "Host-to-Device");
+                       switch (request->
+                               bmRequestType & USB_REQ_RECIPIENT_MASK) {
+                       case USB_REQ_RECIPIENT_DEVICE:
+                               /* XXX DEVICE_REMOTE_WAKEUP or TEST_MODE would be added here */
+                               /* XXX fall through for now as we do not support either */
+                       case USB_REQ_RECIPIENT_INTERFACE:
+                       case USB_REQ_RECIPIENT_OTHER:
+                               dbg_ep0 (0, "request %s not",
+                                        USBD_DEVICE_REQUESTS (request->bRequest));
+                       default:
+                               return -1;
+
+                       case USB_REQ_RECIPIENT_ENDPOINT:
+                               dbg_ep0 (0, "ENDPOINT: %x", le16_to_cpu (request->wValue));
+                               if (le16_to_cpu (request->wValue) == USB_ENDPOINT_HALT) {
+                                       /*return usbd_device_feature (device, le16_to_cpu (request->wIndex), */
+                                       /*                    request->bRequest == USB_REQ_SET_FEATURE); */
+                                       /* NEED TO IMPLEMENT THIS!!! */
+                                       return -1;
+                               } else {
+                                       dbg_ep0 (1, "request %s bad wValue: %04x",
+                                                USBD_DEVICE_REQUESTS
+                                                (request->bRequest),
+                                                le16_to_cpu (request->wValue));
+                                       return -1;
+                               }
+                       }
+
+               case USB_REQ_SET_ADDRESS:
+                       /* check if this is a re-address, reset first if it is (this shouldn't be possible) */
+                       if (device->device_state != STATE_DEFAULT) {
+                               dbg_ep0 (1, "set_address: %02x state: %s",
+                                        le16_to_cpu (request->wValue),
+                                        usbd_device_states[device->device_state]);
+                               return -1;
+                       }
+                       address = le16_to_cpu (request->wValue);
+                       if ((address & 0x7f) != address) {
+                               dbg_ep0 (1, "invalid address %04x %04x",
+                                        address, address & 0x7f);
+                               return -1;
+                       }
+                       device->address = address;
+
+                       /*dbg_ep0(2, "address: %d %d %d", */
+                       /*        request->wValue, le16_to_cpu(request->wValue), device->address); */
+
+                       return 0;
+
+               case USB_REQ_SET_DESCRIPTOR:    /* XXX should we support this? */
+                       dbg_ep0 (0, "set descriptor: NOT SUPPORTED");
+                       return -1;
+
+               case USB_REQ_SET_CONFIGURATION:
+                       /* c.f. 9.4.7 - the top half of wValue is reserved */
+                       /* */
+                       if ((device->configuration =
+                               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 */
+                       device->interface = device->alternate = 0;
+
+                       /*dbg_ep0(2, "set configuration: %d", device->configuration); */
+                       /*serial_printf("DEVICE_CONFIGURED.. event?\n"); */
+                       return 0;
+
+               case USB_REQ_SET_INTERFACE:
+                       device->interface = le16_to_cpu (request->wIndex);
+                       device->alternate = le16_to_cpu (request->wValue);
+                       /*dbg_ep0(2, "set interface: %d alternate: %d", device->interface, device->alternate); */
+                       serial_printf ("DEVICE_SET_INTERFACE.. event?\n");
+                       return 0;
+
+               case USB_REQ_GET_STATUS:
+               case USB_REQ_GET_DESCRIPTOR:
+               case USB_REQ_GET_CONFIGURATION:
+               case USB_REQ_GET_INTERFACE:
+               case USB_REQ_SYNCH_FRAME:       /* XXX should never see this (?) */
+                       return -1;
+               }
+       }
+       return -1;
+}
+
+#endif
diff --git a/drivers/usb/usbdcore_mpc8xx.c b/drivers/usb/usbdcore_mpc8xx.c
new file mode 100644 (file)
index 0000000..d4c4096
--- /dev/null
@@ -0,0 +1,1401 @@
+/*
+ * 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"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#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 */
+       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) */
diff --git a/drivers/usb/usbdcore_omap1510.c b/drivers/usb/usbdcore_omap1510.c
new file mode 100644 (file)
index 0000000..84bb936
--- /dev/null
@@ -0,0 +1,1547 @@
+/*
+ * (C) Copyright 2003
+ * Gerry Hamel, geh@ti.com, Texas Instruments
+ *
+ * Based on
+ * linux/drivers/usb/device/bi/omap.c
+ * TI OMAP1510 USB bus interface driver
+ *
+ * Author: MontaVista Software, Inc.
+ *        source@mvista.com
+ *        (C) Copyright 2002
+ *
+ * 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 <common.h>
+
+#if defined(CONFIG_OMAP1510) && defined(CONFIG_USB_DEVICE)
+
+#include <asm/io.h>
+#ifdef CONFIG_OMAP_SX1
+#include <i2c.h>
+#endif
+
+#include "usbdcore.h"
+#include "usbdcore_omap1510.h"
+#include "usbdcore_ep0.h"
+
+
+#define UDC_INIT_MDELAY                     80 /* Device settle delay */
+#define UDC_MAX_ENDPOINTS           31 /* Number of endpoints on this UDC */
+
+/* Some kind of debugging output... */
+#if 1
+#define UDCDBG(str)
+#define UDCDBGA(fmt,args...)
+#else  /* The bugs still exists... */
+#define UDCDBG(str) serial_printf("[%s] %s:%d: " str "\n", __FILE__,__FUNCTION__,__LINE__)
+#define UDCDBGA(fmt,args...) serial_printf("[%s] %s:%d: " fmt "\n", __FILE__,__FUNCTION__,__LINE__, ##args)
+#endif
+
+#if 1
+#define UDCREG(name)
+#define UDCREGL(name)
+#else  /* The bugs still exists... */
+#define UDCREG(name)    serial_printf("%s():%d: %s[%08x]=%.4x\n",__FUNCTION__,__LINE__, (#name), name, inw(name))      /* For 16-bit regs */
+#define UDCREGL(name)   serial_printf("%s():%d: %s[%08x]=%.8x\n",__FUNCTION__,__LINE__, (#name), name, inl(name))      /* For 32-bit regs */
+#endif
+
+
+static struct urb *ep0_urb = NULL;
+
+static struct usb_device_instance *udc_device; /* Used in interrupt handler */
+static u16 udc_devstat = 0;    /* UDC status (DEVSTAT) */
+static u32 udc_interrupts = 0;
+
+static void udc_stall_ep (unsigned int ep_addr);
+
+
+static struct usb_endpoint_instance *omap1510_find_ep (int ep)
+{
+       int i;
+
+       for (i = 0; i < udc_device->bus->max_endpoints; i++) {
+               if (udc_device->bus->endpoint_array[i].endpoint_address == ep)
+                       return &udc_device->bus->endpoint_array[i];
+       }
+       return NULL;
+}
+
+/* ************************************************************************** */
+/* IO
+ */
+
+/*
+ * omap1510_prepare_endpoint_for_rx
+ *
+ * This function implements TRM Figure 14-11.
+ *
+ * The endpoint to prepare for transfer is specified as a physical endpoint
+ * number.  For OUT (rx) endpoints 1 through 15, the corresponding endpoint
+ * configuration register is checked to see if the endpoint is ISO or not.
+ * If the OUT endpoint is valid and is non-ISO then its FIFO is enabled.
+ * No action is taken for endpoint 0 or for IN (tx) endpoints 16 through 30.
+ */
+static void omap1510_prepare_endpoint_for_rx (int ep_addr)
+{
+       int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+
+       UDCDBGA ("omap1510_prepare_endpoint %x", ep_addr);
+       if (((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)) {
+               if ((inw (UDC_EP_RX (ep_num)) &
+                    (UDC_EPn_RX_Valid | UDC_EPn_RX_Iso)) ==
+                   UDC_EPn_RX_Valid) {
+                       /* rx endpoint is valid, non-ISO, so enable its FIFO */
+                       outw (UDC_EP_Sel | ep_num, UDC_EP_NUM);
+                       outw (UDC_Set_FIFO_En, UDC_CTRL);
+                       outw (0, UDC_EP_NUM);
+               }
+       }
+}
+
+/* omap1510_configure_endpoints
+ *
+ * This function implements TRM Figure 14-10.
+ */
+static void omap1510_configure_endpoints (struct usb_device_instance *device)
+{
+       int ep;
+       struct usb_bus_instance *bus;
+       struct usb_endpoint_instance *endpoint;
+       unsigned short ep_ptr;
+       unsigned short ep_size;
+       unsigned short ep_isoc;
+       unsigned short ep_doublebuffer;
+       int ep_addr;
+       int packet_size;
+       int buffer_size;
+       int attributes;
+
+       bus = device->bus;
+
+       /* There is a dedicated 2048 byte buffer for USB packets that may be
+        * arbitrarily partitioned among the endpoints on 8-byte boundaries.
+        * The first 8 bytes are reserved for receiving setup packets on
+        * endpoint 0.
+        */
+       ep_ptr = 8;             /* reserve the first 8 bytes for the setup fifo */
+
+       for (ep = 0; ep < bus->max_endpoints; ep++) {
+               endpoint = bus->endpoint_array + ep;
+               ep_addr = endpoint->endpoint_address;
+               if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+                       /* IN endpoint */
+                       packet_size = endpoint->tx_packetSize;
+                       attributes = endpoint->tx_attributes;
+               } else {
+                       /* OUT endpoint */
+                       packet_size = endpoint->rcv_packetSize;
+                       attributes = endpoint->rcv_attributes;
+               }
+
+               switch (packet_size) {
+               case 0:
+                       ep_size = 0;
+                       break;
+               case 8:
+                       ep_size = 0;
+                       break;
+               case 16:
+                       ep_size = 1;
+                       break;
+               case 32:
+                       ep_size = 2;
+                       break;
+               case 64:
+                       ep_size = 3;
+                       break;
+               case 128:
+                       ep_size = 4;
+                       break;
+               case 256:
+                       ep_size = 5;
+                       break;
+               case 512:
+                       ep_size = 6;
+                       break;
+               default:
+                       UDCDBGA ("ep 0x%02x has bad packet size %d",
+                                ep_addr, packet_size);
+                       packet_size = 0;
+                       ep_size = 0;
+                       break;
+               }
+
+               switch (attributes & USB_ENDPOINT_XFERTYPE_MASK) {
+               case USB_ENDPOINT_XFER_CONTROL:
+               case USB_ENDPOINT_XFER_BULK:
+               case USB_ENDPOINT_XFER_INT:
+               default:
+                       /* A non-isochronous endpoint may optionally be
+                        * double-buffered. For now we disable
+                        * double-buffering.
+                        */
+                       ep_doublebuffer = 0;
+                       ep_isoc = 0;
+                       if (packet_size > 64)
+                               packet_size = 0;
+                       if (!ep || !ep_doublebuffer)
+                               buffer_size = packet_size;
+                       else
+                               buffer_size = packet_size * 2;
+                       break;
+               case USB_ENDPOINT_XFER_ISOC:
+                       /* Isochronous endpoints are always double-
+                        * buffered, but the double-buffering bit
+                        * in the endpoint configuration register
+                        * becomes the msb of the endpoint size so we
+                        * set the double-buffering flag to zero.
+                        */
+                       ep_doublebuffer = 0;
+                       ep_isoc = 1;
+                       buffer_size = packet_size * 2;
+                       break;
+               }
+
+               /* check to see if our packet buffer RAM is exhausted */
+               if ((ep_ptr + buffer_size) > 2048) {
+                       UDCDBGA ("out of packet RAM for ep 0x%02x buf size %d", ep_addr, buffer_size);
+                       buffer_size = packet_size = 0;
+               }
+
+               /* force a default configuration for endpoint 0 since it is
+                * always enabled
+                */
+               if (!ep && ((packet_size < 8) || (packet_size > 64))) {
+                       buffer_size = packet_size = 64;
+                       ep_size = 3;
+               }
+
+               if (!ep) {
+                       /* configure endpoint 0 */
+                       outw ((ep_size << 12) | (ep_ptr >> 3), UDC_EP0);
+                       /*UDCDBGA("ep 0 buffer offset 0x%03x packet size 0x%03x", */
+                       /*      ep_ptr, packet_size); */
+               } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+                       /* IN endpoint */
+                       if (packet_size) {
+                               outw ((1 << 15) | (ep_doublebuffer << 14) |
+                                     (ep_size << 12) | (ep_isoc << 11) |
+                                     (ep_ptr >> 3),
+                                     UDC_EP_TX (ep_addr &
+                                                USB_ENDPOINT_NUMBER_MASK));
+                               UDCDBGA ("IN ep %d buffer offset 0x%03x"
+                                        " packet size 0x%03x",
+                                        ep_addr & USB_ENDPOINT_NUMBER_MASK,
+                                        ep_ptr, packet_size);
+                       } else {
+                               outw (0,
+                                     UDC_EP_TX (ep_addr &
+                                                USB_ENDPOINT_NUMBER_MASK));
+                       }
+               } else {
+                       /* OUT endpoint */
+                       if (packet_size) {
+                               outw ((1 << 15) | (ep_doublebuffer << 14) |
+                                     (ep_size << 12) | (ep_isoc << 11) |
+                                     (ep_ptr >> 3),
+                                     UDC_EP_RX (ep_addr &
+                                                USB_ENDPOINT_NUMBER_MASK));
+                               UDCDBGA ("OUT ep %d buffer offset 0x%03x"
+                                        " packet size 0x%03x",
+                                        ep_addr & USB_ENDPOINT_NUMBER_MASK,
+                                        ep_ptr, packet_size);
+                       } else {
+                               outw (0,
+                                     UDC_EP_RX (ep_addr &
+                                                USB_ENDPOINT_NUMBER_MASK));
+                       }
+               }
+               ep_ptr += buffer_size;
+       }
+}
+
+/* omap1510_deconfigure_device
+ *
+ * This function balances omap1510_configure_device.
+ */
+static void omap1510_deconfigure_device (void)
+{
+       int epnum;
+
+       UDCDBG ("clear Cfg_Lock");
+       outw (inw (UDC_SYSCON1) & ~UDC_Cfg_Lock, UDC_SYSCON1);
+       UDCREG (UDC_SYSCON1);
+
+       /* deconfigure all endpoints */
+       for (epnum = 1; epnum <= 15; epnum++) {
+               outw (0, UDC_EP_RX (epnum));
+               outw (0, UDC_EP_TX (epnum));
+       }
+}
+
+/* omap1510_configure_device
+ *
+ * This function implements TRM Figure 14-9.
+ */
+static void omap1510_configure_device (struct usb_device_instance *device)
+{
+       omap1510_configure_endpoints (device);
+
+
+       /* Figure 14-9 indicates we should enable interrupts here, but we have
+        * other routines (udc_all_interrupts, udc_suspended_interrupts) to
+        * do that.
+        */
+
+       UDCDBG ("set Cfg_Lock");
+       outw (inw (UDC_SYSCON1) | UDC_Cfg_Lock, UDC_SYSCON1);
+       UDCREG (UDC_SYSCON1);
+}
+
+/* omap1510_write_noniso_tx_fifo
+ *
+ * This function implements TRM Figure 14-30.
+ *
+ * If the endpoint has an active tx_urb, then the next packet of data from the
+ * URB is written to the tx FIFO.  The total amount of data in the urb is given
+ * by urb->actual_length.  The maximum amount of data that can be sent in any
+ * one packet is given by endpoint->tx_packetSize.  The number of data bytes
+ * from this URB that have already been transmitted is given by endpoint->sent.
+ * endpoint->last is updated by this routine with the number of data bytes
+ * transmitted in this packet.
+ *
+ * In accordance with Figure 14-30, the EP_NUM register must already have been
+ * written with the value to select the appropriate tx FIFO before this routine
+ * is called.
+ */
+static void omap1510_write_noniso_tx_fifo (struct usb_endpoint_instance
+                                          *endpoint)
+{
+       struct urb *urb = endpoint->tx_urb;
+
+       if (urb) {
+               unsigned int last, i;
+
+               UDCDBGA ("urb->buffer %p, buffer_length %d, actual_length %d",
+                        urb->buffer, urb->buffer_length, urb->actual_length);
+               if ((last =
+                    MIN (urb->actual_length - endpoint->sent,
+                         endpoint->tx_packetSize))) {
+                       u8 *cp = urb->buffer + endpoint->sent;
+
+                       UDCDBGA ("endpoint->sent %d, tx_packetSize %d, last %d", endpoint->sent, endpoint->tx_packetSize, last);
+
+                       if (((u32) cp & 1) == 0) {      /* word aligned? */
+                               outsw (UDC_DATA, cp, last >> 1);
+                       } else {        /* byte aligned. */
+                               for (i = 0; i < (last >> 1); i++) {
+                                       u16 w = ((u16) cp[2 * i + 1] << 8) |
+                                               (u16) cp[2 * i];
+                                       outw (w, UDC_DATA);
+                               }
+                       }
+                       if (last & 1) {
+                               outb (*(cp + last - 1), UDC_DATA);
+                       }
+               }
+               endpoint->last = last;
+       }
+}
+
+/* omap1510_read_noniso_rx_fifo
+ *
+ * This function implements TRM Figure 14-28.
+ *
+ * If the endpoint has an active rcv_urb, then the next packet of data is read
+ * from the rcv FIFO and written to rcv_urb->buffer at offset
+ * rcv_urb->actual_length to append the packet data to the data from any
+ * previous packets for this transfer. We assume that there is sufficient room
+ * left in the buffer to hold an entire packet of data.
+ *
+ * The return value is the number of bytes read from the FIFO for this packet.
+ *
+ * In accordance with Figure 14-28, the EP_NUM register must already have been
+ * written with the value to select the appropriate rcv FIFO before this routine
+ * is called.
+ */
+static int omap1510_read_noniso_rx_fifo (struct usb_endpoint_instance
+                                        *endpoint)
+{
+       struct urb *urb = endpoint->rcv_urb;
+       int len = 0;
+
+       if (urb) {
+               len = inw (UDC_RXFSTAT);
+
+               if (len) {
+                       unsigned char *cp = urb->buffer + urb->actual_length;
+
+                       insw (UDC_DATA, cp, len >> 1);
+                       if (len & 1)
+                               *(cp + len - 1) = inb (UDC_DATA);
+               }
+       }
+       return len;
+}
+
+/* omap1510_prepare_for_control_write_status
+ *
+ * This function implements TRM Figure 14-17.
+ *
+ * We have to deal here with non-autodecoded control writes that haven't already
+ * been dealt with by ep0_recv_setup.  The non-autodecoded standard control
+ * write requests are: set/clear endpoint feature, set configuration, set
+ * interface, and set descriptor.  ep0_recv_setup handles set/clear requests for
+ * ENDPOINT_HALT by halting the endpoint for a set request and resetting the
+ * endpoint for a clear request.  ep0_recv_setup returns an error for
+ * SET_DESCRIPTOR requests which causes them to be terminated with a stall by
+ * the setup handler.  A SET_INTERFACE request is handled by ep0_recv_setup by
+ * generating a DEVICE_SET_INTERFACE event.  This leaves only the
+ * SET_CONFIGURATION event for us to deal with here.
+ *
+ */
+static void omap1510_prepare_for_control_write_status (struct urb *urb)
+{
+       struct usb_device_request *request = &urb->device_request;;
+
+       /* check for a SET_CONFIGURATION request */
+       if (request->bRequest == USB_REQ_SET_CONFIGURATION) {
+               int configuration = le16_to_cpu (request->wValue) & 0xff;
+               unsigned short devstat = inw (UDC_DEVSTAT);
+
+               if ((devstat & (UDC_ADD | UDC_CFG)) == UDC_ADD) {
+                       /* device is currently in ADDRESSED state */
+                       if (configuration) {
+                               /* Assume the specified non-zero configuration
+                                * value is valid and switch to the CONFIGURED
+                                * state.
+                                */
+                               outw (UDC_Dev_Cfg, UDC_SYSCON2);
+                       }
+               } else if ((devstat & UDC_CFG) == UDC_CFG) {
+                       /* device is currently in CONFIGURED state */
+                       if (!configuration) {
+                               /* Switch to ADDRESSED state. */
+                               outw (UDC_Clr_Cfg, UDC_SYSCON2);
+                       }
+               }
+       }
+
+       /* select EP0 tx FIFO */
+       outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
+       /* clear endpoint (no data bytes in status stage) */
+       outw (UDC_Clr_EP, UDC_CTRL);
+       /* enable the EP0 tx FIFO */
+       outw (UDC_Set_FIFO_En, UDC_CTRL);
+       /* deselect the endpoint */
+       outw (UDC_EP_Dir, UDC_EP_NUM);
+}
+
+/* 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.
+ *
+ * These functions must only be called with interrupts disabled.
+ */
+static void 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 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;
+               }
+       }
+}
+
+/* Handle all device state changes.
+ * This function implements TRM Figure 14-21.
+ */
+static void omap1510_udc_state_changed (void)
+{
+       u16 bits;
+       u16 devstat = inw (UDC_DEVSTAT);
+
+       UDCDBGA ("state changed, devstat %x, old %x", devstat, udc_devstat);
+
+       bits = devstat ^ udc_devstat;
+       if (bits) {
+               if (bits & UDC_ATT) {
+                       if (devstat & UDC_ATT) {
+                               UDCDBG ("device attached and powered");
+                               udc_state_transition_up (udc_device->device_state, STATE_POWERED);
+                       } else {
+                               UDCDBG ("device detached or unpowered");
+                               udc_state_transition_down (udc_device->device_state, STATE_ATTACHED);
+                       }
+               }
+               if (bits & UDC_USB_Reset) {
+                       if (devstat & UDC_USB_Reset) {
+                               UDCDBG ("device reset in progess");
+                               udc_state_transition_down (udc_device->device_state, STATE_POWERED);
+                       } else {
+                               UDCDBG ("device reset completed");
+                       }
+               }
+               if (bits & UDC_DEF) {
+                       if (devstat & UDC_DEF) {
+                               UDCDBG ("device entering default state");
+                               udc_state_transition_up (udc_device->device_state, STATE_DEFAULT);
+                       } else {
+                               UDCDBG ("device leaving default state");
+                               udc_state_transition_down (udc_device->device_state, STATE_POWERED);
+                       }
+               }
+               if (bits & UDC_SUS) {
+                       if (devstat & UDC_SUS) {
+                               UDCDBG ("entering suspended state");
+                               usbd_device_event_irq (udc_device, DEVICE_BUS_INACTIVE, 0);
+                       } else {
+                               UDCDBG ("leaving suspended state");
+                               usbd_device_event_irq (udc_device, DEVICE_BUS_ACTIVITY, 0);
+                       }
+               }
+               if (bits & UDC_R_WK_OK) {
+                       UDCDBGA ("remote wakeup %s", (devstat & UDC_R_WK_OK)
+                                ? "enabled" : "disabled");
+               }
+               if (bits & UDC_ADD) {
+                       if (devstat & UDC_ADD) {
+                               UDCDBG ("default -> addressed");
+                               udc_state_transition_up (udc_device->device_state, STATE_ADDRESSED);
+                       } else {
+                               UDCDBG ("addressed -> default");
+                               udc_state_transition_down (udc_device->device_state, STATE_DEFAULT);
+                       }
+               }
+               if (bits & UDC_CFG) {
+                       if (devstat & UDC_CFG) {
+                               UDCDBG ("device configured");
+                               /* The ep0_recv_setup function generates the
+                                * DEVICE_CONFIGURED event when a
+                                * USB_REQ_SET_CONFIGURATION setup packet is
+                                * received, so we should already be in the
+                                * state STATE_CONFIGURED.
+                                */
+                               udc_state_transition_up (udc_device->device_state, STATE_CONFIGURED);
+                       } else {
+                               UDCDBG ("device deconfigured");
+                               udc_state_transition_down (udc_device->device_state, STATE_ADDRESSED);
+                       }
+               }
+       }
+
+       /* Clear interrupt source */
+       outw (UDC_DS_Chg, UDC_IRQ_SRC);
+
+       /* Save current DEVSTAT */
+       udc_devstat = devstat;
+}
+
+/* Handle SETUP USB interrupt.
+ * This function implements TRM Figure 14-14.
+ */
+static void omap1510_udc_setup (struct usb_endpoint_instance *endpoint)
+{
+       UDCDBG ("-> Entering device setup");
+
+       do {
+               const int setup_pktsize = 8;
+               unsigned char *datap =
+                       (unsigned char *) &ep0_urb->device_request;
+
+               /* Gain access to EP 0 setup FIFO */
+               outw (UDC_Setup_Sel, UDC_EP_NUM);
+
+               /* Read control request data */
+               insb (UDC_DATA, datap, setup_pktsize);
+
+               UDCDBGA ("EP0 setup read [%x %x %x %x %x %x %x %x]",
+                        *(datap + 0), *(datap + 1), *(datap + 2),
+                        *(datap + 3), *(datap + 4), *(datap + 5),
+                        *(datap + 6), *(datap + 7));
+
+               /* Reset EP0 setup FIFO */
+               outw (0, UDC_EP_NUM);
+       } while (inw (UDC_IRQ_SRC) & UDC_Setup);
+
+       /* Try to process setup packet */
+       if (ep0_recv_setup (ep0_urb)) {
+               /* Not a setup packet, stall next EP0 transaction */
+               udc_stall_ep (0);
+               UDCDBG ("can't parse setup packet, still waiting for setup");
+               return;
+       }
+
+       /* Check direction */
+       if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK)
+           == USB_REQ_HOST2DEVICE) {
+               UDCDBG ("control write on EP0");
+               if (le16_to_cpu (ep0_urb->device_request.wLength)) {
+                       /* We don't support control write data stages.
+                        * The only standard control write request with a data
+                        * stage is SET_DESCRIPTOR, and ep0_recv_setup doesn't
+                        * support that so we just stall those requests.  A
+                        * function driver might support a non-standard
+                        * write request with a data stage, but it isn't
+                        * obvious what we would do with the data if we read it
+                        * so we'll just stall it.  It seems like the API isn't
+                        * quite right here.
+                        */
+#if 0
+                       /* Here is what we would do if we did support control
+                        * write data stages.
+                        */
+                       ep0_urb->actual_length = 0;
+                       outw (0, UDC_EP_NUM);
+                       /* enable the EP0 rx FIFO */
+                       outw (UDC_Set_FIFO_En, UDC_CTRL);
+#else
+                       /* Stall this request */
+                       UDCDBG ("Stalling unsupported EP0 control write data "
+                               "stage.");
+                       udc_stall_ep (0);
+#endif
+               } else {
+                       omap1510_prepare_for_control_write_status (ep0_urb);
+               }
+       } else {
+               UDCDBG ("control read on EP0");
+               /* The ep0_recv_setup function has already placed our response
+                * packet data in ep0_urb->buffer and the packet length in
+                * ep0_urb->actual_length.
+                */
+               endpoint->tx_urb = ep0_urb;
+               endpoint->sent = 0;
+               /* select the EP0 tx FIFO */
+               outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
+               /* Write packet data to the FIFO.  omap1510_write_noniso_tx_fifo
+                * will update endpoint->last with the number of bytes written
+                * to the FIFO.
+                */
+               omap1510_write_noniso_tx_fifo (endpoint);
+               /* enable the FIFO to start the packet transmission */
+               outw (UDC_Set_FIFO_En, UDC_CTRL);
+               /* deselect the EP0 tx FIFO */
+               outw (UDC_EP_Dir, UDC_EP_NUM);
+       }
+
+       UDCDBG ("<- Leaving device setup");
+}
+
+/* Handle endpoint 0 RX interrupt
+ * This routine implements TRM Figure 14-16.
+ */
+static void omap1510_udc_ep0_rx (struct usb_endpoint_instance *endpoint)
+{
+       unsigned short status;
+
+       UDCDBG ("RX on EP0");
+       /* select EP0 rx FIFO */
+       outw (UDC_EP_Sel, UDC_EP_NUM);
+
+       status = inw (UDC_STAT_FLG);
+
+       if (status & UDC_ACK) {
+               /* Check direction */
+               if ((ep0_urb->device_request.bmRequestType
+                    & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {
+                       /* This rx interrupt must be for a control write data
+                        * stage packet.
+                        *
+                        * We don't support control write data stages.
+                        * We should never end up here.
+                        */
+
+                       /* clear the EP0 rx FIFO */
+                       outw (UDC_Clr_EP, UDC_CTRL);
+
+                       /* deselect the EP0 rx FIFO */
+                       outw (0, UDC_EP_NUM);
+
+                       UDCDBG ("Stalling unexpected EP0 control write "
+                               "data stage packet");
+                       udc_stall_ep (0);
+               } else {
+                       /* This rx interrupt must be for a control read status
+                        * stage packet.
+                        */
+                       UDCDBG ("ACK on EP0 control read status stage packet");
+                       /* deselect EP0 rx FIFO */
+                       outw (0, UDC_EP_NUM);
+               }
+       } else if (status & UDC_STALL) {
+               UDCDBG ("EP0 stall during RX");
+               /* deselect EP0 rx FIFO */
+               outw (0, UDC_EP_NUM);
+       } else {
+               /* deselect EP0 rx FIFO */
+               outw (0, UDC_EP_NUM);
+       }
+}
+
+/* Handle endpoint 0 TX interrupt
+ * This routine implements TRM Figure 14-18.
+ */
+static void omap1510_udc_ep0_tx (struct usb_endpoint_instance *endpoint)
+{
+       unsigned short status;
+       struct usb_device_request *request = &ep0_urb->device_request;
+
+       UDCDBG ("TX on EP0");
+       /* select EP0 TX FIFO */
+       outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
+
+       status = inw (UDC_STAT_FLG);
+       if (status & UDC_ACK) {
+               /* Check direction */
+               if ((request->bmRequestType & USB_REQ_DIRECTION_MASK) ==
+                   USB_REQ_HOST2DEVICE) {
+                       /* This tx interrupt must be for a control write status
+                        * stage packet.
+                        */
+                       UDCDBG ("ACK on EP0 control write status stage packet");
+                       /* deselect EP0 TX FIFO */
+                       outw (UDC_EP_Dir, UDC_EP_NUM);
+               } else {
+                       /* This tx interrupt must be for a control read data
+                        * stage packet.
+                        */
+                       int wLength = le16_to_cpu (request->wLength);
+
+                       /* Update our count of bytes sent so far in this
+                        * transfer.
+                        */
+                       endpoint->sent += endpoint->last;
+
+                       /* We are finished with this transfer if we have sent
+                        * all of the bytes in our tx urb (urb->actual_length)
+                        * unless we need a zero-length terminating packet.  We
+                        * need a zero-length terminating packet if we returned
+                        * fewer bytes than were requested (wLength) by the host,
+                        * and the number of bytes we returned is an exact
+                        * multiple of the packet size endpoint->tx_packetSize.
+                        */
+                       if ((endpoint->sent == ep0_urb->actual_length)
+                           && ((ep0_urb->actual_length == wLength)
+                               || (endpoint->last !=
+                                   endpoint->tx_packetSize))) {
+                               /* Done with control read data stage. */
+                               UDCDBG ("control read data stage complete");
+                               /* deselect EP0 TX FIFO */
+                               outw (UDC_EP_Dir, UDC_EP_NUM);
+                               /* select EP0 RX FIFO to prepare for control
+                                * read status stage.
+                                */
+                               outw (UDC_EP_Sel, UDC_EP_NUM);
+                               /* clear the EP0 RX FIFO */
+                               outw (UDC_Clr_EP, UDC_CTRL);
+                               /* enable the EP0 RX FIFO */
+                               outw (UDC_Set_FIFO_En, UDC_CTRL);
+                               /* deselect the EP0 RX FIFO */
+                               outw (0, UDC_EP_NUM);
+                       } else {
+                               /* We still have another packet of data to send
+                                * in this control read data stage or else we
+                                * need a zero-length terminating packet.
+                                */
+                               UDCDBG ("ACK control read data stage packet");
+                               omap1510_write_noniso_tx_fifo (endpoint);
+                               /* enable the EP0 tx FIFO to start transmission */
+                               outw (UDC_Set_FIFO_En, UDC_CTRL);
+                               /* deselect EP0 TX FIFO */
+                               outw (UDC_EP_Dir, UDC_EP_NUM);
+                       }
+               }
+       } else if (status & UDC_STALL) {
+               UDCDBG ("EP0 stall during TX");
+               /* deselect EP0 TX FIFO */
+               outw (UDC_EP_Dir, UDC_EP_NUM);
+       } else {
+               /* deselect EP0 TX FIFO */
+               outw (UDC_EP_Dir, UDC_EP_NUM);
+       }
+}
+
+/* Handle RX transaction on non-ISO endpoint.
+ * This function implements TRM Figure 14-27.
+ * The ep argument is a physical endpoint number for a non-ISO OUT endpoint
+ * in the range 1 to 15.
+ */
+static void omap1510_udc_epn_rx (int ep)
+{
+       unsigned short status;
+
+       /* Check endpoint status */
+       status = inw (UDC_STAT_FLG);
+
+       if (status & UDC_ACK) {
+               int nbytes;
+               struct usb_endpoint_instance *endpoint =
+                       omap1510_find_ep (ep);
+
+               nbytes = omap1510_read_noniso_rx_fifo (endpoint);
+               usbd_rcv_complete (endpoint, nbytes, 0);
+
+               /* enable rx FIFO to prepare for next packet */
+               outw (UDC_Set_FIFO_En, UDC_CTRL);
+       } else if (status & UDC_STALL) {
+               UDCDBGA ("STALL on RX endpoint %d", ep);
+       } else if (status & UDC_NAK) {
+               UDCDBGA ("NAK on RX ep %d", ep);
+       } else {
+               serial_printf ("omap-bi: RX on ep %d with status %x", ep,
+                              status);
+       }
+}
+
+/* Handle TX transaction on non-ISO endpoint.
+ * This function implements TRM Figure 14-29.
+ * The ep argument is a physical endpoint number for a non-ISO IN endpoint
+ * in the range 16 to 30.
+ */
+static void omap1510_udc_epn_tx (int ep)
+{
+       unsigned short status;
+
+       /*serial_printf("omap1510_udc_epn_tx( %x )\n",ep); */
+
+       /* Check endpoint status */
+       status = inw (UDC_STAT_FLG);
+
+       if (status & UDC_ACK) {
+               struct usb_endpoint_instance *endpoint =
+                       omap1510_find_ep (ep);
+
+               /* We need to transmit a terminating zero-length packet now if
+                * we have sent all of the data in this URB and the transfer
+                * size was an exact multiple of the packet size.
+                */
+               if (endpoint->tx_urb
+                   && (endpoint->last == endpoint->tx_packetSize)
+                   && (endpoint->tx_urb->actual_length - endpoint->sent -
+                       endpoint->last == 0)) {
+                       /* Prepare to transmit a zero-length packet. */
+                       endpoint->sent += endpoint->last;
+                       /* write 0 bytes of data to FIFO */
+                       omap1510_write_noniso_tx_fifo (endpoint);
+                       /* enable tx FIFO to start transmission */
+                       outw (UDC_Set_FIFO_En, UDC_CTRL);
+               } else if (endpoint->tx_urb
+                          && endpoint->tx_urb->actual_length) {
+                       /* retire the data that was just sent */
+                       usbd_tx_complete (endpoint);
+                       /* Check to see if we have more data ready to transmit
+                        * now.
+                        */
+                       if (endpoint->tx_urb
+                           && endpoint->tx_urb->actual_length) {
+                               /* write data to FIFO */
+                               omap1510_write_noniso_tx_fifo (endpoint);
+                               /* enable tx FIFO to start transmission */
+                               outw (UDC_Set_FIFO_En, UDC_CTRL);
+                       }
+               }
+       } else if (status & UDC_STALL) {
+               UDCDBGA ("STALL on TX endpoint %d", ep);
+       } else if (status & UDC_NAK) {
+               UDCDBGA ("NAK on TX endpoint %d", ep);
+       } else {
+               /*serial_printf("omap-bi: TX on ep %d with status %x\n", ep, status); */
+       }
+}
+
+
+/*
+-------------------------------------------------------------------------------
+*/
+
+/* Handle general USB interrupts and dispatch according to type.
+ * This function implements TRM Figure 14-13.
+ */
+void omap1510_udc_irq (void)
+{
+       u16 irq_src = inw (UDC_IRQ_SRC);
+       int valid_irq = 0;
+
+       if (!(irq_src & ~UDC_SOF_Flg))  /* ignore SOF interrupts ) */
+               return;
+
+       UDCDBGA ("< IRQ #%d start >- %x", udc_interrupts, irq_src);
+       /*serial_printf("< IRQ #%d start >- %x\n", udc_interrupts, irq_src); */
+
+       if (irq_src & UDC_DS_Chg) {
+               /* Device status changed */
+               omap1510_udc_state_changed ();
+               valid_irq++;
+       }
+       if (irq_src & UDC_EP0_RX) {
+               /* Endpoint 0 receive */
+               outw (UDC_EP0_RX, UDC_IRQ_SRC); /* ack interrupt */
+               omap1510_udc_ep0_rx (udc_device->bus->endpoint_array + 0);
+               valid_irq++;
+       }
+       if (irq_src & UDC_EP0_TX) {
+               /* Endpoint 0 transmit */
+               outw (UDC_EP0_TX, UDC_IRQ_SRC); /* ack interrupt */
+               omap1510_udc_ep0_tx (udc_device->bus->endpoint_array + 0);
+               valid_irq++;
+       }
+       if (irq_src & UDC_Setup) {
+               /* Device setup */
+               omap1510_udc_setup (udc_device->bus->endpoint_array + 0);
+               valid_irq++;
+       }
+       /*if (!valid_irq) */
+       /*      serial_printf("unknown interrupt, IRQ_SRC %.4x\n", irq_src); */
+       UDCDBGA ("< IRQ #%d end >", udc_interrupts);
+       udc_interrupts++;
+}
+
+/* This function implements TRM Figure 14-26. */
+void omap1510_udc_noniso_irq (void)
+{
+       unsigned short epnum;
+       unsigned short irq_src = inw (UDC_IRQ_SRC);
+       int valid_irq = 0;
+
+       if (!(irq_src & (UDC_EPn_RX | UDC_EPn_TX)))
+               return;
+
+       UDCDBGA ("non-ISO IRQ, IRQ_SRC %x", inw (UDC_IRQ_SRC));
+
+       if (irq_src & UDC_EPn_RX) {     /* Endpoint N OUT transaction */
+               /* Determine the endpoint number for this interrupt */
+               epnum = (inw (UDC_EPN_STAT) & 0x0f00) >> 8;
+               UDCDBGA ("RX on ep %x", epnum);
+
+               /* acknowledge interrupt */
+               outw (UDC_EPn_RX, UDC_IRQ_SRC);
+
+               if (epnum) {
+                       /* select the endpoint FIFO */
+                       outw (UDC_EP_Sel | epnum, UDC_EP_NUM);
+
+                       omap1510_udc_epn_rx (epnum);
+
+                       /* deselect the endpoint FIFO */
+                       outw (epnum, UDC_EP_NUM);
+               }
+               valid_irq++;
+       }
+       if (irq_src & UDC_EPn_TX) {     /* Endpoint N IN transaction */
+               /* Determine the endpoint number for this interrupt */
+               epnum = (inw (UDC_EPN_STAT) & 0x000f) | USB_DIR_IN;
+               UDCDBGA ("TX on ep %x", epnum);
+
+               /* acknowledge interrupt */
+               outw (UDC_EPn_TX, UDC_IRQ_SRC);
+
+               if (epnum) {
+                       /* select the endpoint FIFO */
+                       outw (UDC_EP_Sel | UDC_EP_Dir | epnum, UDC_EP_NUM);
+
+                       omap1510_udc_epn_tx (epnum);
+
+                       /* deselect the endpoint FIFO */
+                       outw (UDC_EP_Dir | epnum, UDC_EP_NUM);
+               }
+               valid_irq++;
+       }
+       if (!valid_irq)
+               serial_printf (": unknown non-ISO interrupt, IRQ_SRC %.4x\n",
+                              irq_src);
+}
+
+/*
+-------------------------------------------------------------------------------
+*/
+
+
+/*
+ * Start of public functions.
+ */
+
+/* Called to start packet transmission. */
+void udc_endpoint_write (struct usb_endpoint_instance *endpoint)
+{
+       unsigned short epnum =
+               endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
+
+       UDCDBGA ("Starting transmit on ep %x", epnum);
+
+       if (endpoint->tx_urb) {
+               /* select the endpoint FIFO */
+               outw (UDC_EP_Sel | UDC_EP_Dir | epnum, UDC_EP_NUM);
+               /* write data to FIFO */
+               omap1510_write_noniso_tx_fifo (endpoint);
+               /* enable tx FIFO to start transmission */
+               outw (UDC_Set_FIFO_En, UDC_CTRL);
+               /* deselect the endpoint FIFO */
+               outw (UDC_EP_Dir | epnum, UDC_EP_NUM);
+       }
+}
+
+/* Start to initialize h/w stuff */
+int udc_init (void)
+{
+       u16 udc_rev;
+       uchar value;
+       ulong gpio;
+       int i;
+
+       /* Let the device settle down before we start */
+       for (i = 0; i < UDC_INIT_MDELAY; i++) udelay(1000);
+
+       udc_device = NULL;
+
+       UDCDBG ("starting");
+
+       /* Check peripheral reset. Must be 1 to make sure
+          MPU TIPB peripheral reset is inactive */
+       UDCREG (ARM_RSTCT2);
+
+       /* Set and check clock control.
+        * We might ought to be using the clock control API to do
+        * this instead of fiddling with the clock registers directly
+        * here.
+        */
+       outw ((1 << 4) | (1 << 5), CLOCK_CTRL);
+       UDCREG (CLOCK_CTRL);
+       /* Set and check APLL */
+       outw (0x0008, APLL_CTRL);
+       UDCREG (APLL_CTRL);
+       /* Set and check DPLL */
+       outw (0x2210, DPLL_CTRL);
+       UDCREG (DPLL_CTRL);
+       /* Set and check SOFT */
+       outw ((1 << 4) | (1 << 3) | 1, SOFT_REQ);
+       /* Short delay to wait for DPLL */
+       udelay (1000);
+
+       /* Print banner with device revision */
+       udc_rev = inw (UDC_REV) & 0xff;
+       printf ("USB:   TI OMAP1510 USB function module rev %d.%d\n",
+               udc_rev >> 4, udc_rev & 0xf);
+
+#ifdef CONFIG_OMAP_SX1
+       i2c_read (0x32, 0x04, 1, &value, 1);
+       value |= 0x04;
+       i2c_write (0x32, 0x04, 1, &value, 1);
+
+       i2c_read (0x32, 0x03, 1, &value, 1);
+       value |= 0x01;
+       i2c_write (0x32, 0x03, 1, &value, 1);
+
+       gpio = inl(GPIO_PIN_CONTROL_REG);
+       gpio |=  0x0002; /* A_IRDA_OFF */
+       gpio |=  0x0800; /* A_SWITCH   */
+       gpio |=  0x8000; /* A_USB_ON   */
+       outl (gpio, GPIO_PIN_CONTROL_REG);
+
+       gpio = inl(GPIO_DIR_CONTROL_REG);
+       gpio &= ~0x0002; /* A_IRDA_OFF */
+       gpio &= ~0x0800; /* A_SWITCH   */
+       gpio &= ~0x8000; /* A_USB_ON   */
+       outl (gpio, GPIO_DIR_CONTROL_REG);
+
+       gpio = inl(GPIO_DATA_OUTPUT_REG);
+       gpio |=  0x0002; /* A_IRDA_OFF */
+       gpio &= ~0x0800; /* A_SWITCH   */
+       gpio &= ~0x8000; /* A_USB_ON   */
+       outl (gpio, GPIO_DATA_OUTPUT_REG);
+#endif
+
+       /* The VBUS_MODE bit selects whether VBUS detection is done via
+        * software (1) or hardware (0).  When software detection is
+        * selected, VBUS_CTRL selects whether USB is not connected (0)
+        * or connected (1).
+        */
+       outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_MODE, FUNC_MUX_CTRL_0);
+       outl (inl (FUNC_MUX_CTRL_0) & ~UDC_VBUS_CTRL, FUNC_MUX_CTRL_0);
+       UDCREGL (FUNC_MUX_CTRL_0);
+
+       /*
+        * At this point, device is ready for configuration...
+        */
+
+       UDCDBG ("disable USB interrupts");
+       outw (0, UDC_IRQ_EN);
+       UDCREG (UDC_IRQ_EN);
+
+       UDCDBG ("disable USB DMA");
+       outw (0, UDC_DMA_IRQ_EN);
+       UDCREG (UDC_DMA_IRQ_EN);
+
+       UDCDBG ("initialize SYSCON1");
+       outw (UDC_Self_Pwr | UDC_Pullup_En, UDC_SYSCON1);
+       UDCREG (UDC_SYSCON1);
+
+       return 0;
+}
+
+/* Stall endpoint */
+static void udc_stall_ep (unsigned int ep_addr)
+{
+       /*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */
+       int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+
+       UDCDBGA ("stall ep_addr %d", ep_addr);
+
+       /* REVISIT?
+        * The OMAP TRM section 14.2.4.2 says we must check that the FIFO
+        * is empty before halting the endpoint.  The current implementation
+        * doesn't check that the FIFO is empty.
+        */
+
+       if (!ep_num) {
+               outw (UDC_Stall_Cmd, UDC_SYSCON2);
+       } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
+               if (inw (UDC_EP_RX (ep_num)) & UDC_EPn_RX_Valid) {
+                       /* we have a valid rx endpoint, so halt it */
+                       outw (UDC_EP_Sel | ep_num, UDC_EP_NUM);
+                       outw (UDC_Set_Halt, UDC_CTRL);
+                       outw (ep_num, UDC_EP_NUM);
+               }
+       } else {
+               if (inw (UDC_EP_TX (ep_num)) & UDC_EPn_TX_Valid) {
+                       /* we have a valid tx endpoint, so halt it */
+                       outw (UDC_EP_Sel | UDC_EP_Dir | ep_num, UDC_EP_NUM);
+                       outw (UDC_Set_Halt, UDC_CTRL);
+                       outw (ep_num, UDC_EP_NUM);
+               }
+       }
+}
+
+/* Reset endpoint */
+#if 0
+static void udc_reset_ep (unsigned int ep_addr)
+{
+       /*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */
+       int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+
+       UDCDBGA ("reset ep_addr %d", ep_addr);
+
+       if (!ep_num) {
+               /* control endpoint 0 can't be reset */
+       } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
+               UDCDBGA ("UDC_EP_RX(%d) = 0x%04x", ep_num,
+                        inw (UDC_EP_RX (ep_num)));
+               if (inw (UDC_EP_RX (ep_num)) & UDC_EPn_RX_Valid) {
+                       /* we have a valid rx endpoint, so reset it */
+                       outw (ep_num | UDC_EP_Sel, UDC_EP_NUM);
+                       outw (UDC_Reset_EP, UDC_CTRL);
+                       outw (ep_num, UDC_EP_NUM);
+                       UDCDBGA ("OUT endpoint %d reset", ep_num);
+               }
+       } else {
+               UDCDBGA ("UDC_EP_TX(%d) = 0x%04x", ep_num,
+                        inw (UDC_EP_TX (ep_num)));
+               /* Resetting of tx endpoints seems to be causing the USB function
+                * module to fail, which causes problems when the driver is
+                * uninstalled.  We'll skip resetting tx endpoints for now until
+                * we figure out what the problem is.
+                */
+#if 0
+               if (inw (UDC_EP_TX (ep_num)) & UDC_EPn_TX_Valid) {
+                       /* we have a valid tx endpoint, so reset it */
+                       outw (ep_num | UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
+                       outw (UDC_Reset_EP, UDC_CTRL);
+                       outw (ep_num | UDC_EP_Dir, UDC_EP_NUM);
+                       UDCDBGA ("IN endpoint %d reset", ep_num);
+               }
+#endif
+       }
+}
+#endif
+
+/* ************************************************************************** */
+
+/**
+ * udc_check_ep - check logical endpoint
+  *
+ * Return physical endpoint number to use for this logical endpoint or zero if not valid.
+ */
+#if 0
+int udc_check_ep (int logical_endpoint, int packetsize)
+{
+       if ((logical_endpoint == 0x80) ||
+           ((logical_endpoint & 0x8f) != logical_endpoint)) {
+               return 0;
+       }
+
+       switch (packetsize) {
+       case 8:
+       case 16:
+       case 32:
+       case 64:
+       case 128:
+       case 256:
+       case 512:
+               break;
+       default:
+               return 0;
+       }
+
+       return EP_ADDR_TO_PHYS_EP (logical_endpoint);
+}
+#endif
+
+/*
+ * udc_setup_ep - setup endpoint
+ *
+ * Associate a physical endpoint with endpoint_instance
+ */
+void udc_setup_ep (struct usb_device_instance *device,
+                  unsigned int ep, struct usb_endpoint_instance *endpoint)
+{
+       UDCDBGA ("setting up endpoint addr %x", endpoint->endpoint_address);
+
+       /* This routine gets called by bi_modinit for endpoint 0 and from
+        * bi_config for all of the other endpoints.  bi_config gets called
+        * during the DEVICE_CREATE, DEVICE_CONFIGURED, and
+        * DEVICE_SET_INTERFACE events.  We need to reconfigure the OMAP packet
+        * RAM after bi_config scans the selected device configuration and
+        * initializes the endpoint structures, but before this routine enables
+        * the OUT endpoint FIFOs.  Since bi_config calls this routine in a
+        * loop for endpoints 1 through UDC_MAX_ENDPOINTS, we reconfigure our
+        * packet RAM here when ep==1.
+        * I really hate to do this here, but it seems like the API exported
+        * by the USB bus interface controller driver to the usbd-bi module
+        * isn't quite right so there is no good place to do this.
+        */
+       if (ep == 1) {
+               omap1510_deconfigure_device ();
+               omap1510_configure_device (device);
+       }
+
+       if (endpoint && (ep < UDC_MAX_ENDPOINTS)) {
+               int ep_addr = endpoint->endpoint_address;
+
+               if (!ep_addr) {
+                       /* nothing to do for endpoint 0 */
+               } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+                       /* nothing to do for IN (tx) endpoints */
+               } else {        /* OUT (rx) endpoint */
+                       if (endpoint->rcv_packetSize) {
+                               /*struct urb* urb = &(urb_out_array[ep&0xFF]); */
+                               /*urb->endpoint = endpoint; */
+                               /*urb->device = device; */
+                               /*urb->buffer_length = sizeof(urb->buffer); */
+
+                               /*endpoint->rcv_urb = urb; */
+                               omap1510_prepare_endpoint_for_rx (ep_addr);
+                       }
+               }
+       }
+}
+
+/**
+ * udc_disable_ep - disable endpoint
+ * @ep:
+ *
+ * Disable specified endpoint
+ */
+#if 0
+void udc_disable_ep (unsigned int ep_addr)
+{
+       /*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */
+       int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+       struct usb_endpoint_instance *endpoint = omap1510_find_ep (ep_addr);    /*udc_device->bus->endpoint_array + ep; */
+
+       UDCDBGA ("disable ep_addr %d", ep_addr);
+
+       if (!ep_num) {
+               /* nothing to do for endpoint 0 */ ;
+       } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+               if (endpoint->tx_packetSize) {
+                       /* we have a valid tx endpoint */
+                       /*usbd_flush_tx(endpoint); */
+                       endpoint->tx_urb = NULL;
+               }
+       } else {
+               if (endpoint->rcv_packetSize) {
+                       /* we have a valid rx endpoint */
+                       /*usbd_flush_rcv(endpoint); */
+                       endpoint->rcv_urb = NULL;
+               }
+       }
+}
+#endif
+
+/* ************************************************************************** */
+
+/**
+ * udc_connected - is the USB cable connected
+ *
+ * Return non-zero if cable is connected.
+ */
+#if 0
+int udc_connected (void)
+{
+       return ((inw (UDC_DEVSTAT) & UDC_ATT) == UDC_ATT);
+}
+#endif
+
+/* Turn on the USB connection by enabling the pullup resistor */
+void udc_connect (void)
+{
+       UDCDBG ("connect, enable Pullup");
+       outl (0x00000018, FUNC_MUX_CTRL_D);
+}
+
+/* Turn off the USB connection by disabling the pullup resistor */
+void udc_disconnect (void)
+{
+       UDCDBG ("disconnect, disable Pullup");
+       outl (0x00000000, FUNC_MUX_CTRL_D);
+}
+
+/* ************************************************************************** */
+
+
+/*
+ * udc_disable_interrupts - disable interrupts
+ * switch off interrupts
+ */
+#if 0
+void udc_disable_interrupts (struct usb_device_instance *device)
+{
+       UDCDBG ("disabling all interrupts");
+       outw (0, UDC_IRQ_EN);
+}
+#endif
+
+/* ************************************************************************** */
+
+/**
+ * udc_ep0_packetsize - return ep0 packetsize
+ */
+#if 0
+int udc_ep0_packetsize (void)
+{
+       return EP0_PACKETSIZE;
+}
+#endif
+
+/* Switch on the UDC */
+void udc_enable (struct usb_device_instance *device)
+{
+       UDCDBGA ("enable device %p, status %d", device, device->status);
+
+       /* initialize driver state variables */
+       udc_devstat = 0;
+
+       /* Save the device structure pointer */
+       udc_device = device;
+
+       /* Setup ep0 urb */
+       if (!ep0_urb) {
+               ep0_urb =
+                       usbd_alloc_urb (udc_device,
+                                       udc_device->bus->endpoint_array);
+       } else {
+               serial_printf ("udc_enable: ep0_urb already allocated %p\n",
+                              ep0_urb);
+       }
+
+       UDCDBG ("Check clock status");
+       UDCREG (STATUS_REQ);
+
+       /* The VBUS_MODE bit selects whether VBUS detection is done via
+        * software (1) or hardware (0).  When software detection is
+        * selected, VBUS_CTRL selects whether USB is not connected (0)
+        * or connected (1).
+        */
+       outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_CTRL | UDC_VBUS_MODE,
+             FUNC_MUX_CTRL_0);
+       UDCREGL (FUNC_MUX_CTRL_0);
+
+       omap1510_configure_device (device);
+}
+
+/* Switch off the UDC */
+void udc_disable (void)
+{
+       UDCDBG ("disable UDC");
+
+       omap1510_deconfigure_device ();
+
+       /* The VBUS_MODE bit selects whether VBUS detection is done via
+        * software (1) or hardware (0).  When software detection is
+        * selected, VBUS_CTRL selects whether USB is not connected (0)
+        * or connected (1).
+        */
+       outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_MODE, FUNC_MUX_CTRL_0);
+       outl (inl (FUNC_MUX_CTRL_0) & ~UDC_VBUS_CTRL, FUNC_MUX_CTRL_0);
+       UDCREGL (FUNC_MUX_CTRL_0);
+
+       /* Free ep0 URB */
+       if (ep0_urb) {
+               /*usbd_dealloc_urb(ep0_urb); */
+               ep0_urb = NULL;
+       }
+
+       /* Reset device pointer.
+        * We ought to do this here to balance the initialization of udc_device
+        * in udc_enable, but some of our other exported functions get called
+        * by the bus interface driver after udc_disable, so we have to hang on
+        * to the device pointer to avoid a null pointer dereference. */
+       /* udc_device = NULL; */
+}
+
+/**
+ * udc_startup - allow udc code to do any additional startup
+ */
+void udc_startup_events (struct usb_device_instance *device)
+{
+       /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */
+       usbd_device_event_irq (device, DEVICE_INIT, 0);
+
+       /* The DEVICE_CREATE event puts the USB device in the state
+        * STATE_ATTACHED.
+        */
+       usbd_device_event_irq (device, DEVICE_CREATE, 0);
+
+       /* Some USB controller driver implementations signal
+        * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here.
+        * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED,
+        * and DEVICE_RESET causes a transition to the state STATE_DEFAULT.
+        * The OMAP USB client controller has the capability to detect when the
+        * USB cable is connected to a powered USB bus via the ATT bit in the
+        * DEVSTAT register, so we will defer the DEVICE_HUB_CONFIGURED and
+        * DEVICE_RESET events until later.
+        */
+
+       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
diff --git a/drivers/usb_ohci.c b/drivers/usb_ohci.c
deleted file mode 100644 (file)
index cfa384e..0000000
+++ /dev/null
@@ -1,1923 +0,0 @@
-/*
- * URB OHCI HCD (Host Controller Driver) for USB on the AT91RM9200 and PCI bus.
- *
- * Interrupt support is added. Now, it has been tested
- * on ULI1575 chip and works well with USB keyboard.
- *
- * (C) Copyright 2007
- * Zhang Wei, Freescale Semiconductor, Inc. <wei.zhang@freescale.com>
- *
- * (C) Copyright 2003
- * Gary Jennejohn, DENX Software Engineering <gj@denx.de>
- *
- * Note: Much of this code has been derived from Linux 2.4
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2002 David Brownell
- *
- * Modified for the MP2USB by (C) Copyright 2005 Eric Benard
- * ebenard@eukrea.com - based on s3c24x0's driver
- *
- * 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
- *
- */
-/*
- * IMPORTANT NOTES
- * 1 - Read doc/README.generic_usb_ohci
- * 2 - this driver is intended for use with USB Mass Storage Devices
- *     (BBB) and USB keyboard. There is NO support for Isochronous pipes!
- * 2 - when running on a PQFP208 AT91RM9200, define CONFIG_AT91C_PQFP_UHPBUG
- *     to activate workaround for bug #41 or this driver will NOT work!
- */
-
-#include <common.h>
-
-#ifdef CONFIG_USB_OHCI_NEW
-
-#include <asm/byteorder.h>
-
-#if defined(CONFIG_PCI_OHCI)
-# include <pci.h>
-#endif
-
-#include <malloc.h>
-#include <usb.h>
-#include "usb_ohci.h"
-
-#ifdef CONFIG_AT91RM9200
-#include <asm/arch/hardware.h> /* needed for AT91_USB_HOST_BASE */
-#endif
-
-#if defined(CONFIG_ARM920T) || \
-    defined(CONFIG_S3C2400) || \
-    defined(CONFIG_S3C2410) || \
-    defined(CONFIG_440EP) || \
-    defined(CONFIG_PCI_OHCI) || \
-    defined(CONFIG_MPC5200)
-# define OHCI_USE_NPS          /* force NoPowerSwitching mode */
-#endif
-
-#undef OHCI_VERBOSE_DEBUG      /* not always helpful */
-#undef DEBUG
-#undef SHOW_INFO
-#undef OHCI_FILL_TRACE
-
-/* For initializing controller (mask in an HCFS mode too) */
-#define OHCI_CONTROL_INIT \
-       (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
-
-/*
- * e.g. PCI controllers need this
- */
-#ifdef CFG_OHCI_SWAP_REG_ACCESS
-# define readl(a) __swap_32(*((vu_long *)(a)))
-# define writel(a, b) (*((vu_long *)(b)) = __swap_32((vu_long)a))
-#else
-# define readl(a) (*((vu_long *)(a)))
-# define writel(a, b) (*((vu_long *)(b)) = ((vu_long)a))
-#endif /* CFG_OHCI_SWAP_REG_ACCESS */
-
-#define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
-
-#ifdef CONFIG_PCI_OHCI
-static struct pci_device_id ohci_pci_ids[] = {
-       {0x10b9, 0x5237},       /* ULI1575 PCI OHCI module ids */
-       {0x1033, 0x0035},       /* NEC PCI OHCI module ids */
-       /* Please add supported PCI OHCI controller ids here */
-       {0, 0}
-};
-#endif
-
-#ifdef DEBUG
-#define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg)
-#else
-#define dbg(format, arg...) do {} while(0)
-#endif /* DEBUG */
-#define err(format, arg...) printf("ERROR: " format "\n", ## arg)
-#undef SHOW_INFO
-#ifdef SHOW_INFO
-#define info(format, arg...) printf("INFO: " format "\n", ## arg)
-#else
-#define info(format, arg...) do {} while(0)
-#endif
-
-#ifdef CFG_OHCI_BE_CONTROLLER
-# define m16_swap(x) cpu_to_be16(x)
-# define m32_swap(x) cpu_to_be32(x)
-#else
-# define m16_swap(x) cpu_to_le16(x)
-# define m32_swap(x) cpu_to_le32(x)
-#endif /* CFG_OHCI_BE_CONTROLLER */
-
-/* global ohci_t */
-static ohci_t gohci;
-/* this must be aligned to a 256 byte boundary */
-struct ohci_hcca ghcca[1];
-/* a pointer to the aligned storage */
-struct ohci_hcca *phcca;
-/* this allocates EDs for all possible endpoints */
-struct ohci_device ohci_dev;
-/* RHSC flag */
-int got_rhsc;
-/* device which was disconnected */
-struct usb_device *devgone;
-
-/*-------------------------------------------------------------------------*/
-
-/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
- * The erratum (#4) description is incorrect.  AMD's workaround waits
- * till some bits (mostly reserved) are clear; ok for all revs.
- */
-#define OHCI_QUIRK_AMD756 0xabcd
-#define read_roothub(hc, register, mask) ({ \
-       u32 temp = readl (&hc->regs->roothub.register); \
-       if (hc->flags & OHCI_QUIRK_AMD756) \
-               while (temp & mask) \
-                       temp = readl (&hc->regs->roothub.register); \
-       temp; })
-
-static u32 roothub_a (struct ohci *hc)
-       { return read_roothub (hc, a, 0xfc0fe000); }
-static inline u32 roothub_b (struct ohci *hc)
-       { return readl (&hc->regs->roothub.b); }
-static inline u32 roothub_status (struct ohci *hc)
-       { return readl (&hc->regs->roothub.status); }
-static u32 roothub_portstatus (struct ohci *hc, int i)
-       { return read_roothub (hc, portstatus [i], 0xffe0fce0); }
-
-/* forward declaration */
-static int hc_interrupt (void);
-static void
-td_submit_job (struct usb_device * dev, unsigned long pipe, void * buffer,
-       int transfer_len, struct devrequest * setup, urb_priv_t * urb, int interval);
-
-/*-------------------------------------------------------------------------*
- * URB support functions
- *-------------------------------------------------------------------------*/
-
-/* free HCD-private data associated with this URB */
-
-static void urb_free_priv (urb_priv_t * urb)
-{
-       int             i;
-       int             last;
-       struct td       * td;
-
-       last = urb->length - 1;
-       if (last >= 0) {
-               for (i = 0; i <= last; i++) {
-                       td = urb->td[i];
-                       if (td) {
-                               td->usb_dev = NULL;
-                               urb->td[i] = NULL;
-                       }
-               }
-       }
-       free(urb);
-}
-
-/*-------------------------------------------------------------------------*/
-
-#ifdef DEBUG
-static int sohci_get_current_frame_number (struct usb_device * dev);
-
-/* debug| print the main components of an URB
- * small: 0) header + data packets 1) just header */
-
-static void pkt_print (urb_priv_t *purb, struct usb_device * dev,
-       unsigned long pipe, void * buffer,
-       int transfer_len, struct devrequest * setup, char * str, int small)
-{
-       dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d/%d stat:%#lx",
-                       str,
-                       sohci_get_current_frame_number (dev),
-                       usb_pipedevice (pipe),
-                       usb_pipeendpoint (pipe),
-                       usb_pipeout (pipe)? 'O': 'I',
-                       usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):
-                               (usb_pipecontrol (pipe)? "CTRL": "BULK"),
-                       (purb ? purb->actual_length : 0),
-                       transfer_len, dev->status);
-#ifdef OHCI_VERBOSE_DEBUG
-       if (!small) {
-               int i, len;
-
-               if (usb_pipecontrol (pipe)) {
-                       printf (__FILE__ ": cmd(8):");
-                       for (i = 0; i < 8 ; i++)
-                               printf (" %02x", ((__u8 *) setup) [i]);
-                       printf ("\n");
-               }
-               if (transfer_len > 0 && buffer) {
-                       printf (__FILE__ ": data(%d/%d):",
-                               (purb ? purb->actual_length : 0),
-                               transfer_len);
-                       len = usb_pipeout (pipe)?
-                                       transfer_len:
-                                       (purb ? purb->actual_length : 0);
-                       for (i = 0; i < 16 && i < len; i++)
-                               printf (" %02x", ((__u8 *) buffer) [i]);
-                       printf ("%s\n", i < len? "...": "");
-               }
-       }
-#endif
-}
-
-/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
-void ep_print_int_eds (ohci_t *ohci, char * str) {
-       int i, j;
-        __u32 * ed_p;
-       for (i= 0; i < 32; i++) {
-               j = 5;
-               ed_p = &(ohci->hcca->int_table [i]);
-               if (*ed_p == 0)
-                   continue;
-               printf (__FILE__ ": %s branch int %2d(%2x):", str, i, i);
-               while (*ed_p != 0 && j--) {
-                       ed_t *ed = (ed_t *)m32_swap(ed_p);
-                       printf (" ed: %4x;", ed->hwINFO);
-                       ed_p = &ed->hwNextED;
-               }
-               printf ("\n");
-       }
-}
-
-static void ohci_dump_intr_mask (char *label, __u32 mask)
-{
-       dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
-               label,
-               mask,
-               (mask & OHCI_INTR_MIE) ? " MIE" : "",
-               (mask & OHCI_INTR_OC) ? " OC" : "",
-               (mask & OHCI_INTR_RHSC) ? " RHSC" : "",
-               (mask & OHCI_INTR_FNO) ? " FNO" : "",
-               (mask & OHCI_INTR_UE) ? " UE" : "",
-               (mask & OHCI_INTR_RD) ? " RD" : "",
-               (mask & OHCI_INTR_SF) ? " SF" : "",
-               (mask & OHCI_INTR_WDH) ? " WDH" : "",
-               (mask & OHCI_INTR_SO) ? " SO" : ""
-               );
-}
-
-static void maybe_print_eds (char *label, __u32 value)
-{
-       ed_t *edp = (ed_t *)value;
-
-       if (value) {
-               dbg ("%s %08x", label, value);
-               dbg ("%08x", edp->hwINFO);
-               dbg ("%08x", edp->hwTailP);
-               dbg ("%08x", edp->hwHeadP);
-               dbg ("%08x", edp->hwNextED);
-       }
-}
-
-static char * hcfs2string (int state)
-{
-       switch (state) {
-               case OHCI_USB_RESET:    return "reset";
-               case OHCI_USB_RESUME:   return "resume";
-               case OHCI_USB_OPER:     return "operational";
-               case OHCI_USB_SUSPEND:  return "suspend";
-       }
-       return "?";
-}
-
-/* dump control and status registers */
-static void ohci_dump_status (ohci_t *controller)
-{
-       struct ohci_regs        *regs = controller->regs;
-       __u32                   temp;
-
-       temp = readl (&regs->revision) & 0xff;
-       if (temp != 0x10)
-               dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
-
-       temp = readl (&regs->control);
-       dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
-               (temp & OHCI_CTRL_RWE) ? " RWE" : "",
-               (temp & OHCI_CTRL_RWC) ? " RWC" : "",
-               (temp & OHCI_CTRL_IR) ? " IR" : "",
-               hcfs2string (temp & OHCI_CTRL_HCFS),
-               (temp & OHCI_CTRL_BLE) ? " BLE" : "",
-               (temp & OHCI_CTRL_CLE) ? " CLE" : "",
-               (temp & OHCI_CTRL_IE) ? " IE" : "",
-               (temp & OHCI_CTRL_PLE) ? " PLE" : "",
-               temp & OHCI_CTRL_CBSR
-               );
-
-       temp = readl (&regs->cmdstatus);
-       dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
-               (temp & OHCI_SOC) >> 16,
-               (temp & OHCI_OCR) ? " OCR" : "",
-               (temp & OHCI_BLF) ? " BLF" : "",
-               (temp & OHCI_CLF) ? " CLF" : "",
-               (temp & OHCI_HCR) ? " HCR" : ""
-               );
-
-       ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
-       ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
-
-       maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
-
-       maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
-       maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
-
-       maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
-       maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
-
-       maybe_print_eds ("donehead", readl (&regs->donehead));
-}
-
-static void ohci_dump_roothub (ohci_t *controller, int verbose)
-{
-       __u32                   temp, ndp, i;
-
-       temp = roothub_a (controller);
-       ndp = (temp & RH_A_NDP);
-#ifdef CONFIG_AT91C_PQFP_UHPBUG
-       ndp = (ndp == 2) ? 1:0;
-#endif
-       if (verbose) {
-               dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
-                       ((temp & RH_A_POTPGT) >> 24) & 0xff,
-                       (temp & RH_A_NOCP) ? " NOCP" : "",
-                       (temp & RH_A_OCPM) ? " OCPM" : "",
-                       (temp & RH_A_DT) ? " DT" : "",
-                       (temp & RH_A_NPS) ? " NPS" : "",
-                       (temp & RH_A_PSM) ? " PSM" : "",
-                       ndp
-                       );
-               temp = roothub_b (controller);
-               dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
-                       temp,
-                       (temp & RH_B_PPCM) >> 16,
-                       (temp & RH_B_DR)
-                       );
-               temp = roothub_status (controller);
-               dbg ("roothub.status: %08x%s%s%s%s%s%s",
-                       temp,
-                       (temp & RH_HS_CRWE) ? " CRWE" : "",
-                       (temp & RH_HS_OCIC) ? " OCIC" : "",
-                       (temp & RH_HS_LPSC) ? " LPSC" : "",
-                       (temp & RH_HS_DRWE) ? " DRWE" : "",
-                       (temp & RH_HS_OCI) ? " OCI" : "",
-                       (temp & RH_HS_LPS) ? " LPS" : ""
-                       );
-       }
-
-       for (i = 0; i < ndp; i++) {
-               temp = roothub_portstatus (controller, i);
-               dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
-                       i,
-                       temp,
-                       (temp & RH_PS_PRSC) ? " PRSC" : "",
-                       (temp & RH_PS_OCIC) ? " OCIC" : "",
-                       (temp & RH_PS_PSSC) ? " PSSC" : "",
-                       (temp & RH_PS_PESC) ? " PESC" : "",
-                       (temp & RH_PS_CSC) ? " CSC" : "",
-
-                       (temp & RH_PS_LSDA) ? " LSDA" : "",
-                       (temp & RH_PS_PPS) ? " PPS" : "",
-                       (temp & RH_PS_PRS) ? " PRS" : "",
-                       (temp & RH_PS_POCI) ? " POCI" : "",
-                       (temp & RH_PS_PSS) ? " PSS" : "",
-
-                       (temp & RH_PS_PES) ? " PES" : "",
-                       (temp & RH_PS_CCS) ? " CCS" : ""
-                       );
-       }
-}
-
-static void ohci_dump (ohci_t *controller, int verbose)
-{
-       dbg ("OHCI controller usb-%s state", controller->slot_name);
-
-       /* dumps some of the state we know about */
-       ohci_dump_status (controller);
-       if (verbose)
-               ep_print_int_eds (controller, "hcca");
-       dbg ("hcca frame #%04x", controller->hcca->frame_no);
-       ohci_dump_roothub (controller, 1);
-
-#endif /* DEBUG */
-
-/*-------------------------------------------------------------------------*
- * Interface functions (URB)
- *-------------------------------------------------------------------------*/
-
-/* get a transfer request */
-
-int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
-{
-       ohci_t *ohci;
-       ed_t * ed;
-       urb_priv_t *purb_priv = urb;
-       int i, size = 0;
-       struct usb_device *dev = urb->dev;
-       unsigned long pipe = urb->pipe;
-       void *buffer = urb->transfer_buffer;
-       int transfer_len = urb->transfer_buffer_length;
-       int interval = urb->interval;
-
-       ohci = &gohci;
-
-       /* when controller's hung, permit only roothub cleanup attempts
-        * such as powering down ports */
-       if (ohci->disabled) {
-               err("sohci_submit_job: EPIPE");
-               return -1;
-       }
-
-       /* we're about to begin a new transaction here so mark the URB unfinished */
-       urb->finished = 0;
-
-       /* every endpoint has a ed, locate and fill it */
-       if (!(ed = ep_add_ed (dev, pipe, interval, 1))) {
-               err("sohci_submit_job: ENOMEM");
-               return -1;
-       }
-
-       /* for the private part of the URB we need the number of TDs (size) */
-       switch (usb_pipetype (pipe)) {
-               case PIPE_BULK: /* one TD for every 4096 Byte */
-                       size = (transfer_len - 1) / 4096 + 1;
-                       break;
-               case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
-                       size = (transfer_len == 0)? 2:
-                                               (transfer_len - 1) / 4096 + 3;
-                       break;
-               case PIPE_INTERRUPT: /* 1 TD */
-                       size = 1;
-                       break;
-       }
-
-       ed->purb = urb;
-
-       if (size >= (N_URB_TD - 1)) {
-               err("need %d TDs, only have %d", size, N_URB_TD);
-               return -1;
-       }
-       purb_priv->pipe = pipe;
-
-       /* fill the private part of the URB */
-       purb_priv->length = size;
-       purb_priv->ed = ed;
-       purb_priv->actual_length = 0;
-
-       /* allocate the TDs */
-       /* note that td[0] was allocated in ep_add_ed */
-       for (i = 0; i < size; i++) {
-               purb_priv->td[i] = td_alloc (dev);
-               if (!purb_priv->td[i]) {
-                       purb_priv->length = i;
-                       urb_free_priv (purb_priv);
-                       err("sohci_submit_job: ENOMEM");
-                       return -1;
-               }
-       }
-
-       if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
-               urb_free_priv (purb_priv);
-               err("sohci_submit_job: EINVAL");
-               return -1;
-       }
-
-       /* link the ed into a chain if is not already */
-       if (ed->state != ED_OPER)
-               ep_link (ohci, ed);
-
-       /* fill the TDs and link it to the ed */
-       td_submit_job(dev, pipe, buffer, transfer_len, setup, purb_priv, interval);
-
-       return 0;
-}
-
-static inline int sohci_return_job(struct ohci *hc, urb_priv_t *urb)
-{
-       struct ohci_regs *regs = hc->regs;
-
-       switch (usb_pipetype (urb->pipe)) {
-       case PIPE_INTERRUPT:
-               /* implicitly requeued */
-               if (urb->dev->irq_handle &&
-                               (urb->dev->irq_act_len = urb->actual_length)) {
-                       writel (OHCI_INTR_WDH, &regs->intrenable);
-                       readl (&regs->intrenable); /* PCI posting flush */
-                       urb->dev->irq_handle(urb->dev);
-                       writel (OHCI_INTR_WDH, &regs->intrdisable);
-                       readl (&regs->intrdisable); /* PCI posting flush */
-               }
-               urb->actual_length = 0;
-               td_submit_job (
-                               urb->dev,
-                               urb->pipe,
-                               urb->transfer_buffer,
-                               urb->transfer_buffer_length,
-                               NULL,
-                               urb,
-                               urb->interval);
-               break;
-       case PIPE_CONTROL:
-       case PIPE_BULK:
-               break;
-       default:
-               return 0;
-       }
-       return 1;
-}
-
-/*-------------------------------------------------------------------------*/
-
-#ifdef DEBUG
-/* tell us the current USB frame number */
-
-static int sohci_get_current_frame_number (struct usb_device *usb_dev)
-{
-       ohci_t *ohci = &gohci;
-
-       return m16_swap (ohci->hcca->frame_no);
-}
-#endif
-
-/*-------------------------------------------------------------------------*
- * ED handling functions
- *-------------------------------------------------------------------------*/
-
-/* search for the right branch to insert an interrupt ed into the int tree
- * do some load ballancing;
- * returns the branch and
- * sets the interval to interval = 2^integer (ld (interval)) */
-
-static int ep_int_ballance (ohci_t * ohci, int interval, int load)
-{
-       int i, branch = 0;
-
-       /* search for the least loaded interrupt endpoint
-        * branch of all 32 branches
-        */
-       for (i = 0; i < 32; i++)
-               if (ohci->ohci_int_load [branch] > ohci->ohci_int_load [i])
-                       branch = i;
-
-       branch = branch % interval;
-       for (i = branch; i < 32; i += interval)
-               ohci->ohci_int_load [i] += load;
-
-       return branch;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*  2^int( ld (inter)) */
-
-static int ep_2_n_interval (int inter)
-{
-       int i;
-       for (i = 0; ((inter >> i) > 1 ) && (i < 5); i++);
-       return 1 << i;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* the int tree is a binary tree
- * in order to process it sequentially the indexes of the branches have to be mapped
- * the mapping reverses the bits of a word of num_bits length */
-
-static int ep_rev (int num_bits, int word)
-{
-       int i, wout = 0;
-
-       for (i = 0; i < num_bits; i++)
-               wout |= (((word >> i) & 1) << (num_bits - i - 1));
-       return wout;
-}
-
-/*-------------------------------------------------------------------------*
- * ED handling functions
- *-------------------------------------------------------------------------*/
-
-/* link an ed into one of the HC chains */
-
-static int ep_link (ohci_t *ohci, ed_t *edi)
-{
-       volatile ed_t *ed = edi;
-       int int_branch;
-       int i;
-       int inter;
-       int interval;
-       int load;
-       __u32 * ed_p;
-
-       ed->state = ED_OPER;
-       ed->int_interval = 0;
-
-       switch (ed->type) {
-       case PIPE_CONTROL:
-               ed->hwNextED = 0;
-               if (ohci->ed_controltail == NULL) {
-                       writel (ed, &ohci->regs->ed_controlhead);
-               } else {
-                       ohci->ed_controltail->hwNextED = m32_swap ((unsigned long)ed);
-               }
-               ed->ed_prev = ohci->ed_controltail;
-               if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
-                       !ohci->ed_rm_list[1] && !ohci->sleeping) {
-                       ohci->hc_control |= OHCI_CTRL_CLE;
-                       writel (ohci->hc_control, &ohci->regs->control);
-               }
-               ohci->ed_controltail = edi;
-               break;
-
-       case PIPE_BULK:
-               ed->hwNextED = 0;
-               if (ohci->ed_bulktail == NULL) {
-                       writel (ed, &ohci->regs->ed_bulkhead);
-               } else {
-                       ohci->ed_bulktail->hwNextED = m32_swap ((unsigned long)ed);
-               }
-               ed->ed_prev = ohci->ed_bulktail;
-               if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
-                       !ohci->ed_rm_list[1] && !ohci->sleeping) {
-                       ohci->hc_control |= OHCI_CTRL_BLE;
-                       writel (ohci->hc_control, &ohci->regs->control);
-               }
-               ohci->ed_bulktail = edi;
-               break;
-
-       case PIPE_INTERRUPT:
-               load = ed->int_load;
-               interval = ep_2_n_interval (ed->int_period);
-               ed->int_interval = interval;
-               int_branch = ep_int_ballance (ohci, interval, load);
-               ed->int_branch = int_branch;
-
-               for (i = 0; i < ep_rev (6, interval); i += inter) {
-                       inter = 1;
-                       for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) + int_branch]);
-                               (*ed_p != 0) && (((ed_t *)ed_p)->int_interval >= interval);
-                               ed_p = &(((ed_t *)ed_p)->hwNextED))
-                                       inter = ep_rev (6, ((ed_t *)ed_p)->int_interval);
-                       ed->hwNextED = *ed_p;
-                       *ed_p = m32_swap((unsigned long)ed);
-               }
-               break;
-       }
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* scan the periodic table to find and unlink this ED */
-static void periodic_unlink ( struct ohci *ohci, volatile struct ed *ed,
-               unsigned index, unsigned period)
-{
-       for (; index < NUM_INTS; index += period) {
-               __u32   *ed_p = &ohci->hcca->int_table [index];
-
-               /* ED might have been unlinked through another path */
-               while (*ed_p != 0) {
-                       if (((struct ed *)m32_swap ((unsigned long)ed_p)) == ed) {
-                               *ed_p = ed->hwNextED;
-                               break;
-                       }
-                       ed_p = & (((struct ed *)m32_swap ((unsigned long)ed_p))->hwNextED);
-               }
-       }
-}
-
-/* unlink an ed from one of the HC chains.
- * just the link to the ed is unlinked.
- * the link from the ed still points to another operational ed or 0
- * so the HC can eventually finish the processing of the unlinked ed */
-
-static int ep_unlink (ohci_t *ohci, ed_t *edi)
-{
-       volatile ed_t *ed = edi;
-       int i;
-
-       ed->hwINFO |= m32_swap (OHCI_ED_SKIP);
-
-       switch (ed->type) {
-       case PIPE_CONTROL:
-               if (ed->ed_prev == NULL) {
-                       if (!ed->hwNextED) {
-                               ohci->hc_control &= ~OHCI_CTRL_CLE;
-                               writel (ohci->hc_control, &ohci->regs->control);
-                       }
-                       writel (m32_swap (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_controlhead);
-               } else {
-                       ed->ed_prev->hwNextED = ed->hwNextED;
-               }
-               if (ohci->ed_controltail == ed) {
-                       ohci->ed_controltail = ed->ed_prev;
-               } else {
-                       ((ed_t *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
-               }
-               break;
-
-       case PIPE_BULK:
-               if (ed->ed_prev == NULL) {
-                       if (!ed->hwNextED) {
-                               ohci->hc_control &= ~OHCI_CTRL_BLE;
-                               writel (ohci->hc_control, &ohci->regs->control);
-                       }
-                       writel (m32_swap (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_bulkhead);
-               } else {
-                       ed->ed_prev->hwNextED = ed->hwNextED;
-               }
-               if (ohci->ed_bulktail == ed) {
-                       ohci->ed_bulktail = ed->ed_prev;
-               } else {
-                       ((ed_t *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
-               }
-               break;
-
-       case PIPE_INTERRUPT:
-               periodic_unlink (ohci, ed, 0, 1);
-               for (i = ed->int_branch; i < 32; i += ed->int_interval)
-                   ohci->ohci_int_load[i] -= ed->int_load;
-               break;
-       }
-       ed->state = ED_UNLINK;
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* add/reinit an endpoint; this should be done once at the
- * usb_set_configuration command, but the USB stack is a little bit
- * stateless so we do it at every transaction if the state of the ed
- * is ED_NEW then a dummy td is added and the state is changed to
- * ED_UNLINK in all other cases the state is left unchanged the ed
- * info fields are setted anyway even though most of them should not
- * change
- */
-static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe,
-               int interval, int load)
-{
-       td_t *td;
-       ed_t *ed_ret;
-       volatile ed_t *ed;
-
-       ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint (pipe) << 1) |
-                       (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))];
-
-       if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
-               err("ep_add_ed: pending delete");
-               /* pending delete request */
-               return NULL;
-       }
-
-       if (ed->state == ED_NEW) {
-               ed->hwINFO = m32_swap (OHCI_ED_SKIP); /* skip ed */
-               /* dummy td; end of td list for ed */
-               td = td_alloc (usb_dev);
-               ed->hwTailP = m32_swap ((unsigned long)td);
-               ed->hwHeadP = ed->hwTailP;
-               ed->state = ED_UNLINK;
-               ed->type = usb_pipetype (pipe);
-               ohci_dev.ed_cnt++;
-       }
-
-       ed->hwINFO = m32_swap (usb_pipedevice (pipe)
-                       | usb_pipeendpoint (pipe) << 7
-                       | (usb_pipeisoc (pipe)? 0x8000: 0)
-                       | (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000))
-                       | usb_pipeslow (pipe) << 13
-                       | usb_maxpacket (usb_dev, pipe) << 16);
-
-       if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
-               ed->int_period = interval;
-               ed->int_load = load;
-       }
-
-       return ed_ret;
-}
-
-/*-------------------------------------------------------------------------*
- * TD handling functions
- *-------------------------------------------------------------------------*/
-
-/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
-
-static void td_fill (ohci_t *ohci, unsigned int info,
-       void *data, int len,
-       struct usb_device *dev, int index, urb_priv_t *urb_priv)
-{
-       volatile td_t  *td, *td_pt;
-#ifdef OHCI_FILL_TRACE
-       int i;
-#endif
-
-       if (index > urb_priv->length) {
-               err("index > length");
-               return;
-       }
-       /* use this td as the next dummy */
-       td_pt = urb_priv->td [index];
-       td_pt->hwNextTD = 0;
-
-       /* fill the old dummy TD */
-       td = urb_priv->td [index] = (td_t *)(m32_swap (urb_priv->ed->hwTailP) & ~0xf);
-
-       td->ed = urb_priv->ed;
-       td->next_dl_td = NULL;
-       td->index = index;
-       td->data = (__u32)data;
-#ifdef OHCI_FILL_TRACE
-       if ((usb_pipetype(urb_priv->pipe) == PIPE_BULK) && usb_pipeout(urb_priv->pipe)) {
-               for (i = 0; i < len; i++)
-               printf("td->data[%d] %#2x ",i, ((unsigned char *)td->data)[i]);
-               printf("\n");
-       }
-#endif
-       if (!len)
-               data = 0;
-
-       td->hwINFO = m32_swap (info);
-       td->hwCBP = m32_swap ((unsigned long)data);
-       if (data)
-               td->hwBE = m32_swap ((unsigned long)(data + len - 1));
-       else
-               td->hwBE = 0;
-       td->hwNextTD = m32_swap ((unsigned long)td_pt);
-
-       /* append to queue */
-       td->ed->hwTailP = td->hwNextTD;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* prepare all TDs of a transfer */
-
-static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buffer,
-       int transfer_len, struct devrequest *setup, urb_priv_t *urb, int interval)
-{
-       ohci_t *ohci = &gohci;
-       int data_len = transfer_len;
-       void *data;
-       int cnt = 0;
-       __u32 info = 0;
-       unsigned int toggle = 0;
-
-       /* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
-       if(usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
-               toggle = TD_T_TOGGLE;
-       } else {
-               toggle = TD_T_DATA0;
-               usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 1);
-       }
-       urb->td_cnt = 0;
-       if (data_len)
-               data = buffer;
-       else
-               data = 0;
-
-       switch (usb_pipetype (pipe)) {
-       case PIPE_BULK:
-               info = usb_pipeout (pipe)?
-                       TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
-               while(data_len > 4096) {
-                       td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, dev, cnt, urb);
-                       data += 4096; data_len -= 4096; cnt++;
-               }
-               info = usb_pipeout (pipe)?
-                       TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
-               td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, dev, cnt, urb);
-               cnt++;
-
-               if (!ohci->sleeping)
-                       writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
-               break;
-
-       case PIPE_CONTROL:
-               info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
-               td_fill (ohci, info, setup, 8, dev, cnt++, urb);
-               if (data_len > 0) {
-                       info = usb_pipeout (pipe)?
-                               TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
-                       /* NOTE:  mishandles transfers >8K, some >4K */
-                       td_fill (ohci, info, data, data_len, dev, cnt++, urb);
-               }
-               info = usb_pipeout (pipe)?
-                       TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
-               td_fill (ohci, info, data, 0, dev, cnt++, urb);
-               if (!ohci->sleeping)
-                       writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
-               break;
-
-       case PIPE_INTERRUPT:
-               info = usb_pipeout (urb->pipe)?
-                       TD_CC | TD_DP_OUT | toggle:
-                       TD_CC | TD_R | TD_DP_IN | toggle;
-               td_fill (ohci, info, data, data_len, dev, cnt++, urb);
-               break;
-       }
-       if (urb->length != cnt)
-               dbg("TD LENGTH %d != CNT %d", urb->length, cnt);
-}
-
-/*-------------------------------------------------------------------------*
- * Done List handling functions
- *-------------------------------------------------------------------------*/
-
-/* calculate the transfer length and update the urb */
-
-static void dl_transfer_length(td_t * td)
-{
-       __u32 tdINFO, tdBE, tdCBP;
-       urb_priv_t *lurb_priv = td->ed->purb;
-
-       tdINFO = m32_swap (td->hwINFO);
-       tdBE   = m32_swap (td->hwBE);
-       tdCBP  = m32_swap (td->hwCBP);
-
-       if (!(usb_pipetype (lurb_priv->pipe) == PIPE_CONTROL &&
-           ((td->index == 0) || (td->index == lurb_priv->length - 1)))) {
-               if (tdBE != 0) {
-                       if (td->hwCBP == 0)
-                               lurb_priv->actual_length += tdBE - td->data + 1;
-                       else
-                               lurb_priv->actual_length += tdCBP - td->data;
-               }
-       }
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* replies to the request have to be on a FIFO basis so
- * we reverse the reversed done-list */
-
-static td_t * dl_reverse_done_list (ohci_t *ohci)
-{
-       __u32 td_list_hc;
-       td_t *td_rev = NULL;
-       td_t *td_list = NULL;
-       urb_priv_t *lurb_priv = NULL;
-
-       td_list_hc = m32_swap (ohci->hcca->done_head) & 0xfffffff0;
-       ohci->hcca->done_head = 0;
-
-       while (td_list_hc) {
-               td_list = (td_t *)td_list_hc;
-
-               if (TD_CC_GET (m32_swap (td_list->hwINFO))) {
-                       lurb_priv = td_list->ed->purb;
-                       dbg(" USB-error/status: %x : %p",
-                                       TD_CC_GET (m32_swap (td_list->hwINFO)), td_list);
-                       if (td_list->ed->hwHeadP & m32_swap (0x1)) {
-                               if (lurb_priv && ((td_list->index + 1) < lurb_priv->length)) {
-                                       td_list->ed->hwHeadP =
-                                               (lurb_priv->td[lurb_priv->length - 1]->hwNextTD & m32_swap (0xfffffff0)) |
-                                                                       (td_list->ed->hwHeadP & m32_swap (0x2));
-                                       lurb_priv->td_cnt += lurb_priv->length - td_list->index - 1;
-                               } else
-                                       td_list->ed->hwHeadP &= m32_swap (0xfffffff2);
-                       }
-#ifdef CONFIG_MPC5200
-                       td_list->hwNextTD = 0;
-#endif
-               }
-
-               td_list->next_dl_td = td_rev;
-               td_rev = td_list;
-               td_list_hc = m32_swap (td_list->hwNextTD) & 0xfffffff0;
-       }
-       return td_list;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* td done list */
-static int dl_done_list (ohci_t *ohci, td_t *td_list)
-{
-       td_t *td_list_next = NULL;
-       ed_t *ed;
-       int cc = 0;
-       int stat = 0;
-       /* urb_t *urb; */
-       urb_priv_t *lurb_priv;
-       __u32 tdINFO, edHeadP, edTailP;
-
-       while (td_list) {
-               td_list_next = td_list->next_dl_td;
-
-               tdINFO = m32_swap (td_list->hwINFO);
-
-               ed = td_list->ed;
-               lurb_priv = ed->purb;
-
-               dl_transfer_length(td_list);
-
-               /* error code of transfer */
-               cc = TD_CC_GET (tdINFO);
-               if (cc != 0) {
-                       dbg("ConditionCode %#x", cc);
-                       stat = cc_to_error[cc];
-               }
-
-               /* see if this done list makes for all TD's of current URB,
-                * and mark the URB finished if so */
-               if (++(lurb_priv->td_cnt) == lurb_priv->length) {
-#if 1
-                       if ((ed->state & (ED_OPER | ED_UNLINK)) &&
-                           (lurb_priv->state != URB_DEL))
-#else
-                       if ((ed->state & (ED_OPER | ED_UNLINK)))
-#endif
-                               lurb_priv->finished = sohci_return_job(ohci,
-                                               lurb_priv);
-                       else
-                               dbg("dl_done_list: strange.., ED state %x, ed->state\n");
-               } else
-                       dbg("dl_done_list: processing TD %x, len %x\n", lurb_priv->td_cnt,
-                               lurb_priv->length);
-               if (ed->state != ED_NEW &&
-                         (usb_pipetype (lurb_priv->pipe) != PIPE_INTERRUPT)) {
-                       edHeadP = m32_swap (ed->hwHeadP) & 0xfffffff0;
-                       edTailP = m32_swap (ed->hwTailP);
-
-                       /* unlink eds if they are not busy */
-                       if ((edHeadP == edTailP) && (ed->state == ED_OPER))
-                               ep_unlink (ohci, ed);
-               }
-
-               td_list = td_list_next;
-       }
-       return stat;
-}
-
-/*-------------------------------------------------------------------------*
- * Virtual Root Hub
- *-------------------------------------------------------------------------*/
-
-/* Device descriptor */
-static __u8 root_hub_dev_des[] =
-{
-       0x12,       /*  __u8  bLength; */
-       0x01,       /*  __u8  bDescriptorType; Device */
-       0x10,       /*  __u16 bcdUSB; v1.1 */
-       0x01,
-       0x09,       /*  __u8  bDeviceClass; HUB_CLASSCODE */
-       0x00,       /*  __u8  bDeviceSubClass; */
-       0x00,       /*  __u8  bDeviceProtocol; */
-       0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
-       0x00,       /*  __u16 idVendor; */
-       0x00,
-       0x00,       /*  __u16 idProduct; */
-       0x00,
-       0x00,       /*  __u16 bcdDevice; */
-       0x00,
-       0x00,       /*  __u8  iManufacturer; */
-       0x01,       /*  __u8  iProduct; */
-       0x00,       /*  __u8  iSerialNumber; */
-       0x01        /*  __u8  bNumConfigurations; */
-};
-
-/* Configuration descriptor */
-static __u8 root_hub_config_des[] =
-{
-       0x09,       /*  __u8  bLength; */
-       0x02,       /*  __u8  bDescriptorType; Configuration */
-       0x19,       /*  __u16 wTotalLength; */
-       0x00,
-       0x01,       /*  __u8  bNumInterfaces; */
-       0x01,       /*  __u8  bConfigurationValue; */
-       0x00,       /*  __u8  iConfiguration; */
-       0x40,       /*  __u8  bmAttributes;
-                Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
-       0x00,       /*  __u8  MaxPower; */
-
-       /* interface */
-       0x09,       /*  __u8  if_bLength; */
-       0x04,       /*  __u8  if_bDescriptorType; Interface */
-       0x00,       /*  __u8  if_bInterfaceNumber; */
-       0x00,       /*  __u8  if_bAlternateSetting; */
-       0x01,       /*  __u8  if_bNumEndpoints; */
-       0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
-       0x00,       /*  __u8  if_bInterfaceSubClass; */
-       0x00,       /*  __u8  if_bInterfaceProtocol; */
-       0x00,       /*  __u8  if_iInterface; */
-
-       /* endpoint */
-       0x07,       /*  __u8  ep_bLength; */
-       0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
-       0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
-       0x03,       /*  __u8  ep_bmAttributes; Interrupt */
-       0x02,       /*  __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
-       0x00,
-       0xff        /*  __u8  ep_bInterval; 255 ms */
-};
-
-static unsigned char root_hub_str_index0[] =
-{
-       0x04,                   /*  __u8  bLength; */
-       0x03,                   /*  __u8  bDescriptorType; String-descriptor */
-       0x09,                   /*  __u8  lang ID */
-       0x04,                   /*  __u8  lang ID */
-};
-
-static unsigned char root_hub_str_index1[] =
-{
-       28,                     /*  __u8  bLength; */
-       0x03,                   /*  __u8  bDescriptorType; String-descriptor */
-       'O',                    /*  __u8  Unicode */
-       0,                              /*  __u8  Unicode */
-       'H',                    /*  __u8  Unicode */
-       0,                              /*  __u8  Unicode */
-       'C',                    /*  __u8  Unicode */
-       0,                              /*  __u8  Unicode */
-       'I',                    /*  __u8  Unicode */
-       0,                              /*  __u8  Unicode */
-       ' ',                    /*  __u8  Unicode */
-       0,                              /*  __u8  Unicode */
-       'R',                    /*  __u8  Unicode */
-       0,                              /*  __u8  Unicode */
-       'o',                    /*  __u8  Unicode */
-       0,                              /*  __u8  Unicode */
-       'o',                    /*  __u8  Unicode */
-       0,                              /*  __u8  Unicode */
-       't',                    /*  __u8  Unicode */
-       0,                              /*  __u8  Unicode */
-       ' ',                    /*  __u8  Unicode */
-       0,                              /*  __u8  Unicode */
-       'H',                    /*  __u8  Unicode */
-       0,                              /*  __u8  Unicode */
-       'u',                    /*  __u8  Unicode */
-       0,                              /*  __u8  Unicode */
-       'b',                    /*  __u8  Unicode */
-       0,                              /*  __u8  Unicode */
-};
-
-/* Hub class-specific descriptor is constructed dynamically */
-
-/*-------------------------------------------------------------------------*/
-
-#define OK(x)                  len = (x); break
-#ifdef DEBUG
-#define WR_RH_STAT(x)          {info("WR:status %#8x", (x));writel((x), &gohci.regs->roothub.status);}
-#define WR_RH_PORTSTAT(x)      {info("WR:portstatus[%d] %#8x", wIndex-1, (x));writel((x), &gohci.regs->roothub.portstatus[wIndex-1]);}
-#else
-#define WR_RH_STAT(x)          writel((x), &gohci.regs->roothub.status)
-#define WR_RH_PORTSTAT(x)      writel((x), &gohci.regs->roothub.portstatus[wIndex-1])
-#endif
-#define RD_RH_STAT             roothub_status(&gohci)
-#define RD_RH_PORTSTAT         roothub_portstatus(&gohci,wIndex-1)
-
-/* request to virtual root hub */
-
-int rh_check_port_status(ohci_t *controller)
-{
-       __u32 temp, ndp, i;
-       int res;
-
-       res = -1;
-       temp = roothub_a (controller);
-       ndp = (temp & RH_A_NDP);
-#ifdef CONFIG_AT91C_PQFP_UHPBUG
-       ndp = (ndp == 2) ? 1:0;
-#endif
-       for (i = 0; i < ndp; i++) {
-               temp = roothub_portstatus (controller, i);
-               /* check for a device disconnect */
-               if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
-                       (RH_PS_PESC | RH_PS_CSC)) &&
-                       ((temp & RH_PS_CCS) == 0)) {
-                       res = i;
-                       break;
-               }
-       }
-       return res;
-}
-
-static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
-               void *buffer, int transfer_len, struct devrequest *cmd)
-{
-       void * data = buffer;
-       int leni = transfer_len;
-       int len = 0;
-       int stat = 0;
-       __u32 datab[4];
-       __u8 *data_buf = (__u8 *)datab;
-       __u16 bmRType_bReq;
-       __u16 wValue;
-       __u16 wIndex;
-       __u16 wLength;
-
-#ifdef DEBUG
-pkt_print(NULL, dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe));
-#else
-       wait_ms(1);
-#endif
-       if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
-               info("Root-Hub submit IRQ: NOT implemented");
-               return 0;
-       }
-
-       bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
-       wValue        = cpu_to_le16 (cmd->value);
-       wIndex        = cpu_to_le16 (cmd->index);
-       wLength       = cpu_to_le16 (cmd->length);
-
-       info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x",
-               dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
-
-       switch (bmRType_bReq) {
-       /* Request Destination:
-          without flags: Device,
-          RH_INTERFACE: interface,
-          RH_ENDPOINT: endpoint,
-          RH_CLASS means HUB here,
-          RH_OTHER | RH_CLASS  almost ever means HUB_PORT here
-       */
-
-       case RH_GET_STATUS:
-                       *(__u16 *) data_buf = cpu_to_le16 (1); OK (2);
-       case RH_GET_STATUS | RH_INTERFACE:
-                       *(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
-       case RH_GET_STATUS | RH_ENDPOINT:
-                       *(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
-       case RH_GET_STATUS | RH_CLASS:
-                       *(__u32 *) data_buf = cpu_to_le32 (
-                               RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
-                       OK (4);
-       case RH_GET_STATUS | RH_OTHER | RH_CLASS:
-                       *(__u32 *) data_buf = cpu_to_le32 (RD_RH_PORTSTAT); OK (4);
-
-       case RH_CLEAR_FEATURE | RH_ENDPOINT:
-               switch (wValue) {
-                       case (RH_ENDPOINT_STALL): OK (0);
-               }
-               break;
-
-       case RH_CLEAR_FEATURE | RH_CLASS:
-               switch (wValue) {
-                       case RH_C_HUB_LOCAL_POWER:
-                               OK(0);
-                       case (RH_C_HUB_OVER_CURRENT):
-                                       WR_RH_STAT(RH_HS_OCIC); OK (0);
-               }
-               break;
-
-       case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
-               switch (wValue) {
-                       case (RH_PORT_ENABLE):
-                                       WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
-                       case (RH_PORT_SUSPEND):
-                                       WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
-                       case (RH_PORT_POWER):
-                                       WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
-                       case (RH_C_PORT_CONNECTION):
-                                       WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
-                       case (RH_C_PORT_ENABLE):
-                                       WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
-                       case (RH_C_PORT_SUSPEND):
-                                       WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
-                       case (RH_C_PORT_OVER_CURRENT):
-                                       WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
-                       case (RH_C_PORT_RESET):
-                                       WR_RH_PORTSTAT (RH_PS_PRSC); OK (0);
-               }
-               break;
-
-       case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
-               switch (wValue) {
-                       case (RH_PORT_SUSPEND):
-                                       WR_RH_PORTSTAT (RH_PS_PSS ); OK (0);
-                       case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
-                                       if (RD_RH_PORTSTAT & RH_PS_CCS)
-                                           WR_RH_PORTSTAT (RH_PS_PRS);
-                                       OK (0);
-                       case (RH_PORT_POWER):
-                                       WR_RH_PORTSTAT (RH_PS_PPS );
-                                       wait_ms(100);
-                                       OK (0);
-                       case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
-                                       if (RD_RH_PORTSTAT & RH_PS_CCS)
-                                           WR_RH_PORTSTAT (RH_PS_PES );
-                                       OK (0);
-               }
-               break;
-
-       case RH_SET_ADDRESS: gohci.rh.devnum = wValue; OK(0);
-
-       case RH_GET_DESCRIPTOR:
-               switch ((wValue & 0xff00) >> 8) {
-                       case (0x01): /* device descriptor */
-                               len = min_t(unsigned int,
-                                         leni,
-                                         min_t(unsigned int,
-                                             sizeof (root_hub_dev_des),
-                                             wLength));
-                               data_buf = root_hub_dev_des; OK(len);
-                       case (0x02): /* configuration descriptor */
-                               len = min_t(unsigned int,
-                                         leni,
-                                         min_t(unsigned int,
-                                             sizeof (root_hub_config_des),
-                                             wLength));
-                               data_buf = root_hub_config_des; OK(len);
-                       case (0x03): /* string descriptors */
-                               if(wValue==0x0300) {
-                                       len = min_t(unsigned int,
-                                                 leni,
-                                                 min_t(unsigned int,
-                                                     sizeof (root_hub_str_index0),
-                                                     wLength));
-                                       data_buf = root_hub_str_index0;
-                                       OK(len);
-                               }
-                               if(wValue==0x0301) {
-                                       len = min_t(unsigned int,
-                                                 leni,
-                                                 min_t(unsigned int,
-                                                     sizeof (root_hub_str_index1),
-                                                     wLength));
-                                       data_buf = root_hub_str_index1;
-                                       OK(len);
-                       }
-                       default:
-                               stat = USB_ST_STALLED;
-               }
-               break;
-
-       case RH_GET_DESCRIPTOR | RH_CLASS:
-       {
-               __u32 temp = roothub_a (&gohci);
-
-               data_buf [0] = 9;               /* min length; */
-               data_buf [1] = 0x29;
-               data_buf [2] = temp & RH_A_NDP;
-#ifdef CONFIG_AT91C_PQFP_UHPBUG
-               data_buf [2] = (data_buf [2] == 2) ? 1:0;
-#endif
-               data_buf [3] = 0;
-               if (temp & RH_A_PSM)    /* per-port power switching? */
-                       data_buf [3] |= 0x1;
-               if (temp & RH_A_NOCP)   /* no overcurrent reporting? */
-                       data_buf [3] |= 0x10;
-               else if (temp & RH_A_OCPM)      /* per-port overcurrent reporting? */
-                       data_buf [3] |= 0x8;
-
-               /* corresponds to data_buf[4-7] */
-               datab [1] = 0;
-               data_buf [5] = (temp & RH_A_POTPGT) >> 24;
-               temp = roothub_b (&gohci);
-               data_buf [7] = temp & RH_B_DR;
-               if (data_buf [2] < 7) {
-                       data_buf [8] = 0xff;
-               } else {
-                       data_buf [0] += 2;
-                       data_buf [8] = (temp & RH_B_DR) >> 8;
-                       data_buf [10] = data_buf [9] = 0xff;
-               }
-
-               len = min_t(unsigned int, leni,
-                           min_t(unsigned int, data_buf [0], wLength));
-               OK (len);
-       }
-
-       case RH_GET_CONFIGURATION:      *(__u8 *) data_buf = 0x01; OK (1);
-
-       case RH_SET_CONFIGURATION:      WR_RH_STAT (0x10000); OK (0);
-
-       default:
-               dbg ("unsupported root hub command");
-               stat = USB_ST_STALLED;
-       }
-
-#ifdef DEBUG
-       ohci_dump_roothub (&gohci, 1);
-#else
-       wait_ms(1);
-#endif
-
-       len = min_t(int, len, leni);
-       if (data != data_buf)
-           memcpy (data, data_buf, len);
-       dev->act_len = len;
-       dev->status = stat;
-
-#ifdef DEBUG
-       pkt_print(NULL, dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
-#else
-       wait_ms(1);
-#endif
-
-       return stat;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* common code for handling submit messages - used for all but root hub */
-/* accesses. */
-int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
-               int transfer_len, struct devrequest *setup, int interval)
-{
-       int stat = 0;
-       int maxsize = usb_maxpacket(dev, pipe);
-       int timeout;
-       urb_priv_t *urb;
-
-       urb = malloc(sizeof(urb_priv_t));
-       memset(urb, 0, sizeof(urb_priv_t));
-
-       urb->dev = dev;
-       urb->pipe = pipe;
-       urb->transfer_buffer = buffer;
-       urb->transfer_buffer_length = transfer_len;
-       urb->interval = interval;
-
-       /* device pulled? Shortcut the action. */
-       if (devgone == dev) {
-               dev->status = USB_ST_CRC_ERR;
-               return 0;
-       }
-
-#ifdef DEBUG
-       urb->actual_length = 0;
-       pkt_print(urb, dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
-#else
-       wait_ms(1);
-#endif
-       if (!maxsize) {
-               err("submit_common_message: pipesize for pipe %lx is zero",
-                       pipe);
-               return -1;
-       }
-
-       if (sohci_submit_job(urb, setup) < 0) {
-               err("sohci_submit_job failed");
-               return -1;
-       }
-
-#if 0
-       wait_ms(10);
-       /* ohci_dump_status(&gohci); */
-#endif
-
-       /* allow more time for a BULK device to react - some are slow */
-#define BULK_TO         5000   /* timeout in milliseconds */
-       if (usb_pipetype (pipe) == PIPE_BULK)
-               timeout = BULK_TO;
-       else
-               timeout = 100;
-
-       /* wait for it to complete */
-       for (;;) {
-               /* check whether the controller is done */
-               stat = hc_interrupt();
-               if (stat < 0) {
-                       stat = USB_ST_CRC_ERR;
-                       break;
-               }
-
-               /* NOTE: since we are not interrupt driven in U-Boot and always
-                * handle only one URB at a time, we cannot assume the
-                * transaction finished on the first successful return from
-                * hc_interrupt().. unless the flag for current URB is set,
-                * meaning that all TD's to/from device got actually
-                * transferred and processed. If the current URB is not
-                * finished we need to re-iterate this loop so as
-                * hc_interrupt() gets called again as there needs to be some
-                * more TD's to process still */
-               if ((stat >= 0) && (stat != 0xff) && (urb->finished)) {
-                       /* 0xff is returned for an SF-interrupt */
-                       break;
-               }
-
-               if (--timeout) {
-                       wait_ms(1);
-                       if (!urb->finished)
-                               dbg("\%");
-
-               } else {
-                       err("CTL:TIMEOUT ");
-                       dbg("submit_common_msg: TO status %x\n", stat);
-                       urb->finished = 1;
-                       stat = USB_ST_CRC_ERR;
-                       break;
-               }
-       }
-
-       dev->status = stat;
-       dev->act_len = transfer_len;
-
-#ifdef DEBUG
-       pkt_print(urb, dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe));
-#else
-       wait_ms(1);
-#endif
-
-       /* free TDs in urb_priv */
-       if (usb_pipetype (pipe) != PIPE_INTERRUPT)
-               urb_free_priv (urb);
-       return 0;
-}
-
-/* submit routines called from usb.c */
-int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
-               int transfer_len)
-{
-       info("submit_bulk_msg");
-       return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0);
-}
-
-int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
-               int transfer_len, struct devrequest *setup)
-{
-       int maxsize = usb_maxpacket(dev, pipe);
-
-       info("submit_control_msg");
-#ifdef DEBUG
-       pkt_print(NULL, dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
-#else
-       wait_ms(1);
-#endif
-       if (!maxsize) {
-               err("submit_control_message: pipesize for pipe %lx is zero",
-                       pipe);
-               return -1;
-       }
-       if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) {
-               gohci.rh.dev = dev;
-               /* root hub - redirect */
-               return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len,
-                       setup);
-       }
-
-       return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0);
-}
-
-int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
-               int transfer_len, int interval)
-{
-       info("submit_int_msg");
-       return submit_common_msg(dev, pipe, buffer, transfer_len, NULL,
-                       interval);
-}
-
-/*-------------------------------------------------------------------------*
- * HC functions
- *-------------------------------------------------------------------------*/
-
-/* reset the HC and BUS */
-
-static int hc_reset (ohci_t *ohci)
-{
-       int timeout = 30;
-       int smm_timeout = 50; /* 0,5 sec */
-
-       dbg("%s\n", __FUNCTION__);
-
-       if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
-               writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
-               info("USB HC TakeOver from SMM");
-               while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
-                       wait_ms (10);
-                       if (--smm_timeout == 0) {
-                               err("USB HC TakeOver failed!");
-                               return -1;
-                       }
-               }
-       }
-
-       /* Disable HC interrupts */
-       writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
-
-       dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;\n",
-               ohci->slot_name,
-               readl(&ohci->regs->control));
-
-       /* Reset USB (needed by some controllers) */
-       ohci->hc_control = 0;
-       writel (ohci->hc_control, &ohci->regs->control);
-
-       /* HC Reset requires max 10 us delay */
-       writel (OHCI_HCR,  &ohci->regs->cmdstatus);
-       while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
-               if (--timeout == 0) {
-                       err("USB HC reset timed out!");
-                       return -1;
-               }
-               udelay (1);
-       }
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* Start an OHCI controller, set the BUS operational
- * enable interrupts
- * connect the virtual root hub */
-
-static int hc_start (ohci_t * ohci)
-{
-       __u32 mask;
-       unsigned int fminterval;
-
-       ohci->disabled = 1;
-
-       /* Tell the controller where the control and bulk lists are
-        * The lists are empty now. */
-
-       writel (0, &ohci->regs->ed_controlhead);
-       writel (0, &ohci->regs->ed_bulkhead);
-
-       writel ((__u32)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */
-
-       fminterval = 0x2edf;
-       writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
-       fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
-       writel (fminterval, &ohci->regs->fminterval);
-       writel (0x628, &ohci->regs->lsthresh);
-
-       /* start controller operations */
-       ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
-       ohci->disabled = 0;
-       writel (ohci->hc_control, &ohci->regs->control);
-
-       /* disable all interrupts */
-       mask = (OHCI_INTR_SO | OHCI_INTR_WDH | OHCI_INTR_SF | OHCI_INTR_RD |
-                       OHCI_INTR_UE | OHCI_INTR_FNO | OHCI_INTR_RHSC |
-                       OHCI_INTR_OC | OHCI_INTR_MIE);
-       writel (mask, &ohci->regs->intrdisable);
-       /* clear all interrupts */
-       mask &= ~OHCI_INTR_MIE;
-       writel (mask, &ohci->regs->intrstatus);
-       /* Choose the interrupts we care about now  - but w/o MIE */
-       mask = OHCI_INTR_RHSC | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
-       writel (mask, &ohci->regs->intrenable);
-
-#ifdef OHCI_USE_NPS
-       /* required for AMD-756 and some Mac platforms */
-       writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
-               &ohci->regs->roothub.a);
-       writel (RH_HS_LPSC, &ohci->regs->roothub.status);
-#endif /* OHCI_USE_NPS */
-
-#define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);})
-       /* POTPGT delay is bits 24-31, in 2 ms units. */
-       mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
-
-       /* connect the virtual root hub */
-       ohci->rh.devnum = 0;
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* Poll USB interrupt. */
-void usb_event_poll(void)
-{
-       hc_interrupt();
-}
-
-/* an interrupt happens */
-
-static int hc_interrupt (void)
-{
-       ohci_t *ohci = &gohci;
-       struct ohci_regs *regs = ohci->regs;
-       int ints;
-       int stat = -1;
-
-       if ((ohci->hcca->done_head != 0) &&
-           !(m32_swap (ohci->hcca->done_head) & 0x01)) {
-               ints =  OHCI_INTR_WDH;
-       } else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
-               ohci->disabled++;
-               err ("%s device removed!", ohci->slot_name);
-               return -1;
-       } else if ((ints &= readl (&regs->intrenable)) == 0) {
-               dbg("hc_interrupt: returning..\n");
-               return 0xff;
-       }
-
-       /* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */
-
-       if (ints & OHCI_INTR_RHSC) {
-               got_rhsc = 1;
-               stat = 0xff;
-       }
-
-       if (ints & OHCI_INTR_UE) {
-               ohci->disabled++;
-               err ("OHCI Unrecoverable Error, controller usb-%s disabled",
-                       ohci->slot_name);
-               /* e.g. due to PCI Master/Target Abort */
-
-#ifdef DEBUG
-               ohci_dump (ohci, 1);
-#else
-       wait_ms(1);
-#endif
-               /* FIXME: be optimistic, hope that bug won't repeat often. */
-               /* Make some non-interrupt context restart the controller. */
-               /* Count and limit the retries though; either hardware or */
-               /* software errors can go forever... */
-               hc_reset (ohci);
-               return -1;
-       }
-
-       if (ints & OHCI_INTR_WDH) {
-               wait_ms(1);
-               writel (OHCI_INTR_WDH, &regs->intrdisable);
-               (void)readl (&regs->intrdisable); /* flush */
-               stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci));
-               writel (OHCI_INTR_WDH, &regs->intrenable);
-               (void)readl (&regs->intrdisable); /* flush */
-       }
-
-       if (ints & OHCI_INTR_SO) {
-               dbg("USB Schedule overrun\n");
-               writel (OHCI_INTR_SO, &regs->intrenable);
-               stat = -1;
-       }
-
-       /* FIXME:  this assumes SOF (1/ms) interrupts don't get lost... */
-       if (ints & OHCI_INTR_SF) {
-               unsigned int frame = m16_swap (ohci->hcca->frame_no) & 1;
-               wait_ms(1);
-               writel (OHCI_INTR_SF, &regs->intrdisable);
-               if (ohci->ed_rm_list[frame] != NULL)
-                       writel (OHCI_INTR_SF, &regs->intrenable);
-               stat = 0xff;
-       }
-
-       writel (ints, &regs->intrstatus);
-       return stat;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*-------------------------------------------------------------------------*/
-
-/* De-allocate all resources.. */
-
-static void hc_release_ohci (ohci_t *ohci)
-{
-       dbg ("USB HC release ohci usb-%s", ohci->slot_name);
-
-       if (!ohci->disabled)
-               hc_reset (ohci);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * low level initalisation routine, called from usb.c
- */
-static char ohci_inited = 0;
-
-int usb_lowlevel_init(void)
-{
-#ifdef CONFIG_PCI_OHCI
-       pci_dev_t pdev;
-#endif
-
-#ifdef CFG_USB_OHCI_CPU_INIT
-       /* cpu dependant init */
-       if(usb_cpu_init())
-               return -1;
-#endif
-
-#ifdef CFG_USB_OHCI_BOARD_INIT
-       /*  board dependant init */
-       if(usb_board_init())
-               return -1;
-#endif
-       memset (&gohci, 0, sizeof (ohci_t));
-
-       /* align the storage */
-       if ((__u32)&ghcca[0] & 0xff) {
-               err("HCCA not aligned!!");
-               return -1;
-       }
-       phcca = &ghcca[0];
-       info("aligned ghcca %p", phcca);
-       memset(&ohci_dev, 0, sizeof(struct ohci_device));
-       if ((__u32)&ohci_dev.ed[0] & 0x7) {
-               err("EDs not aligned!!");
-               return -1;
-       }
-       memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1));
-       if ((__u32)gtd & 0x7) {
-               err("TDs not aligned!!");
-               return -1;
-       }
-       ptd = gtd;
-       gohci.hcca = phcca;
-       memset (phcca, 0, sizeof (struct ohci_hcca));
-
-       gohci.disabled = 1;
-       gohci.sleeping = 0;
-       gohci.irq = -1;
-#ifdef CONFIG_PCI_OHCI
-       pdev = pci_find_devices(ohci_pci_ids, 0);
-
-       if (pdev != -1) {
-               u16 vid, did;
-               u32 base;
-               pci_read_config_word(pdev, PCI_VENDOR_ID, &vid);
-               pci_read_config_word(pdev, PCI_DEVICE_ID, &did);
-               printf("OHCI pci controller (%04x, %04x) found @(%d:%d:%d)\n",
-                               vid, did, (pdev >> 16) & 0xff,
-                               (pdev >> 11) & 0x1f, (pdev >> 8) & 0x7);
-               pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &base);
-               printf("OHCI regs address 0x%08x\n", base);
-               gohci.regs = (struct ohci_regs *)base;
-       } else
-               return -1;
-#else
-       gohci.regs = (struct ohci_regs *)CFG_USB_OHCI_REGS_BASE;
-#endif
-
-       gohci.flags = 0;
-       gohci.slot_name = CFG_USB_OHCI_SLOT_NAME;
-
-       if (hc_reset (&gohci) < 0) {
-               hc_release_ohci (&gohci);
-               err ("can't reset usb-%s", gohci.slot_name);
-#ifdef CFG_USB_OHCI_BOARD_INIT
-               /* board dependant cleanup */
-               usb_board_init_fail();
-#endif
-
-#ifdef CFG_USB_OHCI_CPU_INIT
-               /* cpu dependant cleanup */
-               usb_cpu_init_fail();
-#endif
-               return -1;
-       }
-
-       /* FIXME this is a second HC reset; why?? */
-       /* writel(gohci.hc_control = OHCI_USB_RESET, &gohci.regs->control);
-          wait_ms(10); */
-       if (hc_start (&gohci) < 0) {
-               err ("can't start usb-%s", gohci.slot_name);
-               hc_release_ohci (&gohci);
-               /* Initialization failed */
-#ifdef CFG_USB_OHCI_BOARD_INIT
-               /* board dependant cleanup */
-               usb_board_stop();
-#endif
-
-#ifdef CFG_USB_OHCI_CPU_INIT
-               /* cpu dependant cleanup */
-               usb_cpu_stop();
-#endif
-               return -1;
-       }
-
-#ifdef DEBUG
-       ohci_dump (&gohci, 1);
-#else
-       wait_ms(1);
-#endif
-       ohci_inited = 1;
-       return 0;
-}
-
-int usb_lowlevel_stop(void)
-{
-       /* this gets called really early - before the controller has */
-       /* even been initialized! */
-       if (!ohci_inited)
-               return 0;
-       /* TODO release any interrupts, etc. */
-       /* call hc_release_ohci() here ? */
-       hc_reset (&gohci);
-
-#ifdef CFG_USB_OHCI_BOARD_INIT
-       /* board dependant cleanup */
-       if(usb_board_stop())
-               return -1;
-#endif
-
-#ifdef CFG_USB_OHCI_CPU_INIT
-       /* cpu dependant cleanup */
-       if(usb_cpu_stop())
-               return -1;
-#endif
-
-       return 0;
-}
-#endif /* CONFIG_USB_OHCI_NEW */
diff --git a/drivers/usb_ohci.h b/drivers/usb_ohci.h
deleted file mode 100644 (file)
index 380cb4c..0000000
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- * URB OHCI HCD (Host Controller Driver) for USB.
- *
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
- *
- * usb-ohci.h
- */
-
-/* functions for doing board or CPU specific setup/cleanup */
-extern int usb_board_init(void);
-extern int usb_board_stop(void);
-extern int usb_board_init_fail(void);
-
-extern int usb_cpu_init(void);
-extern int usb_cpu_stop(void);
-extern int usb_cpu_init_fail(void);
-
-
-static int cc_to_error[16] = {
-
-/* mapping of the OHCI CC status to error codes */
-       /* No  Error  */               0,
-       /* CRC Error  */               USB_ST_CRC_ERR,
-       /* Bit Stuff  */               USB_ST_BIT_ERR,
-       /* Data Togg  */               USB_ST_CRC_ERR,
-       /* Stall      */               USB_ST_STALLED,
-       /* DevNotResp */               -1,
-       /* PIDCheck   */               USB_ST_BIT_ERR,
-       /* UnExpPID   */               USB_ST_BIT_ERR,
-       /* DataOver   */               USB_ST_BUF_ERR,
-       /* DataUnder  */               USB_ST_BUF_ERR,
-       /* reservd    */               -1,
-       /* reservd    */               -1,
-       /* BufferOver */               USB_ST_BUF_ERR,
-       /* BuffUnder  */               USB_ST_BUF_ERR,
-       /* Not Access */               -1,
-       /* Not Access */               -1
-};
-
-/* ED States */
-
-#define ED_NEW         0x00
-#define ED_UNLINK      0x01
-#define ED_OPER                0x02
-#define ED_DEL         0x04
-#define ED_URB_DEL     0x08
-
-/* usb_ohci_ed */
-struct ed {
-       __u32 hwINFO;
-       __u32 hwTailP;
-       __u32 hwHeadP;
-       __u32 hwNextED;
-
-       struct ed *ed_prev;
-       __u8 int_period;
-       __u8 int_branch;
-       __u8 int_load;
-       __u8 int_interval;
-       __u8 state;
-       __u8 type;
-       __u16 last_iso;
-       struct ed *ed_rm_list;
-
-       struct usb_device *usb_dev;
-       void *purb;
-       __u32 unused[2];
-} __attribute((aligned(16)));
-typedef struct ed ed_t;
-
-
-/* TD info field */
-#define TD_CC      0xf0000000
-#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
-#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
-#define TD_EC      0x0C000000
-#define TD_T       0x03000000
-#define TD_T_DATA0  0x02000000
-#define TD_T_DATA1  0x03000000
-#define TD_T_TOGGLE 0x00000000
-#define TD_R       0x00040000
-#define TD_DI      0x00E00000
-#define TD_DI_SET(X) (((X) & 0x07)<< 21)
-#define TD_DP      0x00180000
-#define TD_DP_SETUP 0x00000000
-#define TD_DP_IN    0x00100000
-#define TD_DP_OUT   0x00080000
-
-#define TD_ISO     0x00010000
-#define TD_DEL     0x00020000
-
-/* CC Codes */
-#define TD_CC_NOERROR     0x00
-#define TD_CC_CRC         0x01
-#define TD_CC_BITSTUFFING  0x02
-#define TD_CC_DATATOGGLEM  0x03
-#define TD_CC_STALL       0x04
-#define TD_DEVNOTRESP     0x05
-#define TD_PIDCHECKFAIL           0x06
-#define TD_UNEXPECTEDPID   0x07
-#define TD_DATAOVERRUN    0x08
-#define TD_DATAUNDERRUN           0x09
-#define TD_BUFFEROVERRUN   0x0C
-#define TD_BUFFERUNDERRUN  0x0D
-#define TD_NOTACCESSED    0x0F
-
-
-#define MAXPSW 1
-
-struct td {
-       __u32 hwINFO;
-       __u32 hwCBP;            /* Current Buffer Pointer */
-       __u32 hwNextTD;         /* Next TD Pointer */
-       __u32 hwBE;             /* Memory Buffer End Pointer */
-
-/* #ifndef CONFIG_MPC5200 /\* this seems wrong *\/ */
-       __u16 hwPSW[MAXPSW];
-/* #endif */
-       __u8 unused;
-       __u8 index;
-       struct ed *ed;
-       struct td *next_dl_td;
-       struct usb_device *usb_dev;
-       int transfer_len;
-       __u32 data;
-
-       __u32 unused2[2];
-} __attribute((aligned(32)));
-typedef struct td td_t;
-
-#define OHCI_ED_SKIP   (1 << 14)
-
-/*
- * The HCCA (Host Controller Communications Area) is a 256 byte
- * structure defined in the OHCI spec. that the host controller is
- * told the base address of.  It must be 256-byte aligned.
- */
-
-#define NUM_INTS 32    /* part of the OHCI standard */
-struct ohci_hcca {
-       __u32   int_table[NUM_INTS];    /* Interrupt ED table */
-#if defined(CONFIG_MPC5200)
-       __u16   pad1;                   /* set to 0 on each frame_no change */
-       __u16   frame_no;               /* current frame number */
-#else
-       __u16   frame_no;               /* current frame number */
-       __u16   pad1;                   /* set to 0 on each frame_no change */
-#endif
-       __u32   done_head;              /* info returned for an interrupt */
-       u8              reserved_for_hc[116];
-} __attribute((aligned(256)));
-
-
-/*
- * Maximum number of root hub ports.
- */
-#ifndef CFG_USB_OHCI_MAX_ROOT_PORTS
-# error "CFG_USB_OHCI_MAX_ROOT_PORTS undefined!"
-#endif
-
-/*
- * This is the structure of the OHCI controller's memory mapped I/O
- * region.  This is Memory Mapped I/O. You must use the readl() and
- * writel() macros defined in asm/io.h to access these!!
- */
-struct ohci_regs {
-       /* control and status registers */
-       __u32   revision;
-       __u32   control;
-       __u32   cmdstatus;
-       __u32   intrstatus;
-       __u32   intrenable;
-       __u32   intrdisable;
-       /* memory pointers */
-       __u32   hcca;
-       __u32   ed_periodcurrent;
-       __u32   ed_controlhead;
-       __u32   ed_controlcurrent;
-       __u32   ed_bulkhead;
-       __u32   ed_bulkcurrent;
-       __u32   donehead;
-       /* frame counters */
-       __u32   fminterval;
-       __u32   fmremaining;
-       __u32   fmnumber;
-       __u32   periodicstart;
-       __u32   lsthresh;
-       /* Root hub ports */
-       struct  ohci_roothub_regs {
-               __u32   a;
-               __u32   b;
-               __u32   status;
-               __u32   portstatus[CFG_USB_OHCI_MAX_ROOT_PORTS];
-       } roothub;
-} __attribute((aligned(32)));
-
-
-/* OHCI CONTROL AND STATUS REGISTER MASKS */
-
-/*
- * HcControl (control) register masks
- */
-#define OHCI_CTRL_CBSR (3 << 0)        /* control/bulk service ratio */
-#define OHCI_CTRL_PLE  (1 << 2)        /* periodic list enable */
-#define OHCI_CTRL_IE   (1 << 3)        /* isochronous enable */
-#define OHCI_CTRL_CLE  (1 << 4)        /* control list enable */
-#define OHCI_CTRL_BLE  (1 << 5)        /* bulk list enable */
-#define OHCI_CTRL_HCFS (3 << 6)        /* host controller functional state */
-#define OHCI_CTRL_IR   (1 << 8)        /* interrupt routing */
-#define OHCI_CTRL_RWC  (1 << 9)        /* remote wakeup connected */
-#define OHCI_CTRL_RWE  (1 << 10)       /* remote wakeup enable */
-
-/* pre-shifted values for HCFS */
-#      define OHCI_USB_RESET   (0 << 6)
-#      define OHCI_USB_RESUME  (1 << 6)
-#      define OHCI_USB_OPER    (2 << 6)
-#      define OHCI_USB_SUSPEND (3 << 6)
-
-/*
- * HcCommandStatus (cmdstatus) register masks
- */
-#define OHCI_HCR       (1 << 0)        /* host controller reset */
-#define OHCI_CLF       (1 << 1)        /* control list filled */
-#define OHCI_BLF       (1 << 2)        /* bulk list filled */
-#define OHCI_OCR       (1 << 3)        /* ownership change request */
-#define OHCI_SOC       (3 << 16)       /* scheduling overrun count */
-
-/*
- * masks used with interrupt registers:
- * HcInterruptStatus (intrstatus)
- * HcInterruptEnable (intrenable)
- * HcInterruptDisable (intrdisable)
- */
-#define OHCI_INTR_SO   (1 << 0)        /* scheduling overrun */
-#define OHCI_INTR_WDH  (1 << 1)        /* writeback of done_head */
-#define OHCI_INTR_SF   (1 << 2)        /* start frame */
-#define OHCI_INTR_RD   (1 << 3)        /* resume detect */
-#define OHCI_INTR_UE   (1 << 4)        /* unrecoverable error */
-#define OHCI_INTR_FNO  (1 << 5)        /* frame number overflow */
-#define OHCI_INTR_RHSC (1 << 6)        /* root hub status change */
-#define OHCI_INTR_OC   (1 << 30)       /* ownership change */
-#define OHCI_INTR_MIE  (1 << 31)       /* master interrupt enable */
-
-
-/* Virtual Root HUB */
-struct virt_root_hub {
-       int devnum; /* Address of Root Hub endpoint */
-       void *dev;  /* was urb */
-       void *int_addr;
-       int send;
-       int interval;
-};
-
-/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
-
-/* destination of request */
-#define RH_INTERFACE              0x01
-#define RH_ENDPOINT               0x02
-#define RH_OTHER                  0x03
-
-#define RH_CLASS                  0x20
-#define RH_VENDOR                 0x40
-
-/* Requests: bRequest << 8 | bmRequestType */
-#define RH_GET_STATUS          0x0080
-#define RH_CLEAR_FEATURE       0x0100
-#define RH_SET_FEATURE         0x0300
-#define RH_SET_ADDRESS         0x0500
-#define RH_GET_DESCRIPTOR      0x0680
-#define RH_SET_DESCRIPTOR      0x0700
-#define RH_GET_CONFIGURATION   0x0880
-#define RH_SET_CONFIGURATION   0x0900
-#define RH_GET_STATE           0x0280
-#define RH_GET_INTERFACE       0x0A80
-#define RH_SET_INTERFACE       0x0B00
-#define RH_SYNC_FRAME          0x0C80
-/* Our Vendor Specific Request */
-#define RH_SET_EP              0x2000
-
-
-/* Hub port features */
-#define RH_PORT_CONNECTION        0x00
-#define RH_PORT_ENABLE            0x01
-#define RH_PORT_SUSPEND                   0x02
-#define RH_PORT_OVER_CURRENT      0x03
-#define RH_PORT_RESET             0x04
-#define RH_PORT_POWER             0x08
-#define RH_PORT_LOW_SPEED         0x09
-
-#define RH_C_PORT_CONNECTION      0x10
-#define RH_C_PORT_ENABLE          0x11
-#define RH_C_PORT_SUSPEND         0x12
-#define RH_C_PORT_OVER_CURRENT    0x13
-#define RH_C_PORT_RESET                   0x14
-
-/* Hub features */
-#define RH_C_HUB_LOCAL_POWER      0x00
-#define RH_C_HUB_OVER_CURRENT     0x01
-
-#define RH_DEVICE_REMOTE_WAKEUP           0x00
-#define RH_ENDPOINT_STALL         0x01
-
-#define RH_ACK                    0x01
-#define RH_REQ_ERR                -1
-#define RH_NACK                           0x00
-
-
-/* OHCI ROOT HUB REGISTER MASKS */
-
-/* roothub.portstatus [i] bits */
-#define RH_PS_CCS           0x00000001         /* current connect status */
-#define RH_PS_PES           0x00000002         /* port enable status*/
-#define RH_PS_PSS           0x00000004         /* port suspend status */
-#define RH_PS_POCI          0x00000008         /* port over current indicator */
-#define RH_PS_PRS           0x00000010         /* port reset status */
-#define RH_PS_PPS           0x00000100         /* port power status */
-#define RH_PS_LSDA          0x00000200         /* low speed device attached */
-#define RH_PS_CSC           0x00010000         /* connect status change */
-#define RH_PS_PESC          0x00020000         /* port enable status change */
-#define RH_PS_PSSC          0x00040000         /* port suspend status change */
-#define RH_PS_OCIC          0x00080000         /* over current indicator change */
-#define RH_PS_PRSC          0x00100000         /* port reset status change */
-
-/* roothub.status bits */
-#define RH_HS_LPS           0x00000001         /* local power status */
-#define RH_HS_OCI           0x00000002         /* over current indicator */
-#define RH_HS_DRWE          0x00008000         /* device remote wakeup enable */
-#define RH_HS_LPSC          0x00010000         /* local power status change */
-#define RH_HS_OCIC          0x00020000         /* over current indicator change */
-#define RH_HS_CRWE          0x80000000         /* clear remote wakeup enable */
-
-/* roothub.b masks */
-#define RH_B_DR                0x0000ffff              /* device removable flags */
-#define RH_B_PPCM      0xffff0000              /* port power control mask */
-
-/* roothub.a masks */
-#define RH_A_NDP       (0xff << 0)             /* number of downstream ports */
-#define RH_A_PSM       (1 << 8)                /* power switching mode */
-#define RH_A_NPS       (1 << 9)                /* no power switching */
-#define RH_A_DT                (1 << 10)               /* device type (mbz) */
-#define RH_A_OCPM      (1 << 11)               /* over current protection mode */
-#define RH_A_NOCP      (1 << 12)               /* no over current protection */
-#define RH_A_POTPGT    (0xff << 24)            /* power on to power good time */
-
-/* urb */
-#define N_URB_TD 48
-typedef struct
-{
-       ed_t *ed;
-       __u16 length;   /* number of tds associated with this request */
-       __u16 td_cnt;   /* number of tds already serviced */
-       struct usb_device *dev;
-       int   state;
-       unsigned long pipe;
-       void *transfer_buffer;
-       int transfer_buffer_length;
-       int interval;
-       int actual_length;
-       int finished;
-       td_t *td[N_URB_TD];     /* list pointer to all corresponding TDs associated with this request */
-} urb_priv_t;
-#define URB_DEL 1
-
-/*
- * This is the full ohci controller description
- *
- * Note how the "proper" USB information is just
- * a subset of what the full implementation needs. (Linus)
- */
-
-
-typedef struct ohci {
-       struct ohci_hcca *hcca;         /* hcca */
-       /*dma_addr_t hcca_dma;*/
-
-       int irq;
-       int disabled;                   /* e.g. got a UE, we're hung */
-       int sleeping;
-       unsigned long flags;            /* for HC bugs */
-
-       struct ohci_regs *regs; /* OHCI controller's memory */
-
-       int ohci_int_load[32];   /* load of the 32 Interrupt Chains (for load balancing)*/
-       ed_t *ed_rm_list[2];     /* lists of all endpoints to be removed */
-       ed_t *ed_bulktail;       /* last endpoint of bulk list */
-       ed_t *ed_controltail;    /* last endpoint of control list */
-       int intrstatus;
-       __u32 hc_control;               /* copy of the hc control reg */
-       struct usb_device *dev[32];
-       struct virt_root_hub rh;
-
-       const char      *slot_name;
-} ohci_t;
-
-#define NUM_EDS 8              /* num of preallocated endpoint descriptors */
-
-struct ohci_device {
-       ed_t    ed[NUM_EDS];
-       int ed_cnt;
-};
-
-/* hcd */
-/* endpoint */
-static int ep_link(ohci_t * ohci, ed_t * ed);
-static int ep_unlink(ohci_t * ohci, ed_t * ed);
-static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned long pipe,
-               int interval, int load);
-
-/*-------------------------------------------------------------------------*/
-
-/* we need more TDs than EDs */
-#define NUM_TD 64
-
-/* +1 so we can align the storage */
-td_t gtd[NUM_TD+1];
-/* pointers to aligned storage */
-td_t *ptd;
-
-/* TDs ... */
-static inline struct td *
-td_alloc (struct usb_device *usb_dev)
-{
-       int i;
-       struct td       *td;
-
-       td = NULL;
-       for (i = 0; i < NUM_TD; i++)
-       {
-               if (ptd[i].usb_dev == NULL)
-               {
-                       td = &ptd[i];
-                       td->usb_dev = usb_dev;
-                       break;
-               }
-       }
-
-       return td;
-}
-
-static inline void
-ed_free (struct ed *ed)
-{
-       ed->usb_dev = NULL;
-}
diff --git a/drivers/usbdcore.c b/drivers/usbdcore.c
deleted file mode 100644 (file)
index 308c7ce..0000000
+++ /dev/null
@@ -1,684 +0,0 @@
-/*
- * (C) Copyright 2003
- * Gerry Hamel, geh@ti.com, Texas Instruments
- *
- * Based on
- * linux/drivers/usbd/usbd.c.c - USB Device Core Layer
- *
- * Copyright (c) 2000, 2001, 2002 Lineo
- * Copyright (c) 2001 Hewlett Packard
- *
- * By:
- *     Stuart Lynne <sl@lineo.com>,
- *     Tom Rushworth <tbr@lineo.com>,
- *     Bruce Balden <balden@lineo.com>
- *
- * 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.
- *
- */
-
-#include <malloc.h>
-#include "usbdcore.h"
-
-#define MAX_INTERFACES 2
-
-
-int maxstrings = 20;
-
-/* Global variables ************************************************************************** */
-
-struct usb_string_descriptor **usb_strings;
-
-int usb_devices;
-
-extern struct usb_function_driver ep0_driver;
-
-int registered_functions;
-int registered_devices;
-
-char *usbd_device_events[] = {
-       "DEVICE_UNKNOWN",
-       "DEVICE_INIT",
-       "DEVICE_CREATE",
-       "DEVICE_HUB_CONFIGURED",
-       "DEVICE_RESET",
-       "DEVICE_ADDRESS_ASSIGNED",
-       "DEVICE_CONFIGURED",
-       "DEVICE_SET_INTERFACE",
-       "DEVICE_SET_FEATURE",
-       "DEVICE_CLEAR_FEATURE",
-       "DEVICE_DE_CONFIGURED",
-       "DEVICE_BUS_INACTIVE",
-       "DEVICE_BUS_ACTIVITY",
-       "DEVICE_POWER_INTERRUPTION",
-       "DEVICE_HUB_RESET",
-       "DEVICE_DESTROY",
-       "DEVICE_FUNCTION_PRIVATE",
-};
-
-char *usbd_device_states[] = {
-       "STATE_INIT",
-       "STATE_CREATED",
-       "STATE_ATTACHED",
-       "STATE_POWERED",
-       "STATE_DEFAULT",
-       "STATE_ADDRESSED",
-       "STATE_CONFIGURED",
-       "STATE_UNKNOWN",
-};
-
-char *usbd_device_requests[] = {
-       "GET STATUS",           /* 0 */
-       "CLEAR FEATURE",        /* 1 */
-       "RESERVED",             /* 2 */
-       "SET FEATURE",          /* 3 */
-       "RESERVED",             /* 4 */
-       "SET ADDRESS",          /* 5 */
-       "GET DESCRIPTOR",       /* 6 */
-       "SET DESCRIPTOR",       /* 7 */
-       "GET CONFIGURATION",    /* 8 */
-       "SET CONFIGURATION",    /* 9 */
-       "GET INTERFACE",        /* 10 */
-       "SET INTERFACE",        /* 11 */
-       "SYNC FRAME",           /* 12 */
-};
-
-char *usbd_device_descriptors[] = {
-       "UNKNOWN",              /* 0 */
-       "DEVICE",               /* 1 */
-       "CONFIG",               /* 2 */
-       "STRING",               /* 3 */
-       "INTERFACE",            /* 4 */
-       "ENDPOINT",             /* 5 */
-       "DEVICE QUALIFIER",     /* 6 */
-       "OTHER SPEED",          /* 7 */
-       "INTERFACE POWER",      /* 8 */
-};
-
-char *usbd_device_status[] = {
-       "USBD_OPENING",
-       "USBD_OK",
-       "USBD_SUSPENDED",
-       "USBD_CLOSING",
-};
-
-
-/* Descriptor support functions ************************************************************** */
-
-
-/**
- * usbd_get_string - find and return a string descriptor
- * @index: string index to return
- *
- * Find an indexed string and return a pointer to a it.
- */
-struct usb_string_descriptor *usbd_get_string (__u8 index)
-{
-       if (index >= maxstrings) {
-               return NULL;
-       }
-       return usb_strings[index];
-}
-
-
-/* Access to device descriptor functions ***************************************************** */
-
-
-/* *
- * usbd_device_configuration_instance - find a configuration instance for this device
- * @device:
- * @configuration: index to configuration, 0 - N-1
- *
- * Get specifed device configuration. Index should be bConfigurationValue-1.
- */
-static struct usb_configuration_instance *usbd_device_configuration_instance (struct usb_device_instance *device,
-               unsigned int port, unsigned int configuration)
-{
-       /* XXX */
-       configuration = configuration ? configuration - 1 : 0;
-
-       if (configuration >= device->configurations) {
-               return NULL;
-       }
-       return device->configuration_instance_array + configuration;
-}
-
-
-/* *
- * usbd_device_interface_instance
- * @device:
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- *
- * Return the specified interface descriptor for the specified device.
- */
-struct usb_interface_instance *usbd_device_interface_instance (struct usb_device_instance *device, int port, int configuration, int interface)
-{
-       struct usb_configuration_instance *configuration_instance;
-
-       if ((configuration_instance = usbd_device_configuration_instance (device, port, configuration)) == NULL) {
-               return NULL;
-       }
-       if (interface >= configuration_instance->interfaces) {
-               return NULL;
-       }
-       return configuration_instance->interface_instance_array + interface;
-}
-
-/* *
- * usbd_device_alternate_descriptor_list
- * @device:
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @alternate: alternate setting
- *
- * Return the specified alternate descriptor for the specified device.
- */
-struct usb_alternate_instance *usbd_device_alternate_instance (struct usb_device_instance *device, int port, int configuration, int interface, int alternate)
-{
-       struct usb_interface_instance *interface_instance;
-
-       if ((interface_instance = usbd_device_interface_instance (device, port, configuration, interface)) == NULL) {
-               return NULL;
-       }
-
-       if (alternate >= interface_instance->alternates) {
-               return NULL;
-       }
-
-       return interface_instance->alternates_instance_array + alternate;
-}
-
-
-/* *
- * usbd_device_device_descriptor
- * @device: which device
- * @configuration: index to configuration, 0 - N-1
- * @port: which port
- *
- * Return the specified configuration descriptor for the specified device.
- */
-struct usb_device_descriptor *usbd_device_device_descriptor (struct usb_device_instance *device, int port)
-{
-       return (device->device_descriptor);
-}
-
-
-/**
- * usbd_device_configuration_descriptor
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- *
- * Return the specified configuration descriptor for the specified device.
- */
-struct usb_configuration_descriptor *usbd_device_configuration_descriptor (struct
-                                                                          usb_device_instance
-                                                                          *device, int port, int configuration)
-{
-       struct usb_configuration_instance *configuration_instance;
-       if (!(configuration_instance = usbd_device_configuration_instance (device, port, configuration))) {
-               return NULL;
-       }
-       return (configuration_instance->configuration_descriptor);
-}
-
-
-/**
- * usbd_device_interface_descriptor
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @alternate: alternate setting
- *
- * Return the specified interface descriptor for the specified device.
- */
-struct usb_interface_descriptor *usbd_device_interface_descriptor (struct usb_device_instance
-                                                                  *device, int port, int configuration, int interface, int alternate)
-{
-       struct usb_interface_instance *interface_instance;
-       if (!(interface_instance = usbd_device_interface_instance (device, port, configuration, interface))) {
-               return NULL;
-       }
-       if ((alternate < 0) || (alternate >= interface_instance->alternates)) {
-               return NULL;
-       }
-       return (interface_instance->alternates_instance_array[alternate].interface_descriptor);
-}
-
-/**
- * usbd_device_endpoint_descriptor_index
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @alternate: index setting
- * @index: which index
- *
- * Return the specified endpoint descriptor for the specified device.
- */
-struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor_index (struct usb_device_instance
-                                                                      *device, int port, int configuration, int interface, int alternate, int index)
-{
-       struct usb_alternate_instance *alternate_instance;
-
-       if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
-               return NULL;
-       }
-       if (index >= alternate_instance->endpoints) {
-               return NULL;
-       }
-       return *(alternate_instance->endpoints_descriptor_array + index);
-}
-
-
-/**
- * usbd_device_endpoint_transfersize
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @index: which index
- *
- * Return the specified endpoint transfer size;
- */
-int usbd_device_endpoint_transfersize (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int index)
-{
-       struct usb_alternate_instance *alternate_instance;
-
-       if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
-               return 0;
-       }
-       if (index >= alternate_instance->endpoints) {
-               return 0;
-       }
-       return *(alternate_instance->endpoint_transfersize_array + index);
-}
-
-
-/**
- * usbd_device_endpoint_descriptor
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @alternate: alternate setting
- * @endpoint: which endpoint
- *
- * Return the specified endpoint descriptor for the specified device.
- */
-struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int endpoint)
-{
-       struct usb_endpoint_descriptor *endpoint_descriptor;
-       int i;
-
-       for (i = 0; !(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, configuration, interface, alternate, i)); i++) {
-               if (endpoint_descriptor->bEndpointAddress == endpoint) {
-                       return endpoint_descriptor;
-               }
-       }
-       return NULL;
-}
-
-/**
- * usbd_endpoint_halted
- * @device: point to struct usb_device_instance
- * @endpoint: endpoint to check
- *
- * Return non-zero if endpoint is halted.
- */
-int usbd_endpoint_halted (struct usb_device_instance *device, int endpoint)
-{
-       return (device->status == USB_STATUS_HALT);
-}
-
-
-/**
- * usbd_rcv_complete - complete a receive
- * @endpoint:
- * @len:
- * @urb_bad:
- *
- * Called from rcv interrupt to complete.
- */
-void usbd_rcv_complete(struct usb_endpoint_instance *endpoint, int len, int urb_bad)
-{
-       if (endpoint) {
-               struct urb *rcv_urb;
-
-               /*usbdbg("len: %d urb: %p\n", len, endpoint->rcv_urb); */
-
-               /* if we had an urb then update actual_length, dispatch if neccessary */
-               if ((rcv_urb = endpoint->rcv_urb)) {
-
-                       /*usbdbg("actual: %d buffer: %d\n", */
-                       /*rcv_urb->actual_length, rcv_urb->buffer_length); */
-
-                       /* check the urb is ok, are we adding data less than the packetsize */
-                       if (!urb_bad && (len <= endpoint->rcv_packetSize)) {
-                         /*usbdbg("updating actual_length by %d\n",len); */
-
-                               /* increment the received data size */
-                               rcv_urb->actual_length += len;
-
-                       } else {
-                               usberr(" RECV_ERROR actual: %d buffer: %d urb_bad: %d\n",
-                                      rcv_urb->actual_length, rcv_urb->buffer_length, urb_bad);
-
-                               rcv_urb->actual_length = 0;
-                               rcv_urb->status = RECV_ERROR;
-                       }
-               } else {
-                       usberr("no rcv_urb!");
-               }
-       } else {
-               usberr("no endpoint!");
-       }
-
-}
-
-/**
- * usbd_tx_complete - complete a transmit
- * @endpoint:
- * @resetart:
- *
- * Called from tx interrupt to complete.
- */
-void usbd_tx_complete (struct usb_endpoint_instance *endpoint)
-{
-       if (endpoint) {
-               struct urb *tx_urb;
-
-               /* if we have a tx_urb advance or reset, finish if complete */
-               if ((tx_urb = endpoint->tx_urb)) {
-                       int sent = endpoint->last;
-                       endpoint->sent += sent;
-                       endpoint->last -= sent;
-
-                       if( (endpoint->tx_urb->actual_length - endpoint->sent) <= 0 ) {
-                               tx_urb->actual_length = 0;
-                               endpoint->sent = 0;
-                               endpoint->last = 0;
-
-                               /* Remove from active, save for re-use */
-                               urb_detach(tx_urb);
-                               urb_append(&endpoint->done, tx_urb);
-                               /*usbdbg("done->next %p, tx_urb %p, done %p", */
-                               /*       endpoint->done.next, tx_urb, &endpoint->done); */
-
-                               endpoint->tx_urb = first_urb_detached(&endpoint->tx);
-                               if( endpoint->tx_urb ) {
-                                       endpoint->tx_queue--;
-                                       usbdbg("got urb from tx list");
-                               }
-                               if( !endpoint->tx_urb ) {
-                                       /*usbdbg("taking urb from done list"); */
-                                       endpoint->tx_urb = first_urb_detached(&endpoint->done);
-                               }
-                               if( !endpoint->tx_urb ) {
-                                       usbdbg("allocating new urb for tx_urb");
-                                       endpoint->tx_urb = usbd_alloc_urb(tx_urb->device, endpoint);
-                               }
-                       }
-               }
-       }
-}
-
-/* URB linked list functions ***************************************************** */
-
-/*
- * Initialize an urb_link to be a single element list.
- * If the urb_link is being used as a distinguished list head
- * the list is empty when the head is the only link in the list.
- */
-void urb_link_init (urb_link * ul)
-{
-       if (ul) {
-               ul->prev = ul->next = ul;
-       }
-}
-
-/*
- * Detach an urb_link from a list, and set it
- * up as a single element list, so no dangling
- * pointers can be followed, and so it can be
- * joined to another list if so desired.
- */
-void urb_detach (struct urb *urb)
-{
-       if (urb) {
-               urb_link *ul = &urb->link;
-               ul->next->prev = ul->prev;
-               ul->prev->next = ul->next;
-               urb_link_init (ul);
-       }
-}
-
-/*
- * Return the first urb_link in a list with a distinguished
- * head "hd", or NULL if the list is empty.  This will also
- * work as a predicate, returning NULL if empty, and non-NULL
- * otherwise.
- */
-urb_link *first_urb_link (urb_link * hd)
-{
-       urb_link *nx;
-       if (NULL != hd && NULL != (nx = hd->next) && nx != hd) {
-               /* There is at least one element in the list */
-               /* (besides the distinguished head). */
-               return (nx);
-       }
-       /* The list is empty */
-       return (NULL);
-}
-
-/*
- * Return the first urb in a list with a distinguished
- * head "hd", or NULL if the list is empty.
- */
-struct urb *first_urb (urb_link * hd)
-{
-       urb_link *nx;
-       if (NULL == (nx = first_urb_link (hd))) {
-               /* The list is empty */
-               return (NULL);
-       }
-       return (p2surround (struct urb, link, nx));
-}
-
-/*
- * Detach and return the first urb in a list with a distinguished
- * head "hd", or NULL if the list is empty.
- *
- */
-struct urb *first_urb_detached (urb_link * hd)
-{
-       struct urb *urb;
-       if ((urb = first_urb (hd))) {
-               urb_detach (urb);
-       }
-       return urb;
-}
-
-
-/*
- * Append an urb_link (or a whole list of
- * urb_links) to the tail of another list
- * of urb_links.
- */
-void urb_append (urb_link * hd, struct urb *urb)
-{
-       if (hd && urb) {
-               urb_link *new = &urb->link;
-
-               /* This allows the new urb to be a list of urbs, */
-               /* with new pointing at the first, but the link */
-               /* must be initialized. */
-               /* Order is important here... */
-               urb_link *pul = hd->prev;
-               new->prev->next = hd;
-               hd->prev = new->prev;
-               new->prev = pul;
-               pul->next = new;
-       }
-}
-
-/* URB create/destroy functions ***************************************************** */
-
-/**
- * usbd_alloc_urb - allocate an URB appropriate for specified endpoint
- * @device: device instance
- * @endpoint: endpoint
- *
- * Allocate an urb structure. The usb device urb structure is used to
- * contain all data associated with a transfer, including a setup packet for
- * control transfers.
- *
- * NOTE: endpoint_address MUST contain a direction flag.
- */
-struct urb *usbd_alloc_urb (struct usb_device_instance *device, struct usb_endpoint_instance *endpoint)
-{
-       struct urb *urb;
-
-       if( !(urb = (struct urb*)malloc(sizeof(struct urb))) ) {
-         usberr(" F A T A L:  malloc(%u) FAILED!!!!", sizeof(struct urb));
-         return NULL;
-       }
-
-       /* Fill in known fields */
-       memset(urb, 0, sizeof(struct urb));
-       urb->endpoint = endpoint;
-       urb->device = device;
-       urb->buffer = (u8*)urb->buffer_data;
-       urb->buffer_length = sizeof(urb->buffer_data);
-
-       urb_link_init (&urb->link);
-
-       return urb;
-}
-
-/**
- * usbd_dealloc_urb - deallocate an URB and associated buffer
- * @urb: pointer to an urb structure
- *
- * Deallocate an urb structure and associated data.
- */
-void usbd_dealloc_urb (struct urb *urb)
-{
-       if (urb) {
-               free (urb);
-       }
-}
-
-/* Event signaling functions ***************************************************** */
-
-/**
- * usbd_device_event - called to respond to various usb events
- * @device: pointer to struct device
- * @event: event to respond to
- *
- * Used by a Bus driver to indicate an event.
- */
-void usbd_device_event_irq (struct usb_device_instance *device, usb_device_event_t event, int data)
-{
-       usb_device_state_t state;
-
-       if (!device || !device->bus) {
-               usberr("(%p,%d) NULL device or device->bus", device, event);
-               return;
-       }
-
-       state = device->device_state;
-
-       usbinfo("%s", usbd_device_events[event]);
-
-       switch (event) {
-       case DEVICE_UNKNOWN:
-               break;
-       case DEVICE_INIT:
-               device->device_state = STATE_INIT;
-               break;
-
-       case DEVICE_CREATE:
-               device->device_state = STATE_ATTACHED;
-               break;
-
-       case DEVICE_HUB_CONFIGURED:
-               device->device_state = STATE_POWERED;
-               break;
-
-       case DEVICE_RESET:
-               device->device_state = STATE_DEFAULT;
-               device->address = 0;
-               break;
-
-       case DEVICE_ADDRESS_ASSIGNED:
-               device->device_state = STATE_ADDRESSED;
-               break;
-
-       case DEVICE_CONFIGURED:
-               device->device_state = STATE_CONFIGURED;
-               break;
-
-       case DEVICE_DE_CONFIGURED:
-               device->device_state = STATE_ADDRESSED;
-               break;
-
-       case DEVICE_BUS_INACTIVE:
-               if (device->status != USBD_CLOSING) {
-                       device->status = USBD_SUSPENDED;
-               }
-               break;
-       case DEVICE_BUS_ACTIVITY:
-               if (device->status != USBD_CLOSING) {
-                       device->status = USBD_OK;
-               }
-               break;
-
-       case DEVICE_SET_INTERFACE:
-               break;
-       case DEVICE_SET_FEATURE:
-               break;
-       case DEVICE_CLEAR_FEATURE:
-               break;
-
-       case DEVICE_POWER_INTERRUPTION:
-               device->device_state = STATE_POWERED;
-               break;
-       case DEVICE_HUB_RESET:
-               device->device_state = STATE_ATTACHED;
-               break;
-       case DEVICE_DESTROY:
-               device->device_state = STATE_UNKNOWN;
-               break;
-
-       case DEVICE_FUNCTION_PRIVATE:
-               break;
-
-       default:
-               usbdbg("event %d - not handled",event);
-               break;
-       }
-       /*usbdbg("%s event: %d oldstate: %d newstate: %d status: %d address: %d",
-               device->name, event, state,
-               device->device_state, device->status, device->address); */
-
-       /* tell the bus interface driver */
-       if( device->event ) {
-               /* usbdbg("calling device->event"); */
-               device->event(device, event, data);
-       }
-}
diff --git a/drivers/usbdcore_ep0.c b/drivers/usbdcore_ep0.c
deleted file mode 100644 (file)
index 1e44f32..0000000
+++ /dev/null
@@ -1,607 +0,0 @@
-/*
- * (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
- *
- * Copyright (c) 2000, 2001, 2002 Lineo
- * Copyright (c) 2001 Hewlett Packard
- *
- * By:
- *     Stuart Lynne <sl@lineo.com>,
- *     Tom Rushworth <tbr@lineo.com>,
- *     Bruce Balden <balden@lineo.com>
- *
- * 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.
- *
- */
-
-/*
- * This is the builtin ep0 control function. It implements all required functionality
- * for responding to control requests (SETUP packets).
- *
- * XXX
- *
- * Currently we do not pass any SETUP packets (or other) to the configured
- * 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_USB_DEVICE)
-#include "usbdcore.h"
-
-#if 0
-#define dbg_ep0(lvl,fmt,args...) serial_printf("[%s] %s:%d: "fmt"\n",__FILE__,__FUNCTION__,__LINE__,##args)
-#else
-#define dbg_ep0(lvl,fmt,args...)
-#endif
-
-/* EP0 Configuration Set ********************************************************************* */
-
-
-/**
- * ep0_get_status - fill in URB data with appropriate status
- * @device:
- * @urb:
- * @index:
- * @requesttype:
- *
- */
-static int ep0_get_status (struct usb_device_instance *device,
-                          struct urb *urb, int index, int requesttype)
-{
-       char *cp;
-
-       urb->actual_length = 2;
-       cp = (char*)urb->buffer;
-       cp[0] = cp[1] = 0;
-
-       switch (requesttype) {
-       case USB_REQ_RECIPIENT_DEVICE:
-               cp[0] = USB_STATUS_SELFPOWERED;
-               break;
-       case USB_REQ_RECIPIENT_INTERFACE:
-               break;
-       case USB_REQ_RECIPIENT_ENDPOINT:
-               cp[0] = usbd_endpoint_halted (device, index);
-               break;
-       case USB_REQ_RECIPIENT_OTHER:
-               urb->actual_length = 0;
-       default:
-               break;
-       }
-       dbg_ep0 (2, "%02x %02x", cp[0], cp[1]);
-       return 0;
-}
-
-/**
- * ep0_get_one
- * @device:
- * @urb:
- * @result:
- *
- * Set a single byte value in the urb send buffer. Return non-zero to signal
- * a request error.
- */
-static int ep0_get_one (struct usb_device_instance *device, struct urb *urb,
-                       __u8 result)
-{
-       urb->actual_length = 1; /* XXX 2? */
-       ((char *) urb->buffer)[0] = result;
-       return 0;
-}
-
-/**
- * copy_config
- * @urb: pointer to urb
- * @data: pointer to configuration data
- * @length: length of data
- *
- * Copy configuration data to urb transfer buffer if there is room for it.
- */
-void copy_config (struct urb *urb, void *data, int max_length,
-                        int max_buf)
-{
-       int available;
-       int length;
-
-       /*dbg_ep0(3, "-> actual: %d buf: %d max_buf: %d max_length: %d data: %p", */
-       /*        urb->actual_length, urb->buffer_length, max_buf, max_length, data); */
-
-       if (!data) {
-               dbg_ep0 (1, "data is NULL");
-               return;
-       }
-       length = max_length;
-
-       if (length > max_length) {
-               dbg_ep0 (1, "length: %d >= max_length: %d", length,
-                        max_length);
-               return;
-       }
-       /*dbg_ep0(1, "   actual: %d buf: %d max_buf: %d max_length: %d length: %d", */
-       /*        urb->actual_length, urb->buffer_length, max_buf, max_length, length); */
-
-       if ((available =
-            /*urb->buffer_length */ max_buf - urb->actual_length) <= 0) {
-               return;
-       }
-       /*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */
-       /*        urb->actual_length, urb->buffer_length, max_buf, length, available); */
-
-       if (length > available) {
-               length = available;
-       }
-       /*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */
-       /*        urb->actual_length, urb->buffer_length, max_buf, length, available); */
-
-       memcpy (urb->buffer + urb->actual_length, data, length);
-       urb->actual_length += length;
-
-       dbg_ep0 (3,
-                "copy_config: <- actual: %d buf: %d max_buf: %d max_length: %d available: %d",
-                urb->actual_length, urb->buffer_length, max_buf, max_length,
-                available);
-}
-
-/**
- * ep0_get_descriptor
- * @device:
- * @urb:
- * @max:
- * @descriptor_type:
- * @index:
- *
- * Called by ep0_rx_process for a get descriptor device command. Determine what
- * descriptor is being requested, copy to send buffer. Return zero if ok to send,
- * return non-zero to signal a request error.
- */
-static int ep0_get_descriptor (struct usb_device_instance *device,
-                              struct urb *urb, int max, int descriptor_type,
-                              int index)
-{
-       int port = 0;           /* XXX compound device */
-       char *cp;
-
-       /*dbg_ep0(3, "max: %x type: %x index: %x", max, descriptor_type, index); */
-
-       if (!urb || !urb->buffer || !urb->buffer_length
-           || (urb->buffer_length < 255)) {
-               dbg_ep0 (2, "invalid urb %p", urb);
-               return -1L;
-       }
-
-       /* setup tx urb */
-       urb->actual_length = 0;
-       cp = (char*)urb->buffer;
-
-       dbg_ep0 (2, "%s", USBD_DEVICE_DESCRIPTORS (descriptor_type));
-
-       switch (descriptor_type) {
-       case USB_DESCRIPTOR_TYPE_DEVICE:
-               {
-                       struct usb_device_descriptor *device_descriptor;
-                       if (!
-                           (device_descriptor =
-                            usbd_device_device_descriptor (device, port))) {
-                               return -1;
-                       }
-                       /* copy descriptor for this device */
-                       copy_config (urb, device_descriptor,
-                                    sizeof (struct usb_device_descriptor),
-                                    max);
-
-                       /* correct the correct control endpoint 0 max packet size into the descriptor */
-                       device_descriptor =
-                               (struct usb_device_descriptor *) urb->buffer;
-
-               }
-               dbg_ep0(3, "copied device configuration, actual_length: 0x%x", urb->actual_length);
-               break;
-
-       case USB_DESCRIPTOR_TYPE_CONFIGURATION:
-               {
-                       struct usb_configuration_descriptor
-                               *configuration_descriptor;
-                       struct usb_device_descriptor *device_descriptor;
-                       if (!
-                           (device_descriptor =
-                            usbd_device_device_descriptor (device, port))) {
-                               return -1;
-                       }
-                       /*dbg_ep0(2, "%d %d", index, device_descriptor->bNumConfigurations); */
-                       if (index > device_descriptor->bNumConfigurations) {
-                               dbg_ep0 (0, "index too large: %d > %d", index,
-                                        device_descriptor->
-                                        bNumConfigurations);
-                               return -1;
-                       }
-
-                       if (!
-                           (configuration_descriptor =
-                            usbd_device_configuration_descriptor (device,
-                                                                  port,
-                                                                  index))) {
-                               dbg_ep0 (0,
-                                        "usbd_device_configuration_descriptor failed: %d",
-                                        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,
-
-                                       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 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 =
-                               le16_to_cpu (urb->device_request.wIndex);
-                       int bAlternateSetting = 0;
-                       int class = 0;
-                       struct usb_class_descriptor *class_descriptor;
-
-                       if (!(class_descriptor =
-                             usbd_device_class_descriptor_index (device,
-                                                                 port, 0,
-                                                                 bNumInterface,
-                                                                 bAlternateSetting,
-                                                                 class))
-                           || class_descriptor->descriptor.hid.bDescriptorType != USB_DT_HID) {
-                               dbg_ep0 (3, "[%d] interface is not HID",
-                                        bNumInterface);
-                               return -1;
-                       }
-                       /* copy descriptor for this class */
-                       copy_config (urb, class_descriptor,
-                                    class_descriptor->descriptor.hid.bLength,
-                                    max);
-#endif
-               }
-               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 =
-                               le16_to_cpu (urb->device_request.wIndex);
-                       int bAlternateSetting = 0;
-                       int class = 0;
-                       struct usb_class_report_descriptor *report_descriptor;
-
-                       if (!(report_descriptor =
-                             usbd_device_class_report_descriptor_index
-                             (device, port, 0, bNumInterface,
-                              bAlternateSetting, class))
-                           || report_descriptor->bDescriptorType !=
-                           USB_DT_REPORT) {
-                               dbg_ep0 (3, "[%d] descriptor is not REPORT",
-                                        bNumInterface);
-                               return -1;
-                       }
-                       /* copy report descriptor for this class */
-                       /*copy_config(urb, &report_descriptor->bData[0], report_descriptor->wLength, max); */
-                       if (max - urb->actual_length > 0) {
-                               int length =
-                                       MIN (report_descriptor->wLength,
-                                            max - urb->actual_length);
-                               memcpy (urb->buffer + urb->actual_length,
-                                       &report_descriptor->bData[0], length);
-                               urb->actual_length += length;
-                       }
-#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 tx_packetSize: %2d",
-                urb->buffer, urb->buffer_length, urb->actual_length,
-                device->bus->endpoint_array[0].tx_packetSize);
-/*
-    if ((urb->actual_length < max) && !(urb->actual_length % device->bus->endpoint_array[0].tx_packetSize)) {
-       dbg_ep0(0, "adding null byte");
-       urb->buffer[urb->actual_length++] = 0;
-       dbg_ep0(0, "urb: buffer_length: %2d actual_length: %2d packet size: %2d",
-               urb->buffer_length, urb->actual_length device->bus->endpoint_array[0].tx_packetSize);
-    }
-*/
-       return 0;
-
-}
-
-/**
- * ep0_recv_setup - called to indicate URB has been received
- * @urb: pointer to struct urb
- *
- * Check if this is a setup packet, process the device request, put results
- * back into the urb and return zero or non-zero to indicate success (DATA)
- * or failure (STALL).
- *
- */
-int ep0_recv_setup (struct urb *urb)
-{
-       /*struct usb_device_request *request = urb->buffer; */
-       /*struct usb_device_instance *device = urb->device; */
-
-       struct usb_device_request *request;
-       struct usb_device_instance *device;
-       int address;
-
-       dbg_ep0 (0, "entering ep0_recv_setup()");
-       if (!urb || !urb->device) {
-               dbg_ep0 (3, "invalid URB %p", urb);
-               return -1;
-       }
-
-       request = &urb->device_request;
-       device = urb->device;
-
-       dbg_ep0 (3, "urb: %p device: %p", urb, urb->device);
-
-
-       /*dbg_ep0(2, "-       -       -       -       -       -       -       -       -       -"); */
-
-       dbg_ep0 (2,
-                "bmRequestType:%02x bRequest:%02x wValue:%04x wIndex:%04x wLength:%04x %s",
-                request->bmRequestType, request->bRequest,
-                le16_to_cpu (request->wValue), le16_to_cpu (request->wIndex),
-                le16_to_cpu (request->wLength),
-                USBD_DEVICE_REQUESTS (request->bRequest));
-
-       /* 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 */
-       }
-
-       switch (device->device_state) {
-       case STATE_CREATED:
-       case STATE_ATTACHED:
-       case STATE_POWERED:
-               /* It actually is important to allow requests in these states,
-                * Windows will request descriptors before assigning an
-                * address to the client.
-                */
-
-               /*dbg_ep0 (1, "request %s not allowed in this state: %s", */
-               /*                USBD_DEVICE_REQUESTS(request->bRequest), */
-               /*                usbd_device_states[device->device_state]); */
-               /*return -1; */
-               break;
-
-       case STATE_INIT:
-       case STATE_DEFAULT:
-               switch (request->bRequest) {
-               case USB_REQ_GET_STATUS:
-               case USB_REQ_GET_INTERFACE:
-               case USB_REQ_SYNCH_FRAME:       /* XXX should never see this (?) */
-               case USB_REQ_CLEAR_FEATURE:
-               case USB_REQ_SET_FEATURE:
-               case USB_REQ_SET_DESCRIPTOR:
-                       /* case USB_REQ_SET_CONFIGURATION: */
-               case USB_REQ_SET_INTERFACE:
-                       dbg_ep0 (1,
-                                "request %s not allowed in DEFAULT state: %s",
-                                USBD_DEVICE_REQUESTS (request->bRequest),
-                                usbd_device_states[device->device_state]);
-                       return -1;
-
-               case USB_REQ_SET_CONFIGURATION:
-               case USB_REQ_SET_ADDRESS:
-               case USB_REQ_GET_DESCRIPTOR:
-               case USB_REQ_GET_CONFIGURATION:
-                       break;
-               }
-       case STATE_ADDRESSED:
-       case STATE_CONFIGURED:
-               break;
-       case STATE_UNKNOWN:
-               dbg_ep0 (1, "request %s not allowed in UNKNOWN state: %s",
-                        USBD_DEVICE_REQUESTS (request->bRequest),
-                        usbd_device_states[device->device_state]);
-               return -1;
-       }
-
-       /* handle all requests that return data (direction bit set on bm RequestType) */
-       if ((request->bmRequestType & USB_REQ_DIRECTION_MASK)) {
-
-               dbg_ep0 (3, "Device-to-Host");
-
-               switch (request->bRequest) {
-
-               case USB_REQ_GET_STATUS:
-                       return ep0_get_status (device, urb, request->wIndex,
-                                              request->bmRequestType &
-                                              USB_REQ_RECIPIENT_MASK);
-
-               case USB_REQ_GET_DESCRIPTOR:
-                       return ep0_get_descriptor (device, urb,
-                                                  le16_to_cpu (request->wLength),
-                                                  le16_to_cpu (request->wValue) >> 8,
-                                                  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);
-
-               case USB_REQ_GET_INTERFACE:
-                       return ep0_get_one (device, urb, device->alternate);
-
-               case USB_REQ_SYNCH_FRAME:       /* XXX should never see this (?) */
-                       return -1;
-
-               case USB_REQ_CLEAR_FEATURE:
-               case USB_REQ_SET_FEATURE:
-               case USB_REQ_SET_ADDRESS:
-               case USB_REQ_SET_DESCRIPTOR:
-               case USB_REQ_SET_CONFIGURATION:
-               case USB_REQ_SET_INTERFACE:
-                       return -1;
-               }
-       }
-       /* handle the requests that do not return data */
-       else {
-
-
-               /*dbg_ep0(3, "Host-to-Device"); */
-               switch (request->bRequest) {
-
-               case USB_REQ_CLEAR_FEATURE:
-               case USB_REQ_SET_FEATURE:
-                       dbg_ep0 (0, "Host-to-Device");
-                       switch (request->
-                               bmRequestType & USB_REQ_RECIPIENT_MASK) {
-                       case USB_REQ_RECIPIENT_DEVICE:
-                               /* XXX DEVICE_REMOTE_WAKEUP or TEST_MODE would be added here */
-                               /* XXX fall through for now as we do not support either */
-                       case USB_REQ_RECIPIENT_INTERFACE:
-                       case USB_REQ_RECIPIENT_OTHER:
-                               dbg_ep0 (0, "request %s not",
-                                        USBD_DEVICE_REQUESTS (request->bRequest));
-                       default:
-                               return -1;
-
-                       case USB_REQ_RECIPIENT_ENDPOINT:
-                               dbg_ep0 (0, "ENDPOINT: %x", le16_to_cpu (request->wValue));
-                               if (le16_to_cpu (request->wValue) == USB_ENDPOINT_HALT) {
-                                       /*return usbd_device_feature (device, le16_to_cpu (request->wIndex), */
-                                       /*                    request->bRequest == USB_REQ_SET_FEATURE); */
-                                       /* NEED TO IMPLEMENT THIS!!! */
-                                       return -1;
-                               } else {
-                                       dbg_ep0 (1, "request %s bad wValue: %04x",
-                                                USBD_DEVICE_REQUESTS
-                                                (request->bRequest),
-                                                le16_to_cpu (request->wValue));
-                                       return -1;
-                               }
-                       }
-
-               case USB_REQ_SET_ADDRESS:
-                       /* check if this is a re-address, reset first if it is (this shouldn't be possible) */
-                       if (device->device_state != STATE_DEFAULT) {
-                               dbg_ep0 (1, "set_address: %02x state: %s",
-                                        le16_to_cpu (request->wValue),
-                                        usbd_device_states[device->device_state]);
-                               return -1;
-                       }
-                       address = le16_to_cpu (request->wValue);
-                       if ((address & 0x7f) != address) {
-                               dbg_ep0 (1, "invalid address %04x %04x",
-                                        address, address & 0x7f);
-                               return -1;
-                       }
-                       device->address = address;
-
-                       /*dbg_ep0(2, "address: %d %d %d", */
-                       /*        request->wValue, le16_to_cpu(request->wValue), device->address); */
-
-                       return 0;
-
-               case USB_REQ_SET_DESCRIPTOR:    /* XXX should we support this? */
-                       dbg_ep0 (0, "set descriptor: NOT SUPPORTED");
-                       return -1;
-
-               case USB_REQ_SET_CONFIGURATION:
-                       /* c.f. 9.4.7 - the top half of wValue is reserved */
-                       /* */
-                       if ((device->configuration =
-                               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 */
-                       device->interface = device->alternate = 0;
-
-                       /*dbg_ep0(2, "set configuration: %d", device->configuration); */
-                       /*serial_printf("DEVICE_CONFIGURED.. event?\n"); */
-                       return 0;
-
-               case USB_REQ_SET_INTERFACE:
-                       device->interface = le16_to_cpu (request->wIndex);
-                       device->alternate = le16_to_cpu (request->wValue);
-                       /*dbg_ep0(2, "set interface: %d alternate: %d", device->interface, device->alternate); */
-                       serial_printf ("DEVICE_SET_INTERFACE.. event?\n");
-                       return 0;
-
-               case USB_REQ_GET_STATUS:
-               case USB_REQ_GET_DESCRIPTOR:
-               case USB_REQ_GET_CONFIGURATION:
-               case USB_REQ_GET_INTERFACE:
-               case USB_REQ_SYNCH_FRAME:       /* XXX should never see this (?) */
-                       return -1;
-               }
-       }
-       return -1;
-}
-
-#endif
diff --git a/drivers/usbdcore_mpc8xx.c b/drivers/usbdcore_mpc8xx.c
deleted file mode 100644 (file)
index d4c4096..0000000
+++ /dev/null
@@ -1,1401 +0,0 @@
-/*
- * 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"
-
-DECLARE_GLOBAL_DATA_PTR;
-
-#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 */
-       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) */
diff --git a/drivers/usbdcore_omap1510.c b/drivers/usbdcore_omap1510.c
deleted file mode 100644 (file)
index 84bb936..0000000
+++ /dev/null
@@ -1,1547 +0,0 @@
-/*
- * (C) Copyright 2003
- * Gerry Hamel, geh@ti.com, Texas Instruments
- *
- * Based on
- * linux/drivers/usb/device/bi/omap.c
- * TI OMAP1510 USB bus interface driver
- *
- * Author: MontaVista Software, Inc.
- *        source@mvista.com
- *        (C) Copyright 2002
- *
- * 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 <common.h>
-
-#if defined(CONFIG_OMAP1510) && defined(CONFIG_USB_DEVICE)
-
-#include <asm/io.h>
-#ifdef CONFIG_OMAP_SX1
-#include <i2c.h>
-#endif
-
-#include "usbdcore.h"
-#include "usbdcore_omap1510.h"
-#include "usbdcore_ep0.h"
-
-
-#define UDC_INIT_MDELAY                     80 /* Device settle delay */
-#define UDC_MAX_ENDPOINTS           31 /* Number of endpoints on this UDC */
-
-/* Some kind of debugging output... */
-#if 1
-#define UDCDBG(str)
-#define UDCDBGA(fmt,args...)
-#else  /* The bugs still exists... */
-#define UDCDBG(str) serial_printf("[%s] %s:%d: " str "\n", __FILE__,__FUNCTION__,__LINE__)
-#define UDCDBGA(fmt,args...) serial_printf("[%s] %s:%d: " fmt "\n", __FILE__,__FUNCTION__,__LINE__, ##args)
-#endif
-
-#if 1
-#define UDCREG(name)
-#define UDCREGL(name)
-#else  /* The bugs still exists... */
-#define UDCREG(name)    serial_printf("%s():%d: %s[%08x]=%.4x\n",__FUNCTION__,__LINE__, (#name), name, inw(name))      /* For 16-bit regs */
-#define UDCREGL(name)   serial_printf("%s():%d: %s[%08x]=%.8x\n",__FUNCTION__,__LINE__, (#name), name, inl(name))      /* For 32-bit regs */
-#endif
-
-
-static struct urb *ep0_urb = NULL;
-
-static struct usb_device_instance *udc_device; /* Used in interrupt handler */
-static u16 udc_devstat = 0;    /* UDC status (DEVSTAT) */
-static u32 udc_interrupts = 0;
-
-static void udc_stall_ep (unsigned int ep_addr);
-
-
-static struct usb_endpoint_instance *omap1510_find_ep (int ep)
-{
-       int i;
-
-       for (i = 0; i < udc_device->bus->max_endpoints; i++) {
-               if (udc_device->bus->endpoint_array[i].endpoint_address == ep)
-                       return &udc_device->bus->endpoint_array[i];
-       }
-       return NULL;
-}
-
-/* ************************************************************************** */
-/* IO
- */
-
-/*
- * omap1510_prepare_endpoint_for_rx
- *
- * This function implements TRM Figure 14-11.
- *
- * The endpoint to prepare for transfer is specified as a physical endpoint
- * number.  For OUT (rx) endpoints 1 through 15, the corresponding endpoint
- * configuration register is checked to see if the endpoint is ISO or not.
- * If the OUT endpoint is valid and is non-ISO then its FIFO is enabled.
- * No action is taken for endpoint 0 or for IN (tx) endpoints 16 through 30.
- */
-static void omap1510_prepare_endpoint_for_rx (int ep_addr)
-{
-       int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
-
-       UDCDBGA ("omap1510_prepare_endpoint %x", ep_addr);
-       if (((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)) {
-               if ((inw (UDC_EP_RX (ep_num)) &
-                    (UDC_EPn_RX_Valid | UDC_EPn_RX_Iso)) ==
-                   UDC_EPn_RX_Valid) {
-                       /* rx endpoint is valid, non-ISO, so enable its FIFO */
-                       outw (UDC_EP_Sel | ep_num, UDC_EP_NUM);
-                       outw (UDC_Set_FIFO_En, UDC_CTRL);
-                       outw (0, UDC_EP_NUM);
-               }
-       }
-}
-
-/* omap1510_configure_endpoints
- *
- * This function implements TRM Figure 14-10.
- */
-static void omap1510_configure_endpoints (struct usb_device_instance *device)
-{
-       int ep;
-       struct usb_bus_instance *bus;
-       struct usb_endpoint_instance *endpoint;
-       unsigned short ep_ptr;
-       unsigned short ep_size;
-       unsigned short ep_isoc;
-       unsigned short ep_doublebuffer;
-       int ep_addr;
-       int packet_size;
-       int buffer_size;
-       int attributes;
-
-       bus = device->bus;
-
-       /* There is a dedicated 2048 byte buffer for USB packets that may be
-        * arbitrarily partitioned among the endpoints on 8-byte boundaries.
-        * The first 8 bytes are reserved for receiving setup packets on
-        * endpoint 0.
-        */
-       ep_ptr = 8;             /* reserve the first 8 bytes for the setup fifo */
-
-       for (ep = 0; ep < bus->max_endpoints; ep++) {
-               endpoint = bus->endpoint_array + ep;
-               ep_addr = endpoint->endpoint_address;
-               if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
-                       /* IN endpoint */
-                       packet_size = endpoint->tx_packetSize;
-                       attributes = endpoint->tx_attributes;
-               } else {
-                       /* OUT endpoint */
-                       packet_size = endpoint->rcv_packetSize;
-                       attributes = endpoint->rcv_attributes;
-               }
-
-               switch (packet_size) {
-               case 0:
-                       ep_size = 0;
-                       break;
-               case 8:
-                       ep_size = 0;
-                       break;
-               case 16:
-                       ep_size = 1;
-                       break;
-               case 32:
-                       ep_size = 2;
-                       break;
-               case 64:
-                       ep_size = 3;
-                       break;
-               case 128:
-                       ep_size = 4;
-                       break;
-               case 256:
-                       ep_size = 5;
-                       break;
-               case 512:
-                       ep_size = 6;
-                       break;
-               default:
-                       UDCDBGA ("ep 0x%02x has bad packet size %d",
-                                ep_addr, packet_size);
-                       packet_size = 0;
-                       ep_size = 0;
-                       break;
-               }
-
-               switch (attributes & USB_ENDPOINT_XFERTYPE_MASK) {
-               case USB_ENDPOINT_XFER_CONTROL:
-               case USB_ENDPOINT_XFER_BULK:
-               case USB_ENDPOINT_XFER_INT:
-               default:
-                       /* A non-isochronous endpoint may optionally be
-                        * double-buffered. For now we disable
-                        * double-buffering.
-                        */
-                       ep_doublebuffer = 0;
-                       ep_isoc = 0;
-                       if (packet_size > 64)
-                               packet_size = 0;
-                       if (!ep || !ep_doublebuffer)
-                               buffer_size = packet_size;
-                       else
-                               buffer_size = packet_size * 2;
-                       break;
-               case USB_ENDPOINT_XFER_ISOC:
-                       /* Isochronous endpoints are always double-
-                        * buffered, but the double-buffering bit
-                        * in the endpoint configuration register
-                        * becomes the msb of the endpoint size so we
-                        * set the double-buffering flag to zero.
-                        */
-                       ep_doublebuffer = 0;
-                       ep_isoc = 1;
-                       buffer_size = packet_size * 2;
-                       break;
-               }
-
-               /* check to see if our packet buffer RAM is exhausted */
-               if ((ep_ptr + buffer_size) > 2048) {
-                       UDCDBGA ("out of packet RAM for ep 0x%02x buf size %d", ep_addr, buffer_size);
-                       buffer_size = packet_size = 0;
-               }
-
-               /* force a default configuration for endpoint 0 since it is
-                * always enabled
-                */
-               if (!ep && ((packet_size < 8) || (packet_size > 64))) {
-                       buffer_size = packet_size = 64;
-                       ep_size = 3;
-               }
-
-               if (!ep) {
-                       /* configure endpoint 0 */
-                       outw ((ep_size << 12) | (ep_ptr >> 3), UDC_EP0);
-                       /*UDCDBGA("ep 0 buffer offset 0x%03x packet size 0x%03x", */
-                       /*      ep_ptr, packet_size); */
-               } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
-                       /* IN endpoint */
-                       if (packet_size) {
-                               outw ((1 << 15) | (ep_doublebuffer << 14) |
-                                     (ep_size << 12) | (ep_isoc << 11) |
-                                     (ep_ptr >> 3),
-                                     UDC_EP_TX (ep_addr &
-                                                USB_ENDPOINT_NUMBER_MASK));
-                               UDCDBGA ("IN ep %d buffer offset 0x%03x"
-                                        " packet size 0x%03x",
-                                        ep_addr & USB_ENDPOINT_NUMBER_MASK,
-                                        ep_ptr, packet_size);
-                       } else {
-                               outw (0,
-                                     UDC_EP_TX (ep_addr &
-                                                USB_ENDPOINT_NUMBER_MASK));
-                       }
-               } else {
-                       /* OUT endpoint */
-                       if (packet_size) {
-                               outw ((1 << 15) | (ep_doublebuffer << 14) |
-                                     (ep_size << 12) | (ep_isoc << 11) |
-                                     (ep_ptr >> 3),
-                                     UDC_EP_RX (ep_addr &
-                                                USB_ENDPOINT_NUMBER_MASK));
-                               UDCDBGA ("OUT ep %d buffer offset 0x%03x"
-                                        " packet size 0x%03x",
-                                        ep_addr & USB_ENDPOINT_NUMBER_MASK,
-                                        ep_ptr, packet_size);
-                       } else {
-                               outw (0,
-                                     UDC_EP_RX (ep_addr &
-                                                USB_ENDPOINT_NUMBER_MASK));
-                       }
-               }
-               ep_ptr += buffer_size;
-       }
-}
-
-/* omap1510_deconfigure_device
- *
- * This function balances omap1510_configure_device.
- */
-static void omap1510_deconfigure_device (void)
-{
-       int epnum;
-
-       UDCDBG ("clear Cfg_Lock");
-       outw (inw (UDC_SYSCON1) & ~UDC_Cfg_Lock, UDC_SYSCON1);
-       UDCREG (UDC_SYSCON1);
-
-       /* deconfigure all endpoints */
-       for (epnum = 1; epnum <= 15; epnum++) {
-               outw (0, UDC_EP_RX (epnum));
-               outw (0, UDC_EP_TX (epnum));
-       }
-}
-
-/* omap1510_configure_device
- *
- * This function implements TRM Figure 14-9.
- */
-static void omap1510_configure_device (struct usb_device_instance *device)
-{
-       omap1510_configure_endpoints (device);
-
-
-       /* Figure 14-9 indicates we should enable interrupts here, but we have
-        * other routines (udc_all_interrupts, udc_suspended_interrupts) to
-        * do that.
-        */
-
-       UDCDBG ("set Cfg_Lock");
-       outw (inw (UDC_SYSCON1) | UDC_Cfg_Lock, UDC_SYSCON1);
-       UDCREG (UDC_SYSCON1);
-}
-
-/* omap1510_write_noniso_tx_fifo
- *
- * This function implements TRM Figure 14-30.
- *
- * If the endpoint has an active tx_urb, then the next packet of data from the
- * URB is written to the tx FIFO.  The total amount of data in the urb is given
- * by urb->actual_length.  The maximum amount of data that can be sent in any
- * one packet is given by endpoint->tx_packetSize.  The number of data bytes
- * from this URB that have already been transmitted is given by endpoint->sent.
- * endpoint->last is updated by this routine with the number of data bytes
- * transmitted in this packet.
- *
- * In accordance with Figure 14-30, the EP_NUM register must already have been
- * written with the value to select the appropriate tx FIFO before this routine
- * is called.
- */
-static void omap1510_write_noniso_tx_fifo (struct usb_endpoint_instance
-                                          *endpoint)
-{
-       struct urb *urb = endpoint->tx_urb;
-
-       if (urb) {
-               unsigned int last, i;
-
-               UDCDBGA ("urb->buffer %p, buffer_length %d, actual_length %d",
-                        urb->buffer, urb->buffer_length, urb->actual_length);
-               if ((last =
-                    MIN (urb->actual_length - endpoint->sent,
-                         endpoint->tx_packetSize))) {
-                       u8 *cp = urb->buffer + endpoint->sent;
-
-                       UDCDBGA ("endpoint->sent %d, tx_packetSize %d, last %d", endpoint->sent, endpoint->tx_packetSize, last);
-
-                       if (((u32) cp & 1) == 0) {      /* word aligned? */
-                               outsw (UDC_DATA, cp, last >> 1);
-                       } else {        /* byte aligned. */
-                               for (i = 0; i < (last >> 1); i++) {
-                                       u16 w = ((u16) cp[2 * i + 1] << 8) |
-                                               (u16) cp[2 * i];
-                                       outw (w, UDC_DATA);
-                               }
-                       }
-                       if (last & 1) {
-                               outb (*(cp + last - 1), UDC_DATA);
-                       }
-               }
-               endpoint->last = last;
-       }
-}
-
-/* omap1510_read_noniso_rx_fifo
- *
- * This function implements TRM Figure 14-28.
- *
- * If the endpoint has an active rcv_urb, then the next packet of data is read
- * from the rcv FIFO and written to rcv_urb->buffer at offset
- * rcv_urb->actual_length to append the packet data to the data from any
- * previous packets for this transfer. We assume that there is sufficient room
- * left in the buffer to hold an entire packet of data.
- *
- * The return value is the number of bytes read from the FIFO for this packet.
- *
- * In accordance with Figure 14-28, the EP_NUM register must already have been
- * written with the value to select the appropriate rcv FIFO before this routine
- * is called.
- */
-static int omap1510_read_noniso_rx_fifo (struct usb_endpoint_instance
-                                        *endpoint)
-{
-       struct urb *urb = endpoint->rcv_urb;
-       int len = 0;
-
-       if (urb) {
-               len = inw (UDC_RXFSTAT);
-
-               if (len) {
-                       unsigned char *cp = urb->buffer + urb->actual_length;
-
-                       insw (UDC_DATA, cp, len >> 1);
-                       if (len & 1)
-                               *(cp + len - 1) = inb (UDC_DATA);
-               }
-       }
-       return len;
-}
-
-/* omap1510_prepare_for_control_write_status
- *
- * This function implements TRM Figure 14-17.
- *
- * We have to deal here with non-autodecoded control writes that haven't already
- * been dealt with by ep0_recv_setup.  The non-autodecoded standard control
- * write requests are: set/clear endpoint feature, set configuration, set
- * interface, and set descriptor.  ep0_recv_setup handles set/clear requests for
- * ENDPOINT_HALT by halting the endpoint for a set request and resetting the
- * endpoint for a clear request.  ep0_recv_setup returns an error for
- * SET_DESCRIPTOR requests which causes them to be terminated with a stall by
- * the setup handler.  A SET_INTERFACE request is handled by ep0_recv_setup by
- * generating a DEVICE_SET_INTERFACE event.  This leaves only the
- * SET_CONFIGURATION event for us to deal with here.
- *
- */
-static void omap1510_prepare_for_control_write_status (struct urb *urb)
-{
-       struct usb_device_request *request = &urb->device_request;;
-
-       /* check for a SET_CONFIGURATION request */
-       if (request->bRequest == USB_REQ_SET_CONFIGURATION) {
-               int configuration = le16_to_cpu (request->wValue) & 0xff;
-               unsigned short devstat = inw (UDC_DEVSTAT);
-
-               if ((devstat & (UDC_ADD | UDC_CFG)) == UDC_ADD) {
-                       /* device is currently in ADDRESSED state */
-                       if (configuration) {
-                               /* Assume the specified non-zero configuration
-                                * value is valid and switch to the CONFIGURED
-                                * state.
-                                */
-                               outw (UDC_Dev_Cfg, UDC_SYSCON2);
-                       }
-               } else if ((devstat & UDC_CFG) == UDC_CFG) {
-                       /* device is currently in CONFIGURED state */
-                       if (!configuration) {
-                               /* Switch to ADDRESSED state. */
-                               outw (UDC_Clr_Cfg, UDC_SYSCON2);
-                       }
-               }
-       }
-
-       /* select EP0 tx FIFO */
-       outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
-       /* clear endpoint (no data bytes in status stage) */
-       outw (UDC_Clr_EP, UDC_CTRL);
-       /* enable the EP0 tx FIFO */
-       outw (UDC_Set_FIFO_En, UDC_CTRL);
-       /* deselect the endpoint */
-       outw (UDC_EP_Dir, UDC_EP_NUM);
-}
-
-/* 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.
- *
- * These functions must only be called with interrupts disabled.
- */
-static void 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 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;
-               }
-       }
-}
-
-/* Handle all device state changes.
- * This function implements TRM Figure 14-21.
- */
-static void omap1510_udc_state_changed (void)
-{
-       u16 bits;
-       u16 devstat = inw (UDC_DEVSTAT);
-
-       UDCDBGA ("state changed, devstat %x, old %x", devstat, udc_devstat);
-
-       bits = devstat ^ udc_devstat;
-       if (bits) {
-               if (bits & UDC_ATT) {
-                       if (devstat & UDC_ATT) {
-                               UDCDBG ("device attached and powered");
-                               udc_state_transition_up (udc_device->device_state, STATE_POWERED);
-                       } else {
-                               UDCDBG ("device detached or unpowered");
-                               udc_state_transition_down (udc_device->device_state, STATE_ATTACHED);
-                       }
-               }
-               if (bits & UDC_USB_Reset) {
-                       if (devstat & UDC_USB_Reset) {
-                               UDCDBG ("device reset in progess");
-                               udc_state_transition_down (udc_device->device_state, STATE_POWERED);
-                       } else {
-                               UDCDBG ("device reset completed");
-                       }
-               }
-               if (bits & UDC_DEF) {
-                       if (devstat & UDC_DEF) {
-                               UDCDBG ("device entering default state");
-                               udc_state_transition_up (udc_device->device_state, STATE_DEFAULT);
-                       } else {
-                               UDCDBG ("device leaving default state");
-                               udc_state_transition_down (udc_device->device_state, STATE_POWERED);
-                       }
-               }
-               if (bits & UDC_SUS) {
-                       if (devstat & UDC_SUS) {
-                               UDCDBG ("entering suspended state");
-                               usbd_device_event_irq (udc_device, DEVICE_BUS_INACTIVE, 0);
-                       } else {
-                               UDCDBG ("leaving suspended state");
-                               usbd_device_event_irq (udc_device, DEVICE_BUS_ACTIVITY, 0);
-                       }
-               }
-               if (bits & UDC_R_WK_OK) {
-                       UDCDBGA ("remote wakeup %s", (devstat & UDC_R_WK_OK)
-                                ? "enabled" : "disabled");
-               }
-               if (bits & UDC_ADD) {
-                       if (devstat & UDC_ADD) {
-                               UDCDBG ("default -> addressed");
-                               udc_state_transition_up (udc_device->device_state, STATE_ADDRESSED);
-                       } else {
-                               UDCDBG ("addressed -> default");
-                               udc_state_transition_down (udc_device->device_state, STATE_DEFAULT);
-                       }
-               }
-               if (bits & UDC_CFG) {
-                       if (devstat & UDC_CFG) {
-                               UDCDBG ("device configured");
-                               /* The ep0_recv_setup function generates the
-                                * DEVICE_CONFIGURED event when a
-                                * USB_REQ_SET_CONFIGURATION setup packet is
-                                * received, so we should already be in the
-                                * state STATE_CONFIGURED.
-                                */
-                               udc_state_transition_up (udc_device->device_state, STATE_CONFIGURED);
-                       } else {
-                               UDCDBG ("device deconfigured");
-                               udc_state_transition_down (udc_device->device_state, STATE_ADDRESSED);
-                       }
-               }
-       }
-
-       /* Clear interrupt source */
-       outw (UDC_DS_Chg, UDC_IRQ_SRC);
-
-       /* Save current DEVSTAT */
-       udc_devstat = devstat;
-}
-
-/* Handle SETUP USB interrupt.
- * This function implements TRM Figure 14-14.
- */
-static void omap1510_udc_setup (struct usb_endpoint_instance *endpoint)
-{
-       UDCDBG ("-> Entering device setup");
-
-       do {
-               const int setup_pktsize = 8;
-               unsigned char *datap =
-                       (unsigned char *) &ep0_urb->device_request;
-
-               /* Gain access to EP 0 setup FIFO */
-               outw (UDC_Setup_Sel, UDC_EP_NUM);
-
-               /* Read control request data */
-               insb (UDC_DATA, datap, setup_pktsize);
-
-               UDCDBGA ("EP0 setup read [%x %x %x %x %x %x %x %x]",
-                        *(datap + 0), *(datap + 1), *(datap + 2),
-                        *(datap + 3), *(datap + 4), *(datap + 5),
-                        *(datap + 6), *(datap + 7));
-
-               /* Reset EP0 setup FIFO */
-               outw (0, UDC_EP_NUM);
-       } while (inw (UDC_IRQ_SRC) & UDC_Setup);
-
-       /* Try to process setup packet */
-       if (ep0_recv_setup (ep0_urb)) {
-               /* Not a setup packet, stall next EP0 transaction */
-               udc_stall_ep (0);
-               UDCDBG ("can't parse setup packet, still waiting for setup");
-               return;
-       }
-
-       /* Check direction */
-       if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK)
-           == USB_REQ_HOST2DEVICE) {
-               UDCDBG ("control write on EP0");
-               if (le16_to_cpu (ep0_urb->device_request.wLength)) {
-                       /* We don't support control write data stages.
-                        * The only standard control write request with a data
-                        * stage is SET_DESCRIPTOR, and ep0_recv_setup doesn't
-                        * support that so we just stall those requests.  A
-                        * function driver might support a non-standard
-                        * write request with a data stage, but it isn't
-                        * obvious what we would do with the data if we read it
-                        * so we'll just stall it.  It seems like the API isn't
-                        * quite right here.
-                        */
-#if 0
-                       /* Here is what we would do if we did support control
-                        * write data stages.
-                        */
-                       ep0_urb->actual_length = 0;
-                       outw (0, UDC_EP_NUM);
-                       /* enable the EP0 rx FIFO */
-                       outw (UDC_Set_FIFO_En, UDC_CTRL);
-#else
-                       /* Stall this request */
-                       UDCDBG ("Stalling unsupported EP0 control write data "
-                               "stage.");
-                       udc_stall_ep (0);
-#endif
-               } else {
-                       omap1510_prepare_for_control_write_status (ep0_urb);
-               }
-       } else {
-               UDCDBG ("control read on EP0");
-               /* The ep0_recv_setup function has already placed our response
-                * packet data in ep0_urb->buffer and the packet length in
-                * ep0_urb->actual_length.
-                */
-               endpoint->tx_urb = ep0_urb;
-               endpoint->sent = 0;
-               /* select the EP0 tx FIFO */
-               outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
-               /* Write packet data to the FIFO.  omap1510_write_noniso_tx_fifo
-                * will update endpoint->last with the number of bytes written
-                * to the FIFO.
-                */
-               omap1510_write_noniso_tx_fifo (endpoint);
-               /* enable the FIFO to start the packet transmission */
-               outw (UDC_Set_FIFO_En, UDC_CTRL);
-               /* deselect the EP0 tx FIFO */
-               outw (UDC_EP_Dir, UDC_EP_NUM);
-       }
-
-       UDCDBG ("<- Leaving device setup");
-}
-
-/* Handle endpoint 0 RX interrupt
- * This routine implements TRM Figure 14-16.
- */
-static void omap1510_udc_ep0_rx (struct usb_endpoint_instance *endpoint)
-{
-       unsigned short status;
-
-       UDCDBG ("RX on EP0");
-       /* select EP0 rx FIFO */
-       outw (UDC_EP_Sel, UDC_EP_NUM);
-
-       status = inw (UDC_STAT_FLG);
-
-       if (status & UDC_ACK) {
-               /* Check direction */
-               if ((ep0_urb->device_request.bmRequestType
-                    & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {
-                       /* This rx interrupt must be for a control write data
-                        * stage packet.
-                        *
-                        * We don't support control write data stages.
-                        * We should never end up here.
-                        */
-
-                       /* clear the EP0 rx FIFO */
-                       outw (UDC_Clr_EP, UDC_CTRL);
-
-                       /* deselect the EP0 rx FIFO */
-                       outw (0, UDC_EP_NUM);
-
-                       UDCDBG ("Stalling unexpected EP0 control write "
-                               "data stage packet");
-                       udc_stall_ep (0);
-               } else {
-                       /* This rx interrupt must be for a control read status
-                        * stage packet.
-                        */
-                       UDCDBG ("ACK on EP0 control read status stage packet");
-                       /* deselect EP0 rx FIFO */
-                       outw (0, UDC_EP_NUM);
-               }
-       } else if (status & UDC_STALL) {
-               UDCDBG ("EP0 stall during RX");
-               /* deselect EP0 rx FIFO */
-               outw (0, UDC_EP_NUM);
-       } else {
-               /* deselect EP0 rx FIFO */
-               outw (0, UDC_EP_NUM);
-       }
-}
-
-/* Handle endpoint 0 TX interrupt
- * This routine implements TRM Figure 14-18.
- */
-static void omap1510_udc_ep0_tx (struct usb_endpoint_instance *endpoint)
-{
-       unsigned short status;
-       struct usb_device_request *request = &ep0_urb->device_request;
-
-       UDCDBG ("TX on EP0");
-       /* select EP0 TX FIFO */
-       outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
-
-       status = inw (UDC_STAT_FLG);
-       if (status & UDC_ACK) {
-               /* Check direction */
-               if ((request->bmRequestType & USB_REQ_DIRECTION_MASK) ==
-                   USB_REQ_HOST2DEVICE) {
-                       /* This tx interrupt must be for a control write status
-                        * stage packet.
-                        */
-                       UDCDBG ("ACK on EP0 control write status stage packet");
-                       /* deselect EP0 TX FIFO */
-                       outw (UDC_EP_Dir, UDC_EP_NUM);
-               } else {
-                       /* This tx interrupt must be for a control read data
-                        * stage packet.
-                        */
-                       int wLength = le16_to_cpu (request->wLength);
-
-                       /* Update our count of bytes sent so far in this
-                        * transfer.
-                        */
-                       endpoint->sent += endpoint->last;
-
-                       /* We are finished with this transfer if we have sent
-                        * all of the bytes in our tx urb (urb->actual_length)
-                        * unless we need a zero-length terminating packet.  We
-                        * need a zero-length terminating packet if we returned
-                        * fewer bytes than were requested (wLength) by the host,
-                        * and the number of bytes we returned is an exact
-                        * multiple of the packet size endpoint->tx_packetSize.
-                        */
-                       if ((endpoint->sent == ep0_urb->actual_length)
-                           && ((ep0_urb->actual_length == wLength)
-                               || (endpoint->last !=
-                                   endpoint->tx_packetSize))) {
-                               /* Done with control read data stage. */
-                               UDCDBG ("control read data stage complete");
-                               /* deselect EP0 TX FIFO */
-                               outw (UDC_EP_Dir, UDC_EP_NUM);
-                               /* select EP0 RX FIFO to prepare for control
-                                * read status stage.
-                                */
-                               outw (UDC_EP_Sel, UDC_EP_NUM);
-                               /* clear the EP0 RX FIFO */
-                               outw (UDC_Clr_EP, UDC_CTRL);
-                               /* enable the EP0 RX FIFO */
-                               outw (UDC_Set_FIFO_En, UDC_CTRL);
-                               /* deselect the EP0 RX FIFO */
-                               outw (0, UDC_EP_NUM);
-                       } else {
-                               /* We still have another packet of data to send
-                                * in this control read data stage or else we
-                                * need a zero-length terminating packet.
-                                */
-                               UDCDBG ("ACK control read data stage packet");
-                               omap1510_write_noniso_tx_fifo (endpoint);
-                               /* enable the EP0 tx FIFO to start transmission */
-                               outw (UDC_Set_FIFO_En, UDC_CTRL);
-                               /* deselect EP0 TX FIFO */
-                               outw (UDC_EP_Dir, UDC_EP_NUM);
-                       }
-               }
-       } else if (status & UDC_STALL) {
-               UDCDBG ("EP0 stall during TX");
-               /* deselect EP0 TX FIFO */
-               outw (UDC_EP_Dir, UDC_EP_NUM);
-       } else {
-               /* deselect EP0 TX FIFO */
-               outw (UDC_EP_Dir, UDC_EP_NUM);
-       }
-}
-
-/* Handle RX transaction on non-ISO endpoint.
- * This function implements TRM Figure 14-27.
- * The ep argument is a physical endpoint number for a non-ISO OUT endpoint
- * in the range 1 to 15.
- */
-static void omap1510_udc_epn_rx (int ep)
-{
-       unsigned short status;
-
-       /* Check endpoint status */
-       status = inw (UDC_STAT_FLG);
-
-       if (status & UDC_ACK) {
-               int nbytes;
-               struct usb_endpoint_instance *endpoint =
-                       omap1510_find_ep (ep);
-
-               nbytes = omap1510_read_noniso_rx_fifo (endpoint);
-               usbd_rcv_complete (endpoint, nbytes, 0);
-
-               /* enable rx FIFO to prepare for next packet */
-               outw (UDC_Set_FIFO_En, UDC_CTRL);
-       } else if (status & UDC_STALL) {
-               UDCDBGA ("STALL on RX endpoint %d", ep);
-       } else if (status & UDC_NAK) {
-               UDCDBGA ("NAK on RX ep %d", ep);
-       } else {
-               serial_printf ("omap-bi: RX on ep %d with status %x", ep,
-                              status);
-       }
-}
-
-/* Handle TX transaction on non-ISO endpoint.
- * This function implements TRM Figure 14-29.
- * The ep argument is a physical endpoint number for a non-ISO IN endpoint
- * in the range 16 to 30.
- */
-static void omap1510_udc_epn_tx (int ep)
-{
-       unsigned short status;
-
-       /*serial_printf("omap1510_udc_epn_tx( %x )\n",ep); */
-
-       /* Check endpoint status */
-       status = inw (UDC_STAT_FLG);
-
-       if (status & UDC_ACK) {
-               struct usb_endpoint_instance *endpoint =
-                       omap1510_find_ep (ep);
-
-               /* We need to transmit a terminating zero-length packet now if
-                * we have sent all of the data in this URB and the transfer
-                * size was an exact multiple of the packet size.
-                */
-               if (endpoint->tx_urb
-                   && (endpoint->last == endpoint->tx_packetSize)
-                   && (endpoint->tx_urb->actual_length - endpoint->sent -
-                       endpoint->last == 0)) {
-                       /* Prepare to transmit a zero-length packet. */
-                       endpoint->sent += endpoint->last;
-                       /* write 0 bytes of data to FIFO */
-                       omap1510_write_noniso_tx_fifo (endpoint);
-                       /* enable tx FIFO to start transmission */
-                       outw (UDC_Set_FIFO_En, UDC_CTRL);
-               } else if (endpoint->tx_urb
-                          && endpoint->tx_urb->actual_length) {
-                       /* retire the data that was just sent */
-                       usbd_tx_complete (endpoint);
-                       /* Check to see if we have more data ready to transmit
-                        * now.
-                        */
-                       if (endpoint->tx_urb
-                           && endpoint->tx_urb->actual_length) {
-                               /* write data to FIFO */
-                               omap1510_write_noniso_tx_fifo (endpoint);
-                               /* enable tx FIFO to start transmission */
-                               outw (UDC_Set_FIFO_En, UDC_CTRL);
-                       }
-               }
-       } else if (status & UDC_STALL) {
-               UDCDBGA ("STALL on TX endpoint %d", ep);
-       } else if (status & UDC_NAK) {
-               UDCDBGA ("NAK on TX endpoint %d", ep);
-       } else {
-               /*serial_printf("omap-bi: TX on ep %d with status %x\n", ep, status); */
-       }
-}
-
-
-/*
--------------------------------------------------------------------------------
-*/
-
-/* Handle general USB interrupts and dispatch according to type.
- * This function implements TRM Figure 14-13.
- */
-void omap1510_udc_irq (void)
-{
-       u16 irq_src = inw (UDC_IRQ_SRC);
-       int valid_irq = 0;
-
-       if (!(irq_src & ~UDC_SOF_Flg))  /* ignore SOF interrupts ) */
-               return;
-
-       UDCDBGA ("< IRQ #%d start >- %x", udc_interrupts, irq_src);
-       /*serial_printf("< IRQ #%d start >- %x\n", udc_interrupts, irq_src); */
-
-       if (irq_src & UDC_DS_Chg) {
-               /* Device status changed */
-               omap1510_udc_state_changed ();
-               valid_irq++;
-       }
-       if (irq_src & UDC_EP0_RX) {
-               /* Endpoint 0 receive */
-               outw (UDC_EP0_RX, UDC_IRQ_SRC); /* ack interrupt */
-               omap1510_udc_ep0_rx (udc_device->bus->endpoint_array + 0);
-               valid_irq++;
-       }
-       if (irq_src & UDC_EP0_TX) {
-               /* Endpoint 0 transmit */
-               outw (UDC_EP0_TX, UDC_IRQ_SRC); /* ack interrupt */
-               omap1510_udc_ep0_tx (udc_device->bus->endpoint_array + 0);
-               valid_irq++;
-       }
-       if (irq_src & UDC_Setup) {
-               /* Device setup */
-               omap1510_udc_setup (udc_device->bus->endpoint_array + 0);
-               valid_irq++;
-       }
-       /*if (!valid_irq) */
-       /*      serial_printf("unknown interrupt, IRQ_SRC %.4x\n", irq_src); */
-       UDCDBGA ("< IRQ #%d end >", udc_interrupts);
-       udc_interrupts++;
-}
-
-/* This function implements TRM Figure 14-26. */
-void omap1510_udc_noniso_irq (void)
-{
-       unsigned short epnum;
-       unsigned short irq_src = inw (UDC_IRQ_SRC);
-       int valid_irq = 0;
-
-       if (!(irq_src & (UDC_EPn_RX | UDC_EPn_TX)))
-               return;
-
-       UDCDBGA ("non-ISO IRQ, IRQ_SRC %x", inw (UDC_IRQ_SRC));
-
-       if (irq_src & UDC_EPn_RX) {     /* Endpoint N OUT transaction */
-               /* Determine the endpoint number for this interrupt */
-               epnum = (inw (UDC_EPN_STAT) & 0x0f00) >> 8;
-               UDCDBGA ("RX on ep %x", epnum);
-
-               /* acknowledge interrupt */
-               outw (UDC_EPn_RX, UDC_IRQ_SRC);
-
-               if (epnum) {
-                       /* select the endpoint FIFO */
-                       outw (UDC_EP_Sel | epnum, UDC_EP_NUM);
-
-                       omap1510_udc_epn_rx (epnum);
-
-                       /* deselect the endpoint FIFO */
-                       outw (epnum, UDC_EP_NUM);
-               }
-               valid_irq++;
-       }
-       if (irq_src & UDC_EPn_TX) {     /* Endpoint N IN transaction */
-               /* Determine the endpoint number for this interrupt */
-               epnum = (inw (UDC_EPN_STAT) & 0x000f) | USB_DIR_IN;
-               UDCDBGA ("TX on ep %x", epnum);
-
-               /* acknowledge interrupt */
-               outw (UDC_EPn_TX, UDC_IRQ_SRC);
-
-               if (epnum) {
-                       /* select the endpoint FIFO */
-                       outw (UDC_EP_Sel | UDC_EP_Dir | epnum, UDC_EP_NUM);
-
-                       omap1510_udc_epn_tx (epnum);
-
-                       /* deselect the endpoint FIFO */
-                       outw (UDC_EP_Dir | epnum, UDC_EP_NUM);
-               }
-               valid_irq++;
-       }
-       if (!valid_irq)
-               serial_printf (": unknown non-ISO interrupt, IRQ_SRC %.4x\n",
-                              irq_src);
-}
-
-/*
--------------------------------------------------------------------------------
-*/
-
-
-/*
- * Start of public functions.
- */
-
-/* Called to start packet transmission. */
-void udc_endpoint_write (struct usb_endpoint_instance *endpoint)
-{
-       unsigned short epnum =
-               endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
-
-       UDCDBGA ("Starting transmit on ep %x", epnum);
-
-       if (endpoint->tx_urb) {
-               /* select the endpoint FIFO */
-               outw (UDC_EP_Sel | UDC_EP_Dir | epnum, UDC_EP_NUM);
-               /* write data to FIFO */
-               omap1510_write_noniso_tx_fifo (endpoint);
-               /* enable tx FIFO to start transmission */
-               outw (UDC_Set_FIFO_En, UDC_CTRL);
-               /* deselect the endpoint FIFO */
-               outw (UDC_EP_Dir | epnum, UDC_EP_NUM);
-       }
-}
-
-/* Start to initialize h/w stuff */
-int udc_init (void)
-{
-       u16 udc_rev;
-       uchar value;
-       ulong gpio;
-       int i;
-
-       /* Let the device settle down before we start */
-       for (i = 0; i < UDC_INIT_MDELAY; i++) udelay(1000);
-
-       udc_device = NULL;
-
-       UDCDBG ("starting");
-
-       /* Check peripheral reset. Must be 1 to make sure
-          MPU TIPB peripheral reset is inactive */
-       UDCREG (ARM_RSTCT2);
-
-       /* Set and check clock control.
-        * We might ought to be using the clock control API to do
-        * this instead of fiddling with the clock registers directly
-        * here.
-        */
-       outw ((1 << 4) | (1 << 5), CLOCK_CTRL);
-       UDCREG (CLOCK_CTRL);
-       /* Set and check APLL */
-       outw (0x0008, APLL_CTRL);
-       UDCREG (APLL_CTRL);
-       /* Set and check DPLL */
-       outw (0x2210, DPLL_CTRL);
-       UDCREG (DPLL_CTRL);
-       /* Set and check SOFT */
-       outw ((1 << 4) | (1 << 3) | 1, SOFT_REQ);
-       /* Short delay to wait for DPLL */
-       udelay (1000);
-
-       /* Print banner with device revision */
-       udc_rev = inw (UDC_REV) & 0xff;
-       printf ("USB:   TI OMAP1510 USB function module rev %d.%d\n",
-               udc_rev >> 4, udc_rev & 0xf);
-
-#ifdef CONFIG_OMAP_SX1
-       i2c_read (0x32, 0x04, 1, &value, 1);
-       value |= 0x04;
-       i2c_write (0x32, 0x04, 1, &value, 1);
-
-       i2c_read (0x32, 0x03, 1, &value, 1);
-       value |= 0x01;
-       i2c_write (0x32, 0x03, 1, &value, 1);
-
-       gpio = inl(GPIO_PIN_CONTROL_REG);
-       gpio |=  0x0002; /* A_IRDA_OFF */
-       gpio |=  0x0800; /* A_SWITCH   */
-       gpio |=  0x8000; /* A_USB_ON   */
-       outl (gpio, GPIO_PIN_CONTROL_REG);
-
-       gpio = inl(GPIO_DIR_CONTROL_REG);
-       gpio &= ~0x0002; /* A_IRDA_OFF */
-       gpio &= ~0x0800; /* A_SWITCH   */
-       gpio &= ~0x8000; /* A_USB_ON   */
-       outl (gpio, GPIO_DIR_CONTROL_REG);
-
-       gpio = inl(GPIO_DATA_OUTPUT_REG);
-       gpio |=  0x0002; /* A_IRDA_OFF */
-       gpio &= ~0x0800; /* A_SWITCH   */
-       gpio &= ~0x8000; /* A_USB_ON   */
-       outl (gpio, GPIO_DATA_OUTPUT_REG);
-#endif
-
-       /* The VBUS_MODE bit selects whether VBUS detection is done via
-        * software (1) or hardware (0).  When software detection is
-        * selected, VBUS_CTRL selects whether USB is not connected (0)
-        * or connected (1).
-        */
-       outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_MODE, FUNC_MUX_CTRL_0);
-       outl (inl (FUNC_MUX_CTRL_0) & ~UDC_VBUS_CTRL, FUNC_MUX_CTRL_0);
-       UDCREGL (FUNC_MUX_CTRL_0);
-
-       /*
-        * At this point, device is ready for configuration...
-        */
-
-       UDCDBG ("disable USB interrupts");
-       outw (0, UDC_IRQ_EN);
-       UDCREG (UDC_IRQ_EN);
-
-       UDCDBG ("disable USB DMA");
-       outw (0, UDC_DMA_IRQ_EN);
-       UDCREG (UDC_DMA_IRQ_EN);
-
-       UDCDBG ("initialize SYSCON1");
-       outw (UDC_Self_Pwr | UDC_Pullup_En, UDC_SYSCON1);
-       UDCREG (UDC_SYSCON1);
-
-       return 0;
-}
-
-/* Stall endpoint */
-static void udc_stall_ep (unsigned int ep_addr)
-{
-       /*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */
-       int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
-
-       UDCDBGA ("stall ep_addr %d", ep_addr);
-
-       /* REVISIT?
-        * The OMAP TRM section 14.2.4.2 says we must check that the FIFO
-        * is empty before halting the endpoint.  The current implementation
-        * doesn't check that the FIFO is empty.
-        */
-
-       if (!ep_num) {
-               outw (UDC_Stall_Cmd, UDC_SYSCON2);
-       } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
-               if (inw (UDC_EP_RX (ep_num)) & UDC_EPn_RX_Valid) {
-                       /* we have a valid rx endpoint, so halt it */
-                       outw (UDC_EP_Sel | ep_num, UDC_EP_NUM);
-                       outw (UDC_Set_Halt, UDC_CTRL);
-                       outw (ep_num, UDC_EP_NUM);
-               }
-       } else {
-               if (inw (UDC_EP_TX (ep_num)) & UDC_EPn_TX_Valid) {
-                       /* we have a valid tx endpoint, so halt it */
-                       outw (UDC_EP_Sel | UDC_EP_Dir | ep_num, UDC_EP_NUM);
-                       outw (UDC_Set_Halt, UDC_CTRL);
-                       outw (ep_num, UDC_EP_NUM);
-               }
-       }
-}
-
-/* Reset endpoint */
-#if 0
-static void udc_reset_ep (unsigned int ep_addr)
-{
-       /*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */
-       int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
-
-       UDCDBGA ("reset ep_addr %d", ep_addr);
-
-       if (!ep_num) {
-               /* control endpoint 0 can't be reset */
-       } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
-               UDCDBGA ("UDC_EP_RX(%d) = 0x%04x", ep_num,
-                        inw (UDC_EP_RX (ep_num)));
-               if (inw (UDC_EP_RX (ep_num)) & UDC_EPn_RX_Valid) {
-                       /* we have a valid rx endpoint, so reset it */
-                       outw (ep_num | UDC_EP_Sel, UDC_EP_NUM);
-                       outw (UDC_Reset_EP, UDC_CTRL);
-                       outw (ep_num, UDC_EP_NUM);
-                       UDCDBGA ("OUT endpoint %d reset", ep_num);
-               }
-       } else {
-               UDCDBGA ("UDC_EP_TX(%d) = 0x%04x", ep_num,
-                        inw (UDC_EP_TX (ep_num)));
-               /* Resetting of tx endpoints seems to be causing the USB function
-                * module to fail, which causes problems when the driver is
-                * uninstalled.  We'll skip resetting tx endpoints for now until
-                * we figure out what the problem is.
-                */
-#if 0
-               if (inw (UDC_EP_TX (ep_num)) & UDC_EPn_TX_Valid) {
-                       /* we have a valid tx endpoint, so reset it */
-                       outw (ep_num | UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
-                       outw (UDC_Reset_EP, UDC_CTRL);
-                       outw (ep_num | UDC_EP_Dir, UDC_EP_NUM);
-                       UDCDBGA ("IN endpoint %d reset", ep_num);
-               }
-#endif
-       }
-}
-#endif
-
-/* ************************************************************************** */
-
-/**
- * udc_check_ep - check logical endpoint
-  *
- * Return physical endpoint number to use for this logical endpoint or zero if not valid.
- */
-#if 0
-int udc_check_ep (int logical_endpoint, int packetsize)
-{
-       if ((logical_endpoint == 0x80) ||
-           ((logical_endpoint & 0x8f) != logical_endpoint)) {
-               return 0;
-       }
-
-       switch (packetsize) {
-       case 8:
-       case 16:
-       case 32:
-       case 64:
-       case 128:
-       case 256:
-       case 512:
-               break;
-       default:
-               return 0;
-       }
-
-       return EP_ADDR_TO_PHYS_EP (logical_endpoint);
-}
-#endif
-
-/*
- * udc_setup_ep - setup endpoint
- *
- * Associate a physical endpoint with endpoint_instance
- */
-void udc_setup_ep (struct usb_device_instance *device,
-                  unsigned int ep, struct usb_endpoint_instance *endpoint)
-{
-       UDCDBGA ("setting up endpoint addr %x", endpoint->endpoint_address);
-
-       /* This routine gets called by bi_modinit for endpoint 0 and from
-        * bi_config for all of the other endpoints.  bi_config gets called
-        * during the DEVICE_CREATE, DEVICE_CONFIGURED, and
-        * DEVICE_SET_INTERFACE events.  We need to reconfigure the OMAP packet
-        * RAM after bi_config scans the selected device configuration and
-        * initializes the endpoint structures, but before this routine enables
-        * the OUT endpoint FIFOs.  Since bi_config calls this routine in a
-        * loop for endpoints 1 through UDC_MAX_ENDPOINTS, we reconfigure our
-        * packet RAM here when ep==1.
-        * I really hate to do this here, but it seems like the API exported
-        * by the USB bus interface controller driver to the usbd-bi module
-        * isn't quite right so there is no good place to do this.
-        */
-       if (ep == 1) {
-               omap1510_deconfigure_device ();
-               omap1510_configure_device (device);
-       }
-
-       if (endpoint && (ep < UDC_MAX_ENDPOINTS)) {
-               int ep_addr = endpoint->endpoint_address;
-
-               if (!ep_addr) {
-                       /* nothing to do for endpoint 0 */
-               } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
-                       /* nothing to do for IN (tx) endpoints */
-               } else {        /* OUT (rx) endpoint */
-                       if (endpoint->rcv_packetSize) {
-                               /*struct urb* urb = &(urb_out_array[ep&0xFF]); */
-                               /*urb->endpoint = endpoint; */
-                               /*urb->device = device; */
-                               /*urb->buffer_length = sizeof(urb->buffer); */
-
-                               /*endpoint->rcv_urb = urb; */
-                               omap1510_prepare_endpoint_for_rx (ep_addr);
-                       }
-               }
-       }
-}
-
-/**
- * udc_disable_ep - disable endpoint
- * @ep:
- *
- * Disable specified endpoint
- */
-#if 0
-void udc_disable_ep (unsigned int ep_addr)
-{
-       /*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */
-       int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
-       struct usb_endpoint_instance *endpoint = omap1510_find_ep (ep_addr);    /*udc_device->bus->endpoint_array + ep; */
-
-       UDCDBGA ("disable ep_addr %d", ep_addr);
-
-       if (!ep_num) {
-               /* nothing to do for endpoint 0 */ ;
-       } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
-               if (endpoint->tx_packetSize) {
-                       /* we have a valid tx endpoint */
-                       /*usbd_flush_tx(endpoint); */
-                       endpoint->tx_urb = NULL;
-               }
-       } else {
-               if (endpoint->rcv_packetSize) {
-                       /* we have a valid rx endpoint */
-                       /*usbd_flush_rcv(endpoint); */
-                       endpoint->rcv_urb = NULL;
-               }
-       }
-}
-#endif
-
-/* ************************************************************************** */
-
-/**
- * udc_connected - is the USB cable connected
- *
- * Return non-zero if cable is connected.
- */
-#if 0
-int udc_connected (void)
-{
-       return ((inw (UDC_DEVSTAT) & UDC_ATT) == UDC_ATT);
-}
-#endif
-
-/* Turn on the USB connection by enabling the pullup resistor */
-void udc_connect (void)
-{
-       UDCDBG ("connect, enable Pullup");
-       outl (0x00000018, FUNC_MUX_CTRL_D);
-}
-
-/* Turn off the USB connection by disabling the pullup resistor */
-void udc_disconnect (void)
-{
-       UDCDBG ("disconnect, disable Pullup");
-       outl (0x00000000, FUNC_MUX_CTRL_D);
-}
-
-/* ************************************************************************** */
-
-
-/*
- * udc_disable_interrupts - disable interrupts
- * switch off interrupts
- */
-#if 0
-void udc_disable_interrupts (struct usb_device_instance *device)
-{
-       UDCDBG ("disabling all interrupts");
-       outw (0, UDC_IRQ_EN);
-}
-#endif
-
-/* ************************************************************************** */
-
-/**
- * udc_ep0_packetsize - return ep0 packetsize
- */
-#if 0
-int udc_ep0_packetsize (void)
-{
-       return EP0_PACKETSIZE;
-}
-#endif
-
-/* Switch on the UDC */
-void udc_enable (struct usb_device_instance *device)
-{
-       UDCDBGA ("enable device %p, status %d", device, device->status);
-
-       /* initialize driver state variables */
-       udc_devstat = 0;
-
-       /* Save the device structure pointer */
-       udc_device = device;
-
-       /* Setup ep0 urb */
-       if (!ep0_urb) {
-               ep0_urb =
-                       usbd_alloc_urb (udc_device,
-                                       udc_device->bus->endpoint_array);
-       } else {
-               serial_printf ("udc_enable: ep0_urb already allocated %p\n",
-                              ep0_urb);
-       }
-
-       UDCDBG ("Check clock status");
-       UDCREG (STATUS_REQ);
-
-       /* The VBUS_MODE bit selects whether VBUS detection is done via
-        * software (1) or hardware (0).  When software detection is
-        * selected, VBUS_CTRL selects whether USB is not connected (0)
-        * or connected (1).
-        */
-       outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_CTRL | UDC_VBUS_MODE,
-             FUNC_MUX_CTRL_0);
-       UDCREGL (FUNC_MUX_CTRL_0);
-
-       omap1510_configure_device (device);
-}
-
-/* Switch off the UDC */
-void udc_disable (void)
-{
-       UDCDBG ("disable UDC");
-
-       omap1510_deconfigure_device ();
-
-       /* The VBUS_MODE bit selects whether VBUS detection is done via
-        * software (1) or hardware (0).  When software detection is
-        * selected, VBUS_CTRL selects whether USB is not connected (0)
-        * or connected (1).
-        */
-       outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_MODE, FUNC_MUX_CTRL_0);
-       outl (inl (FUNC_MUX_CTRL_0) & ~UDC_VBUS_CTRL, FUNC_MUX_CTRL_0);
-       UDCREGL (FUNC_MUX_CTRL_0);
-
-       /* Free ep0 URB */
-       if (ep0_urb) {
-               /*usbd_dealloc_urb(ep0_urb); */
-               ep0_urb = NULL;
-       }
-
-       /* Reset device pointer.
-        * We ought to do this here to balance the initialization of udc_device
-        * in udc_enable, but some of our other exported functions get called
-        * by the bus interface driver after udc_disable, so we have to hang on
-        * to the device pointer to avoid a null pointer dereference. */
-       /* udc_device = NULL; */
-}
-
-/**
- * udc_startup - allow udc code to do any additional startup
- */
-void udc_startup_events (struct usb_device_instance *device)
-{
-       /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */
-       usbd_device_event_irq (device, DEVICE_INIT, 0);
-
-       /* The DEVICE_CREATE event puts the USB device in the state
-        * STATE_ATTACHED.
-        */
-       usbd_device_event_irq (device, DEVICE_CREATE, 0);
-
-       /* Some USB controller driver implementations signal
-        * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here.
-        * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED,
-        * and DEVICE_RESET causes a transition to the state STATE_DEFAULT.
-        * The OMAP USB client controller has the capability to detect when the
-        * USB cable is connected to a powered USB bus via the ATT bit in the
-        * DEVSTAT register, so we will defer the DEVICE_HUB_CONFIGURED and
-        * DEVICE_RESET events until later.
-        */
-
-       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