Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
new file mode 100644
index 0000000..3196c32
--- /dev/null
+++ b/drivers/usb/host/Kconfig
@@ -0,0 +1,126 @@
+#
+# USB Host Controller Drivers
+#
+comment "USB Host Controller Drivers"
+	depends on USB
+
+config USB_EHCI_HCD
+	tristate "EHCI HCD (USB 2.0) support"
+	depends on USB && PCI
+	---help---
+	  The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
+	  "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware.
+	  If your USB host controller supports USB 2.0, you will likely want to
+	  configure this Host Controller Driver.  At this writing, the primary
+	  implementation of EHCI is a chip from NEC, widely available in add-on
+	  PCI cards, but implementations are in the works from other vendors
+	  including Intel and Philips.  Motherboard support is appearing.
+
+	  EHCI controllers are packaged with "companion" host controllers (OHCI
+	  or UHCI) to handle USB 1.1 devices connected to root hub ports.  Ports
+	  will connect to EHCI if it the device is high speed, otherwise they
+	  connect to a companion controller.  If you configure EHCI, you should
+	  probably configure the OHCI (for NEC and some other vendors) USB Host
+	  Controller Driver or UHCI (for Via motherboards) Host Controller
+	  Driver too.
+
+	  You may want to read <file:Documentation/usb/ehci.txt>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ehci-hcd.
+
+config USB_EHCI_SPLIT_ISO
+	bool "Full speed ISO transactions (EXPERIMENTAL)"
+	depends on USB_EHCI_HCD && EXPERIMENTAL
+	default n
+	---help---
+	  This code is new and hasn't been used with many different
+	  EHCI or USB 2.0 transaction translator implementations.
+	  It should work for ISO-OUT transfers, like audio.
+
+config USB_EHCI_ROOT_HUB_TT
+	bool "Root Hub Transaction Translators (EXPERIMENTAL)"
+	depends on USB_EHCI_HCD && EXPERIMENTAL
+	---help---
+	  Some EHCI chips have vendor-specific extensions to integrate
+	  transaction translators, so that no OHCI or UHCI companion
+	  controller is needed.  It's safe to say "y" even if your
+	  controller doesn't support this feature.
+
+	  This supports the EHCI implementation from TransDimension Inc.
+
+config USB_OHCI_HCD
+	tristate "OHCI HCD support"
+	depends on USB && USB_ARCH_HAS_OHCI
+	select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
+	---help---
+	  The Open Host Controller Interface (OHCI) is a standard for accessing
+	  USB 1.1 host controller hardware.  It does more in hardware than Intel's
+	  UHCI specification.  If your USB host controller follows the OHCI spec,
+	  say Y.  On most non-x86 systems, and on x86 hardware that's not using a
+	  USB controller from Intel or VIA, this is appropriate.  If your host
+	  controller doesn't use PCI, this is probably appropriate.  For a PCI
+	  based system where you're not sure, the "lspci -v" entry will list the
+	  right "prog-if" for your USB controller(s):  EHCI, OHCI, or UHCI.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ohci-hcd.
+
+config USB_OHCI_HCD_PPC_SOC
+	bool "OHCI support for on-chip PPC USB controller"
+	depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
+	default y
+	select USB_OHCI_BIG_ENDIAN
+	---help---
+	  Enables support for the USB controller on the MPC52xx or
+	  STB03xxx processor chip.  If unsure, say Y.
+
+config USB_OHCI_HCD_PCI
+	bool "OHCI support for PCI-bus USB controllers"
+	depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx)
+	default y
+	select USB_OHCI_LITTLE_ENDIAN
+	---help---
+	  Enables support for PCI-bus plug-in USB controller cards.
+	  If unsure, say Y.
+
+config USB_OHCI_BIG_ENDIAN
+	bool
+	depends on USB_OHCI_HCD
+	default n
+
+config USB_OHCI_LITTLE_ENDIAN
+	bool
+	depends on USB_OHCI_HCD
+	default n if STB03xxx || PPC_MPC52xx
+	default y
+
+config USB_UHCI_HCD
+	tristate "UHCI HCD (most Intel and VIA) support"
+	depends on USB && PCI
+	---help---
+	  The Universal Host Controller Interface is a standard by Intel for
+	  accessing the USB hardware in the PC (which is also called the USB
+	  host controller). If your USB host controller conforms to this
+	  standard, you may want to say Y, but see below. All recent boards
+	  with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX,
+	  i810, i820) conform to this standard. Also all VIA PCI chipsets
+	  (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro
+	  133). If unsure, say Y.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called uhci-hcd.
+
+config USB_SL811_HCD
+	tristate "SL811HS HCD support"
+	depends on USB
+	default N
+	help
+	  The SL811HS is a single-port USB controller that supports either
+	  host side or peripheral side roles.  Enable this option if your
+	  board has this chip, and you want to use it as a host controller. 
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sl811-hcd.
+
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
new file mode 100644
index 0000000..a574ca0
--- /dev/null
+++ b/drivers/usb/host/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for USB Host Controller Driver
+# framework and drivers
+#
+
+obj-$(CONFIG_USB_EHCI_HCD)	+= ehci-hcd.o
+obj-$(CONFIG_USB_OHCI_HCD)	+= ohci-hcd.o
+obj-$(CONFIG_USB_UHCI_HCD)	+= uhci-hcd.o
+obj-$(CONFIG_USB_SL811_HCD)	+= sl811-hcd.o
+obj-$(CONFIG_ETRAX_ARCH_V10)	+= hc_crisv10.o
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
new file mode 100644
index 0000000..495e2a3
--- /dev/null
+++ b/drivers/usb/host/ehci-dbg.c
@@ -0,0 +1,755 @@
+/*
+ * Copyright (c) 2001-2002 by 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+#define ehci_dbg(ehci, fmt, args...) \
+	dev_dbg (ehci_to_hcd(ehci)->self.controller , fmt , ## args )
+#define ehci_err(ehci, fmt, args...) \
+	dev_err (ehci_to_hcd(ehci)->self.controller , fmt , ## args )
+#define ehci_info(ehci, fmt, args...) \
+	dev_info (ehci_to_hcd(ehci)->self.controller , fmt , ## args )
+#define ehci_warn(ehci, fmt, args...) \
+	dev_warn (ehci_to_hcd(ehci)->self.controller , fmt , ## args )
+
+#ifdef EHCI_VERBOSE_DEBUG
+#	define vdbg dbg
+#	define ehci_vdbg ehci_dbg
+#else
+#	define vdbg(fmt,args...) do { } while (0)
+#	define ehci_vdbg(ehci, fmt, args...) do { } while (0)
+#endif
+
+#ifdef	DEBUG
+
+/* check the values in the HCSPARAMS register
+ * (host controller _Structural_ parameters)
+ * see EHCI spec, Table 2-4 for each value
+ */
+static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
+{
+	u32	params = readl (&ehci->caps->hcs_params);
+
+	ehci_dbg (ehci,
+		"%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n",
+		label, params,
+		HCS_DEBUG_PORT (params),
+		HCS_INDICATOR (params) ? " ind" : "",
+		HCS_N_CC (params),
+		HCS_N_PCC (params),
+	        HCS_PORTROUTED (params) ? "" : " ordered",
+		HCS_PPC (params) ? "" : " !ppc",
+		HCS_N_PORTS (params)
+		);
+	/* Port routing, per EHCI 0.95 Spec, Section 2.2.5 */
+	if (HCS_PORTROUTED (params)) {
+		int i;
+		char buf [46], tmp [7], byte;
+
+		buf[0] = 0;
+		for (i = 0; i < HCS_N_PORTS (params); i++) {
+			// FIXME MIPS won't readb() ...
+			byte = readb (&ehci->caps->portroute[(i>>1)]);
+			sprintf(tmp, "%d ", 
+				((i & 0x1) ? ((byte)&0xf) : ((byte>>4)&0xf)));
+			strcat(buf, tmp);
+		}
+		ehci_dbg (ehci, "%s portroute %s\n",
+				label, buf);
+	}
+}
+#else
+
+static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}
+
+#endif
+
+#ifdef	DEBUG
+
+/* check the values in the HCCPARAMS register
+ * (host controller _Capability_ parameters)
+ * see EHCI Spec, Table 2-5 for each value
+ * */
+static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
+{
+	u32	params = readl (&ehci->caps->hcc_params);
+
+	if (HCC_ISOC_CACHE (params)) {
+		ehci_dbg (ehci,
+		     "%s hcc_params %04x caching frame %s%s%s\n",
+		     label, params,
+		     HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
+		     HCC_CANPARK (params) ? " park" : "",
+		     HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
+	} else {
+		ehci_dbg (ehci,
+		     "%s hcc_params %04x thresh %d uframes %s%s%s\n",
+		     label,
+		     params,
+		     HCC_ISOC_THRES (params),
+		     HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
+		     HCC_CANPARK (params) ? " park" : "",
+		     HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
+	}
+}
+#else
+
+static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {}
+
+#endif
+
+#ifdef	DEBUG
+
+static void __attribute__((__unused__))
+dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
+{
+	ehci_dbg (ehci, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
+		le32_to_cpup (&qtd->hw_next),
+		le32_to_cpup (&qtd->hw_alt_next),
+		le32_to_cpup (&qtd->hw_token),
+		le32_to_cpup (&qtd->hw_buf [0]));
+	if (qtd->hw_buf [1])
+		ehci_dbg (ehci, "  p1=%08x p2=%08x p3=%08x p4=%08x\n",
+			le32_to_cpup (&qtd->hw_buf [1]),
+			le32_to_cpup (&qtd->hw_buf [2]),
+			le32_to_cpup (&qtd->hw_buf [3]),
+			le32_to_cpup (&qtd->hw_buf [4]));
+}
+
+static void __attribute__((__unused__))
+dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	ehci_dbg (ehci, "%s qh %p n%08x info %x %x qtd %x\n", label,
+		qh, qh->hw_next, qh->hw_info1, qh->hw_info2,
+		qh->hw_current);
+	dbg_qtd ("overlay", ehci, (struct ehci_qtd *) &qh->hw_qtd_next);
+}
+
+static void __attribute__((__unused__))
+dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd) 
+{
+	ehci_dbg (ehci, "%s [%d] itd %p, next %08x, urb %p\n",
+		label, itd->frame, itd, le32_to_cpu(itd->hw_next), itd->urb);
+	ehci_dbg (ehci,
+		"  trans: %08x %08x %08x %08x %08x %08x %08x %08x\n", 
+		le32_to_cpu(itd->hw_transaction[0]),
+		le32_to_cpu(itd->hw_transaction[1]),
+		le32_to_cpu(itd->hw_transaction[2]),
+		le32_to_cpu(itd->hw_transaction[3]),
+		le32_to_cpu(itd->hw_transaction[4]),
+		le32_to_cpu(itd->hw_transaction[5]),
+		le32_to_cpu(itd->hw_transaction[6]),
+		le32_to_cpu(itd->hw_transaction[7]));
+	ehci_dbg (ehci,
+		"  buf:   %08x %08x %08x %08x %08x %08x %08x\n", 
+		le32_to_cpu(itd->hw_bufp[0]),
+		le32_to_cpu(itd->hw_bufp[1]),
+		le32_to_cpu(itd->hw_bufp[2]),
+		le32_to_cpu(itd->hw_bufp[3]),
+		le32_to_cpu(itd->hw_bufp[4]),
+		le32_to_cpu(itd->hw_bufp[5]),
+		le32_to_cpu(itd->hw_bufp[6]));
+	ehci_dbg (ehci, "  index: %d %d %d %d %d %d %d %d\n",
+		itd->index[0], itd->index[1], itd->index[2],
+		itd->index[3], itd->index[4], itd->index[5],
+		itd->index[6], itd->index[7]);
+}
+
+static void __attribute__((__unused__))
+dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd) 
+{
+	ehci_dbg (ehci, "%s [%d] sitd %p, next %08x, urb %p\n",
+		label, sitd->frame, sitd, le32_to_cpu(sitd->hw_next), sitd->urb);
+	ehci_dbg (ehci,
+		"  addr %08x sched %04x result %08x buf %08x %08x\n", 
+		le32_to_cpu(sitd->hw_fullspeed_ep),
+		le32_to_cpu(sitd->hw_uframe),
+		le32_to_cpu(sitd->hw_results),
+		le32_to_cpu(sitd->hw_buf [0]),
+		le32_to_cpu(sitd->hw_buf [1]));
+}
+
+static int __attribute__((__unused__))
+dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
+{
+	return scnprintf (buf, len,
+		"%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s",
+		label, label [0] ? " " : "", status,
+		(status & STS_ASS) ? " Async" : "",
+		(status & STS_PSS) ? " Periodic" : "",
+		(status & STS_RECL) ? " Recl" : "",
+		(status & STS_HALT) ? " Halt" : "",
+		(status & STS_IAA) ? " IAA" : "",
+		(status & STS_FATAL) ? " FATAL" : "",
+		(status & STS_FLR) ? " FLR" : "",
+		(status & STS_PCD) ? " PCD" : "",
+		(status & STS_ERR) ? " ERR" : "",
+		(status & STS_INT) ? " INT" : ""
+		);
+}
+
+static int __attribute__((__unused__))
+dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable)
+{
+	return scnprintf (buf, len,
+		"%s%sintrenable %02x%s%s%s%s%s%s",
+		label, label [0] ? " " : "", enable,
+		(enable & STS_IAA) ? " IAA" : "",
+		(enable & STS_FATAL) ? " FATAL" : "",
+		(enable & STS_FLR) ? " FLR" : "",
+		(enable & STS_PCD) ? " PCD" : "",
+		(enable & STS_ERR) ? " ERR" : "",
+		(enable & STS_INT) ? " INT" : ""
+		);
+}
+
+static const char *const fls_strings [] =
+    { "1024", "512", "256", "??" };
+
+static int
+dbg_command_buf (char *buf, unsigned len, const char *label, u32 command)
+{
+	return scnprintf (buf, len,
+		"%s%scommand %06x %s=%d ithresh=%d%s%s%s%s period=%s%s %s",
+		label, label [0] ? " " : "", command,
+		(command & CMD_PARK) ? "park" : "(park)",
+		CMD_PARK_CNT (command),
+		(command >> 16) & 0x3f,
+		(command & CMD_LRESET) ? " LReset" : "",
+		(command & CMD_IAAD) ? " IAAD" : "",
+		(command & CMD_ASE) ? " Async" : "",
+		(command & CMD_PSE) ? " Periodic" : "",
+		fls_strings [(command >> 2) & 0x3],
+		(command & CMD_RESET) ? " Reset" : "",
+		(command & CMD_RUN) ? "RUN" : "HALT"
+		);
+}
+
+static int
+dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
+{
+	char	*sig;
+
+	/* signaling state */
+	switch (status & (3 << 10)) {
+	case 0 << 10: sig = "se0"; break;
+	case 1 << 10: sig = "k"; break;		/* low speed */
+	case 2 << 10: sig = "j"; break;
+	default: sig = "?"; break;
+	}
+
+	return scnprintf (buf, len,
+		"%s%sport %d status %06x%s%s sig=%s %s%s%s%s%s%s%s%s%s",
+		label, label [0] ? " " : "", port, status,
+		(status & PORT_POWER) ? " POWER" : "",
+		(status & PORT_OWNER) ? " OWNER" : "",
+		sig,
+		(status & PORT_RESET) ? " RESET" : "",
+		(status & PORT_SUSPEND) ? " SUSPEND" : "",
+		(status & PORT_RESUME) ? " RESUME" : "",
+		(status & PORT_OCC) ? " OCC" : "",
+		(status & PORT_OC) ? " OC" : "",
+		(status & PORT_PEC) ? " PEC" : "",
+		(status & PORT_PE) ? " PE" : "",
+		(status & PORT_CSC) ? " CSC" : "",
+		(status & PORT_CONNECT) ? " CONNECT" : ""
+	    );
+}
+
+#else
+static inline void __attribute__((__unused__))
+dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
+{}
+
+static inline int __attribute__((__unused__))
+dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
+{ return 0; }
+
+static inline int __attribute__((__unused__))
+dbg_command_buf (char *buf, unsigned len, const char *label, u32 command)
+{ return 0; }
+
+static inline int __attribute__((__unused__))
+dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable)
+{ return 0; }
+
+static inline int __attribute__((__unused__))
+dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
+{ return 0; }
+
+#endif	/* DEBUG */
+
+/* functions have the "wrong" filename when they're output... */
+#define dbg_status(ehci, label, status) { \
+	char _buf [80]; \
+	dbg_status_buf (_buf, sizeof _buf, label, status); \
+	ehci_dbg (ehci, "%s\n", _buf); \
+}
+
+#define dbg_cmd(ehci, label, command) { \
+	char _buf [80]; \
+	dbg_command_buf (_buf, sizeof _buf, label, command); \
+	ehci_dbg (ehci, "%s\n", _buf); \
+}
+
+#define dbg_port(ehci, label, port, status) { \
+	char _buf [80]; \
+	dbg_port_buf (_buf, sizeof _buf, label, port, status); \
+	ehci_dbg (ehci, "%s\n", _buf); \
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef STUB_DEBUG_FILES
+
+static inline void create_debug_files (struct ehci_hcd *bus) { }
+static inline void remove_debug_files (struct ehci_hcd *bus) { }
+
+#else
+
+/* troubleshooting help: expose state in driverfs */
+
+#define speed_char(info1) ({ char tmp; \
+		switch (info1 & (3 << 12)) { \
+		case 0 << 12: tmp = 'f'; break; \
+		case 1 << 12: tmp = 'l'; break; \
+		case 2 << 12: tmp = 'h'; break; \
+		default: tmp = '?'; break; \
+		}; tmp; })
+
+static inline char token_mark (__le32 token)
+{
+	__u32 v = le32_to_cpu (token);
+	if (v & QTD_STS_ACTIVE)
+		return '*';
+	if (v & QTD_STS_HALT)
+		return '-';
+	if (!IS_SHORT_READ (v))
+		return ' ';
+	/* tries to advance through hw_alt_next */
+	return '/';
+}
+
+static void qh_lines (
+	struct ehci_hcd *ehci,
+	struct ehci_qh *qh,
+	char **nextp,
+	unsigned *sizep
+)
+{
+	u32			scratch;
+	u32			hw_curr;
+	struct list_head	*entry;
+	struct ehci_qtd		*td;
+	unsigned		temp;
+	unsigned		size = *sizep;
+	char			*next = *nextp;
+	char			mark;
+
+	if (qh->hw_qtd_next == EHCI_LIST_END)	/* NEC does this */
+		mark = '@';
+	else
+		mark = token_mark (qh->hw_token);
+	if (mark == '/') {	/* qh_alt_next controls qh advance? */
+		if ((qh->hw_alt_next & QTD_MASK) == ehci->async->hw_alt_next)
+			mark = '#';	/* blocked */
+		else if (qh->hw_alt_next == EHCI_LIST_END)
+			mark = '.';	/* use hw_qtd_next */
+		/* else alt_next points to some other qtd */
+	}
+	scratch = le32_to_cpup (&qh->hw_info1);
+	hw_curr = (mark == '*') ? le32_to_cpup (&qh->hw_current) : 0;
+	temp = scnprintf (next, size,
+			"qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)",
+			qh, scratch & 0x007f,
+			speed_char (scratch),
+			(scratch >> 8) & 0x000f,
+			scratch, le32_to_cpup (&qh->hw_info2),
+			le32_to_cpup (&qh->hw_token), mark,
+			(__constant_cpu_to_le32 (QTD_TOGGLE) & qh->hw_token)
+				? "data1" : "data0",
+			(le32_to_cpup (&qh->hw_alt_next) >> 1) & 0x0f);
+	size -= temp;
+	next += temp;
+
+	/* hc may be modifying the list as we read it ... */
+	list_for_each (entry, &qh->qtd_list) {
+		td = list_entry (entry, struct ehci_qtd, qtd_list);
+		scratch = le32_to_cpup (&td->hw_token);
+		mark = ' ';
+		if (hw_curr == td->qtd_dma)
+			mark = '*';
+		else if (qh->hw_qtd_next == td->qtd_dma)
+			mark = '+';
+		else if (QTD_LENGTH (scratch)) {
+			if (td->hw_alt_next == ehci->async->hw_alt_next)
+				mark = '#';
+			else if (td->hw_alt_next != EHCI_LIST_END)
+				mark = '/';
+		}
+		temp = snprintf (next, size,
+				"\n\t%p%c%s len=%d %08x urb %p",
+				td, mark, ({ char *tmp;
+				 switch ((scratch>>8)&0x03) {
+				 case 0: tmp = "out"; break;
+				 case 1: tmp = "in"; break;
+				 case 2: tmp = "setup"; break;
+				 default: tmp = "?"; break;
+				 } tmp;}),
+				(scratch >> 16) & 0x7fff,
+				scratch,
+				td->urb);
+		if (temp < 0)
+			temp = 0;
+		else if (size < temp)
+			temp = size;
+		size -= temp;
+		next += temp;
+		if (temp == size)
+			goto done;
+	}
+
+	temp = snprintf (next, size, "\n");
+	if (temp < 0)
+		temp = 0;
+	else if (size < temp)
+		temp = size;
+	size -= temp;
+	next += temp;
+
+done:
+	*sizep = size;
+	*nextp = next;
+}
+
+static ssize_t
+show_async (struct class_device *class_dev, char *buf)
+{
+	struct usb_bus		*bus;
+	struct usb_hcd		*hcd;
+	struct ehci_hcd		*ehci;
+	unsigned long		flags;
+	unsigned		temp, size;
+	char			*next;
+	struct ehci_qh		*qh;
+
+	*buf = 0;
+
+	bus = to_usb_bus(class_dev);
+	hcd = bus->hcpriv;
+	ehci = hcd_to_ehci (hcd);
+	next = buf;
+	size = PAGE_SIZE;
+
+	/* dumps a snapshot of the async schedule.
+	 * usually empty except for long-term bulk reads, or head.
+	 * one QH per line, and TDs we know about
+	 */
+	spin_lock_irqsave (&ehci->lock, flags);
+	for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh)
+		qh_lines (ehci, qh, &next, &size);
+	if (ehci->reclaim && size > 0) {
+		temp = scnprintf (next, size, "\nreclaim =\n");
+		size -= temp;
+		next += temp;
+
+		for (qh = ehci->reclaim; size > 0 && qh; qh = qh->reclaim)
+			qh_lines (ehci, qh, &next, &size);
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+
+	return strlen (buf);
+}
+static CLASS_DEVICE_ATTR (async, S_IRUGO, show_async, NULL);
+
+#define DBG_SCHED_LIMIT 64
+
+static ssize_t
+show_periodic (struct class_device *class_dev, char *buf)
+{
+	struct usb_bus		*bus;
+	struct usb_hcd		*hcd;
+	struct ehci_hcd		*ehci;
+	unsigned long		flags;
+	union ehci_shadow	p, *seen;
+	unsigned		temp, size, seen_count;
+	char			*next;
+	unsigned		i;
+	__le32			tag;
+
+	if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, SLAB_ATOMIC)))
+		return 0;
+	seen_count = 0;
+
+	bus = to_usb_bus(class_dev);
+	hcd = bus->hcpriv;
+	ehci = hcd_to_ehci (hcd);
+	next = buf;
+	size = PAGE_SIZE;
+
+	temp = scnprintf (next, size, "size = %d\n", ehci->periodic_size);
+	size -= temp;
+	next += temp;
+
+	/* dump a snapshot of the periodic schedule.
+	 * iso changes, interrupt usually doesn't.
+	 */
+	spin_lock_irqsave (&ehci->lock, flags);
+	for (i = 0; i < ehci->periodic_size; i++) {
+		p = ehci->pshadow [i];
+		if (likely (!p.ptr))
+			continue;
+		tag = Q_NEXT_TYPE (ehci->periodic [i]);
+
+		temp = scnprintf (next, size, "%4d: ", i);
+		size -= temp;
+		next += temp;
+
+		do {
+			switch (tag) {
+			case Q_TYPE_QH:
+				temp = scnprintf (next, size, " qh%d-%04x/%p",
+						p.qh->period,
+						le32_to_cpup (&p.qh->hw_info2)
+							/* uframe masks */
+							& 0xffff,
+						p.qh);
+				size -= temp;
+				next += temp;
+				/* don't repeat what follows this qh */
+				for (temp = 0; temp < seen_count; temp++) {
+					if (seen [temp].ptr != p.ptr)
+						continue;
+					if (p.qh->qh_next.ptr)
+						temp = scnprintf (next, size,
+							" ...");
+					p.ptr = NULL;
+					break;
+				}
+				/* show more info the first time around */
+				if (temp == seen_count && p.ptr) {
+					u32	scratch = le32_to_cpup (
+							&p.qh->hw_info1);
+					struct ehci_qtd	*qtd;
+					char		*type = "";
+
+					/* count tds, get ep direction */
+					temp = 0;
+					list_for_each_entry (qtd,
+							&p.qh->qtd_list,
+							qtd_list) {
+						temp++;
+						switch (0x03 & (le32_to_cpu (
+							qtd->hw_token) >> 8)) {
+						case 0: type = "out"; continue;
+						case 1: type = "in"; continue;
+						}
+					}
+
+					temp = scnprintf (next, size,
+						" (%c%d ep%d%s "
+						"[%d/%d] q%d p%d)",
+						speed_char (scratch),
+						scratch & 0x007f,
+						(scratch >> 8) & 0x000f, type,
+						p.qh->usecs, p.qh->c_usecs,
+						temp,
+						0x7ff & (scratch >> 16));
+
+					if (seen_count < DBG_SCHED_LIMIT)
+						seen [seen_count++].qh = p.qh;
+				} else
+					temp = 0;
+				if (p.qh) {
+					tag = Q_NEXT_TYPE (p.qh->hw_next);
+					p = p.qh->qh_next;
+				}
+				break;
+			case Q_TYPE_FSTN:
+				temp = scnprintf (next, size,
+					" fstn-%8x/%p", p.fstn->hw_prev,
+					p.fstn);
+				tag = Q_NEXT_TYPE (p.fstn->hw_next);
+				p = p.fstn->fstn_next;
+				break;
+			case Q_TYPE_ITD:
+				temp = scnprintf (next, size,
+					" itd/%p", p.itd);
+				tag = Q_NEXT_TYPE (p.itd->hw_next);
+				p = p.itd->itd_next;
+				break;
+			case Q_TYPE_SITD:
+				temp = scnprintf (next, size,
+					" sitd%d-%04x/%p",
+					p.sitd->stream->interval,
+					le32_to_cpup (&p.sitd->hw_uframe)
+						& 0x0000ffff,
+					p.sitd);
+				tag = Q_NEXT_TYPE (p.sitd->hw_next);
+				p = p.sitd->sitd_next;
+				break;
+			}
+			size -= temp;
+			next += temp;
+		} while (p.ptr);
+
+		temp = scnprintf (next, size, "\n");
+		size -= temp;
+		next += temp;
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	kfree (seen);
+
+	return PAGE_SIZE - size;
+}
+static CLASS_DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);
+
+#undef DBG_SCHED_LIMIT
+
+static ssize_t
+show_registers (struct class_device *class_dev, char *buf)
+{
+	struct usb_bus		*bus;
+	struct usb_hcd		*hcd;
+	struct ehci_hcd		*ehci;
+	unsigned long		flags;
+	unsigned		temp, size, i;
+	char			*next, scratch [80];
+	static char		fmt [] = "%*s\n";
+	static char		label [] = "";
+
+	bus = to_usb_bus(class_dev);
+	hcd = bus->hcpriv;
+	ehci = hcd_to_ehci (hcd);
+	next = buf;
+	size = PAGE_SIZE;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	if (bus->controller->power.power_state) {
+		size = scnprintf (next, size,
+			"bus %s, device %s (driver " DRIVER_VERSION ")\n"
+			"SUSPENDED (no register access)\n",
+			hcd->self.controller->bus->name,
+			hcd->self.controller->bus_id);
+		goto done;
+	}
+
+	/* Capability Registers */
+	i = HC_VERSION(readl (&ehci->caps->hc_capbase));
+	temp = scnprintf (next, size,
+		"bus %s, device %s (driver " DRIVER_VERSION ")\n"
+		"EHCI %x.%02x, hcd state %d\n",
+		hcd->self.controller->bus->name,
+		hcd->self.controller->bus_id,
+		i >> 8, i & 0x0ff, hcd->state);
+	size -= temp;
+	next += temp;
+
+	// FIXME interpret both types of params
+	i = readl (&ehci->caps->hcs_params);
+	temp = scnprintf (next, size, "structural params 0x%08x\n", i);
+	size -= temp;
+	next += temp;
+
+	i = readl (&ehci->caps->hcc_params);
+	temp = scnprintf (next, size, "capability params 0x%08x\n", i);
+	size -= temp;
+	next += temp;
+
+	/* Operational Registers */
+	temp = dbg_status_buf (scratch, sizeof scratch, label,
+			readl (&ehci->regs->status));
+	temp = scnprintf (next, size, fmt, temp, scratch);
+	size -= temp;
+	next += temp;
+
+	temp = dbg_command_buf (scratch, sizeof scratch, label,
+			readl (&ehci->regs->command));
+	temp = scnprintf (next, size, fmt, temp, scratch);
+	size -= temp;
+	next += temp;
+
+	temp = dbg_intr_buf (scratch, sizeof scratch, label,
+			readl (&ehci->regs->intr_enable));
+	temp = scnprintf (next, size, fmt, temp, scratch);
+	size -= temp;
+	next += temp;
+
+	temp = scnprintf (next, size, "uframe %04x\n",
+			readl (&ehci->regs->frame_index));
+	size -= temp;
+	next += temp;
+
+	for (i = 0; i < HCS_N_PORTS (ehci->hcs_params); i++) {
+		temp = dbg_port_buf (scratch, sizeof scratch, label, i + 1,
+				readl (&ehci->regs->port_status [i]));
+		temp = scnprintf (next, size, fmt, temp, scratch);
+		size -= temp;
+		next += temp;
+	}
+
+	if (ehci->reclaim) {
+		temp = scnprintf (next, size, "reclaim qh %p%s\n",
+				ehci->reclaim,
+				ehci->reclaim_ready ? " ready" : "");
+		size -= temp;
+		next += temp;
+	}
+
+#ifdef EHCI_STATS
+	temp = scnprintf (next, size,
+		"irq normal %ld err %ld reclaim %ld (lost %ld)\n",
+		ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,
+		ehci->stats.lost_iaa);
+	size -= temp;
+	next += temp;
+
+	temp = scnprintf (next, size, "complete %ld unlink %ld\n",
+		ehci->stats.complete, ehci->stats.unlink);
+	size -= temp;
+	next += temp;
+#endif
+
+done:
+	spin_unlock_irqrestore (&ehci->lock, flags);
+
+	return PAGE_SIZE - size;
+}
+static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
+
+static inline void create_debug_files (struct ehci_hcd *ehci)
+{
+	struct class_device *cldev = &ehci_to_hcd(ehci)->self.class_dev;
+
+	class_device_create_file(cldev, &class_device_attr_async);
+	class_device_create_file(cldev, &class_device_attr_periodic);
+	class_device_create_file(cldev, &class_device_attr_registers);
+}
+
+static inline void remove_debug_files (struct ehci_hcd *ehci)
+{
+	struct class_device *cldev = &ehci_to_hcd(ehci)->self.class_dev;
+
+	class_device_remove_file(cldev, &class_device_attr_async);
+	class_device_remove_file(cldev, &class_device_attr_periodic);
+	class_device_remove_file(cldev, &class_device_attr_registers);
+}
+
+#endif /* STUB_DEBUG_FILES */
+
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
new file mode 100644
index 0000000..a63bb79
--- /dev/null
+++ b/drivers/usb/host/ehci-hcd.c
@@ -0,0 +1,1261 @@
+/*
+ * Copyright (c) 2000-2004 by 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/dmapool.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/usb.h>
+#include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
+
+#include "../core/hcd.h"
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI hc_driver implementation ... experimental, incomplete.
+ * Based on the final 1.0 register interface specification.
+ *
+ * USB 2.0 shows up in upcoming www.pcmcia.org technology.
+ * First was PCMCIA, like ISA; then CardBus, which is PCI.
+ * Next comes "CardBay", using USB 2.0 signals.
+ *
+ * Contains additional contributions by Brad Hards, Rory Bolt, and others.
+ * Special thanks to Intel and VIA for providing host controllers to
+ * test this driver on, and Cypress (including In-System Design) for
+ * providing early devices for those host controllers to talk to!
+ *
+ * HISTORY:
+ *
+ * 2004-05-10 Root hub and PCI suspend/resume support; remote wakeup. (db)
+ * 2004-02-24 Replace pci_* with generic dma_* API calls (dsaxena@plexity.net)
+ * 2003-12-29 Rewritten high speed iso transfer support (by Michal Sojka,
+ *	<sojkam@centrum.cz>, updates by DB).
+ *
+ * 2002-11-29	Correct handling for hw async_next register.
+ * 2002-08-06	Handling for bulk and interrupt transfers is mostly shared;
+ *	only scheduling is different, no arbitrary limitations.
+ * 2002-07-25	Sanity check PCI reads, mostly for better cardbus support,
+ * 	clean up HC run state handshaking.
+ * 2002-05-24	Preliminary FS/LS interrupts, using scheduling shortcuts
+ * 2002-05-11	Clear TT errors for FS/LS ctrl/bulk.  Fill in some other
+ *	missing pieces:  enabling 64bit dma, handoff from BIOS/SMM.
+ * 2002-05-07	Some error path cleanups to report better errors; wmb();
+ *	use non-CVS version id; better iso bandwidth claim.
+ * 2002-04-19	Control/bulk/interrupt submit no longer uses giveback() on
+ *	errors in submit path.  Bugfixes to interrupt scheduling/processing.
+ * 2002-03-05	Initial high-speed ISO support; reduce ITD memory; shift
+ *	more checking to generic hcd framework (db).  Make it work with
+ *	Philips EHCI; reduce PCI traffic; shorten IRQ path (Rory Bolt).
+ * 2002-01-14	Minor cleanup; version synch.
+ * 2002-01-08	Fix roothub handoff of FS/LS to companion controllers.
+ * 2002-01-04	Control/Bulk queuing behaves.
+ *
+ * 2001-12-12	Initial patch version for Linux 2.5.1 kernel.
+ * 2001-June	Works with usb-storage and NEC EHCI on 2.4
+ */
+
+#define DRIVER_VERSION "10 Dec 2004"
+#define DRIVER_AUTHOR "David Brownell"
+#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
+
+static const char	hcd_name [] = "ehci_hcd";
+
+
+#undef EHCI_VERBOSE_DEBUG
+#undef EHCI_URB_TRACE
+
+#ifdef DEBUG
+#define EHCI_STATS
+#endif
+
+/* magic numbers that can affect system performance */
+#define	EHCI_TUNE_CERR		3	/* 0-3 qtd retries; 0 == don't stop */
+#define	EHCI_TUNE_RL_HS		4	/* nak throttle; see 4.9 */
+#define	EHCI_TUNE_RL_TT		0
+#define	EHCI_TUNE_MULT_HS	1	/* 1-3 transactions/uframe; 4.10.3 */
+#define	EHCI_TUNE_MULT_TT	1
+#define	EHCI_TUNE_FLS		2	/* (small) 256 frame schedule */
+
+#define EHCI_IAA_JIFFIES	(HZ/100)	/* arbitrary; ~10 msec */
+#define EHCI_IO_JIFFIES		(HZ/10)		/* io watchdog > irq_thresh */
+#define EHCI_ASYNC_JIFFIES	(HZ/20)		/* async idle timeout */
+#define EHCI_SHRINK_JIFFIES	(HZ/200)	/* async qh unlink delay */
+
+/* Initial IRQ latency:  faster than hw default */
+static int log2_irq_thresh = 0;		// 0 to 6
+module_param (log2_irq_thresh, int, S_IRUGO);
+MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
+
+/* initial park setting:  slower than hw default */
+static unsigned park = 0;
+module_param (park, uint, S_IRUGO);
+MODULE_PARM_DESC (park, "park setting; 1-3 back-to-back async packets");
+
+#define	INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
+
+/*-------------------------------------------------------------------------*/
+
+#include "ehci.h"
+#include "ehci-dbg.c"
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * handshake - spin reading hc until handshake completes or fails
+ * @ptr: address of hc register to be read
+ * @mask: bits to look at in result of read
+ * @done: value of those bits when handshake succeeds
+ * @usec: timeout in microseconds
+ *
+ * Returns negative errno, or zero on success
+ *
+ * Success happens when the "mask" bits have the specified value (hardware
+ * handshake done).  There are two failure modes:  "usec" have passed (major
+ * hardware flakeout), or the register reads as all-ones (hardware removed).
+ *
+ * That last failure should_only happen in cases like physical cardbus eject
+ * before driver shutdown. But it also seems to be caused by bugs in cardbus
+ * bridge shutdown:  shutting down the bridge before the devices using it.
+ */
+static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
+{
+	u32	result;
+
+	do {
+		result = readl (ptr);
+		if (result == ~(u32)0)		/* card removed */
+			return -ENODEV;
+		result &= mask;
+		if (result == done)
+			return 0;
+		udelay (1);
+		usec--;
+	} while (usec > 0);
+	return -ETIMEDOUT;
+}
+
+/* force HC to halt state from unknown (EHCI spec section 2.3) */
+static int ehci_halt (struct ehci_hcd *ehci)
+{
+	u32	temp = readl (&ehci->regs->status);
+
+	if ((temp & STS_HALT) != 0)
+		return 0;
+
+	temp = readl (&ehci->regs->command);
+	temp &= ~CMD_RUN;
+	writel (temp, &ehci->regs->command);
+	return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125);
+}
+
+/* put TDI/ARC silicon into EHCI mode */
+static void tdi_reset (struct ehci_hcd *ehci)
+{
+	u32 __iomem	*reg_ptr;
+	u32		tmp;
+
+	reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68);
+	tmp = readl (reg_ptr);
+	tmp |= 0x3;
+	writel (tmp, reg_ptr);
+}
+
+/* reset a non-running (STS_HALT == 1) controller */
+static int ehci_reset (struct ehci_hcd *ehci)
+{
+	int	retval;
+	u32	command = readl (&ehci->regs->command);
+
+	command |= CMD_RESET;
+	dbg_cmd (ehci, "reset", command);
+	writel (command, &ehci->regs->command);
+	ehci_to_hcd(ehci)->state = HC_STATE_HALT;
+	ehci->next_statechange = jiffies;
+	retval = handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000);
+
+	if (retval)
+		return retval;
+
+	if (ehci_is_TDI(ehci))
+		tdi_reset (ehci);
+
+	return retval;
+}
+
+/* idle the controller (from running) */
+static void ehci_quiesce (struct ehci_hcd *ehci)
+{
+	u32	temp;
+
+#ifdef DEBUG
+	if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
+		BUG ();
+#endif
+
+	/* wait for any schedule enables/disables to take effect */
+	temp = readl (&ehci->regs->command) << 10;
+	temp &= STS_ASS | STS_PSS;
+	if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+				temp, 16 * 125) != 0) {
+		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
+		return;
+	}
+
+	/* then disable anything that's still active */
+	temp = readl (&ehci->regs->command);
+	temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
+	writel (temp, &ehci->regs->command);
+
+	/* hardware can take 16 microframes to turn off ... */
+	if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+				0, 16 * 125) != 0) {
+		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
+		return;
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs);
+
+#include "ehci-hub.c"
+#include "ehci-mem.c"
+#include "ehci-q.c"
+#include "ehci-sched.c"
+
+/*-------------------------------------------------------------------------*/
+
+static void ehci_watchdog (unsigned long param)
+{
+	struct ehci_hcd		*ehci = (struct ehci_hcd *) param;
+	unsigned long		flags;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	/* lost IAA irqs wedge things badly; seen with a vt8235 */
+	if (ehci->reclaim) {
+		u32		status = readl (&ehci->regs->status);
+
+		if (status & STS_IAA) {
+			ehci_vdbg (ehci, "lost IAA\n");
+			COUNT (ehci->stats.lost_iaa);
+			writel (STS_IAA, &ehci->regs->status);
+			ehci->reclaim_ready = 1;
+		}
+	}
+
+ 	/* stop async processing after it's idled a bit */
+	if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
+ 		start_unlink_async (ehci, ehci->async);
+
+	/* ehci could run by timer, without IRQs ... */
+	ehci_work (ehci, NULL);
+
+	spin_unlock_irqrestore (&ehci->lock, flags);
+}
+
+#ifdef	CONFIG_PCI
+
+/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/...
+ * off the controller (maybe it can boot from highspeed USB disks).
+ */
+static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
+{
+	if (cap & (1 << 16)) {
+		int msec = 5000;
+		struct pci_dev *pdev =
+				to_pci_dev(ehci_to_hcd(ehci)->self.controller);
+
+		/* request handoff to OS */
+		cap |= 1 << 24;
+		pci_write_config_dword(pdev, where, cap);
+
+		/* and wait a while for it to happen */
+		do {
+			msleep(10);
+			msec -= 10;
+			pci_read_config_dword(pdev, where, &cap);
+		} while ((cap & (1 << 16)) && msec);
+		if (cap & (1 << 16)) {
+			ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n",
+				where, cap);
+			// some BIOS versions seem buggy...
+			// return 1;
+			ehci_warn (ehci, "continuing after BIOS bug...\n");
+			return 0;
+		} 
+		ehci_dbg (ehci, "BIOS handoff succeeded\n");
+	}
+	return 0;
+}
+
+#endif
+
+static int
+ehci_reboot (struct notifier_block *self, unsigned long code, void *null)
+{
+	struct ehci_hcd		*ehci;
+
+	ehci = container_of (self, struct ehci_hcd, reboot_notifier);
+
+	/* make BIOS/etc use companion controller during reboot */
+	writel (0, &ehci->regs->configured_flag);
+	return 0;
+}
+
+
+/* called by khubd or root hub init threads */
+
+static int ehci_hc_reset (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	u32			temp;
+	unsigned		count = 256/4;
+
+	spin_lock_init (&ehci->lock);
+
+	ehci->caps = hcd->regs;
+	ehci->regs = hcd->regs + HC_LENGTH (readl (&ehci->caps->hc_capbase));
+	dbg_hcs_params (ehci, "reset");
+	dbg_hcc_params (ehci, "reset");
+
+#ifdef	CONFIG_PCI
+	/* EHCI 0.96 and later may have "extended capabilities" */
+	if (hcd->self.controller->bus == &pci_bus_type) {
+		struct pci_dev	*pdev = to_pci_dev(hcd->self.controller);
+
+		switch (pdev->vendor) {
+		case PCI_VENDOR_ID_TDI:
+			if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
+				ehci->is_tdi_rh_tt = 1;
+				tdi_reset (ehci);
+			}
+			break;
+		case PCI_VENDOR_ID_AMD:
+			/* AMD8111 EHCI doesn't work, according to AMD errata */
+			if (pdev->device == 0x7463) {
+				ehci_info (ehci, "ignoring AMD8111 (errata)\n");
+				return -EIO;
+			}
+			break;
+		}
+
+		temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
+	} else
+		temp = 0;
+	while (temp && count--) {
+		u32		cap;
+
+		pci_read_config_dword (to_pci_dev(hcd->self.controller),
+				temp, &cap);
+		ehci_dbg (ehci, "capability %04x at %02x\n", cap, temp);
+		switch (cap & 0xff) {
+		case 1:			/* BIOS/SMM/... handoff */
+			if (bios_handoff (ehci, temp, cap) != 0)
+				return -EOPNOTSUPP;
+			break;
+		case 0:			/* illegal reserved capability */
+			ehci_warn (ehci, "illegal capability!\n");
+			cap = 0;
+			/* FALLTHROUGH */
+		default:		/* unknown */
+			break;
+		}
+		temp = (cap >> 8) & 0xff;
+	}
+	if (!count) {
+		ehci_err (ehci, "bogus capabilities ... PCI problems!\n");
+		return -EIO;
+	}
+	if (ehci_is_TDI(ehci))
+		ehci_reset (ehci);
+#endif
+
+	/* cache this readonly data; minimize PCI reads */
+	ehci->hcs_params = readl (&ehci->caps->hcs_params);
+
+	/* at least the Genesys GL880S needs fixup here */
+	temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
+	temp &= 0x0f;
+	if (temp && HCS_N_PORTS(ehci->hcs_params) > temp) {
+		ehci_dbg (ehci, "bogus port configuration: "
+			"cc=%d x pcc=%d < ports=%d\n",
+			HCS_N_CC(ehci->hcs_params),
+			HCS_N_PCC(ehci->hcs_params),
+			HCS_N_PORTS(ehci->hcs_params));
+
+#ifdef	CONFIG_PCI
+		if (hcd->self.controller->bus == &pci_bus_type) {
+			struct pci_dev	*pdev;
+
+			pdev = to_pci_dev(hcd->self.controller);
+			switch (pdev->vendor) {
+			case 0x17a0:		/* GENESYS */
+				/* GL880S: should be PORTS=2 */
+				temp |= (ehci->hcs_params & ~0xf);
+				ehci->hcs_params = temp;
+				break;
+			case PCI_VENDOR_ID_NVIDIA:
+				/* NF4: should be PCC=10 */
+				break;
+			}
+		}
+#endif
+	}
+
+	/* force HC to halt state */
+	return ehci_halt (ehci);
+}
+
+static int ehci_start (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	u32			temp;
+	struct usb_device	*udev;
+	struct usb_bus		*bus;
+	int			retval;
+	u32			hcc_params;
+	u8                      sbrn = 0;
+	int			first;
+
+	/* skip some things on restart paths */
+	first = (ehci->watchdog.data == 0);
+	if (first) {
+		init_timer (&ehci->watchdog);
+		ehci->watchdog.function = ehci_watchdog;
+		ehci->watchdog.data = (unsigned long) ehci;
+	}
+
+	/*
+	 * hw default: 1K periodic list heads, one per frame.
+	 * periodic_size can shrink by USBCMD update if hcc_params allows.
+	 */
+	ehci->periodic_size = DEFAULT_I_TDPS;
+	if (first && (retval = ehci_mem_init (ehci, GFP_KERNEL)) < 0)
+		return retval;
+
+	/* controllers may cache some of the periodic schedule ... */
+	hcc_params = readl (&ehci->caps->hcc_params);
+	if (HCC_ISOC_CACHE (hcc_params)) 	// full frame cache
+		ehci->i_thresh = 8;
+	else					// N microframes cached
+		ehci->i_thresh = 2 + HCC_ISOC_THRES (hcc_params);
+
+	ehci->reclaim = NULL;
+	ehci->reclaim_ready = 0;
+	ehci->next_uframe = -1;
+
+	/* controller state:  unknown --> reset */
+
+	/* EHCI spec section 4.1 */
+	if ((retval = ehci_reset (ehci)) != 0) {
+		ehci_mem_cleanup (ehci);
+		return retval;
+	}
+	writel (ehci->periodic_dma, &ehci->regs->frame_list);
+
+#ifdef	CONFIG_PCI
+	if (hcd->self.controller->bus == &pci_bus_type) {
+		struct pci_dev		*pdev;
+		u16			port_wake;
+
+		pdev = to_pci_dev(hcd->self.controller);
+
+		/* Serial Bus Release Number is at PCI 0x60 offset */
+		pci_read_config_byte(pdev, 0x60, &sbrn);
+
+		/* port wake capability, reported by boot firmware */
+		pci_read_config_word(pdev, 0x62, &port_wake);
+		hcd->can_wakeup = (port_wake & 1) != 0;
+
+		/* help hc dma work well with cachelines */
+		pci_set_mwi (pdev);
+	}
+#endif
+
+	/*
+	 * dedicate a qh for the async ring head, since we couldn't unlink
+	 * a 'real' qh without stopping the async schedule [4.8].  use it
+	 * as the 'reclamation list head' too.
+	 * its dummy is used in hw_alt_next of many tds, to prevent the qh
+	 * from automatically advancing to the next td after short reads.
+	 */
+	if (first) {
+		ehci->async->qh_next.qh = NULL;
+		ehci->async->hw_next = QH_NEXT (ehci->async->qh_dma);
+		ehci->async->hw_info1 = cpu_to_le32 (QH_HEAD);
+		ehci->async->hw_token = cpu_to_le32 (QTD_STS_HALT);
+		ehci->async->hw_qtd_next = EHCI_LIST_END;
+		ehci->async->qh_state = QH_STATE_LINKED;
+		ehci->async->hw_alt_next = QTD_NEXT (ehci->async->dummy->qtd_dma);
+	}
+	writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
+
+	/*
+	 * hcc_params controls whether ehci->regs->segment must (!!!)
+	 * be used; it constrains QH/ITD/SITD and QTD locations.
+	 * pci_pool consistent memory always uses segment zero.
+	 * streaming mappings for I/O buffers, like pci_map_single(),
+	 * can return segments above 4GB, if the device allows.
+	 *
+	 * NOTE:  the dma mask is visible through dma_supported(), so
+	 * drivers can pass this info along ... like NETIF_F_HIGHDMA,
+	 * Scsi_Host.highmem_io, and so forth.  It's readonly to all
+	 * host side drivers though.
+	 */
+	if (HCC_64BIT_ADDR (hcc_params)) {
+		writel (0, &ehci->regs->segment);
+#if 0
+// this is deeply broken on almost all architectures
+		if (!pci_set_dma_mask (to_pci_dev(hcd->self.controller), 0xffffffffffffffffULL))
+			ehci_info (ehci, "enabled 64bit PCI DMA\n");
+#endif
+	}
+
+	/* clear interrupt enables, set irq latency */
+	if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
+		log2_irq_thresh = 0;
+	temp = 1 << (16 + log2_irq_thresh);
+	if (HCC_CANPARK(hcc_params)) {
+		/* HW default park == 3, on hardware that supports it (like
+		 * NVidia and ALI silicon), maximizes throughput on the async
+		 * schedule by avoiding QH fetches between transfers.
+		 *
+		 * With fast usb storage devices and NForce2, "park" seems to
+		 * make problems:  throughput reduction (!), data errors...
+		 */
+		if (park) {
+			park = min (park, (unsigned) 3);
+			temp |= CMD_PARK;
+			temp |= park << 8;
+		}
+		ehci_info (ehci, "park %d\n", park);
+	}
+	if (HCC_PGM_FRAMELISTLEN (hcc_params)) {
+		/* periodic schedule size can be smaller than default */
+		temp &= ~(3 << 2);
+		temp |= (EHCI_TUNE_FLS << 2);
+		switch (EHCI_TUNE_FLS) {
+		case 0: ehci->periodic_size = 1024; break;
+		case 1: ehci->periodic_size = 512; break;
+		case 2: ehci->periodic_size = 256; break;
+		default:	BUG ();
+		}
+	}
+	// Philips, Intel, and maybe others need CMD_RUN before the
+	// root hub will detect new devices (why?); NEC doesn't
+	temp |= CMD_RUN;
+	writel (temp, &ehci->regs->command);
+	dbg_cmd (ehci, "init", temp);
+
+	/* set async sleep time = 10 us ... ? */
+
+	/* wire up the root hub */
+	bus = hcd_to_bus (hcd);
+	udev = first ? usb_alloc_dev (NULL, bus, 0) : bus->root_hub;
+	if (!udev) {
+done2:
+		ehci_mem_cleanup (ehci);
+		return -ENOMEM;
+	}
+	udev->speed = USB_SPEED_HIGH;
+	udev->state = first ? USB_STATE_ATTACHED : USB_STATE_CONFIGURED;
+
+	/*
+	 * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
+	 * are explicitly handed to companion controller(s), so no TT is
+	 * involved with the root hub.  (Except where one is integrated,
+	 * and there's no companion controller unless maybe for USB OTG.)
+	 */
+	if (first) {
+		ehci->reboot_notifier.notifier_call = ehci_reboot;
+		register_reboot_notifier (&ehci->reboot_notifier);
+	}
+
+	hcd->state = HC_STATE_RUNNING;
+	writel (FLAG_CF, &ehci->regs->configured_flag);
+	readl (&ehci->regs->command);	/* unblock posted write */
+
+	temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
+	ehci_info (ehci,
+		"USB %x.%x %s, EHCI %x.%02x, driver %s\n",
+		((sbrn & 0xf0)>>4), (sbrn & 0x0f),
+		first ? "initialized" : "restarted",
+		temp >> 8, temp & 0xff, DRIVER_VERSION);
+
+	/*
+	 * From here on, khubd concurrently accesses the root
+	 * hub; drivers will be talking to enumerated devices.
+	 * (On restart paths, khubd already knows about the root
+	 * hub and could find work as soon as we wrote FLAG_CF.)
+	 *
+	 * Before this point the HC was idle/ready.  After, khubd
+	 * and device drivers may start it running.
+	 */
+	if (first && usb_hcd_register_root_hub (udev, hcd) != 0) {
+		if (hcd->state == HC_STATE_RUNNING)
+			ehci_quiesce (ehci);
+		ehci_reset (ehci);
+		usb_put_dev (udev); 
+		retval = -ENODEV;
+		goto done2;
+	}
+
+	writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
+
+	if (first)
+		create_debug_files (ehci);
+
+	return 0;
+}
+
+/* always called by thread; normally rmmod */
+
+static void ehci_stop (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	u8			rh_ports, port;
+
+	ehci_dbg (ehci, "stop\n");
+
+	/* Turn off port power on all root hub ports. */
+	rh_ports = HCS_N_PORTS (ehci->hcs_params);
+	for (port = 1; port <= rh_ports; port++)
+		(void) ehci_hub_control(hcd,
+			ClearPortFeature, USB_PORT_FEAT_POWER,
+			port, NULL, 0);
+
+	/* no more interrupts ... */
+	del_timer_sync (&ehci->watchdog);
+
+	spin_lock_irq(&ehci->lock);
+	if (HC_IS_RUNNING (hcd->state))
+		ehci_quiesce (ehci);
+
+	ehci_reset (ehci);
+	writel (0, &ehci->regs->intr_enable);
+	spin_unlock_irq(&ehci->lock);
+
+	/* let companion controllers work when we aren't */
+	writel (0, &ehci->regs->configured_flag);
+	unregister_reboot_notifier (&ehci->reboot_notifier);
+
+	remove_debug_files (ehci);
+
+	/* root hub is shut down separately (first, when possible) */
+	spin_lock_irq (&ehci->lock);
+	if (ehci->async)
+		ehci_work (ehci, NULL);
+	spin_unlock_irq (&ehci->lock);
+	ehci_mem_cleanup (ehci);
+
+#ifdef	EHCI_STATS
+	ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n",
+		ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,
+		ehci->stats.lost_iaa);
+	ehci_dbg (ehci, "complete %ld unlink %ld\n",
+		ehci->stats.complete, ehci->stats.unlink);
+#endif
+
+	dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
+}
+
+static int ehci_get_frame (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	CONFIG_PM
+
+/* suspend/resume, section 4.3 */
+
+/* These routines rely on the bus (pci, platform, etc)
+ * to handle powerdown and wakeup, and currently also on
+ * transceivers that don't need any software attention to set up
+ * the right sort of wakeup.  
+ */
+
+static int ehci_suspend (struct usb_hcd *hcd, u32 state)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+
+	if (time_before (jiffies, ehci->next_statechange))
+		msleep (100);
+
+#ifdef	CONFIG_USB_SUSPEND
+	(void) usb_suspend_device (hcd->self.root_hub, state);
+#else
+	usb_lock_device (hcd->self.root_hub);
+	(void) ehci_hub_suspend (hcd);
+	usb_unlock_device (hcd->self.root_hub);
+#endif
+
+	// save (PCI) FLADJ in case of Vaux power loss
+	// ... we'd only use it to handle clock skew
+
+	return 0;
+}
+
+static int ehci_resume (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	unsigned		port;
+	struct usb_device	*root = hcd->self.root_hub;
+	int			retval = -EINVAL;
+	int			powerup = 0;
+
+	// maybe restore (PCI) FLADJ
+
+	if (time_before (jiffies, ehci->next_statechange))
+		msleep (100);
+
+	/* If any port is suspended, we know we can/must resume the HC. */
+	for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) {
+		u32	status;
+		port--;
+		status = readl (&ehci->regs->port_status [port]);
+		if (status & PORT_SUSPEND) {
+			down (&hcd->self.root_hub->serialize);
+			retval = ehci_hub_resume (hcd);
+			up (&hcd->self.root_hub->serialize);
+			break;
+		}
+		if ((status & PORT_POWER) == 0)
+			powerup = 1;
+		if (!root->children [port])
+			continue;
+		dbg_port (ehci, __FUNCTION__, port + 1, status);
+		usb_set_device_state (root->children[port],
+					USB_STATE_NOTATTACHED);
+	}
+
+	/* Else reset, to cope with power loss or flush-to-storage
+	 * style "resume" having activated BIOS during reboot.
+	 */
+	if (port == 0) {
+		(void) ehci_halt (ehci);
+		(void) ehci_reset (ehci);
+		(void) ehci_hc_reset (hcd);
+
+		/* emptying the schedule aborts any urbs */
+		spin_lock_irq (&ehci->lock);
+		if (ehci->reclaim)
+			ehci->reclaim_ready = 1;
+		ehci_work (ehci, NULL);
+		spin_unlock_irq (&ehci->lock);
+
+		/* restart; khubd will disconnect devices */
+		retval = ehci_start (hcd);
+
+		/* here we "know" root ports should always stay powered;
+		 * but some controllers may lost all power.
+		 */
+		if (powerup) {
+			ehci_dbg (ehci, "...powerup ports...\n");
+			for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; )
+				(void) ehci_hub_control(hcd,
+					SetPortFeature, USB_PORT_FEAT_POWER,
+						port--, NULL, 0);
+			msleep(20);
+		}
+	}
+
+	return retval;
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * ehci_work is called from some interrupts, timers, and so on.
+ * it calls driver completion functions, after dropping ehci->lock.
+ */
+static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
+{
+	timer_action_done (ehci, TIMER_IO_WATCHDOG);
+	if (ehci->reclaim_ready)
+		end_unlink_async (ehci, regs);
+
+	/* another CPU may drop ehci->lock during a schedule scan while
+	 * it reports urb completions.  this flag guards against bogus
+	 * attempts at re-entrant schedule scanning.
+	 */
+	if (ehci->scanning)
+		return;
+	ehci->scanning = 1;
+	scan_async (ehci, regs);
+	if (ehci->next_uframe != -1)
+		scan_periodic (ehci, regs);
+	ehci->scanning = 0;
+
+	/* the IO watchdog guards against hardware or driver bugs that
+	 * misplace IRQs, and should let us run completely without IRQs.
+	 * such lossage has been observed on both VT6202 and VT8235. 
+	 */
+	if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state) &&
+			(ehci->async->qh_next.ptr != NULL ||
+			 ehci->periodic_sched != 0))
+		timer_action (ehci, TIMER_IO_WATCHDOG);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	u32			status;
+	int			bh;
+
+	spin_lock (&ehci->lock);
+
+	status = readl (&ehci->regs->status);
+
+	/* e.g. cardbus physical eject */
+	if (status == ~(u32) 0) {
+		ehci_dbg (ehci, "device removed\n");
+		goto dead;
+	}
+
+	status &= INTR_MASK;
+	if (!status) {			/* irq sharing? */
+		spin_unlock(&ehci->lock);
+		return IRQ_NONE;
+	}
+
+	/* clear (just) interrupts */
+	writel (status, &ehci->regs->status);
+	readl (&ehci->regs->command);	/* unblock posted write */
+	bh = 0;
+
+#ifdef	EHCI_VERBOSE_DEBUG
+	/* unrequested/ignored: Frame List Rollover */
+	dbg_status (ehci, "irq", status);
+#endif
+
+	/* INT, ERR, and IAA interrupt rates can be throttled */
+
+	/* normal [4.15.1.2] or error [4.15.1.1] completion */
+	if (likely ((status & (STS_INT|STS_ERR)) != 0)) {
+		if (likely ((status & STS_ERR) == 0))
+			COUNT (ehci->stats.normal);
+		else
+			COUNT (ehci->stats.error);
+		bh = 1;
+	}
+
+	/* complete the unlinking of some qh [4.15.2.3] */
+	if (status & STS_IAA) {
+		COUNT (ehci->stats.reclaim);
+		ehci->reclaim_ready = 1;
+		bh = 1;
+	}
+
+	/* remote wakeup [4.3.1] */
+	if ((status & STS_PCD) && hcd->remote_wakeup) {
+		unsigned	i = HCS_N_PORTS (ehci->hcs_params);
+
+		/* resume root hub? */
+		status = readl (&ehci->regs->command);
+		if (!(status & CMD_RUN))
+			writel (status | CMD_RUN, &ehci->regs->command);
+
+		while (i--) {
+			status = readl (&ehci->regs->port_status [i]);
+			if (status & PORT_OWNER)
+				continue;
+			if (!(status & PORT_RESUME)
+					|| ehci->reset_done [i] != 0)
+				continue;
+
+			/* start 20 msec resume signaling from this port,
+			 * and make khubd collect PORT_STAT_C_SUSPEND to
+			 * stop that signaling.
+			 */
+			ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
+			mod_timer (&hcd->rh_timer,
+					ehci->reset_done [i] + 1);
+			ehci_dbg (ehci, "port %d remote wakeup\n", i + 1);
+		}
+	}
+
+	/* PCI errors [4.15.2.4] */
+	if (unlikely ((status & STS_FATAL) != 0)) {
+		/* bogus "fatal" IRQs appear on some chips... why?  */
+		status = readl (&ehci->regs->status);
+		dbg_cmd (ehci, "fatal", readl (&ehci->regs->command));
+		dbg_status (ehci, "fatal", status);
+		if (status & STS_HALT) {
+			ehci_err (ehci, "fatal error\n");
+dead:
+			ehci_reset (ehci);
+			writel (0, &ehci->regs->configured_flag);
+			/* generic layer kills/unlinks all urbs, then
+			 * uses ehci_stop to clean up the rest
+			 */
+			bh = 1;
+		}
+	}
+
+	if (bh)
+		ehci_work (ehci, regs);
+	spin_unlock (&ehci->lock);
+	return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * non-error returns are a promise to giveback() the urb later
+ * we drop ownership so next owner (or urb unlink) can get it
+ *
+ * urb + dev is in hcd.self.controller.urb_list
+ * we're queueing TDs onto software and hardware lists
+ *
+ * hcd-specific init for hcpriv hasn't been done yet
+ *
+ * NOTE:  control, bulk, and interrupt share the same code to append TDs
+ * to a (possibly active) QH, and the same QH scanning code.
+ */
+static int ehci_urb_enqueue (
+	struct usb_hcd	*hcd,
+	struct usb_host_endpoint *ep,
+	struct urb	*urb,
+	int		mem_flags
+) {
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	struct list_head	qtd_list;
+
+	INIT_LIST_HEAD (&qtd_list);
+
+	switch (usb_pipetype (urb->pipe)) {
+	// case PIPE_CONTROL:
+	// case PIPE_BULK:
+	default:
+		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
+			return -ENOMEM;
+		return submit_async (ehci, ep, urb, &qtd_list, mem_flags);
+
+	case PIPE_INTERRUPT:
+		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
+			return -ENOMEM;
+		return intr_submit (ehci, ep, urb, &qtd_list, mem_flags);
+
+	case PIPE_ISOCHRONOUS:
+		if (urb->dev->speed == USB_SPEED_HIGH)
+			return itd_submit (ehci, urb, mem_flags);
+		else
+			return sitd_submit (ehci, urb, mem_flags);
+	}
+}
+
+static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	/* if we need to use IAA and it's busy, defer */
+	if (qh->qh_state == QH_STATE_LINKED
+			&& ehci->reclaim
+			&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) {
+		struct ehci_qh		*last;
+
+		for (last = ehci->reclaim;
+				last->reclaim;
+				last = last->reclaim)
+			continue;
+		qh->qh_state = QH_STATE_UNLINK_WAIT;
+		last->reclaim = qh;
+
+	/* bypass IAA if the hc can't care */
+	} else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim)
+		end_unlink_async (ehci, NULL);
+
+	/* something else might have unlinked the qh by now */
+	if (qh->qh_state == QH_STATE_LINKED)
+		start_unlink_async (ehci, qh);
+}
+
+/* remove from hardware lists
+ * completions normally happen asynchronously
+ */
+
+static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	struct ehci_qh		*qh;
+	unsigned long		flags;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	switch (usb_pipetype (urb->pipe)) {
+	// case PIPE_CONTROL:
+	// case PIPE_BULK:
+	default:
+		qh = (struct ehci_qh *) urb->hcpriv;
+		if (!qh)
+			break;
+		unlink_async (ehci, qh);
+		break;
+
+	case PIPE_INTERRUPT:
+		qh = (struct ehci_qh *) urb->hcpriv;
+		if (!qh)
+			break;
+		switch (qh->qh_state) {
+		case QH_STATE_LINKED:
+			intr_deschedule (ehci, qh);
+			/* FALL THROUGH */
+		case QH_STATE_IDLE:
+			qh_completions (ehci, qh, NULL);
+			break;
+		default:
+			ehci_dbg (ehci, "bogus qh %p state %d\n",
+					qh, qh->qh_state);
+			goto done;
+		}
+
+		/* reschedule QH iff another request is queued */
+		if (!list_empty (&qh->qtd_list)
+				&& HC_IS_RUNNING (hcd->state)) {
+			int status;
+
+			status = qh_schedule (ehci, qh);
+			spin_unlock_irqrestore (&ehci->lock, flags);
+
+			if (status != 0) {
+				// shouldn't happen often, but ...
+				// FIXME kill those tds' urbs
+				err ("can't reschedule qh %p, err %d",
+					qh, status);
+			}
+			return status;
+		}
+		break;
+
+	case PIPE_ISOCHRONOUS:
+		// itd or sitd ...
+
+		// wait till next completion, do it then.
+		// completion irqs can wait up to 1024 msec,
+		break;
+	}
+done:
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+// bulk qh holds the data toggle
+
+static void
+ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	unsigned long		flags;
+	struct ehci_qh		*qh, *tmp;
+
+	/* ASSERT:  any requests/urbs are being unlinked */
+	/* ASSERT:  nobody can be submitting urbs for this any more */
+
+rescan:
+	spin_lock_irqsave (&ehci->lock, flags);
+	qh = ep->hcpriv;
+	if (!qh)
+		goto done;
+
+	/* endpoints can be iso streams.  for now, we don't
+	 * accelerate iso completions ... so spin a while.
+	 */
+	if (qh->hw_info1 == 0) {
+		ehci_vdbg (ehci, "iso delay\n");
+		goto idle_timeout;
+	}
+
+	if (!HC_IS_RUNNING (hcd->state))
+		qh->qh_state = QH_STATE_IDLE;
+	switch (qh->qh_state) {
+	case QH_STATE_LINKED:
+		for (tmp = ehci->async->qh_next.qh;
+				tmp && tmp != qh;
+				tmp = tmp->qh_next.qh)
+			continue;
+		/* periodic qh self-unlinks on empty */
+		if (!tmp)
+			goto nogood;
+		unlink_async (ehci, qh);
+		/* FALL THROUGH */
+	case QH_STATE_UNLINK:		/* wait for hw to finish? */
+idle_timeout:
+		spin_unlock_irqrestore (&ehci->lock, flags);
+		set_current_state (TASK_UNINTERRUPTIBLE);
+		schedule_timeout (1);
+		goto rescan;
+	case QH_STATE_IDLE:		/* fully unlinked */
+		if (list_empty (&qh->qtd_list)) {
+			qh_put (qh);
+			break;
+		}
+		/* else FALL THROUGH */
+	default:
+nogood:
+		/* caller was supposed to have unlinked any requests;
+		 * that's not our job.  just leak this memory.
+		 */
+		ehci_err (ehci, "qh %p (#%02x) state %d%s\n",
+			qh, ep->desc.bEndpointAddress, qh->qh_state,
+			list_empty (&qh->qtd_list) ? "" : "(has tds)");
+		break;
+	}
+	ep->hcpriv = NULL;
+done:
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	return;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ehci_driver = {
+	.description =		hcd_name,
+	.product_desc =		"EHCI Host Controller",
+	.hcd_priv_size =	sizeof(struct ehci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ehci_irq,
+	.flags =		HCD_MEMORY | HCD_USB2,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset =		ehci_hc_reset,
+	.start =		ehci_start,
+#ifdef	CONFIG_PM
+	.suspend =		ehci_suspend,
+	.resume =		ehci_resume,
+#endif
+	.stop =			ehci_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ehci_urb_enqueue,
+	.urb_dequeue =		ehci_urb_dequeue,
+	.endpoint_disable =	ehci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ehci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ehci_hub_status_data,
+	.hub_control =		ehci_hub_control,
+	.hub_suspend =		ehci_hub_suspend,
+	.hub_resume =		ehci_hub_resume,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* EHCI 1.0 doesn't require PCI */
+
+#ifdef	CONFIG_PCI
+
+/* PCI driver selection metadata; PCI hotplugging uses this */
+static const struct pci_device_id pci_ids [] = { {
+	/* handle any USB 2.0 EHCI controller */
+	PCI_DEVICE_CLASS(((PCI_CLASS_SERIAL_USB << 8) | 0x20), ~0),
+	.driver_data =	(unsigned long) &ehci_driver,
+	},
+	{ /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE (pci, pci_ids);
+
+/* pci driver glue; this is a "new style" PCI driver module */
+static struct pci_driver ehci_pci_driver = {
+	.name =		(char *) hcd_name,
+	.id_table =	pci_ids,
+
+	.probe =	usb_hcd_pci_probe,
+	.remove =	usb_hcd_pci_remove,
+
+#ifdef	CONFIG_PM
+	.suspend =	usb_hcd_pci_suspend,
+	.resume =	usb_hcd_pci_resume,
+#endif
+};
+
+#endif	/* PCI */
+
+
+#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
+
+MODULE_DESCRIPTION (DRIVER_INFO);
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_LICENSE ("GPL");
+
+static int __init init (void) 
+{
+	if (usb_disabled())
+		return -ENODEV;
+
+	pr_debug ("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n",
+		hcd_name,
+		sizeof (struct ehci_qh), sizeof (struct ehci_qtd),
+		sizeof (struct ehci_itd), sizeof (struct ehci_sitd));
+
+	return pci_register_driver (&ehci_pci_driver);
+}
+module_init (init);
+
+static void __exit cleanup (void) 
+{	
+	pci_unregister_driver (&ehci_pci_driver);
+}
+module_exit (cleanup);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
new file mode 100644
index 0000000..2373537
--- /dev/null
+++ b/drivers/usb/host/ehci-hub.c
@@ -0,0 +1,553 @@
+/*
+ * Copyright (c) 2001-2002 by 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Root Hub ... the nonsharable stuff
+ *
+ * Registers don't need cpu_to_le32, that happens transparently
+ */
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	CONFIG_PM
+
+static int ehci_hub_suspend (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	int			port;
+
+	if (time_before (jiffies, ehci->next_statechange))
+		msleep(5);
+
+	port = HCS_N_PORTS (ehci->hcs_params);
+	spin_lock_irq (&ehci->lock);
+
+	/* stop schedules, clean any completed work */
+	if (HC_IS_RUNNING(hcd->state)) {
+		ehci_quiesce (ehci);
+		hcd->state = HC_STATE_QUIESCING;
+	}
+	ehci->command = readl (&ehci->regs->command);
+	if (ehci->reclaim)
+		ehci->reclaim_ready = 1;
+	ehci_work(ehci, NULL);
+
+	/* suspend any active/unsuspended ports, maybe allow wakeup */
+	while (port--) {
+		u32 __iomem	*reg = &ehci->regs->port_status [port];
+		u32		t1 = readl (reg);
+		u32		t2 = t1;
+
+		if ((t1 & PORT_PE) && !(t1 & PORT_OWNER))
+			t2 |= PORT_SUSPEND;
+		if (hcd->remote_wakeup)
+			t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E;
+		else
+			t2 &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E);
+
+		if (t1 != t2) {
+			ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
+				port + 1, t1, t2);
+			writel (t2, reg);
+		}
+	}
+
+	/* turn off now-idle HC */
+	ehci_halt (ehci);
+	hcd->state = HC_STATE_SUSPENDED;
+
+	ehci->next_statechange = jiffies + msecs_to_jiffies(10);
+	spin_unlock_irq (&ehci->lock);
+	return 0;
+}
+
+
+/* caller has locked the root hub, and should reset/reinit on error */
+static int ehci_hub_resume (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	u32			temp;
+	int			i;
+	int			intr_enable;
+
+	if (time_before (jiffies, ehci->next_statechange))
+		msleep(5);
+	spin_lock_irq (&ehci->lock);
+
+	/* re-init operational registers in case we lost power */
+	if (readl (&ehci->regs->intr_enable) == 0) {
+ 		/* at least some APM implementations will try to deliver
+		 * IRQs right away, so delay them until we're ready.
+ 		 */
+ 		intr_enable = 1;
+		writel (0, &ehci->regs->segment);
+		writel (ehci->periodic_dma, &ehci->regs->frame_list);
+		writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
+	} else
+		intr_enable = 0;
+	ehci_dbg(ehci, "resume root hub%s\n",
+			intr_enable ? " after power loss" : "");
+
+	/* restore CMD_RUN, framelist size, and irq threshold */
+	writel (ehci->command, &ehci->regs->command);
+
+	/* take ports out of suspend */
+	i = HCS_N_PORTS (ehci->hcs_params);
+	while (i--) {
+		temp = readl (&ehci->regs->port_status [i]);
+		temp &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E);
+		if (temp & PORT_SUSPEND) {
+			ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
+			temp |= PORT_RESUME;
+		}
+		writel (temp, &ehci->regs->port_status [i]);
+	}
+	i = HCS_N_PORTS (ehci->hcs_params);
+	mdelay (20);
+	while (i--) {
+		temp = readl (&ehci->regs->port_status [i]);
+		if ((temp & PORT_SUSPEND) == 0)
+			continue;
+		temp &= ~PORT_RESUME;
+		writel (temp, &ehci->regs->port_status [i]);
+		ehci_vdbg (ehci, "resumed port %d\n", i + 1);
+	}
+	(void) readl (&ehci->regs->command);
+
+	/* maybe re-activate the schedule(s) */
+	temp = 0;
+	if (ehci->async->qh_next.qh)
+		temp |= CMD_ASE;
+	if (ehci->periodic_sched)
+		temp |= CMD_PSE;
+	if (temp) {
+		ehci->command |= temp;
+		writel (ehci->command, &ehci->regs->command);
+	}
+
+	ehci->next_statechange = jiffies + msecs_to_jiffies(5);
+	hcd->state = HC_STATE_RUNNING;
+
+	/* Now we can safely re-enable irqs */
+	if (intr_enable)
+		writel (INTR_MASK, &ehci->regs->intr_enable);
+
+	spin_unlock_irq (&ehci->lock);
+	return 0;
+}
+
+#else
+
+#define ehci_hub_suspend	NULL
+#define ehci_hub_resume		NULL
+
+#endif	/* CONFIG_PM */
+
+/*-------------------------------------------------------------------------*/
+
+static int check_reset_complete (
+	struct ehci_hcd	*ehci,
+	int		index,
+	int		port_status
+) {
+	if (!(port_status & PORT_CONNECT)) {
+		ehci->reset_done [index] = 0;
+		return port_status;
+	}
+
+	/* if reset finished and it's still not enabled -- handoff */
+	if (!(port_status & PORT_PE)) {
+
+		/* with integrated TT, there's nobody to hand it to! */
+		if (ehci_is_TDI(ehci)) {
+			ehci_dbg (ehci,
+				"Failed to enable port %d on root hub TT\n",
+				index+1);
+			return port_status;
+		}
+
+		ehci_dbg (ehci, "port %d full speed --> companion\n",
+			index + 1);
+
+		// what happens if HCS_N_CC(params) == 0 ?
+		port_status |= PORT_OWNER;
+		writel (port_status, &ehci->regs->port_status [index]);
+
+	} else
+		ehci_dbg (ehci, "port %d high speed\n", index + 1);
+
+	return port_status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+
+/* build "status change" packet (one or two bytes) from HC registers */
+
+static int
+ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
+{
+	struct ehci_hcd	*ehci = hcd_to_ehci (hcd);
+	u32		temp, status = 0;
+	int		ports, i, retval = 1;
+	unsigned long	flags;
+
+	/* if !USB_SUSPEND, root hub timers won't get shut down ... */
+	if (!HC_IS_RUNNING(hcd->state))
+		return 0;
+
+	/* init status to no-changes */
+	buf [0] = 0;
+	ports = HCS_N_PORTS (ehci->hcs_params);
+	if (ports > 7) {
+		buf [1] = 0;
+		retval++;
+	}
+	
+	/* no hub change reports (bit 0) for now (power, ...) */
+
+	/* port N changes (bit N)? */
+	spin_lock_irqsave (&ehci->lock, flags);
+	for (i = 0; i < ports; i++) {
+		temp = readl (&ehci->regs->port_status [i]);
+		if (temp & PORT_OWNER) {
+			/* don't report this in GetPortStatus */
+			if (temp & PORT_CSC) {
+				temp &= ~PORT_CSC;
+				writel (temp, &ehci->regs->port_status [i]);
+			}
+			continue;
+		}
+		if (!(temp & PORT_CONNECT))
+			ehci->reset_done [i] = 0;
+		if ((temp & (PORT_CSC | PORT_PEC | PORT_OCC)) != 0
+				// PORT_STAT_C_SUSPEND?
+				|| ((temp & PORT_RESUME) != 0
+					&& time_after (jiffies,
+						ehci->reset_done [i]))) {
+			if (i < 7)
+			    buf [0] |= 1 << (i + 1);
+			else
+			    buf [1] |= 1 << (i - 7);
+			status = STS_PCD;
+		}
+	}
+	/* FIXME autosuspend idle root hubs */
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	return status ? retval : 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+ehci_hub_descriptor (
+	struct ehci_hcd			*ehci,
+	struct usb_hub_descriptor	*desc
+) {
+	int		ports = HCS_N_PORTS (ehci->hcs_params);
+	u16		temp;
+
+	desc->bDescriptorType = 0x29;
+	desc->bPwrOn2PwrGood = 10;	/* ehci 1.0, 2.3.9 says 20ms max */
+	desc->bHubContrCurrent = 0;
+
+	desc->bNbrPorts = ports;
+	temp = 1 + (ports / 8);
+	desc->bDescLength = 7 + 2 * temp;
+
+	/* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+	memset (&desc->bitmap [0], 0, temp);
+	memset (&desc->bitmap [temp], 0xff, temp);
+
+	temp = 0x0008;			/* per-port overcurrent reporting */
+	if (HCS_PPC (ehci->hcs_params))
+		temp |= 0x0001;		/* per-port power control */
+#if 0
+// re-enable when we support USB_PORT_FEAT_INDICATOR below.
+	if (HCS_INDICATOR (ehci->hcs_params))
+		temp |= 0x0080;		/* per-port indicators (LEDs) */
+#endif
+	desc->wHubCharacteristics = (__force __u16)cpu_to_le16 (temp);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define	PORT_WAKE_BITS 	(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
+
+static int ehci_hub_control (
+	struct usb_hcd	*hcd,
+	u16		typeReq,
+	u16		wValue,
+	u16		wIndex,
+	char		*buf,
+	u16		wLength
+) {
+	struct ehci_hcd	*ehci = hcd_to_ehci (hcd);
+	int		ports = HCS_N_PORTS (ehci->hcs_params);
+	u32		temp, status;
+	unsigned long	flags;
+	int		retval = 0;
+
+	/*
+	 * FIXME:  support SetPortFeatures USB_PORT_FEAT_INDICATOR.
+	 * HCS_INDICATOR may say we can change LEDs to off/amber/green.
+	 * (track current state ourselves) ... blink for diagnostics,
+	 * power, "this is the one", etc.  EHCI spec supports this.
+	 */
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	switch (typeReq) {
+	case ClearHubFeature:
+		switch (wValue) {
+		case C_HUB_LOCAL_POWER:
+		case C_HUB_OVER_CURRENT:
+			/* no hub-wide feature/status flags */
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case ClearPortFeature:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		temp = readl (&ehci->regs->port_status [wIndex]);
+		if (temp & PORT_OWNER)
+			break;
+
+		switch (wValue) {
+		case USB_PORT_FEAT_ENABLE:
+			writel (temp & ~PORT_PE,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_C_ENABLE:
+			writel (temp | PORT_PEC,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_SUSPEND:
+			if (temp & PORT_RESET)
+				goto error;
+			if (temp & PORT_SUSPEND) {
+				if ((temp & PORT_PE) == 0)
+					goto error;
+				/* resume signaling for 20 msec */
+				writel ((temp & ~PORT_WAKE_BITS) | PORT_RESUME,
+					&ehci->regs->port_status [wIndex]);
+				ehci->reset_done [wIndex] = jiffies
+						+ msecs_to_jiffies (20);
+			}
+			break;
+		case USB_PORT_FEAT_C_SUSPEND:
+			/* we auto-clear this feature */
+			break;
+		case USB_PORT_FEAT_POWER:
+			if (HCS_PPC (ehci->hcs_params))
+				writel (temp & ~PORT_POWER,
+					&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_C_CONNECTION:
+			writel (temp | PORT_CSC,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+			writel (temp | PORT_OCC,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_C_RESET:
+			/* GetPortStatus clears reset */
+			break;
+		default:
+			goto error;
+		}
+		readl (&ehci->regs->command);	/* unblock posted write */
+		break;
+	case GetHubDescriptor:
+		ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
+			buf);
+		break;
+	case GetHubStatus:
+		/* no hub-wide feature/status flags */
+		memset (buf, 0, 4);
+		//cpu_to_le32s ((u32 *) buf);
+		break;
+	case GetPortStatus:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		status = 0;
+		temp = readl (&ehci->regs->port_status [wIndex]);
+
+		// wPortChange bits
+		if (temp & PORT_CSC)
+			status |= 1 << USB_PORT_FEAT_C_CONNECTION;
+		if (temp & PORT_PEC)
+			status |= 1 << USB_PORT_FEAT_C_ENABLE;
+		if (temp & PORT_OCC)
+			status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
+
+		/* whoever resumes must GetPortStatus to complete it!! */
+		if ((temp & PORT_RESUME)
+				&& time_after (jiffies,
+					ehci->reset_done [wIndex])) {
+			status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+			ehci->reset_done [wIndex] = 0;
+
+			/* stop resume signaling */
+			temp = readl (&ehci->regs->port_status [wIndex]);
+			writel (temp & ~PORT_RESUME,
+				&ehci->regs->port_status [wIndex]);
+			retval = handshake (
+					&ehci->regs->port_status [wIndex],
+					PORT_RESUME, 0, 2000 /* 2msec */);
+			if (retval != 0) {
+				ehci_err (ehci, "port %d resume error %d\n",
+					wIndex + 1, retval);
+				goto error;
+			}
+			temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+		}
+
+		/* whoever resets must GetPortStatus to complete it!! */
+		if ((temp & PORT_RESET)
+				&& time_after (jiffies,
+					ehci->reset_done [wIndex])) {
+			status |= 1 << USB_PORT_FEAT_C_RESET;
+			ehci->reset_done [wIndex] = 0;
+
+			/* force reset to complete */
+			writel (temp & ~PORT_RESET,
+					&ehci->regs->port_status [wIndex]);
+			retval = handshake (
+					&ehci->regs->port_status [wIndex],
+					PORT_RESET, 0, 500);
+			if (retval != 0) {
+				ehci_err (ehci, "port %d reset error %d\n",
+					wIndex + 1, retval);
+				goto error;
+			}
+
+			/* see what we found out */
+			temp = check_reset_complete (ehci, wIndex,
+				readl (&ehci->regs->port_status [wIndex]));
+		}
+
+		// don't show wPortStatus if it's owned by a companion hc
+		if (!(temp & PORT_OWNER)) {
+			if (temp & PORT_CONNECT) {
+				status |= 1 << USB_PORT_FEAT_CONNECTION;
+				// status may be from integrated TT
+				status |= ehci_port_speed(ehci, temp);
+			}
+			if (temp & PORT_PE)
+				status |= 1 << USB_PORT_FEAT_ENABLE;
+			if (temp & (PORT_SUSPEND|PORT_RESUME))
+				status |= 1 << USB_PORT_FEAT_SUSPEND;
+			if (temp & PORT_OC)
+				status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
+			if (temp & PORT_RESET)
+				status |= 1 << USB_PORT_FEAT_RESET;
+			if (temp & PORT_POWER)
+				status |= 1 << USB_PORT_FEAT_POWER;
+		}
+
+#ifndef	EHCI_VERBOSE_DEBUG
+	if (status & ~0xffff)	/* only if wPortChange is interesting */
+#endif
+		dbg_port (ehci, "GetStatus", wIndex + 1, temp);
+		// we "know" this alignment is good, caller used kmalloc()...
+		*((__le32 *) buf) = cpu_to_le32 (status);
+		break;
+	case SetHubFeature:
+		switch (wValue) {
+		case C_HUB_LOCAL_POWER:
+		case C_HUB_OVER_CURRENT:
+			/* no hub-wide feature/status flags */
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case SetPortFeature:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		temp = readl (&ehci->regs->port_status [wIndex]);
+		if (temp & PORT_OWNER)
+			break;
+
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			if ((temp & PORT_PE) == 0
+					|| (temp & PORT_RESET) != 0)
+				goto error;
+			if (hcd->remote_wakeup)
+				temp |= PORT_WAKE_BITS;
+			writel (temp | PORT_SUSPEND,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_POWER:
+			if (HCS_PPC (ehci->hcs_params))
+				writel (temp | PORT_POWER,
+					&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_RESET:
+			if (temp & PORT_RESUME)
+				goto error;
+			/* line status bits may report this as low speed,
+			 * which can be fine if this root hub has a
+			 * transaction translator built in.
+			 */
+			if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
+					&& !ehci_is_TDI(ehci)
+					&& PORT_USB11 (temp)) {
+				ehci_dbg (ehci,
+					"port %d low speed --> companion\n",
+					wIndex + 1);
+				temp |= PORT_OWNER;
+			} else {
+				ehci_vdbg (ehci, "port %d reset\n", wIndex + 1);
+				temp |= PORT_RESET;
+				temp &= ~PORT_PE;
+
+				/*
+				 * caller must wait, then call GetPortStatus
+				 * usb 2.0 spec says 50 ms resets on root
+				 */
+				ehci->reset_done [wIndex] = jiffies
+						+ msecs_to_jiffies (50);
+			}
+			writel (temp, &ehci->regs->port_status [wIndex]);
+			break;
+		default:
+			goto error;
+		}
+		readl (&ehci->regs->command);	/* unblock posted writes */
+		break;
+
+	default:
+error:
+		/* "stall" on error */
+		retval = -EPIPE;
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	return retval;
+}
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
new file mode 100644
index 0000000..9938697
--- /dev/null
+++ b/drivers/usb/host/ehci-mem.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2001 by 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * There's basically three types of memory:
+ *	- data used only by the HCD ... kmalloc is fine
+ *	- async and periodic schedules, shared by HC and HCD ... these
+ *	  need to use dma_pool or dma_alloc_coherent
+ *	- driver buffers, read/written by HC ... single shot DMA mapped 
+ *
+ * There's also PCI "register" data, which is memory mapped.
+ * No memory seen by this driver is pageable.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* Allocate the key transfer structures from the previously allocated pool */
+
+static inline void ehci_qtd_init (struct ehci_qtd *qtd, dma_addr_t dma)
+{
+	memset (qtd, 0, sizeof *qtd);
+	qtd->qtd_dma = dma;
+	qtd->hw_token = cpu_to_le32 (QTD_STS_HALT);
+	qtd->hw_next = EHCI_LIST_END;
+	qtd->hw_alt_next = EHCI_LIST_END;
+	INIT_LIST_HEAD (&qtd->qtd_list);
+}
+
+static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags)
+{
+	struct ehci_qtd		*qtd;
+	dma_addr_t		dma;
+
+	qtd = dma_pool_alloc (ehci->qtd_pool, flags, &dma);
+	if (qtd != NULL) {
+		ehci_qtd_init (qtd, dma);
+	}
+	return qtd;
+}
+
+static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
+{
+	dma_pool_free (ehci->qtd_pool, qtd, qtd->qtd_dma);
+}
+
+
+static void qh_destroy (struct kref *kref)
+{
+	struct ehci_qh *qh = container_of(kref, struct ehci_qh, kref);
+	struct ehci_hcd *ehci = qh->ehci;
+
+	/* clean qtds first, and know this is not linked */
+	if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
+		ehci_dbg (ehci, "unused qh not empty!\n");
+		BUG ();
+	}
+	if (qh->dummy)
+		ehci_qtd_free (ehci, qh->dummy);
+	usb_put_dev (qh->dev);
+	dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
+}
+
+static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
+{
+	struct ehci_qh		*qh;
+	dma_addr_t		dma;
+
+	qh = (struct ehci_qh *)
+		dma_pool_alloc (ehci->qh_pool, flags, &dma);
+	if (!qh)
+		return qh;
+
+	memset (qh, 0, sizeof *qh);
+	kref_init(&qh->kref);
+	qh->ehci = ehci;
+	qh->qh_dma = dma;
+	// INIT_LIST_HEAD (&qh->qh_list);
+	INIT_LIST_HEAD (&qh->qtd_list);
+
+	/* dummy td enables safe urb queuing */
+	qh->dummy = ehci_qtd_alloc (ehci, flags);
+	if (qh->dummy == NULL) {
+		ehci_dbg (ehci, "no dummy td\n");
+		dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
+		qh = NULL;
+	}
+	return qh;
+}
+
+/* to share a qh (cpu threads, or hc) */
+static inline struct ehci_qh *qh_get (struct ehci_qh *qh)
+{
+	kref_get(&qh->kref);
+	return qh;
+}
+
+static inline void qh_put (struct ehci_qh *qh)
+{
+	kref_put(&qh->kref, qh_destroy);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* The queue heads and transfer descriptors are managed from pools tied 
+ * to each of the "per device" structures.
+ * This is the initialisation and cleanup code.
+ */
+
+static void ehci_mem_cleanup (struct ehci_hcd *ehci)
+{
+	if (ehci->async)
+		qh_put (ehci->async);
+	ehci->async = NULL;
+
+	/* DMA consistent memory and pools */
+	if (ehci->qtd_pool)
+		dma_pool_destroy (ehci->qtd_pool);
+	ehci->qtd_pool = NULL;
+
+	if (ehci->qh_pool) {
+		dma_pool_destroy (ehci->qh_pool);
+		ehci->qh_pool = NULL;
+	}
+
+	if (ehci->itd_pool)
+		dma_pool_destroy (ehci->itd_pool);
+	ehci->itd_pool = NULL;
+
+	if (ehci->sitd_pool)
+		dma_pool_destroy (ehci->sitd_pool);
+	ehci->sitd_pool = NULL;
+
+	if (ehci->periodic)
+		dma_free_coherent (ehci_to_hcd(ehci)->self.controller,
+			ehci->periodic_size * sizeof (u32),
+			ehci->periodic, ehci->periodic_dma);
+	ehci->periodic = NULL;
+
+	/* shadow periodic table */
+	if (ehci->pshadow)
+		kfree (ehci->pshadow);
+	ehci->pshadow = NULL;
+}
+
+/* remember to add cleanup code (above) if you add anything here */
+static int ehci_mem_init (struct ehci_hcd *ehci, int flags)
+{
+	int i;
+
+	/* QTDs for control/bulk/intr transfers */
+	ehci->qtd_pool = dma_pool_create ("ehci_qtd", 
+			ehci_to_hcd(ehci)->self.controller,
+			sizeof (struct ehci_qtd),
+			32 /* byte alignment (for hw parts) */,
+			4096 /* can't cross 4K */);
+	if (!ehci->qtd_pool) {
+		goto fail;
+	}
+
+	/* QHs for control/bulk/intr transfers */
+	ehci->qh_pool = dma_pool_create ("ehci_qh", 
+			ehci_to_hcd(ehci)->self.controller,
+			sizeof (struct ehci_qh),
+			32 /* byte alignment (for hw parts) */,
+			4096 /* can't cross 4K */);
+	if (!ehci->qh_pool) {
+		goto fail;
+	}
+	ehci->async = ehci_qh_alloc (ehci, flags);
+	if (!ehci->async) {
+		goto fail;
+	}
+
+	/* ITD for high speed ISO transfers */
+	ehci->itd_pool = dma_pool_create ("ehci_itd", 
+			ehci_to_hcd(ehci)->self.controller,
+			sizeof (struct ehci_itd),
+			32 /* byte alignment (for hw parts) */,
+			4096 /* can't cross 4K */);
+	if (!ehci->itd_pool) {
+		goto fail;
+	}
+
+	/* SITD for full/low speed split ISO transfers */
+	ehci->sitd_pool = dma_pool_create ("ehci_sitd", 
+			ehci_to_hcd(ehci)->self.controller,
+			sizeof (struct ehci_sitd),
+			32 /* byte alignment (for hw parts) */,
+			4096 /* can't cross 4K */);
+	if (!ehci->sitd_pool) {
+		goto fail;
+	}
+
+	/* Hardware periodic table */
+	ehci->periodic = (__le32 *)
+		dma_alloc_coherent (ehci_to_hcd(ehci)->self.controller,
+			ehci->periodic_size * sizeof(__le32),
+			&ehci->periodic_dma, 0);
+	if (ehci->periodic == NULL) {
+		goto fail;
+	}
+	for (i = 0; i < ehci->periodic_size; i++)
+		ehci->periodic [i] = EHCI_LIST_END;
+
+	/* software shadow of hardware table */
+	ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *), flags);
+	if (ehci->pshadow == NULL) {
+		goto fail;
+	}
+	memset (ehci->pshadow, 0, ehci->periodic_size * sizeof (void *));
+
+	return 0;
+
+fail:
+	ehci_dbg (ehci, "couldn't init memory\n");
+	ehci_mem_cleanup (ehci);
+	return -ENOMEM;
+}
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
new file mode 100644
index 0000000..7df9b9a
--- /dev/null
+++ b/drivers/usb/host/ehci-q.c
@@ -0,0 +1,1090 @@
+/*
+ * Copyright (c) 2001-2002 by 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI hardware queue manipulation ... the core.  QH/QTD manipulation.
+ *
+ * Control, bulk, and interrupt traffic all use "qh" lists.  They list "qtd"
+ * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned
+ * buffers needed for the larger number).  We use one QH per endpoint, queue
+ * multiple urbs (all three types) per endpoint.  URBs may need several qtds.
+ *
+ * ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with
+ * interrupts) needs careful scheduling.  Performance improvements can be
+ * an ongoing challenge.  That's in "ehci-sched.c".
+ * 
+ * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
+ * or otherwise through transaction translators (TTs) in USB 2.0 hubs using
+ * (b) special fields in qh entries or (c) split iso entries.  TTs will
+ * buffer low/full speed data so the host collects it at high speed.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* fill a qtd, returning how much of the buffer we were able to queue up */
+
+static int
+qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len,
+		int token, int maxpacket)
+{
+	int	i, count;
+	u64	addr = buf;
+
+	/* one buffer entry per 4K ... first might be short or unaligned */
+	qtd->hw_buf [0] = cpu_to_le32 ((u32)addr);
+	qtd->hw_buf_hi [0] = cpu_to_le32 ((u32)(addr >> 32));
+	count = 0x1000 - (buf & 0x0fff);	/* rest of that page */
+	if (likely (len < count))		/* ... iff needed */
+		count = len;
+	else {
+		buf +=  0x1000;
+		buf &= ~0x0fff;
+
+		/* per-qtd limit: from 16K to 20K (best alignment) */
+		for (i = 1; count < len && i < 5; i++) {
+			addr = buf;
+			qtd->hw_buf [i] = cpu_to_le32 ((u32)addr);
+			qtd->hw_buf_hi [i] = cpu_to_le32 ((u32)(addr >> 32));
+			buf += 0x1000;
+			if ((count + 0x1000) < len)
+				count += 0x1000;
+			else
+				count = len;
+		}
+
+		/* short packets may only terminate transfers */
+		if (count != len)
+			count -= (count % maxpacket);
+	}
+	qtd->hw_token = cpu_to_le32 ((count << 16) | token);
+	qtd->length = count;
+
+	return count;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline void
+qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
+{
+	/* writes to an active overlay are unsafe */
+	BUG_ON(qh->qh_state != QH_STATE_IDLE);
+
+	qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma);
+	qh->hw_alt_next = EHCI_LIST_END;
+
+	/* Except for control endpoints, we make hardware maintain data
+	 * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
+	 * and set the pseudo-toggle in udev. Only usb_clear_halt() will
+	 * ever clear it.
+	 */
+	if (!(qh->hw_info1 & cpu_to_le32(1 << 14))) {
+		unsigned	is_out, epnum;
+
+		is_out = !(qtd->hw_token & cpu_to_le32(1 << 8));
+		epnum = (le32_to_cpup(&qh->hw_info1) >> 8) & 0x0f;
+		if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
+			qh->hw_token &= ~__constant_cpu_to_le32 (QTD_TOGGLE);
+			usb_settoggle (qh->dev, epnum, is_out, 1);
+		}
+	}
+
+	/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
+	wmb ();
+	qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING);
+}
+
+/* if it weren't for a common silicon quirk (writing the dummy into the qh
+ * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault
+ * recovery (including urb dequeue) would need software changes to a QH...
+ */
+static void
+qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	struct ehci_qtd *qtd;
+
+	if (list_empty (&qh->qtd_list))
+		qtd = qh->dummy;
+	else {
+		qtd = list_entry (qh->qtd_list.next,
+				struct ehci_qtd, qtd_list);
+		/* first qtd may already be partially processed */
+		if (cpu_to_le32 (qtd->qtd_dma) == qh->hw_current)
+			qtd = NULL;
+	}
+
+	if (qtd)
+		qh_update (ehci, qh, qtd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void qtd_copy_status (
+	struct ehci_hcd *ehci,
+	struct urb *urb,
+	size_t length,
+	u32 token
+)
+{
+	/* count IN/OUT bytes, not SETUP (even short packets) */
+	if (likely (QTD_PID (token) != 2))
+		urb->actual_length += length - QTD_LENGTH (token);
+
+	/* don't modify error codes */
+	if (unlikely (urb->status != -EINPROGRESS))
+		return;
+
+	/* force cleanup after short read; not always an error */
+	if (unlikely (IS_SHORT_READ (token)))
+		urb->status = -EREMOTEIO;
+
+	/* serious "can't proceed" faults reported by the hardware */
+	if (token & QTD_STS_HALT) {
+		if (token & QTD_STS_BABBLE) {
+			/* FIXME "must" disable babbling device's port too */
+			urb->status = -EOVERFLOW;
+		} else if (token & QTD_STS_MMF) {
+			/* fs/ls interrupt xfer missed the complete-split */
+			urb->status = -EPROTO;
+		} else if (token & QTD_STS_DBE) {
+			urb->status = (QTD_PID (token) == 1) /* IN ? */
+				? -ENOSR  /* hc couldn't read data */
+				: -ECOMM; /* hc couldn't write data */
+		} else if (token & QTD_STS_XACT) {
+			/* timeout, bad crc, wrong PID, etc; retried */
+			if (QTD_CERR (token))
+				urb->status = -EPIPE;
+			else {
+				ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n",
+					urb->dev->devpath,
+					usb_pipeendpoint (urb->pipe),
+					usb_pipein (urb->pipe) ? "in" : "out");
+				urb->status = -EPROTO;
+			}
+		/* CERR nonzero + no errors + halt --> stall */
+		} else if (QTD_CERR (token))
+			urb->status = -EPIPE;
+		else	/* unknown */
+			urb->status = -EPROTO;
+
+		ehci_vdbg (ehci,
+			"dev%d ep%d%s qtd token %08x --> status %d\n",
+			usb_pipedevice (urb->pipe),
+			usb_pipeendpoint (urb->pipe),
+			usb_pipein (urb->pipe) ? "in" : "out",
+			token, urb->status);
+
+		/* if async CSPLIT failed, try cleaning out the TT buffer */
+		if (urb->status != -EPIPE
+				&& urb->dev->tt && !usb_pipeint (urb->pipe)
+				&& ((token & QTD_STS_MMF) != 0
+					|| QTD_CERR(token) == 0)
+				&& (!ehci_is_TDI(ehci)
+                	                || urb->dev->tt->hub !=
+					   ehci_to_hcd(ehci)->self.root_hub)) {
+#ifdef DEBUG
+			struct usb_device *tt = urb->dev->tt->hub;
+			dev_dbg (&tt->dev,
+				"clear tt buffer port %d, a%d ep%d t%08x\n",
+				urb->dev->ttport, urb->dev->devnum,
+				usb_pipeendpoint (urb->pipe), token);
+#endif /* DEBUG */
+			usb_hub_tt_clear_buffer (urb->dev, urb->pipe);
+		}
+	}
+}
+
+static void
+ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs)
+__releases(ehci->lock)
+__acquires(ehci->lock)
+{
+	if (likely (urb->hcpriv != NULL)) {
+		struct ehci_qh	*qh = (struct ehci_qh *) urb->hcpriv;
+
+		/* S-mask in a QH means it's an interrupt urb */
+		if ((qh->hw_info2 & __constant_cpu_to_le32 (0x00ff)) != 0) {
+
+			/* ... update hc-wide periodic stats (for usbfs) */
+			ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
+		}
+		qh_put (qh);
+	}
+
+	spin_lock (&urb->lock);
+	urb->hcpriv = NULL;
+	switch (urb->status) {
+	case -EINPROGRESS:		/* success */
+		urb->status = 0;
+	default:			/* fault */
+		COUNT (ehci->stats.complete);
+		break;
+	case -EREMOTEIO:		/* fault or normal */
+		if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
+			urb->status = 0;
+		COUNT (ehci->stats.complete);
+		break;
+	case -ECONNRESET:		/* canceled */
+	case -ENOENT:
+		COUNT (ehci->stats.unlink);
+		break;
+	}
+	spin_unlock (&urb->lock);
+
+#ifdef EHCI_URB_TRACE
+	ehci_dbg (ehci,
+		"%s %s urb %p ep%d%s status %d len %d/%d\n",
+		__FUNCTION__, urb->dev->devpath, urb,
+		usb_pipeendpoint (urb->pipe),
+		usb_pipein (urb->pipe) ? "in" : "out",
+		urb->status,
+		urb->actual_length, urb->transfer_buffer_length);
+#endif
+
+	/* complete() can reenter this HCD */
+	spin_unlock (&ehci->lock);
+	usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb, regs);
+	spin_lock (&ehci->lock);
+}
+
+static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
+static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
+
+static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
+static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
+
+/*
+ * Process and free completed qtds for a qh, returning URBs to drivers.
+ * Chases up to qh->hw_current.  Returns number of completions called,
+ * indicating how much "real" work we did.
+ */
+#define HALT_BIT __constant_cpu_to_le32(QTD_STS_HALT)
+static unsigned
+qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
+{
+	struct ehci_qtd		*last = NULL, *end = qh->dummy;
+	struct list_head	*entry, *tmp;
+	int			stopped;
+	unsigned		count = 0;
+	int			do_status = 0;
+	u8			state;
+
+	if (unlikely (list_empty (&qh->qtd_list)))
+		return count;
+
+	/* completions (or tasks on other cpus) must never clobber HALT
+	 * till we've gone through and cleaned everything up, even when
+	 * they add urbs to this qh's queue or mark them for unlinking.
+	 *
+	 * NOTE:  unlinking expects to be done in queue order.
+	 */
+	state = qh->qh_state;
+	qh->qh_state = QH_STATE_COMPLETING;
+	stopped = (state == QH_STATE_IDLE);
+
+	/* remove de-activated QTDs from front of queue.
+	 * after faults (including short reads), cleanup this urb
+	 * then let the queue advance.
+	 * if queue is stopped, handles unlinks.
+	 */
+	list_for_each_safe (entry, tmp, &qh->qtd_list) {
+		struct ehci_qtd	*qtd;
+		struct urb	*urb;
+		u32		token = 0;
+
+		qtd = list_entry (entry, struct ehci_qtd, qtd_list);
+		urb = qtd->urb;
+
+		/* clean up any state from previous QTD ...*/
+		if (last) {
+			if (likely (last->urb != urb)) {
+				ehci_urb_done (ehci, last->urb, regs);
+				count++;
+			}
+			ehci_qtd_free (ehci, last);
+			last = NULL;
+		}
+
+		/* ignore urbs submitted during completions we reported */
+		if (qtd == end)
+			break;
+
+		/* hardware copies qtd out of qh overlay */
+		rmb ();
+		token = le32_to_cpu (qtd->hw_token);
+
+		/* always clean up qtds the hc de-activated */
+		if ((token & QTD_STS_ACTIVE) == 0) {
+
+			if ((token & QTD_STS_HALT) != 0) {
+				stopped = 1;
+
+			/* magic dummy for some short reads; qh won't advance.
+			 * that silicon quirk can kick in with this dummy too.
+			 */
+			} else if (IS_SHORT_READ (token)
+					&& !(qtd->hw_alt_next & EHCI_LIST_END)) {
+				stopped = 1;
+				goto halt;
+			}
+
+		/* stop scanning when we reach qtds the hc is using */
+		} else if (likely (!stopped
+				&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) {
+			break;
+
+		} else {
+			stopped = 1;
+
+			if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)))
+				urb->status = -ESHUTDOWN;
+
+			/* ignore active urbs unless some previous qtd
+			 * for the urb faulted (including short read) or
+			 * its urb was canceled.  we may patch qh or qtds.
+			 */
+			if (likely (urb->status == -EINPROGRESS))
+				continue;
+			
+			/* issue status after short control reads */
+			if (unlikely (do_status != 0)
+					&& QTD_PID (token) == 0 /* OUT */) {
+				do_status = 0;
+				continue;
+			}
+
+			/* token in overlay may be most current */
+			if (state == QH_STATE_IDLE
+					&& cpu_to_le32 (qtd->qtd_dma)
+						== qh->hw_current)
+				token = le32_to_cpu (qh->hw_token);
+
+			/* force halt for unlinked or blocked qh, so we'll
+			 * patch the qh later and so that completions can't
+			 * activate it while we "know" it's stopped.
+			 */
+			if ((HALT_BIT & qh->hw_token) == 0) {
+halt:
+				qh->hw_token |= HALT_BIT;
+				wmb ();
+			}
+		}
+ 
+		/* remove it from the queue */
+		spin_lock (&urb->lock);
+		qtd_copy_status (ehci, urb, qtd->length, token);
+		do_status = (urb->status == -EREMOTEIO)
+				&& usb_pipecontrol (urb->pipe);
+		spin_unlock (&urb->lock);
+
+		if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
+			last = list_entry (qtd->qtd_list.prev,
+					struct ehci_qtd, qtd_list);
+			last->hw_next = qtd->hw_next;
+		}
+		list_del (&qtd->qtd_list);
+		last = qtd;
+	}
+
+	/* last urb's completion might still need calling */
+	if (likely (last != NULL)) {
+		ehci_urb_done (ehci, last->urb, regs);
+		count++;
+		ehci_qtd_free (ehci, last);
+	}
+
+	/* restore original state; caller must unlink or relink */
+	qh->qh_state = state;
+
+	/* be sure the hardware's done with the qh before refreshing
+	 * it after fault cleanup, or recovering from silicon wrongly
+	 * overlaying the dummy qtd (which reduces DMA chatter).
+	 */
+	if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END) {
+		switch (state) {
+		case QH_STATE_IDLE:
+			qh_refresh(ehci, qh);
+			break;
+		case QH_STATE_LINKED:
+			/* should be rare for periodic transfers,
+			 * except maybe high bandwidth ...
+			 */
+			if (qh->period) {
+				intr_deschedule (ehci, qh);
+				(void) qh_schedule (ehci, qh);
+			} else
+				unlink_async (ehci, qh);
+			break;
+		/* otherwise, unlink already started */
+		}
+	}
+
+	return count;
+}
+
+/*-------------------------------------------------------------------------*/
+
+// high bandwidth multiplier, as encoded in highspeed endpoint descriptors
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+// ... and packet size, for any kind of endpoint descriptor
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
+
+/*
+ * reverse of qh_urb_transaction:  free a list of TDs.
+ * used for cleanup after errors, before HC sees an URB's TDs.
+ */
+static void qtd_list_free (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*qtd_list
+) {
+	struct list_head	*entry, *temp;
+
+	list_for_each_safe (entry, temp, qtd_list) {
+		struct ehci_qtd	*qtd;
+
+		qtd = list_entry (entry, struct ehci_qtd, qtd_list);
+		list_del (&qtd->qtd_list);
+		ehci_qtd_free (ehci, qtd);
+	}
+}
+
+/*
+ * create a list of filled qtds for this URB; won't link into qh.
+ */
+static struct list_head *
+qh_urb_transaction (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*head,
+	int			flags
+) {
+	struct ehci_qtd		*qtd, *qtd_prev;
+	dma_addr_t		buf;
+	int			len, maxpacket;
+	int			is_input;
+	u32			token;
+
+	/*
+	 * URBs map to sequences of QTDs:  one logical transaction
+	 */
+	qtd = ehci_qtd_alloc (ehci, flags);
+	if (unlikely (!qtd))
+		return NULL;
+	list_add_tail (&qtd->qtd_list, head);
+	qtd->urb = urb;
+
+	token = QTD_STS_ACTIVE;
+	token |= (EHCI_TUNE_CERR << 10);
+	/* for split transactions, SplitXState initialized to zero */
+
+	len = urb->transfer_buffer_length;
+	is_input = usb_pipein (urb->pipe);
+	if (usb_pipecontrol (urb->pipe)) {
+		/* SETUP pid */
+		qtd_fill (qtd, urb->setup_dma, sizeof (struct usb_ctrlrequest),
+			token | (2 /* "setup" */ << 8), 8);
+
+		/* ... and always at least one more pid */
+		token ^= QTD_TOGGLE;
+		qtd_prev = qtd;
+		qtd = ehci_qtd_alloc (ehci, flags);
+		if (unlikely (!qtd))
+			goto cleanup;
+		qtd->urb = urb;
+		qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+		list_add_tail (&qtd->qtd_list, head);
+	} 
+
+	/*
+	 * data transfer stage:  buffer setup
+	 */
+	if (likely (len > 0))
+		buf = urb->transfer_dma;
+	else
+		buf = 0;
+
+	/* for zero length DATA stages, STATUS is always IN */
+	if (!buf || is_input)
+		token |= (1 /* "in" */ << 8);
+	/* else it's already initted to "out" pid (0 << 8) */
+
+	maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input));
+
+	/*
+	 * buffer gets wrapped in one or more qtds;
+	 * last one may be "short" (including zero len)
+	 * and may serve as a control status ack
+	 */
+	for (;;) {
+		int this_qtd_len;
+
+		this_qtd_len = qtd_fill (qtd, buf, len, token, maxpacket);
+		len -= this_qtd_len;
+		buf += this_qtd_len;
+		if (is_input)
+			qtd->hw_alt_next = ehci->async->hw_alt_next;
+
+		/* qh makes control packets use qtd toggle; maybe switch it */
+		if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
+			token ^= QTD_TOGGLE;
+
+		if (likely (len <= 0))
+			break;
+
+		qtd_prev = qtd;
+		qtd = ehci_qtd_alloc (ehci, flags);
+		if (unlikely (!qtd))
+			goto cleanup;
+		qtd->urb = urb;
+		qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+		list_add_tail (&qtd->qtd_list, head);
+	}
+
+	/* unless the bulk/interrupt caller wants a chance to clean
+	 * up after short reads, hc should advance qh past this urb
+	 */
+	if (likely ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0
+				|| usb_pipecontrol (urb->pipe)))
+		qtd->hw_alt_next = EHCI_LIST_END;
+
+	/*
+	 * control requests may need a terminating data "status" ack;
+	 * bulk ones may need a terminating short packet (zero length).
+	 */
+	if (likely (buf != 0)) {
+		int	one_more = 0;
+
+		if (usb_pipecontrol (urb->pipe)) {
+			one_more = 1;
+			token ^= 0x0100;	/* "in" <--> "out"  */
+			token |= QTD_TOGGLE;	/* force DATA1 */
+		} else if (usb_pipebulk (urb->pipe)
+				&& (urb->transfer_flags & URB_ZERO_PACKET)
+				&& !(urb->transfer_buffer_length % maxpacket)) {
+			one_more = 1;
+		}
+		if (one_more) {
+			qtd_prev = qtd;
+			qtd = ehci_qtd_alloc (ehci, flags);
+			if (unlikely (!qtd))
+				goto cleanup;
+			qtd->urb = urb;
+			qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+			list_add_tail (&qtd->qtd_list, head);
+
+			/* never any data in such packets */
+			qtd_fill (qtd, 0, 0, token, 0);
+		}
+	}
+
+	/* by default, enable interrupt on urb completion */
+	if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
+		qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC);
+	return head;
+
+cleanup:
+	qtd_list_free (ehci, urb, head);
+	return NULL;
+}
+
+/*-------------------------------------------------------------------------*/
+
+// Would be best to create all qh's from config descriptors,
+// when each interface/altsetting is established.  Unlink
+// any previous qh and cancel its urbs first; endpoints are
+// implicitly reset then (data toggle too).
+// That'd mean updating how usbcore talks to HCDs. (2.7?)
+
+
+/*
+ * Each QH holds a qtd list; a QH is used for everything except iso.
+ *
+ * For interrupt urbs, the scheduler must set the microframe scheduling
+ * mask(s) each time the QH gets scheduled.  For highspeed, that's
+ * just one microframe in the s-mask.  For split interrupt transactions
+ * there are additional complications: c-mask, maybe FSTNs.
+ */
+static struct ehci_qh *
+qh_make (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	int			flags
+) {
+	struct ehci_qh		*qh = ehci_qh_alloc (ehci, flags);
+	u32			info1 = 0, info2 = 0;
+	int			is_input, type;
+	int			maxp = 0;
+
+	if (!qh)
+		return qh;
+
+	/*
+	 * init endpoint/device data for this QH
+	 */
+	info1 |= usb_pipeendpoint (urb->pipe) << 8;
+	info1 |= usb_pipedevice (urb->pipe) << 0;
+
+	is_input = usb_pipein (urb->pipe);
+	type = usb_pipetype (urb->pipe);
+	maxp = usb_maxpacket (urb->dev, urb->pipe, !is_input);
+
+	/* Compute interrupt scheduling parameters just once, and save.
+	 * - allowing for high bandwidth, how many nsec/uframe are used?
+	 * - split transactions need a second CSPLIT uframe; same question
+	 * - splits also need a schedule gap (for full/low speed I/O)
+	 * - qh has a polling interval
+	 *
+	 * For control/bulk requests, the HC or TT handles these.
+	 */
+	if (type == PIPE_INTERRUPT) {
+		qh->usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,
+				hb_mult (maxp) * max_packet (maxp));
+		qh->start = NO_FRAME;
+
+		if (urb->dev->speed == USB_SPEED_HIGH) {
+			qh->c_usecs = 0;
+			qh->gap_uf = 0;
+
+			qh->period = urb->interval >> 3;
+			if (qh->period == 0 && urb->interval != 1) {
+				/* NOTE interval 2 or 4 uframes could work.
+				 * But interval 1 scheduling is simpler, and
+				 * includes high bandwidth.
+				 */
+				dbg ("intr period %d uframes, NYET!",
+						urb->interval);
+				goto done;
+			}
+		} else {
+			/* gap is f(FS/LS transfer times) */
+			qh->gap_uf = 1 + usb_calc_bus_time (urb->dev->speed,
+					is_input, 0, maxp) / (125 * 1000);
+
+			/* FIXME this just approximates SPLIT/CSPLIT times */
+			if (is_input) {		// SPLIT, gap, CSPLIT+DATA
+				qh->c_usecs = qh->usecs + HS_USECS (0);
+				qh->usecs = HS_USECS (1);
+			} else {		// SPLIT+DATA, gap, CSPLIT
+				qh->usecs += HS_USECS (1);
+				qh->c_usecs = HS_USECS (0);
+			}
+
+			qh->period = urb->interval;
+		}
+	}
+
+	/* support for tt scheduling, and access to toggles */
+	qh->dev = usb_get_dev (urb->dev);
+
+	/* using TT? */
+	switch (urb->dev->speed) {
+	case USB_SPEED_LOW:
+		info1 |= (1 << 12);	/* EPS "low" */
+		/* FALL THROUGH */
+
+	case USB_SPEED_FULL:
+		/* EPS 0 means "full" */
+		if (type != PIPE_INTERRUPT)
+			info1 |= (EHCI_TUNE_RL_TT << 28);
+		if (type == PIPE_CONTROL) {
+			info1 |= (1 << 27);	/* for TT */
+			info1 |= 1 << 14;	/* toggle from qtd */
+		}
+		info1 |= maxp << 16;
+
+		info2 |= (EHCI_TUNE_MULT_TT << 30);
+		info2 |= urb->dev->ttport << 23;
+
+		/* set the address of the TT; for TDI's integrated
+		 * root hub tt, leave it zeroed.
+		 */
+		if (!ehci_is_TDI(ehci)
+				|| urb->dev->tt->hub !=
+					ehci_to_hcd(ehci)->self.root_hub)
+			info2 |= urb->dev->tt->hub->devnum << 16;
+
+		/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets c-mask } */
+
+		break;
+
+	case USB_SPEED_HIGH:		/* no TT involved */
+		info1 |= (2 << 12);	/* EPS "high" */
+		if (type == PIPE_CONTROL) {
+			info1 |= (EHCI_TUNE_RL_HS << 28);
+			info1 |= 64 << 16;	/* usb2 fixed maxpacket */
+			info1 |= 1 << 14;	/* toggle from qtd */
+			info2 |= (EHCI_TUNE_MULT_HS << 30);
+		} else if (type == PIPE_BULK) {
+			info1 |= (EHCI_TUNE_RL_HS << 28);
+			info1 |= 512 << 16;	/* usb2 fixed maxpacket */
+			info2 |= (EHCI_TUNE_MULT_HS << 30);
+		} else {		/* PIPE_INTERRUPT */
+			info1 |= max_packet (maxp) << 16;
+			info2 |= hb_mult (maxp) << 30;
+		}
+		break;
+	default:
+ 		dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
+done:
+		qh_put (qh);
+		return NULL;
+	}
+
+	/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets s-mask } */
+
+	/* init as live, toggle clear, advance to dummy */
+	qh->qh_state = QH_STATE_IDLE;
+	qh->hw_info1 = cpu_to_le32 (info1);
+	qh->hw_info2 = cpu_to_le32 (info2);
+	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
+	qh_refresh (ehci, qh);
+	return qh;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* move qh (and its qtds) onto async queue; maybe enable queue.  */
+
+static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	__le32		dma = QH_NEXT (qh->qh_dma);
+	struct ehci_qh	*head;
+
+	/* (re)start the async schedule? */
+	head = ehci->async;
+	timer_action_done (ehci, TIMER_ASYNC_OFF);
+	if (!head->qh_next.qh) {
+		u32	cmd = readl (&ehci->regs->command);
+
+		if (!(cmd & CMD_ASE)) {
+			/* in case a clear of CMD_ASE didn't take yet */
+			(void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
+			cmd |= CMD_ASE | CMD_RUN;
+			writel (cmd, &ehci->regs->command);
+			ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
+			/* posted write need not be known to HC yet ... */
+		}
+	}
+
+	/* clear halt and/or toggle; and maybe recover from silicon quirk */
+	if (qh->qh_state == QH_STATE_IDLE)
+		qh_refresh (ehci, qh);
+
+	/* splice right after start */
+	qh->qh_next = head->qh_next;
+	qh->hw_next = head->hw_next;
+	wmb ();
+
+	head->qh_next.qh = qh;
+	head->hw_next = dma;
+
+	qh->qh_state = QH_STATE_LINKED;
+	/* qtd completions reported later by interrupt */
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define	QH_ADDR_MASK	__constant_cpu_to_le32(0x7f)
+
+/*
+ * For control/bulk/interrupt, return QH with these TDs appended.
+ * Allocates and initializes the QH if necessary.
+ * Returns null if it can't allocate a QH it needs to.
+ * If the QH has TDs (urbs) already, that's great.
+ */
+static struct ehci_qh *qh_append_tds (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	int			epnum,
+	void			**ptr
+)
+{
+	struct ehci_qh		*qh = NULL;
+
+	qh = (struct ehci_qh *) *ptr;
+	if (unlikely (qh == NULL)) {
+		/* can't sleep here, we have ehci->lock... */
+		qh = qh_make (ehci, urb, GFP_ATOMIC);
+		*ptr = qh;
+	}
+	if (likely (qh != NULL)) {
+		struct ehci_qtd	*qtd;
+
+		if (unlikely (list_empty (qtd_list)))
+			qtd = NULL;
+		else
+			qtd = list_entry (qtd_list->next, struct ehci_qtd,
+					qtd_list);
+
+		/* control qh may need patching ... */
+		if (unlikely (epnum == 0)) {
+
+                        /* usb_reset_device() briefly reverts to address 0 */
+                        if (usb_pipedevice (urb->pipe) == 0)
+                                qh->hw_info1 &= ~QH_ADDR_MASK;
+		}
+
+		/* just one way to queue requests: swap with the dummy qtd.
+		 * only hc or qh_refresh() ever modify the overlay.
+		 */
+		if (likely (qtd != NULL)) {
+			struct ehci_qtd		*dummy;
+			dma_addr_t		dma;
+			__le32			token;
+
+			/* to avoid racing the HC, use the dummy td instead of
+			 * the first td of our list (becomes new dummy).  both
+			 * tds stay deactivated until we're done, when the
+			 * HC is allowed to fetch the old dummy (4.10.2).
+			 */
+			token = qtd->hw_token;
+			qtd->hw_token = HALT_BIT;
+			wmb ();
+			dummy = qh->dummy;
+
+			dma = dummy->qtd_dma;
+			*dummy = *qtd;
+			dummy->qtd_dma = dma;
+
+			list_del (&qtd->qtd_list);
+			list_add (&dummy->qtd_list, qtd_list);
+			__list_splice (qtd_list, qh->qtd_list.prev);
+
+			ehci_qtd_init (qtd, qtd->qtd_dma);
+			qh->dummy = qtd;
+
+			/* hc must see the new dummy at list end */
+			dma = qtd->qtd_dma;
+			qtd = list_entry (qh->qtd_list.prev,
+					struct ehci_qtd, qtd_list);
+			qtd->hw_next = QTD_NEXT (dma);
+
+			/* let the hc process these next qtds */
+			wmb ();
+			dummy->hw_token = token;
+
+			urb->hcpriv = qh_get (qh);
+		}
+	}
+	return qh;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+submit_async (
+	struct ehci_hcd		*ehci,
+	struct usb_host_endpoint *ep,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	int			mem_flags
+) {
+	struct ehci_qtd		*qtd;
+	int			epnum;
+	unsigned long		flags;
+	struct ehci_qh		*qh = NULL;
+
+	qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
+	epnum = ep->desc.bEndpointAddress;
+
+#ifdef EHCI_URB_TRACE
+	ehci_dbg (ehci,
+		"%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n",
+		__FUNCTION__, urb->dev->devpath, urb,
+		epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
+		urb->transfer_buffer_length,
+		qtd, ep->hcpriv);
+#endif
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+
+	/* Control/bulk operations through TTs don't need scheduling,
+	 * the HC and TT handle it when the TT has a buffer ready.
+	 */
+	if (likely (qh != NULL)) {
+		if (likely (qh->qh_state == QH_STATE_IDLE))
+			qh_link_async (ehci, qh_get (qh));
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	if (unlikely (qh == NULL)) {
+		qtd_list_free (ehci, urb, qtd_list);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* the async qh for the qtds being reclaimed are now unlinked from the HC */
+
+static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
+{
+	struct ehci_qh		*qh = ehci->reclaim;
+	struct ehci_qh		*next;
+
+	timer_action_done (ehci, TIMER_IAA_WATCHDOG);
+
+	// qh->hw_next = cpu_to_le32 (qh->qh_dma);
+	qh->qh_state = QH_STATE_IDLE;
+	qh->qh_next.qh = NULL;
+	qh_put (qh);			// refcount from reclaim 
+
+	/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
+	next = qh->reclaim;
+	ehci->reclaim = next;
+	ehci->reclaim_ready = 0;
+	qh->reclaim = NULL;
+
+	qh_completions (ehci, qh, regs);
+
+	if (!list_empty (&qh->qtd_list)
+			&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
+		qh_link_async (ehci, qh);
+	else {
+		qh_put (qh);		// refcount from async list
+
+		/* it's not free to turn the async schedule on/off; leave it
+		 * active but idle for a while once it empties.
+		 */
+		if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state)
+				&& ehci->async->qh_next.qh == NULL)
+			timer_action (ehci, TIMER_ASYNC_OFF);
+	}
+
+	if (next) {
+		ehci->reclaim = NULL;
+		start_unlink_async (ehci, next);
+	}
+}
+
+/* makes sure the async qh will become idle */
+/* caller must own ehci->lock */
+
+static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	int		cmd = readl (&ehci->regs->command);
+	struct ehci_qh	*prev;
+
+#ifdef DEBUG
+	assert_spin_locked(&ehci->lock);
+	if (ehci->reclaim
+			|| (qh->qh_state != QH_STATE_LINKED
+				&& qh->qh_state != QH_STATE_UNLINK_WAIT)
+			)
+		BUG ();
+#endif
+
+	/* stop async schedule right now? */
+	if (unlikely (qh == ehci->async)) {
+		/* can't get here without STS_ASS set */
+		if (ehci_to_hcd(ehci)->state != HC_STATE_HALT) {
+			writel (cmd & ~CMD_ASE, &ehci->regs->command);
+			wmb ();
+			// handshake later, if we need to
+		}
+		timer_action_done (ehci, TIMER_ASYNC_OFF);
+		return;
+	} 
+
+	qh->qh_state = QH_STATE_UNLINK;
+	ehci->reclaim = qh = qh_get (qh);
+
+	prev = ehci->async;
+	while (prev->qh_next.qh != qh)
+		prev = prev->qh_next.qh;
+
+	prev->hw_next = qh->hw_next;
+	prev->qh_next = qh->qh_next;
+	wmb ();
+
+	if (unlikely (ehci_to_hcd(ehci)->state == HC_STATE_HALT)) {
+		/* if (unlikely (qh->reclaim != 0))
+		 * 	this will recurse, probably not much
+		 */
+		end_unlink_async (ehci, NULL);
+		return;
+	}
+
+	ehci->reclaim_ready = 0;
+	cmd |= CMD_IAAD;
+	writel (cmd, &ehci->regs->command);
+	(void) readl (&ehci->regs->command);
+	timer_action (ehci, TIMER_IAA_WATCHDOG);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+scan_async (struct ehci_hcd *ehci, struct pt_regs *regs)
+{
+	struct ehci_qh		*qh;
+	enum ehci_timer_action	action = TIMER_IO_WATCHDOG;
+
+	if (!++(ehci->stamp))
+		ehci->stamp++;
+	timer_action_done (ehci, TIMER_ASYNC_SHRINK);
+rescan:
+	qh = ehci->async->qh_next.qh;
+	if (likely (qh != NULL)) {
+		do {
+			/* clean any finished work for this qh */
+			if (!list_empty (&qh->qtd_list)
+					&& qh->stamp != ehci->stamp) {
+				int temp;
+
+				/* unlinks could happen here; completion
+				 * reporting drops the lock.  rescan using
+				 * the latest schedule, but don't rescan
+				 * qhs we already finished (no looping).
+				 */
+				qh = qh_get (qh);
+				qh->stamp = ehci->stamp;
+				temp = qh_completions (ehci, qh, regs);
+				qh_put (qh);
+				if (temp != 0) {
+					goto rescan;
+				}
+			}
+
+			/* unlink idle entries, reducing HC PCI usage as well
+			 * as HCD schedule-scanning costs.  delay for any qh
+			 * we just scanned, there's a not-unusual case that it
+			 * doesn't stay idle for long.
+			 * (plus, avoids some kind of re-activation race.)
+			 */
+			if (list_empty (&qh->qtd_list)) {
+				if (qh->stamp == ehci->stamp)
+					action = TIMER_ASYNC_SHRINK;
+				else if (!ehci->reclaim
+					    && qh->qh_state == QH_STATE_LINKED)
+					start_unlink_async (ehci, qh);
+			}
+
+			qh = qh->qh_next.qh;
+		} while (qh);
+	}
+	if (action == TIMER_ASYNC_SHRINK)
+		timer_action (ehci, TIMER_ASYNC_SHRINK);
+}
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
new file mode 100644
index 0000000..f6c8635
--- /dev/null
+++ b/drivers/usb/host/ehci-sched.c
@@ -0,0 +1,1999 @@
+/*
+ * Copyright (c) 2001-2004 by David Brownell
+ * Copyright (c) 2003 Michal Sojka, for high-speed iso transfers
+ * 
+ * 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 file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI scheduled transaction support:  interrupt, iso, split iso
+ * These are called "periodic" transactions in the EHCI spec.
+ *
+ * Note that for interrupt transfers, the QH/QTD manipulation is shared
+ * with the "asynchronous" transaction support (control/bulk transfers).
+ * The only real difference is in how interrupt transfers are scheduled.
+ *
+ * For ISO, we make an "iso_stream" head to serve the same role as a QH.
+ * It keeps track of every ITD (or SITD) that's linked, and holds enough
+ * pre-calculated schedule data to make appending to the queue be quick.
+ */
+
+static int ehci_get_frame (struct usb_hcd *hcd);
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * periodic_next_shadow - return "next" pointer on shadow list
+ * @periodic: host pointer to qh/itd/sitd
+ * @tag: hardware tag for type of this record
+ */
+static union ehci_shadow *
+periodic_next_shadow (union ehci_shadow *periodic, __le32 tag)
+{
+	switch (tag) {
+	case Q_TYPE_QH:
+		return &periodic->qh->qh_next;
+	case Q_TYPE_FSTN:
+		return &periodic->fstn->fstn_next;
+	case Q_TYPE_ITD:
+		return &periodic->itd->itd_next;
+	// case Q_TYPE_SITD:
+	default:
+		return &periodic->sitd->sitd_next;
+	}
+}
+
+/* caller must hold ehci->lock */
+static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
+{
+	union ehci_shadow	*prev_p = &ehci->pshadow [frame];
+	__le32			*hw_p = &ehci->periodic [frame];
+	union ehci_shadow	here = *prev_p;
+
+	/* find predecessor of "ptr"; hw and shadow lists are in sync */
+	while (here.ptr && here.ptr != ptr) {
+		prev_p = periodic_next_shadow (prev_p, Q_NEXT_TYPE (*hw_p));
+		hw_p = here.hw_next;
+		here = *prev_p;
+	}
+	/* an interrupt entry (at list end) could have been shared */
+	if (!here.ptr)
+		return;
+
+	/* update shadow and hardware lists ... the old "next" pointers
+	 * from ptr may still be in use, the caller updates them.
+	 */
+	*prev_p = *periodic_next_shadow (&here, Q_NEXT_TYPE (*hw_p));
+	*hw_p = *here.hw_next;
+}
+
+/* how many of the uframe's 125 usecs are allocated? */
+static unsigned short
+periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
+{
+	__le32			*hw_p = &ehci->periodic [frame];
+	union ehci_shadow	*q = &ehci->pshadow [frame];
+	unsigned		usecs = 0;
+
+	while (q->ptr) {
+		switch (Q_NEXT_TYPE (*hw_p)) {
+		case Q_TYPE_QH:
+			/* is it in the S-mask? */
+			if (q->qh->hw_info2 & cpu_to_le32 (1 << uframe))
+				usecs += q->qh->usecs;
+			/* ... or C-mask? */
+			if (q->qh->hw_info2 & cpu_to_le32 (1 << (8 + uframe)))
+				usecs += q->qh->c_usecs;
+			hw_p = &q->qh->hw_next;
+			q = &q->qh->qh_next;
+			break;
+		// case Q_TYPE_FSTN:
+		default:
+			/* for "save place" FSTNs, count the relevant INTR
+			 * bandwidth from the previous frame
+			 */
+			if (q->fstn->hw_prev != EHCI_LIST_END) {
+				ehci_dbg (ehci, "ignoring FSTN cost ...\n");
+			}
+			hw_p = &q->fstn->hw_next;
+			q = &q->fstn->fstn_next;
+			break;
+		case Q_TYPE_ITD:
+			usecs += q->itd->usecs [uframe];
+			hw_p = &q->itd->hw_next;
+			q = &q->itd->itd_next;
+			break;
+		case Q_TYPE_SITD:
+			/* is it in the S-mask?  (count SPLIT, DATA) */
+			if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) {
+				if (q->sitd->hw_fullspeed_ep &
+						__constant_cpu_to_le32 (1<<31))
+					usecs += q->sitd->stream->usecs;
+				else	/* worst case for OUT start-split */
+					usecs += HS_USECS_ISO (188);
+			}
+
+			/* ... C-mask?  (count CSPLIT, DATA) */
+			if (q->sitd->hw_uframe &
+					cpu_to_le32 (1 << (8 + uframe))) {
+				/* worst case for IN complete-split */
+				usecs += q->sitd->stream->c_usecs;
+			}
+
+			hw_p = &q->sitd->hw_next;
+			q = &q->sitd->sitd_next;
+			break;
+		}
+	}
+#ifdef	DEBUG
+	if (usecs > 100)
+		ehci_err (ehci, "uframe %d sched overrun: %d usecs\n",
+			frame * 8 + uframe, usecs);
+#endif
+	return usecs;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int same_tt (struct usb_device *dev1, struct usb_device *dev2)
+{
+	if (!dev1->tt || !dev2->tt)
+		return 0;
+	if (dev1->tt != dev2->tt)
+		return 0;
+	if (dev1->tt->multi)
+		return dev1->ttport == dev2->ttport;
+	else
+		return 1;
+}
+
+/* return true iff the device's transaction translator is available
+ * for a periodic transfer starting at the specified frame, using
+ * all the uframes in the mask.
+ */
+static int tt_no_collision (
+	struct ehci_hcd		*ehci,
+	unsigned		period,
+	struct usb_device	*dev,
+	unsigned		frame,
+	u32			uf_mask
+)
+{
+	if (period == 0)	/* error */
+		return 0;
+
+	/* note bandwidth wastage:  split never follows csplit
+	 * (different dev or endpoint) until the next uframe.
+	 * calling convention doesn't make that distinction.
+	 */
+	for (; frame < ehci->periodic_size; frame += period) {
+		union ehci_shadow	here;
+		__le32			type;
+
+		here = ehci->pshadow [frame];
+		type = Q_NEXT_TYPE (ehci->periodic [frame]);
+		while (here.ptr) {
+			switch (type) {
+			case Q_TYPE_ITD:
+				type = Q_NEXT_TYPE (here.itd->hw_next);
+				here = here.itd->itd_next;
+				continue;
+			case Q_TYPE_QH:
+				if (same_tt (dev, here.qh->dev)) {
+					u32		mask;
+
+					mask = le32_to_cpu (here.qh->hw_info2);
+					/* "knows" no gap is needed */
+					mask |= mask >> 8;
+					if (mask & uf_mask)
+						break;
+				}
+				type = Q_NEXT_TYPE (here.qh->hw_next);
+				here = here.qh->qh_next;
+				continue;
+			case Q_TYPE_SITD:
+				if (same_tt (dev, here.sitd->urb->dev)) {
+					u16		mask;
+
+					mask = le32_to_cpu (here.sitd
+								->hw_uframe);
+					/* FIXME assumes no gap for IN! */
+					mask |= mask >> 8;
+					if (mask & uf_mask)
+						break;
+				}
+				type = Q_NEXT_TYPE (here.sitd->hw_next);
+				here = here.sitd->sitd_next;
+				continue;
+			// case Q_TYPE_FSTN:
+			default:
+				ehci_dbg (ehci,
+					"periodic frame %d bogus type %d\n",
+					frame, type);
+			}
+
+			/* collision or error */
+			return 0;
+		}
+	}
+
+	/* no collision */
+	return 1;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int enable_periodic (struct ehci_hcd *ehci)
+{
+	u32	cmd;
+	int	status;
+
+	/* did clearing PSE did take effect yet?
+	 * takes effect only at frame boundaries...
+	 */
+	status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125);
+	if (status != 0) {
+		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
+		return status;
+	}
+
+	cmd = readl (&ehci->regs->command) | CMD_PSE;
+	writel (cmd, &ehci->regs->command);
+	/* posted write ... PSS happens later */
+	ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
+
+	/* make sure ehci_work scans these */
+	ehci->next_uframe = readl (&ehci->regs->frame_index)
+				% (ehci->periodic_size << 3);
+	return 0;
+}
+
+static int disable_periodic (struct ehci_hcd *ehci)
+{
+	u32	cmd;
+	int	status;
+
+	/* did setting PSE not take effect yet?
+	 * takes effect only at frame boundaries...
+	 */
+	status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
+	if (status != 0) {
+		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
+		return status;
+	}
+
+	cmd = readl (&ehci->regs->command) & ~CMD_PSE;
+	writel (cmd, &ehci->regs->command);
+	/* posted write ... */
+
+	ehci->next_uframe = -1;
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* periodic schedule slots have iso tds (normal or split) first, then a
+ * sparse tree for active interrupt transfers.
+ *
+ * this just links in a qh; caller guarantees uframe masks are set right.
+ * no FSTN support (yet; ehci 0.96+)
+ */
+static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	unsigned	i;
+	unsigned	period = qh->period;
+
+	dev_dbg (&qh->dev->dev,
+		"link qh%d-%04x/%p start %d [%d/%d us]\n",
+		period, le32_to_cpup (&qh->hw_info2) & 0xffff,
+		qh, qh->start, qh->usecs, qh->c_usecs);
+
+	/* high bandwidth, or otherwise every microframe */
+	if (period == 0)
+		period = 1;
+
+	for (i = qh->start; i < ehci->periodic_size; i += period) {
+		union ehci_shadow	*prev = &ehci->pshadow [i];
+		u32			*hw_p = &ehci->periodic [i];
+		union ehci_shadow	here = *prev;
+		u32			type = 0;
+
+		/* skip the iso nodes at list head */
+		while (here.ptr) {
+			type = Q_NEXT_TYPE (*hw_p);
+			if (type == Q_TYPE_QH)
+				break;
+			prev = periodic_next_shadow (prev, type);
+			hw_p = &here.qh->hw_next;
+			here = *prev;
+		}
+
+		/* sorting each branch by period (slow-->fast)
+		 * enables sharing interior tree nodes
+		 */
+		while (here.ptr && qh != here.qh) {
+			if (qh->period > here.qh->period)
+				break;
+			prev = &here.qh->qh_next;
+			hw_p = &here.qh->hw_next;
+			here = *prev;
+		}
+		/* link in this qh, unless some earlier pass did that */
+		if (qh != here.qh) {
+			qh->qh_next = here;
+			if (here.qh)
+				qh->hw_next = *hw_p;
+			wmb ();
+			prev->qh = qh;
+			*hw_p = QH_NEXT (qh->qh_dma);
+		}
+	}
+	qh->qh_state = QH_STATE_LINKED;
+	qh_get (qh);
+
+	/* update per-qh bandwidth for usbfs */
+	ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->period
+		? ((qh->usecs + qh->c_usecs) / qh->period)
+		: (qh->usecs * 8);
+
+	/* maybe enable periodic schedule processing */
+	if (!ehci->periodic_sched++)
+		return enable_periodic (ehci);
+
+	return 0;
+}
+
+static void qh_unlink_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	unsigned	i;
+	unsigned	period;
+
+	// FIXME:
+	// IF this isn't high speed
+	//   and this qh is active in the current uframe
+	//   (and overlay token SplitXstate is false?)
+	// THEN
+	//   qh->hw_info1 |= __constant_cpu_to_le32 (1 << 7 /* "ignore" */);
+
+	/* high bandwidth, or otherwise part of every microframe */
+	if ((period = qh->period) == 0)
+		period = 1;
+
+	for (i = qh->start; i < ehci->periodic_size; i += period)
+		periodic_unlink (ehci, i, qh);
+
+	/* update per-qh bandwidth for usbfs */
+	ehci_to_hcd(ehci)->self.bandwidth_allocated -= qh->period
+		? ((qh->usecs + qh->c_usecs) / qh->period)
+		: (qh->usecs * 8);
+
+	dev_dbg (&qh->dev->dev,
+		"unlink qh%d-%04x/%p start %d [%d/%d us]\n",
+		qh->period, le32_to_cpup (&qh->hw_info2) & 0xffff,
+		qh, qh->start, qh->usecs, qh->c_usecs);
+
+	/* qh->qh_next still "live" to HC */
+	qh->qh_state = QH_STATE_UNLINK;
+	qh->qh_next.ptr = NULL;
+	qh_put (qh);
+
+	/* maybe turn off periodic schedule */
+	ehci->periodic_sched--;
+	if (!ehci->periodic_sched)
+		(void) disable_periodic (ehci);
+}
+
+static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	unsigned	wait;
+
+	qh_unlink_periodic (ehci, qh);
+
+	/* simple/paranoid:  always delay, expecting the HC needs to read
+	 * qh->hw_next or finish a writeback after SPLIT/CSPLIT ... and
+	 * expect khubd to clean up after any CSPLITs we won't issue.
+	 * active high speed queues may need bigger delays...
+	 */
+	if (list_empty (&qh->qtd_list)
+			|| (__constant_cpu_to_le32 (0x0ff << 8)
+					& qh->hw_info2) != 0)
+		wait = 2;
+	else
+		wait = 55;	/* worst case: 3 * 1024 */
+
+	udelay (wait);
+	qh->qh_state = QH_STATE_IDLE;
+	qh->hw_next = EHCI_LIST_END;
+	wmb ();
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int check_period (
+	struct ehci_hcd *ehci, 
+	unsigned	frame,
+	unsigned	uframe,
+	unsigned	period,
+	unsigned	usecs
+) {
+	int		claimed;
+
+	/* complete split running into next frame?
+	 * given FSTN support, we could sometimes check...
+	 */
+	if (uframe >= 8)
+		return 0;
+
+	/*
+	 * 80% periodic == 100 usec/uframe available
+	 * convert "usecs we need" to "max already claimed" 
+	 */
+	usecs = 100 - usecs;
+
+	/* we "know" 2 and 4 uframe intervals were rejected; so
+	 * for period 0, check _every_ microframe in the schedule.
+	 */
+	if (unlikely (period == 0)) {
+		do {
+			for (uframe = 0; uframe < 7; uframe++) {
+				claimed = periodic_usecs (ehci, frame, uframe);
+				if (claimed > usecs)
+					return 0;
+			}
+		} while ((frame += 1) < ehci->periodic_size);
+
+	/* just check the specified uframe, at that period */
+	} else {
+		do {
+			claimed = periodic_usecs (ehci, frame, uframe);
+			if (claimed > usecs)
+				return 0;
+		} while ((frame += period) < ehci->periodic_size);
+	}
+
+	// success!
+	return 1;
+}
+
+static int check_intr_schedule (
+	struct ehci_hcd		*ehci, 
+	unsigned		frame,
+	unsigned		uframe,
+	const struct ehci_qh	*qh,
+	__le32			*c_maskp
+)
+{
+    	int		retval = -ENOSPC;
+	u8		mask;
+
+	if (qh->c_usecs && uframe >= 6)		/* FSTN territory? */
+		goto done;
+
+	if (!check_period (ehci, frame, uframe, qh->period, qh->usecs))
+		goto done;
+	if (!qh->c_usecs) {
+		retval = 0;
+		*c_maskp = 0;
+		goto done;
+	}
+
+	/* Make sure this tt's buffer is also available for CSPLITs.
+	 * We pessimize a bit; probably the typical full speed case
+	 * doesn't need the second CSPLIT.
+	 * 
+	 * NOTE:  both SPLIT and CSPLIT could be checked in just
+	 * one smart pass...
+	 */
+	mask = 0x03 << (uframe + qh->gap_uf);
+	*c_maskp = cpu_to_le32 (mask << 8);
+
+	mask |= 1 << uframe;
+	if (tt_no_collision (ehci, qh->period, qh->dev, frame, mask)) {
+		if (!check_period (ehci, frame, uframe + qh->gap_uf + 1,
+					qh->period, qh->c_usecs))
+			goto done;
+		if (!check_period (ehci, frame, uframe + qh->gap_uf,
+					qh->period, qh->c_usecs))
+			goto done;
+		retval = 0;
+	}
+done:
+	return retval;
+}
+
+/* "first fit" scheduling policy used the first time through,
+ * or when the previous schedule slot can't be re-used.
+ */
+static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	int 		status;
+	unsigned	uframe;
+	__le32		c_mask;
+	unsigned	frame;		/* 0..(qh->period - 1), or NO_FRAME */
+
+	qh_refresh(ehci, qh);
+	qh->hw_next = EHCI_LIST_END;
+	frame = qh->start;
+
+	/* reuse the previous schedule slots, if we can */
+	if (frame < qh->period) {
+		uframe = ffs (le32_to_cpup (&qh->hw_info2) & 0x00ff);
+		status = check_intr_schedule (ehci, frame, --uframe,
+				qh, &c_mask);
+	} else {
+		uframe = 0;
+		c_mask = 0;
+		status = -ENOSPC;
+	}
+
+	/* else scan the schedule to find a group of slots such that all
+	 * uframes have enough periodic bandwidth available.
+	 */
+	if (status) {
+		/* "normal" case, uframing flexible except with splits */
+		if (qh->period) {
+			frame = qh->period - 1;
+			do {
+				for (uframe = 0; uframe < 8; uframe++) {
+					status = check_intr_schedule (ehci,
+							frame, uframe, qh,
+							&c_mask);
+					if (status == 0)
+						break;
+				}
+			} while (status && frame--);
+
+		/* qh->period == 0 means every uframe */
+		} else {
+			frame = 0;
+			status = check_intr_schedule (ehci, 0, 0, qh, &c_mask);
+		}
+		if (status)
+			goto done;
+		qh->start = frame;
+
+		/* reset S-frame and (maybe) C-frame masks */
+		qh->hw_info2 &= __constant_cpu_to_le32 (~0xffff);
+		qh->hw_info2 |= qh->period
+			? cpu_to_le32 (1 << uframe)
+			: __constant_cpu_to_le32 (0xff);
+		qh->hw_info2 |= c_mask;
+	} else
+		ehci_dbg (ehci, "reused qh %p schedule\n", qh);
+
+	/* stuff into the periodic schedule */
+ 	status = qh_link_periodic (ehci, qh);
+done:
+	return status;
+}
+
+static int intr_submit (
+	struct ehci_hcd		*ehci,
+	struct usb_host_endpoint *ep,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	int			mem_flags
+) {
+	unsigned		epnum;
+	unsigned long		flags;
+	struct ehci_qh		*qh;
+	int			status = 0;
+	struct list_head	empty;
+
+	/* get endpoint and transfer/schedule data */
+	epnum = ep->desc.bEndpointAddress;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	/* get qh and force any scheduling errors */
+	INIT_LIST_HEAD (&empty);
+	qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv);
+	if (qh == NULL) {
+		status = -ENOMEM;
+		goto done;
+	}
+	if (qh->qh_state == QH_STATE_IDLE) {
+		if ((status = qh_schedule (ehci, qh)) != 0)
+			goto done;
+	}
+
+	/* then queue the urb's tds to the qh */
+	qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+	BUG_ON (qh == NULL);
+
+	/* ... update usbfs periodic stats */
+	ehci_to_hcd(ehci)->self.bandwidth_int_reqs++;
+
+done:
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	if (status)
+		qtd_list_free (ehci, urb, qtd_list);
+
+	return status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* ehci_iso_stream ops work with both ITD and SITD */
+
+static struct ehci_iso_stream *
+iso_stream_alloc (int mem_flags)
+{
+	struct ehci_iso_stream *stream;
+
+	stream = kmalloc(sizeof *stream, mem_flags);
+	if (likely (stream != NULL)) {
+		memset (stream, 0, sizeof(*stream));
+		INIT_LIST_HEAD(&stream->td_list);
+		INIT_LIST_HEAD(&stream->free_list);
+		stream->next_uframe = -1;
+		stream->refcount = 1;
+	}
+	return stream;
+}
+
+static void
+iso_stream_init (
+	struct ehci_hcd		*ehci,
+	struct ehci_iso_stream	*stream,
+	struct usb_device	*dev,
+	int			pipe,
+	unsigned		interval
+)
+{
+	static const u8 smask_out [] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f };
+
+	u32			buf1;
+	unsigned		epnum, maxp;
+	int			is_input;
+	long			bandwidth;
+
+	/*
+	 * this might be a "high bandwidth" highspeed endpoint,
+	 * as encoded in the ep descriptor's wMaxPacket field
+	 */
+	epnum = usb_pipeendpoint (pipe);
+	is_input = usb_pipein (pipe) ? USB_DIR_IN : 0;
+	maxp = usb_maxpacket(dev, pipe, !is_input);
+	if (is_input) {
+		buf1 = (1 << 11);
+	} else {
+		buf1 = 0;
+	}
+
+	/* knows about ITD vs SITD */
+	if (dev->speed == USB_SPEED_HIGH) {
+		unsigned multi = hb_mult(maxp);
+
+		stream->highspeed = 1;
+
+		maxp = max_packet(maxp);
+		buf1 |= maxp;
+		maxp *= multi;
+
+		stream->buf0 = cpu_to_le32 ((epnum << 8) | dev->devnum);
+		stream->buf1 = cpu_to_le32 (buf1);
+		stream->buf2 = cpu_to_le32 (multi);
+
+		/* usbfs wants to report the average usecs per frame tied up
+		 * when transfers on this endpoint are scheduled ...
+		 */
+		stream->usecs = HS_USECS_ISO (maxp);
+		bandwidth = stream->usecs * 8;
+		bandwidth /= 1 << (interval - 1);
+
+	} else {
+		u32		addr;
+
+		addr = dev->ttport << 24;
+		if (!ehci_is_TDI(ehci)
+				|| (dev->tt->hub !=
+					ehci_to_hcd(ehci)->self.root_hub))
+			addr |= dev->tt->hub->devnum << 16;
+		addr |= epnum << 8;
+		addr |= dev->devnum;
+		stream->usecs = HS_USECS_ISO (maxp);
+		if (is_input) {
+			u32	tmp;
+
+			addr |= 1 << 31;
+			stream->c_usecs = stream->usecs;
+			stream->usecs = HS_USECS_ISO (1);
+			stream->raw_mask = 1;
+
+			/* pessimistic c-mask */
+			tmp = usb_calc_bus_time (USB_SPEED_FULL, 1, 0, maxp)
+					/ (125 * 1000);
+			stream->raw_mask |= 3 << (tmp + 9);
+		} else
+			stream->raw_mask = smask_out [maxp / 188];
+		bandwidth = stream->usecs + stream->c_usecs;
+		bandwidth /= 1 << (interval + 2);
+
+		/* stream->splits gets created from raw_mask later */
+		stream->address = cpu_to_le32 (addr);
+	}
+	stream->bandwidth = bandwidth;
+
+	stream->udev = dev;
+
+	stream->bEndpointAddress = is_input | epnum;
+	stream->interval = interval;
+	stream->maxp = maxp;
+}
+
+static void
+iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream)
+{
+	stream->refcount--;
+
+	/* free whenever just a dev->ep reference remains.
+	 * not like a QH -- no persistent state (toggle, halt)
+	 */
+	if (stream->refcount == 1) {
+		int		is_in;
+
+		// BUG_ON (!list_empty(&stream->td_list));
+
+		while (!list_empty (&stream->free_list)) {
+			struct list_head	*entry;
+
+			entry = stream->free_list.next;
+			list_del (entry);
+
+			/* knows about ITD vs SITD */
+			if (stream->highspeed) {
+				struct ehci_itd		*itd;
+
+				itd = list_entry (entry, struct ehci_itd,
+						itd_list);
+				dma_pool_free (ehci->itd_pool, itd,
+						itd->itd_dma);
+			} else {
+				struct ehci_sitd	*sitd;
+
+				sitd = list_entry (entry, struct ehci_sitd,
+						sitd_list);
+				dma_pool_free (ehci->sitd_pool, sitd,
+						sitd->sitd_dma);
+			}
+		}
+
+		is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0;
+		stream->bEndpointAddress &= 0x0f;
+		stream->ep->hcpriv = NULL;
+
+		if (stream->rescheduled) {
+			ehci_info (ehci, "ep%d%s-iso rescheduled "
+				"%lu times in %lu seconds\n",
+				stream->bEndpointAddress, is_in ? "in" : "out",
+				stream->rescheduled,
+				((jiffies - stream->start)/HZ)
+				);
+		}
+
+		kfree(stream);
+	}
+}
+
+static inline struct ehci_iso_stream *
+iso_stream_get (struct ehci_iso_stream *stream)
+{
+	if (likely (stream != NULL))
+		stream->refcount++;
+	return stream;
+}
+
+static struct ehci_iso_stream *
+iso_stream_find (struct ehci_hcd *ehci, struct urb *urb)
+{
+	unsigned		epnum;
+	struct ehci_iso_stream	*stream;
+	struct usb_host_endpoint *ep;
+	unsigned long		flags;
+
+	epnum = usb_pipeendpoint (urb->pipe);
+	if (usb_pipein(urb->pipe))
+		ep = urb->dev->ep_in[epnum];
+	else
+		ep = urb->dev->ep_out[epnum];
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	stream = ep->hcpriv;
+
+	if (unlikely (stream == NULL)) {
+		stream = iso_stream_alloc(GFP_ATOMIC);
+		if (likely (stream != NULL)) {
+			/* dev->ep owns the initial refcount */
+			ep->hcpriv = stream;
+			stream->ep = ep;
+			iso_stream_init(ehci, stream, urb->dev, urb->pipe,
+					urb->interval);
+		}
+
+	/* if dev->ep [epnum] is a QH, info1.maxpacket is nonzero */
+	} else if (unlikely (stream->hw_info1 != 0)) {
+		ehci_dbg (ehci, "dev %s ep%d%s, not iso??\n",
+			urb->dev->devpath, epnum,
+			usb_pipein(urb->pipe) ? "in" : "out");
+		stream = NULL;
+	}
+
+	/* caller guarantees an eventual matching iso_stream_put */
+	stream = iso_stream_get (stream);
+
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	return stream;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* ehci_iso_sched ops can be ITD-only or SITD-only */
+
+static struct ehci_iso_sched *
+iso_sched_alloc (unsigned packets, int mem_flags)
+{
+	struct ehci_iso_sched	*iso_sched;
+	int			size = sizeof *iso_sched;
+
+	size += packets * sizeof (struct ehci_iso_packet);
+	iso_sched = kmalloc (size, mem_flags);
+	if (likely (iso_sched != NULL)) {
+		memset(iso_sched, 0, size);
+		INIT_LIST_HEAD (&iso_sched->td_list);
+	}
+	return iso_sched;
+}
+
+static inline void
+itd_sched_init (
+	struct ehci_iso_sched	*iso_sched,
+	struct ehci_iso_stream	*stream,
+	struct urb		*urb
+)
+{
+	unsigned	i;
+	dma_addr_t	dma = urb->transfer_dma;
+
+	/* how many uframes are needed for these transfers */
+	iso_sched->span = urb->number_of_packets * stream->interval;
+
+	/* figure out per-uframe itd fields that we'll need later
+	 * when we fit new itds into the schedule.
+	 */
+	for (i = 0; i < urb->number_of_packets; i++) {
+		struct ehci_iso_packet	*uframe = &iso_sched->packet [i];
+		unsigned		length;
+		dma_addr_t		buf;
+		u32			trans;
+
+		length = urb->iso_frame_desc [i].length;
+		buf = dma + urb->iso_frame_desc [i].offset;
+
+		trans = EHCI_ISOC_ACTIVE;
+		trans |= buf & 0x0fff;
+		if (unlikely (((i + 1) == urb->number_of_packets))
+				&& !(urb->transfer_flags & URB_NO_INTERRUPT))
+			trans |= EHCI_ITD_IOC;
+		trans |= length << 16;
+		uframe->transaction = cpu_to_le32 (trans);
+
+		/* might need to cross a buffer page within a td */
+		uframe->bufp = (buf & ~(u64)0x0fff);
+		buf += length;
+		if (unlikely ((uframe->bufp != (buf & ~(u64)0x0fff))))
+			uframe->cross = 1;
+	}
+}
+
+static void
+iso_sched_free (
+	struct ehci_iso_stream	*stream,
+	struct ehci_iso_sched	*iso_sched
+)
+{
+	if (!iso_sched)
+		return;
+	// caller must hold ehci->lock!
+	list_splice (&iso_sched->td_list, &stream->free_list);
+	kfree (iso_sched);
+}
+
+static int
+itd_urb_transaction (
+	struct ehci_iso_stream	*stream,
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	int			mem_flags
+)
+{
+	struct ehci_itd		*itd;
+	dma_addr_t		itd_dma;
+	int			i;
+	unsigned		num_itds;
+	struct ehci_iso_sched	*sched;
+	unsigned long		flags;
+
+	sched = iso_sched_alloc (urb->number_of_packets, mem_flags);
+	if (unlikely (sched == NULL))
+		return -ENOMEM;
+
+	itd_sched_init (sched, stream, urb);
+
+	if (urb->interval < 8)
+		num_itds = 1 + (sched->span + 7) / 8;
+	else
+		num_itds = urb->number_of_packets;
+
+	/* allocate/init ITDs */
+	spin_lock_irqsave (&ehci->lock, flags);
+	for (i = 0; i < num_itds; i++) {
+
+		/* free_list.next might be cache-hot ... but maybe
+		 * the HC caches it too. avoid that issue for now.
+		 */
+
+		/* prefer previously-allocated itds */
+		if (likely (!list_empty(&stream->free_list))) {
+			itd = list_entry (stream->free_list.prev,
+					 struct ehci_itd, itd_list);
+			list_del (&itd->itd_list);
+			itd_dma = itd->itd_dma;
+		} else
+			itd = NULL;
+
+		if (!itd) {
+			spin_unlock_irqrestore (&ehci->lock, flags);
+			itd = dma_pool_alloc (ehci->itd_pool, mem_flags,
+					&itd_dma);
+			spin_lock_irqsave (&ehci->lock, flags);
+		}
+
+		if (unlikely (NULL == itd)) {
+			iso_sched_free (stream, sched);
+			spin_unlock_irqrestore (&ehci->lock, flags);
+			return -ENOMEM;
+		}
+		memset (itd, 0, sizeof *itd);
+		itd->itd_dma = itd_dma;
+		list_add (&itd->itd_list, &sched->td_list);
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+
+	/* temporarily store schedule info in hcpriv */
+	urb->hcpriv = sched;
+	urb->error_count = 0;
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline int
+itd_slot_ok (
+	struct ehci_hcd		*ehci,
+	u32			mod,
+	u32			uframe,
+	u8			usecs,
+	u32			period
+)
+{
+	uframe %= period;
+	do {
+		/* can't commit more than 80% periodic == 100 usec */
+		if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7)
+				> (100 - usecs))
+			return 0;
+
+		/* we know urb->interval is 2^N uframes */
+		uframe += period;
+	} while (uframe < mod);
+	return 1;
+}
+
+static inline int
+sitd_slot_ok (
+	struct ehci_hcd		*ehci,
+	u32			mod,
+	struct ehci_iso_stream	*stream,
+	u32			uframe,
+	struct ehci_iso_sched	*sched,
+	u32			period_uframes
+)
+{
+	u32			mask, tmp;
+	u32			frame, uf;
+
+	mask = stream->raw_mask << (uframe & 7);
+
+	/* for IN, don't wrap CSPLIT into the next frame */
+	if (mask & ~0xffff)
+		return 0;
+
+	/* this multi-pass logic is simple, but performance may
+	 * suffer when the schedule data isn't cached.
+	 */
+
+	/* check bandwidth */
+	uframe %= period_uframes;
+	do {
+		u32		max_used;
+
+		frame = uframe >> 3;
+		uf = uframe & 7;
+
+		/* tt must be idle for start(s), any gap, and csplit.
+		 * assume scheduling slop leaves 10+% for control/bulk.
+		 */
+		if (!tt_no_collision (ehci, period_uframes << 3,
+				stream->udev, frame, mask))
+			return 0;
+
+		/* check starts (OUT uses more than one) */
+		max_used = 100 - stream->usecs;
+		for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) {
+			if (periodic_usecs (ehci, frame, uf) > max_used)
+				return 0;
+		}
+
+		/* for IN, check CSPLIT */
+		if (stream->c_usecs) {
+			max_used = 100 - stream->c_usecs;
+			do {
+				tmp = 1 << uf;
+				tmp <<= 8;
+				if ((stream->raw_mask & tmp) == 0)
+					continue;
+				if (periodic_usecs (ehci, frame, uf)
+						> max_used)
+					return 0;
+			} while (++uf < 8);
+		}
+
+		/* we know urb->interval is 2^N uframes */
+		uframe += period_uframes;
+	} while (uframe < mod);
+
+	stream->splits = cpu_to_le32(stream->raw_mask << (uframe & 7));
+	return 1;
+}
+
+/*
+ * This scheduler plans almost as far into the future as it has actual
+ * periodic schedule slots.  (Affected by TUNE_FLS, which defaults to
+ * "as small as possible" to be cache-friendlier.)  That limits the size
+ * transfers you can stream reliably; avoid more than 64 msec per urb.
+ * Also avoid queue depths of less than ehci's worst irq latency (affected
+ * by the per-urb URB_NO_INTERRUPT hint, the log2_irq_thresh module parameter,
+ * and other factors); or more than about 230 msec total (for portability,
+ * given EHCI_TUNE_FLS and the slop).  Or, write a smarter scheduler!
+ */
+
+#define SCHEDULE_SLOP	10	/* frames */
+
+static int
+iso_stream_schedule (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct ehci_iso_stream	*stream
+)
+{
+	u32			now, start, max, period;
+	int			status;
+	unsigned		mod = ehci->periodic_size << 3;
+	struct ehci_iso_sched	*sched = urb->hcpriv;
+
+	if (sched->span > (mod - 8 * SCHEDULE_SLOP)) {
+		ehci_dbg (ehci, "iso request %p too long\n", urb);
+		status = -EFBIG;
+		goto fail;
+	}
+
+	if ((stream->depth + sched->span) > mod) {
+		ehci_dbg (ehci, "request %p would overflow (%d+%d>%d)\n",
+			urb, stream->depth, sched->span, mod);
+		status = -EFBIG;
+		goto fail;
+	}
+
+	now = readl (&ehci->regs->frame_index) % mod;
+
+	/* when's the last uframe this urb could start? */
+	max = now + mod;
+
+	/* typical case: reuse current schedule. stream is still active,
+	 * and no gaps from host falling behind (irq delays etc)
+	 */
+	if (likely (!list_empty (&stream->td_list))) {
+		start = stream->next_uframe;
+		if (start < now)
+			start += mod;
+		if (likely ((start + sched->span) < max))
+			goto ready;
+		/* else fell behind; someday, try to reschedule */
+		status = -EL2NSYNC;
+		goto fail;
+	}
+
+	/* need to schedule; when's the next (u)frame we could start?
+	 * this is bigger than ehci->i_thresh allows; scheduling itself
+	 * isn't free, the slop should handle reasonably slow cpus.  it
+	 * can also help high bandwidth if the dma and irq loads don't
+	 * jump until after the queue is primed.
+	 */
+	start = SCHEDULE_SLOP * 8 + (now & ~0x07);
+	start %= mod;
+	stream->next_uframe = start;
+
+	/* NOTE:  assumes URB_ISO_ASAP, to limit complexity/bugs */
+
+	period = urb->interval;
+	if (!stream->highspeed)
+		period <<= 3;
+
+	/* find a uframe slot with enough bandwidth */
+	for (; start < (stream->next_uframe + period); start++) {
+		int		enough_space;
+
+		/* check schedule: enough space? */
+		if (stream->highspeed)
+			enough_space = itd_slot_ok (ehci, mod, start,
+					stream->usecs, period);
+		else {
+			if ((start % 8) >= 6)
+				continue;
+			enough_space = sitd_slot_ok (ehci, mod, stream,
+					start, sched, period);
+		}
+
+		/* schedule it here if there's enough bandwidth */
+		if (enough_space) {
+			stream->next_uframe = start % mod;
+			goto ready;
+		}
+	}
+
+	/* no room in the schedule */
+	ehci_dbg (ehci, "iso %ssched full %p (now %d max %d)\n",
+		list_empty (&stream->td_list) ? "" : "re",
+		urb, now, max);
+	status = -ENOSPC;
+
+fail:
+	iso_sched_free (stream, sched);
+	urb->hcpriv = NULL;
+	return status;
+
+ready:
+	/* report high speed start in uframes; full speed, in frames */
+	urb->start_frame = stream->next_uframe;
+	if (!stream->highspeed)
+		urb->start_frame >>= 3;
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline void
+itd_init (struct ehci_iso_stream *stream, struct ehci_itd *itd)
+{
+	int i;
+
+	itd->hw_next = EHCI_LIST_END;
+	itd->hw_bufp [0] = stream->buf0;
+	itd->hw_bufp [1] = stream->buf1;
+	itd->hw_bufp [2] = stream->buf2;
+
+	for (i = 0; i < 8; i++)
+		itd->index[i] = -1;
+
+	/* All other fields are filled when scheduling */
+}
+
+static inline void
+itd_patch (
+	struct ehci_itd		*itd,
+	struct ehci_iso_sched	*iso_sched,
+	unsigned		index,
+	u16			uframe,
+	int			first
+)
+{
+	struct ehci_iso_packet	*uf = &iso_sched->packet [index];
+	unsigned		pg = itd->pg;
+
+	// BUG_ON (pg == 6 && uf->cross);
+
+	uframe &= 0x07;
+	itd->index [uframe] = index;
+
+	itd->hw_transaction [uframe] = uf->transaction;
+	itd->hw_transaction [uframe] |= cpu_to_le32 (pg << 12);
+	itd->hw_bufp [pg] |= cpu_to_le32 (uf->bufp & ~(u32)0);
+	itd->hw_bufp_hi [pg] |= cpu_to_le32 ((u32)(uf->bufp >> 32));
+
+	/* iso_frame_desc[].offset must be strictly increasing */
+	if (unlikely (!first && uf->cross)) {
+		u64	bufp = uf->bufp + 4096;
+		itd->pg = ++pg;
+		itd->hw_bufp [pg] |= cpu_to_le32 (bufp & ~(u32)0);
+		itd->hw_bufp_hi [pg] |= cpu_to_le32 ((u32)(bufp >> 32));
+	}
+}
+
+static inline void
+itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
+{
+	/* always prepend ITD/SITD ... only QH tree is order-sensitive */
+	itd->itd_next = ehci->pshadow [frame];
+	itd->hw_next = ehci->periodic [frame];
+	ehci->pshadow [frame].itd = itd;
+	itd->frame = frame;
+	wmb ();
+	ehci->periodic [frame] = cpu_to_le32 (itd->itd_dma) | Q_TYPE_ITD;
+}
+
+/* fit urb's itds into the selected schedule slot; activate as needed */
+static int
+itd_link_urb (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	unsigned		mod,
+	struct ehci_iso_stream	*stream
+)
+{
+	int			packet, first = 1;
+	unsigned		next_uframe, uframe, frame;
+	struct ehci_iso_sched	*iso_sched = urb->hcpriv;
+	struct ehci_itd		*itd;
+
+	next_uframe = stream->next_uframe % mod;
+
+	if (unlikely (list_empty(&stream->td_list))) {
+		ehci_to_hcd(ehci)->self.bandwidth_allocated
+				+= stream->bandwidth;
+		ehci_vdbg (ehci,
+			"schedule devp %s ep%d%s-iso period %d start %d.%d\n",
+			urb->dev->devpath, stream->bEndpointAddress & 0x0f,
+			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
+			urb->interval,
+			next_uframe >> 3, next_uframe & 0x7);
+		stream->start = jiffies;
+	}
+	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
+
+	/* fill iTDs uframe by uframe */
+	for (packet = 0, itd = NULL; packet < urb->number_of_packets; ) {
+		if (itd == NULL) {
+			/* ASSERT:  we have all necessary itds */
+			// BUG_ON (list_empty (&iso_sched->td_list));
+
+			/* ASSERT:  no itds for this endpoint in this uframe */
+
+			itd = list_entry (iso_sched->td_list.next,
+					struct ehci_itd, itd_list);
+			list_move_tail (&itd->itd_list, &stream->td_list);
+			itd->stream = iso_stream_get (stream);
+			itd->urb = usb_get_urb (urb);
+			first = 1;
+			itd_init (stream, itd);
+		}
+
+		uframe = next_uframe & 0x07;
+		frame = next_uframe >> 3;
+
+		itd->usecs [uframe] = stream->usecs;
+		itd_patch (itd, iso_sched, packet, uframe, first);
+		first = 0;
+
+		next_uframe += stream->interval;
+		stream->depth += stream->interval;
+		next_uframe %= mod;
+		packet++;
+
+		/* link completed itds into the schedule */
+		if (((next_uframe >> 3) != frame)
+				|| packet == urb->number_of_packets) {
+			itd_link (ehci, frame % ehci->periodic_size, itd);
+			itd = NULL;
+		}
+	}
+	stream->next_uframe = next_uframe;
+
+	/* don't need that schedule data any more */
+	iso_sched_free (stream, iso_sched);
+	urb->hcpriv = NULL;
+
+	timer_action (ehci, TIMER_IO_WATCHDOG);
+	if (unlikely (!ehci->periodic_sched++))
+		return enable_periodic (ehci);
+	return 0;
+}
+
+#define	ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
+
+static unsigned
+itd_complete (
+	struct ehci_hcd	*ehci,
+	struct ehci_itd	*itd,
+	struct pt_regs	*regs
+) {
+	struct urb				*urb = itd->urb;
+	struct usb_iso_packet_descriptor	*desc;
+	u32					t;
+	unsigned				uframe;
+	int					urb_index = -1;
+	struct ehci_iso_stream			*stream = itd->stream;
+	struct usb_device			*dev;
+
+	/* for each uframe with a packet */
+	for (uframe = 0; uframe < 8; uframe++) {
+		if (likely (itd->index[uframe] == -1))
+			continue;
+		urb_index = itd->index[uframe];
+		desc = &urb->iso_frame_desc [urb_index];
+
+		t = le32_to_cpup (&itd->hw_transaction [uframe]);
+		itd->hw_transaction [uframe] = 0;
+		stream->depth -= stream->interval;
+
+		/* report transfer status */
+		if (unlikely (t & ISO_ERRS)) {
+			urb->error_count++;
+			if (t & EHCI_ISOC_BUF_ERR)
+				desc->status = usb_pipein (urb->pipe)
+					? -ENOSR  /* hc couldn't read */
+					: -ECOMM; /* hc couldn't write */
+			else if (t & EHCI_ISOC_BABBLE)
+				desc->status = -EOVERFLOW;
+			else /* (t & EHCI_ISOC_XACTERR) */
+				desc->status = -EPROTO;
+
+			/* HC need not update length with this error */
+			if (!(t & EHCI_ISOC_BABBLE))
+				desc->actual_length = EHCI_ITD_LENGTH (t);
+		} else if (likely ((t & EHCI_ISOC_ACTIVE) == 0)) {
+			desc->status = 0;
+			desc->actual_length = EHCI_ITD_LENGTH (t);
+		}
+	}
+
+	usb_put_urb (urb);
+	itd->urb = NULL;
+	itd->stream = NULL;
+	list_move (&itd->itd_list, &stream->free_list);
+	iso_stream_put (ehci, stream);
+
+	/* handle completion now? */
+	if (likely ((urb_index + 1) != urb->number_of_packets))
+		return 0;
+
+	/* ASSERT: it's really the last itd for this urb
+	list_for_each_entry (itd, &stream->td_list, itd_list)
+		BUG_ON (itd->urb == urb);
+	 */
+
+	/* give urb back to the driver ... can be out-of-order */
+	dev = usb_get_dev (urb->dev);
+	ehci_urb_done (ehci, urb, regs);
+	urb = NULL;
+
+	/* defer stopping schedule; completion can submit */
+	ehci->periodic_sched--;
+	if (unlikely (!ehci->periodic_sched))
+		(void) disable_periodic (ehci);
+	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
+
+	if (unlikely (list_empty (&stream->td_list))) {
+		ehci_to_hcd(ehci)->self.bandwidth_allocated
+				-= stream->bandwidth;
+		ehci_vdbg (ehci,
+			"deschedule devp %s ep%d%s-iso\n",
+			dev->devpath, stream->bEndpointAddress & 0x0f,
+			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
+	}
+	iso_stream_put (ehci, stream);
+	usb_put_dev (dev);
+
+	return 1;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
+{
+	int			status = -EINVAL;
+	unsigned long		flags;
+	struct ehci_iso_stream	*stream;
+
+	/* Get iso_stream head */
+	stream = iso_stream_find (ehci, urb);
+	if (unlikely (stream == NULL)) {
+		ehci_dbg (ehci, "can't get iso stream\n");
+		return -ENOMEM;
+	}
+	if (unlikely (urb->interval != stream->interval)) {
+		ehci_dbg (ehci, "can't change iso interval %d --> %d\n",
+			stream->interval, urb->interval);
+		goto done;
+	}
+
+#ifdef EHCI_URB_TRACE
+	ehci_dbg (ehci,
+		"%s %s urb %p ep%d%s len %d, %d pkts %d uframes [%p]\n",
+		__FUNCTION__, urb->dev->devpath, urb,
+		usb_pipeendpoint (urb->pipe),
+		usb_pipein (urb->pipe) ? "in" : "out",
+		urb->transfer_buffer_length,
+		urb->number_of_packets, urb->interval,
+		stream);
+#endif
+
+	/* allocate ITDs w/o locking anything */
+	status = itd_urb_transaction (stream, ehci, urb, mem_flags);
+	if (unlikely (status < 0)) {
+		ehci_dbg (ehci, "can't init itds\n");
+		goto done;
+	}
+
+	/* schedule ... need to lock */
+	spin_lock_irqsave (&ehci->lock, flags);
+	status = iso_stream_schedule (ehci, urb, stream);
+ 	if (likely (status == 0))
+		itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+	spin_unlock_irqrestore (&ehci->lock, flags);
+
+done:
+	if (unlikely (status < 0))
+		iso_stream_put (ehci, stream);
+	return status;
+}
+
+#ifdef CONFIG_USB_EHCI_SPLIT_ISO
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * "Split ISO TDs" ... used for USB 1.1 devices going through the
+ * TTs in USB 2.0 hubs.  These need microframe scheduling.
+ */
+
+static inline void
+sitd_sched_init (
+	struct ehci_iso_sched	*iso_sched,
+	struct ehci_iso_stream	*stream,
+	struct urb		*urb
+)
+{
+	unsigned	i;
+	dma_addr_t	dma = urb->transfer_dma;
+
+	/* how many frames are needed for these transfers */
+	iso_sched->span = urb->number_of_packets * stream->interval;
+
+	/* figure out per-frame sitd fields that we'll need later
+	 * when we fit new sitds into the schedule.
+	 */
+	for (i = 0; i < urb->number_of_packets; i++) {
+		struct ehci_iso_packet	*packet = &iso_sched->packet [i];
+		unsigned		length;
+		dma_addr_t		buf;
+		u32			trans;
+
+		length = urb->iso_frame_desc [i].length & 0x03ff;
+		buf = dma + urb->iso_frame_desc [i].offset;
+
+		trans = SITD_STS_ACTIVE;
+		if (((i + 1) == urb->number_of_packets)
+				&& !(urb->transfer_flags & URB_NO_INTERRUPT))
+			trans |= SITD_IOC;
+		trans |= length << 16;
+		packet->transaction = cpu_to_le32 (trans);
+
+		/* might need to cross a buffer page within a td */
+		packet->bufp = buf;
+		packet->buf1 = (buf + length) & ~0x0fff;
+		if (packet->buf1 != (buf & ~(u64)0x0fff))
+			packet->cross = 1;
+
+		/* OUT uses multiple start-splits */ 
+		if (stream->bEndpointAddress & USB_DIR_IN)
+			continue;
+		length = (length + 187) / 188;
+		if (length > 1) /* BEGIN vs ALL */
+			length |= 1 << 3;
+		packet->buf1 |= length;
+	}
+}
+
+static int
+sitd_urb_transaction (
+	struct ehci_iso_stream	*stream,
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	int			mem_flags
+)
+{
+	struct ehci_sitd	*sitd;
+	dma_addr_t		sitd_dma;
+	int			i;
+	struct ehci_iso_sched	*iso_sched;
+	unsigned long		flags;
+
+	iso_sched = iso_sched_alloc (urb->number_of_packets, mem_flags);
+	if (iso_sched == NULL)
+		return -ENOMEM;
+
+	sitd_sched_init (iso_sched, stream, urb);
+
+	/* allocate/init sITDs */
+	spin_lock_irqsave (&ehci->lock, flags);
+	for (i = 0; i < urb->number_of_packets; i++) {
+
+		/* NOTE:  for now, we don't try to handle wraparound cases
+		 * for IN (using sitd->hw_backpointer, like a FSTN), which
+		 * means we never need two sitds for full speed packets.
+		 */
+
+		/* free_list.next might be cache-hot ... but maybe
+		 * the HC caches it too. avoid that issue for now.
+		 */
+
+		/* prefer previously-allocated sitds */
+		if (!list_empty(&stream->free_list)) {
+			sitd = list_entry (stream->free_list.prev,
+					 struct ehci_sitd, sitd_list);
+			list_del (&sitd->sitd_list);
+			sitd_dma = sitd->sitd_dma;
+		} else
+			sitd = NULL;
+
+		if (!sitd) {
+			spin_unlock_irqrestore (&ehci->lock, flags);
+			sitd = dma_pool_alloc (ehci->sitd_pool, mem_flags,
+					&sitd_dma);
+			spin_lock_irqsave (&ehci->lock, flags);
+		}
+
+		if (!sitd) {
+			iso_sched_free (stream, iso_sched);
+			spin_unlock_irqrestore (&ehci->lock, flags);
+			return -ENOMEM;
+		}
+		memset (sitd, 0, sizeof *sitd);
+		sitd->sitd_dma = sitd_dma;
+		list_add (&sitd->sitd_list, &iso_sched->td_list);
+	}
+
+	/* temporarily store schedule info in hcpriv */
+	urb->hcpriv = iso_sched;
+	urb->error_count = 0;
+
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline void
+sitd_patch (
+	struct ehci_iso_stream	*stream,
+	struct ehci_sitd	*sitd,
+	struct ehci_iso_sched	*iso_sched,
+	unsigned		index
+)
+{
+	struct ehci_iso_packet	*uf = &iso_sched->packet [index];
+	u64			bufp = uf->bufp;
+
+	sitd->hw_next = EHCI_LIST_END;
+	sitd->hw_fullspeed_ep = stream->address;
+	sitd->hw_uframe = stream->splits;
+	sitd->hw_results = uf->transaction;
+	sitd->hw_backpointer = EHCI_LIST_END;
+
+	bufp = uf->bufp;
+	sitd->hw_buf [0] = cpu_to_le32 (bufp);
+	sitd->hw_buf_hi [0] = cpu_to_le32 (bufp >> 32);
+
+	sitd->hw_buf [1] = cpu_to_le32 (uf->buf1);
+	if (uf->cross)
+		bufp += 4096;
+	sitd->hw_buf_hi [1] = cpu_to_le32 (bufp >> 32);
+	sitd->index = index;
+}
+
+static inline void
+sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
+{
+	/* note: sitd ordering could matter (CSPLIT then SSPLIT) */
+	sitd->sitd_next = ehci->pshadow [frame];
+	sitd->hw_next = ehci->periodic [frame];
+	ehci->pshadow [frame].sitd = sitd;
+	sitd->frame = frame;
+	wmb ();
+	ehci->periodic [frame] = cpu_to_le32 (sitd->sitd_dma) | Q_TYPE_SITD;
+}
+
+/* fit urb's sitds into the selected schedule slot; activate as needed */
+static int
+sitd_link_urb (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	unsigned		mod,
+	struct ehci_iso_stream	*stream
+)
+{
+	int			packet;
+	unsigned		next_uframe;
+	struct ehci_iso_sched	*sched = urb->hcpriv;
+	struct ehci_sitd	*sitd;
+
+	next_uframe = stream->next_uframe;
+
+	if (list_empty(&stream->td_list)) {
+		/* usbfs ignores TT bandwidth */
+		ehci_to_hcd(ehci)->self.bandwidth_allocated
+				+= stream->bandwidth;
+		ehci_vdbg (ehci,
+			"sched devp %s ep%d%s-iso [%d] %dms/%04x\n",
+			urb->dev->devpath, stream->bEndpointAddress & 0x0f,
+			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
+			(next_uframe >> 3) % ehci->periodic_size,
+			stream->interval, le32_to_cpu (stream->splits));
+		stream->start = jiffies;
+	}
+	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
+
+	/* fill sITDs frame by frame */
+	for (packet = 0, sitd = NULL;
+			packet < urb->number_of_packets;
+			packet++) {
+
+		/* ASSERT:  we have all necessary sitds */
+		BUG_ON (list_empty (&sched->td_list));
+
+		/* ASSERT:  no itds for this endpoint in this frame */
+
+		sitd = list_entry (sched->td_list.next,
+				struct ehci_sitd, sitd_list);
+		list_move_tail (&sitd->sitd_list, &stream->td_list);
+		sitd->stream = iso_stream_get (stream);
+		sitd->urb = usb_get_urb (urb);
+
+		sitd_patch (stream, sitd, sched, packet);
+		sitd_link (ehci, (next_uframe >> 3) % ehci->periodic_size,
+				sitd);
+
+		next_uframe += stream->interval << 3;
+		stream->depth += stream->interval << 3;
+	}
+	stream->next_uframe = next_uframe % mod;
+
+	/* don't need that schedule data any more */
+	iso_sched_free (stream, sched);
+	urb->hcpriv = NULL;
+
+	timer_action (ehci, TIMER_IO_WATCHDOG);
+	if (!ehci->periodic_sched++)
+		return enable_periodic (ehci);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define	SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \
+	       			| SITD_STS_XACT | SITD_STS_MMF)
+
+static unsigned
+sitd_complete (
+	struct ehci_hcd		*ehci,
+	struct ehci_sitd	*sitd,
+	struct pt_regs		*regs
+) {
+	struct urb				*urb = sitd->urb;
+	struct usb_iso_packet_descriptor	*desc;
+	u32					t;
+	int					urb_index = -1;
+	struct ehci_iso_stream			*stream = sitd->stream;
+	struct usb_device			*dev;
+
+	urb_index = sitd->index;
+	desc = &urb->iso_frame_desc [urb_index];
+	t = le32_to_cpup (&sitd->hw_results);
+
+	/* report transfer status */
+	if (t & SITD_ERRS) {
+		urb->error_count++;
+		if (t & SITD_STS_DBE)
+			desc->status = usb_pipein (urb->pipe)
+				? -ENOSR  /* hc couldn't read */
+				: -ECOMM; /* hc couldn't write */
+		else if (t & SITD_STS_BABBLE)
+			desc->status = -EOVERFLOW;
+		else /* XACT, MMF, etc */
+			desc->status = -EPROTO;
+	} else {
+		desc->status = 0;
+		desc->actual_length = desc->length - SITD_LENGTH (t);
+	}
+
+	usb_put_urb (urb);
+	sitd->urb = NULL;
+	sitd->stream = NULL;
+	list_move (&sitd->sitd_list, &stream->free_list);
+	stream->depth -= stream->interval << 3;
+	iso_stream_put (ehci, stream);
+
+	/* handle completion now? */
+	if ((urb_index + 1) != urb->number_of_packets)
+		return 0;
+
+	/* ASSERT: it's really the last sitd for this urb
+	list_for_each_entry (sitd, &stream->td_list, sitd_list)
+		BUG_ON (sitd->urb == urb);
+	 */
+
+	/* give urb back to the driver */
+	dev = usb_get_dev (urb->dev);
+	ehci_urb_done (ehci, urb, regs);
+	urb = NULL;
+
+	/* defer stopping schedule; completion can submit */
+	ehci->periodic_sched--;
+	if (!ehci->periodic_sched)
+		(void) disable_periodic (ehci);
+	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
+
+	if (list_empty (&stream->td_list)) {
+		ehci_to_hcd(ehci)->self.bandwidth_allocated
+				-= stream->bandwidth;
+		ehci_vdbg (ehci,
+			"deschedule devp %s ep%d%s-iso\n",
+			dev->devpath, stream->bEndpointAddress & 0x0f,
+			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
+	}
+	iso_stream_put (ehci, stream);
+	usb_put_dev (dev);
+
+	return 1;
+}
+
+
+static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
+{
+	int			status = -EINVAL;
+	unsigned long		flags;
+	struct ehci_iso_stream	*stream;
+
+	/* Get iso_stream head */
+	stream = iso_stream_find (ehci, urb);
+	if (stream == NULL) {
+		ehci_dbg (ehci, "can't get iso stream\n");
+		return -ENOMEM;
+	}
+	if (urb->interval != stream->interval) {
+		ehci_dbg (ehci, "can't change iso interval %d --> %d\n",
+			stream->interval, urb->interval);
+		goto done;
+	}
+
+#ifdef EHCI_URB_TRACE
+	ehci_dbg (ehci,
+		"submit %p dev%s ep%d%s-iso len %d\n",
+		urb, urb->dev->devpath,
+		usb_pipeendpoint (urb->pipe),
+		usb_pipein (urb->pipe) ? "in" : "out",
+		urb->transfer_buffer_length);
+#endif
+
+	/* allocate SITDs */
+	status = sitd_urb_transaction (stream, ehci, urb, mem_flags);
+	if (status < 0) {
+		ehci_dbg (ehci, "can't init sitds\n");
+		goto done;
+	}
+
+	/* schedule ... need to lock */
+	spin_lock_irqsave (&ehci->lock, flags);
+	status = iso_stream_schedule (ehci, urb, stream);
+ 	if (status == 0)
+		sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+	spin_unlock_irqrestore (&ehci->lock, flags);
+
+done:
+	if (status < 0)
+		iso_stream_put (ehci, stream);
+	return status;
+}
+
+#else
+
+static inline int
+sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
+{
+	ehci_dbg (ehci, "split iso support is disabled\n");
+	return -ENOSYS;
+}
+
+static inline unsigned
+sitd_complete (
+	struct ehci_hcd		*ehci,
+	struct ehci_sitd	*sitd,
+	struct pt_regs		*regs
+) {
+	ehci_err (ehci, "sitd_complete %p?\n", sitd);
+	return 0;
+}
+
+#endif /* USB_EHCI_SPLIT_ISO */
+
+/*-------------------------------------------------------------------------*/
+
+static void
+scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs)
+{
+	unsigned	frame, clock, now_uframe, mod;
+	unsigned	modified;
+
+	mod = ehci->periodic_size << 3;
+
+	/*
+	 * When running, scan from last scan point up to "now"
+	 * else clean up by scanning everything that's left.
+	 * Touches as few pages as possible:  cache-friendly.
+	 */
+	now_uframe = ehci->next_uframe;
+	if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
+		clock = readl (&ehci->regs->frame_index);
+	else
+		clock = now_uframe + mod - 1;
+	clock %= mod;
+
+	for (;;) {
+		union ehci_shadow	q, *q_p;
+		__le32			type, *hw_p;
+		unsigned		uframes;
+
+		/* don't scan past the live uframe */
+		frame = now_uframe >> 3;
+		if (frame == (clock >> 3))
+			uframes = now_uframe & 0x07;
+		else {
+			/* safe to scan the whole frame at once */
+			now_uframe |= 0x07;
+			uframes = 8;
+		}
+
+restart:
+		/* scan each element in frame's queue for completions */
+		q_p = &ehci->pshadow [frame];
+		hw_p = &ehci->periodic [frame];
+		q.ptr = q_p->ptr;
+		type = Q_NEXT_TYPE (*hw_p);
+		modified = 0;
+
+		while (q.ptr != NULL) {
+			unsigned		uf;
+			union ehci_shadow	temp;
+			int			live;
+
+			live = HC_IS_RUNNING (ehci_to_hcd(ehci)->state);
+			switch (type) {
+			case Q_TYPE_QH:
+				/* handle any completions */
+				temp.qh = qh_get (q.qh);
+				type = Q_NEXT_TYPE (q.qh->hw_next);
+				q = q.qh->qh_next;
+				modified = qh_completions (ehci, temp.qh, regs);
+				if (unlikely (list_empty (&temp.qh->qtd_list)))
+					intr_deschedule (ehci, temp.qh);
+				qh_put (temp.qh);
+				break;
+			case Q_TYPE_FSTN:
+				/* for "save place" FSTNs, look at QH entries
+				 * in the previous frame for completions.
+				 */
+				if (q.fstn->hw_prev != EHCI_LIST_END) {
+					dbg ("ignoring completions from FSTNs");
+				}
+				type = Q_NEXT_TYPE (q.fstn->hw_next);
+				q = q.fstn->fstn_next;
+				break;
+			case Q_TYPE_ITD:
+				/* skip itds for later in the frame */
+				rmb ();
+				for (uf = live ? uframes : 8; uf < 8; uf++) {
+					if (0 == (q.itd->hw_transaction [uf]
+							& ITD_ACTIVE))
+						continue;
+					q_p = &q.itd->itd_next;
+					hw_p = &q.itd->hw_next;
+					type = Q_NEXT_TYPE (q.itd->hw_next);
+					q = *q_p;
+					break;
+				}
+				if (uf != 8)
+					break;
+
+				/* this one's ready ... HC won't cache the
+				 * pointer for much longer, if at all.
+				 */
+				*q_p = q.itd->itd_next;
+				*hw_p = q.itd->hw_next;
+				type = Q_NEXT_TYPE (q.itd->hw_next);
+				wmb();
+				modified = itd_complete (ehci, q.itd, regs);
+				q = *q_p;
+				break;
+			case Q_TYPE_SITD:
+				if ((q.sitd->hw_results & SITD_ACTIVE)
+						&& live) {
+					q_p = &q.sitd->sitd_next;
+					hw_p = &q.sitd->hw_next;
+					type = Q_NEXT_TYPE (q.sitd->hw_next);
+					q = *q_p;
+					break;
+				}
+				*q_p = q.sitd->sitd_next;
+				*hw_p = q.sitd->hw_next;
+				type = Q_NEXT_TYPE (q.sitd->hw_next);
+				wmb();
+				modified = sitd_complete (ehci, q.sitd, regs);
+				q = *q_p;
+				break;
+			default:
+				dbg ("corrupt type %d frame %d shadow %p",
+					type, frame, q.ptr);
+				// BUG ();
+				q.ptr = NULL;
+			}
+
+			/* assume completion callbacks modify the queue */
+			if (unlikely (modified))
+				goto restart;
+		}
+
+		/* stop when we catch up to the HC */
+
+		// FIXME:  this assumes we won't get lapped when
+		// latencies climb; that should be rare, but...
+		// detect it, and just go all the way around.
+		// FLR might help detect this case, so long as latencies
+		// don't exceed periodic_size msec (default 1.024 sec).
+
+		// FIXME:  likewise assumes HC doesn't halt mid-scan
+
+		if (now_uframe == clock) {
+			unsigned	now;
+
+			if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
+				break;
+			ehci->next_uframe = now_uframe;
+			now = readl (&ehci->regs->frame_index) % mod;
+			if (now_uframe == now)
+				break;
+
+			/* rescan the rest of this frame, then ... */
+			clock = now;
+		} else {
+			now_uframe++;
+			now_uframe %= mod;
+		}
+	} 
+}
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
new file mode 100644
index 0000000..67988db
--- /dev/null
+++ b/drivers/usb/host/ehci.h
@@ -0,0 +1,637 @@
+/*
+ * Copyright (c) 2001-2002 by 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_EHCI_HCD_H
+#define __LINUX_EHCI_HCD_H
+
+/* definitions used for the EHCI driver */
+
+/* statistics can be kept for for tuning/monitoring */
+struct ehci_stats {
+	/* irq usage */
+	unsigned long		normal;
+	unsigned long		error;
+	unsigned long		reclaim;
+	unsigned long		lost_iaa;
+
+	/* termination of urbs from core */
+	unsigned long		complete;
+	unsigned long		unlink;
+};
+
+/* ehci_hcd->lock guards shared data against other CPUs:
+ *   ehci_hcd:	async, reclaim, periodic (and shadow), ...
+ *   usb_host_endpoint: hcpriv
+ *   ehci_qh:	qh_next, qtd_list
+ *   ehci_qtd:	qtd_list
+ *
+ * Also, hold this lock when talking to HC registers or
+ * when updating hw_* fields in shared qh/qtd/... structures.
+ */
+
+#define	EHCI_MAX_ROOT_PORTS	15		/* see HCS_N_PORTS */
+
+struct ehci_hcd {			/* one per controller */
+	spinlock_t		lock;
+
+	/* async schedule support */
+	struct ehci_qh		*async;
+	struct ehci_qh		*reclaim;
+	unsigned		reclaim_ready : 1;
+	unsigned		scanning : 1;
+
+	/* periodic schedule support */
+#define	DEFAULT_I_TDPS		1024		/* some HCs can do less */
+	unsigned		periodic_size;
+	__le32			*periodic;	/* hw periodic table */
+	dma_addr_t		periodic_dma;
+	unsigned		i_thresh;	/* uframes HC might cache */
+
+	union ehci_shadow	*pshadow;	/* mirror hw periodic table */
+	int			next_uframe;	/* scan periodic, start here */
+	unsigned		periodic_sched;	/* periodic activity count */
+
+	/* per root hub port */
+	unsigned long		reset_done [EHCI_MAX_ROOT_PORTS];
+
+	/* per-HC memory pools (could be per-bus, but ...) */
+	struct dma_pool		*qh_pool;	/* qh per active urb */
+	struct dma_pool		*qtd_pool;	/* one or more per qh */
+	struct dma_pool		*itd_pool;	/* itd per iso urb */
+	struct dma_pool		*sitd_pool;	/* sitd per split iso urb */
+
+	struct timer_list	watchdog;
+	struct notifier_block	reboot_notifier;
+	unsigned long		actions;
+	unsigned		stamp;
+	unsigned long		next_statechange;
+	u32			command;
+
+	unsigned		is_tdi_rh_tt:1;	/* TDI roothub with TT */
+
+	/* glue to PCI and HCD framework */
+	struct ehci_caps __iomem *caps;
+	struct ehci_regs __iomem *regs;
+	__u32			hcs_params;	/* cached register copy */
+
+	/* irq statistics */
+#ifdef EHCI_STATS
+	struct ehci_stats	stats;
+#	define COUNT(x) do { (x)++; } while (0)
+#else
+#	define COUNT(x) do {} while (0)
+#endif
+};
+
+/* convert between an HCD pointer and the corresponding EHCI_HCD */ 
+static inline struct ehci_hcd *hcd_to_ehci (struct usb_hcd *hcd)
+{
+	return (struct ehci_hcd *) (hcd->hcd_priv);
+}
+static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci)
+{
+	return container_of ((void *) ehci, struct usb_hcd, hcd_priv);
+}
+
+
+enum ehci_timer_action {
+	TIMER_IO_WATCHDOG,
+	TIMER_IAA_WATCHDOG,
+	TIMER_ASYNC_SHRINK,
+	TIMER_ASYNC_OFF,
+};
+
+static inline void
+timer_action_done (struct ehci_hcd *ehci, enum ehci_timer_action action)
+{
+	clear_bit (action, &ehci->actions);
+}
+
+static inline void
+timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
+{
+	if (!test_and_set_bit (action, &ehci->actions)) {
+		unsigned long t;
+
+		switch (action) {
+		case TIMER_IAA_WATCHDOG:
+			t = EHCI_IAA_JIFFIES;
+			break;
+		case TIMER_IO_WATCHDOG:
+			t = EHCI_IO_JIFFIES;
+			break;
+		case TIMER_ASYNC_OFF:
+			t = EHCI_ASYNC_JIFFIES;
+			break;
+		// case TIMER_ASYNC_SHRINK:
+		default:
+			t = EHCI_SHRINK_JIFFIES;
+			break;
+		}
+		t += jiffies;
+		// all timings except IAA watchdog can be overridden.
+		// async queue SHRINK often precedes IAA.  while it's ready
+		// to go OFF neither can matter, and afterwards the IO
+		// watchdog stops unless there's still periodic traffic.
+		if (action != TIMER_IAA_WATCHDOG
+				&& t > ehci->watchdog.expires
+				&& timer_pending (&ehci->watchdog))
+			return;
+		mod_timer (&ehci->watchdog, t);
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
+
+/* Section 2.2 Host Controller Capability Registers */
+struct ehci_caps {
+	/* these fields are specified as 8 and 16 bit registers,
+	 * but some hosts can't perform 8 or 16 bit PCI accesses.
+	 */
+	u32	hc_capbase;
+#define HC_LENGTH(p)		(((p)>>00)&0x00ff)	/* bits 7:0 */
+#define HC_VERSION(p)		(((p)>>16)&0xffff)	/* bits 31:16 */
+	u32		hcs_params;     /* HCSPARAMS - offset 0x4 */
+#define HCS_DEBUG_PORT(p)	(((p)>>20)&0xf)	/* bits 23:20, debug port? */
+#define HCS_INDICATOR(p)	((p)&(1 << 16))	/* true: has port indicators */
+#define HCS_N_CC(p)		(((p)>>12)&0xf)	/* bits 15:12, #companion HCs */
+#define HCS_N_PCC(p)		(((p)>>8)&0xf)	/* bits 11:8, ports per CC */
+#define HCS_PORTROUTED(p)	((p)&(1 << 7))	/* true: port routing */ 
+#define HCS_PPC(p)		((p)&(1 << 4))	/* true: port power control */ 
+#define HCS_N_PORTS(p)		(((p)>>0)&0xf)	/* bits 3:0, ports on HC */
+
+	u32		hcc_params;      /* HCCPARAMS - offset 0x8 */
+#define HCC_EXT_CAPS(p)		(((p)>>8)&0xff)	/* for pci extended caps */
+#define HCC_ISOC_CACHE(p)       ((p)&(1 << 7))  /* true: can cache isoc frame */
+#define HCC_ISOC_THRES(p)       (((p)>>4)&0x7)  /* bits 6:4, uframes cached */
+#define HCC_CANPARK(p)		((p)&(1 << 2))  /* true: can park on async qh */
+#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1))  /* true: periodic_size changes*/
+#define HCC_64BIT_ADDR(p)       ((p)&(1))       /* true: can use 64-bit addr */
+	u8		portroute [8];	 /* nibbles for routing - offset 0xC */
+} __attribute__ ((packed));
+
+
+/* Section 2.3 Host Controller Operational Registers */
+struct ehci_regs {
+
+	/* USBCMD: offset 0x00 */
+	u32		command;
+/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
+#define CMD_PARK	(1<<11)		/* enable "park" on async qh */
+#define CMD_PARK_CNT(c)	(((c)>>8)&3)	/* how many transfers to park for */
+#define CMD_LRESET	(1<<7)		/* partial reset (no ports, etc) */
+#define CMD_IAAD	(1<<6)		/* "doorbell" interrupt async advance */
+#define CMD_ASE		(1<<5)		/* async schedule enable */
+#define CMD_PSE  	(1<<4)		/* periodic schedule enable */
+/* 3:2 is periodic frame list size */
+#define CMD_RESET	(1<<1)		/* reset HC not bus */
+#define CMD_RUN		(1<<0)		/* start/stop HC */
+
+	/* USBSTS: offset 0x04 */
+	u32		status;
+#define STS_ASS		(1<<15)		/* Async Schedule Status */
+#define STS_PSS		(1<<14)		/* Periodic Schedule Status */
+#define STS_RECL	(1<<13)		/* Reclamation */
+#define STS_HALT	(1<<12)		/* Not running (any reason) */
+/* some bits reserved */
+	/* these STS_* flags are also intr_enable bits (USBINTR) */
+#define STS_IAA		(1<<5)		/* Interrupted on async advance */
+#define STS_FATAL	(1<<4)		/* such as some PCI access errors */
+#define STS_FLR		(1<<3)		/* frame list rolled over */
+#define STS_PCD		(1<<2)		/* port change detect */
+#define STS_ERR		(1<<1)		/* "error" completion (overflow, ...) */
+#define STS_INT		(1<<0)		/* "normal" completion (short, ...) */
+
+	/* USBINTR: offset 0x08 */
+	u32		intr_enable;
+
+	/* FRINDEX: offset 0x0C */
+	u32		frame_index;	/* current microframe number */
+	/* CTRLDSSEGMENT: offset 0x10 */
+	u32		segment; 	/* address bits 63:32 if needed */
+	/* PERIODICLISTBASE: offset 0x14 */
+	u32		frame_list; 	/* points to periodic list */
+	/* ASYNCLISTADDR: offset 0x18 */
+	u32		async_next;	/* address of next async queue head */
+
+	u32		reserved [9];
+
+	/* CONFIGFLAG: offset 0x40 */
+	u32		configured_flag;
+#define FLAG_CF		(1<<0)		/* true: we'll support "high speed" */
+
+	/* PORTSC: offset 0x44 */
+	u32		port_status [0];	/* up to N_PORTS */
+/* 31:23 reserved */
+#define PORT_WKOC_E	(1<<22)		/* wake on overcurrent (enable) */
+#define PORT_WKDISC_E	(1<<21)		/* wake on disconnect (enable) */
+#define PORT_WKCONN_E	(1<<20)		/* wake on connect (enable) */
+/* 19:16 for port testing */
+#define PORT_LED_OFF	(0<<14)
+#define PORT_LED_AMBER	(1<<14)
+#define PORT_LED_GREEN	(2<<14)
+#define PORT_LED_MASK	(3<<14)
+#define PORT_OWNER	(1<<13)		/* true: companion hc owns this port */
+#define PORT_POWER	(1<<12)		/* true: has power (see PPC) */
+#define PORT_USB11(x) (((x)&(3<<10))==(1<<10))	/* USB 1.1 device */
+/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
+/* 9 reserved */
+#define PORT_RESET	(1<<8)		/* reset port */
+#define PORT_SUSPEND	(1<<7)		/* suspend port */
+#define PORT_RESUME	(1<<6)		/* resume it */
+#define PORT_OCC	(1<<5)		/* over current change */
+#define PORT_OC		(1<<4)		/* over current active */
+#define PORT_PEC	(1<<3)		/* port enable change */
+#define PORT_PE		(1<<2)		/* port enable */
+#define PORT_CSC	(1<<1)		/* connect status change */
+#define PORT_CONNECT	(1<<0)		/* device connected */
+} __attribute__ ((packed));
+
+/* Appendix C, Debug port ... intended for use with special "debug devices"
+ * that can help if there's no serial console.  (nonstandard enumeration.)
+ */
+struct ehci_dbg_port {
+	u32	control;
+#define DBGP_OWNER	(1<<30)
+#define DBGP_ENABLED	(1<<28)
+#define DBGP_DONE	(1<<16)
+#define DBGP_INUSE	(1<<10)
+#define DBGP_ERRCODE(x)	(((x)>>7)&0x0f)
+#	define DBGP_ERR_BAD	1
+#	define DBGP_ERR_SIGNAL	2
+#define DBGP_ERROR	(1<<6)
+#define DBGP_GO		(1<<5)
+#define DBGP_OUT	(1<<4)
+#define DBGP_LEN(x)	(((x)>>0)&0x0f)
+	u32	pids;
+#define DBGP_PID_GET(x)		(((x)>>16)&0xff)
+#define DBGP_PID_SET(data,tok)	(((data)<<8)|(tok));
+	u32	data03;
+	u32	data47;
+	u32	address;
+#define DBGP_EPADDR(dev,ep)	(((dev)<<8)|(ep));
+} __attribute__ ((packed));
+
+/*-------------------------------------------------------------------------*/
+
+#define	QTD_NEXT(dma)	cpu_to_le32((u32)dma)
+
+/*
+ * EHCI Specification 0.95 Section 3.5
+ * QTD: describe data transfer components (buffer, direction, ...) 
+ * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
+ *
+ * These are associated only with "QH" (Queue Head) structures,
+ * used with control, bulk, and interrupt transfers.
+ */
+struct ehci_qtd {
+	/* first part defined by EHCI spec */
+	__le32			hw_next;	  /* see EHCI 3.5.1 */
+	__le32			hw_alt_next;      /* see EHCI 3.5.2 */
+	__le32			hw_token;         /* see EHCI 3.5.3 */       
+#define	QTD_TOGGLE	(1 << 31)	/* data toggle */
+#define	QTD_LENGTH(tok)	(((tok)>>16) & 0x7fff)
+#define	QTD_IOC		(1 << 15)	/* interrupt on complete */
+#define	QTD_CERR(tok)	(((tok)>>10) & 0x3)
+#define	QTD_PID(tok)	(((tok)>>8) & 0x3)
+#define	QTD_STS_ACTIVE	(1 << 7)	/* HC may execute this */
+#define	QTD_STS_HALT	(1 << 6)	/* halted on error */
+#define	QTD_STS_DBE	(1 << 5)	/* data buffer error (in HC) */
+#define	QTD_STS_BABBLE	(1 << 4)	/* device was babbling (qtd halted) */
+#define	QTD_STS_XACT	(1 << 3)	/* device gave illegal response */
+#define	QTD_STS_MMF	(1 << 2)	/* incomplete split transaction */
+#define	QTD_STS_STS	(1 << 1)	/* split transaction state */
+#define	QTD_STS_PING	(1 << 0)	/* issue PING? */
+	__le32			hw_buf [5];        /* see EHCI 3.5.4 */
+	__le32			hw_buf_hi [5];        /* Appendix B */
+
+	/* the rest is HCD-private */
+	dma_addr_t		qtd_dma;		/* qtd address */
+	struct list_head	qtd_list;		/* sw qtd list */
+	struct urb		*urb;			/* qtd's urb */
+	size_t			length;			/* length of buffer */
+} __attribute__ ((aligned (32)));
+
+/* mask NakCnt+T in qh->hw_alt_next */
+#define QTD_MASK __constant_cpu_to_le32 (~0x1f)
+
+#define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1)
+
+/*-------------------------------------------------------------------------*/
+
+/* type tag from {qh,itd,sitd,fstn}->hw_next */
+#define Q_NEXT_TYPE(dma) ((dma) & __constant_cpu_to_le32 (3 << 1))
+
+/* values for that type tag */
+#define Q_TYPE_ITD	__constant_cpu_to_le32 (0 << 1)
+#define Q_TYPE_QH	__constant_cpu_to_le32 (1 << 1)
+#define Q_TYPE_SITD 	__constant_cpu_to_le32 (2 << 1)
+#define Q_TYPE_FSTN 	__constant_cpu_to_le32 (3 << 1)
+
+/* next async queue entry, or pointer to interrupt/periodic QH */
+#define	QH_NEXT(dma)	(cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH)
+
+/* for periodic/async schedules and qtd lists, mark end of list */
+#define	EHCI_LIST_END	__constant_cpu_to_le32(1) /* "null pointer" to hw */
+
+/*
+ * Entries in periodic shadow table are pointers to one of four kinds
+ * of data structure.  That's dictated by the hardware; a type tag is
+ * encoded in the low bits of the hardware's periodic schedule.  Use
+ * Q_NEXT_TYPE to get the tag.
+ *
+ * For entries in the async schedule, the type tag always says "qh".
+ */
+union ehci_shadow {
+	struct ehci_qh 		*qh;		/* Q_TYPE_QH */
+	struct ehci_itd		*itd;		/* Q_TYPE_ITD */
+	struct ehci_sitd	*sitd;		/* Q_TYPE_SITD */
+	struct ehci_fstn	*fstn;		/* Q_TYPE_FSTN */
+	u32			*hw_next;	/* (all types) */
+	void			*ptr;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.6
+ * QH: describes control/bulk/interrupt endpoints
+ * See Fig 3-7 "Queue Head Structure Layout".
+ *
+ * These appear in both the async and (for interrupt) periodic schedules.
+ */
+
+struct ehci_qh {
+	/* first part defined by EHCI spec */
+	__le32			hw_next;	 /* see EHCI 3.6.1 */
+	__le32			hw_info1;        /* see EHCI 3.6.2 */
+#define	QH_HEAD		0x00008000
+	__le32			hw_info2;        /* see EHCI 3.6.2 */
+	__le32			hw_current;	 /* qtd list - see EHCI 3.6.4 */
+	
+	/* qtd overlay (hardware parts of a struct ehci_qtd) */
+	__le32			hw_qtd_next;
+	__le32			hw_alt_next;
+	__le32			hw_token;
+	__le32			hw_buf [5];
+	__le32			hw_buf_hi [5];
+
+	/* the rest is HCD-private */
+	dma_addr_t		qh_dma;		/* address of qh */
+	union ehci_shadow	qh_next;	/* ptr to qh; or periodic */
+	struct list_head	qtd_list;	/* sw qtd list */
+	struct ehci_qtd		*dummy;
+	struct ehci_qh		*reclaim;	/* next to reclaim */
+
+	struct ehci_hcd		*ehci;
+	struct kref		kref;
+	unsigned		stamp;
+
+	u8			qh_state;
+#define	QH_STATE_LINKED		1		/* HC sees this */
+#define	QH_STATE_UNLINK		2		/* HC may still see this */
+#define	QH_STATE_IDLE		3		/* HC doesn't see this */
+#define	QH_STATE_UNLINK_WAIT	4		/* LINKED and on reclaim q */
+#define	QH_STATE_COMPLETING	5		/* don't touch token.HALT */
+
+	/* periodic schedule info */
+	u8			usecs;		/* intr bandwidth */
+	u8			gap_uf;		/* uframes split/csplit gap */
+	u8			c_usecs;	/* ... split completion bw */
+	unsigned short		period;		/* polling interval */
+	unsigned short		start;		/* where polling starts */
+#define NO_FRAME ((unsigned short)~0)			/* pick new start */
+	struct usb_device	*dev;		/* access to TT */
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+/* description of one iso transaction (up to 3 KB data if highspeed) */
+struct ehci_iso_packet {
+	/* These will be copied to iTD when scheduling */
+	u64			bufp;		/* itd->hw_bufp{,_hi}[pg] |= */
+	__le32			transaction;	/* itd->hw_transaction[i] |= */
+	u8			cross;		/* buf crosses pages */
+	/* for full speed OUT splits */
+	u32			buf1;
+};
+
+/* temporary schedule data for packets from iso urbs (both speeds)
+ * each packet is one logical usb transaction to the device (not TT),
+ * beginning at stream->next_uframe
+ */
+struct ehci_iso_sched {
+	struct list_head	td_list;
+	unsigned		span;
+	struct ehci_iso_packet	packet [0];
+};
+
+/*
+ * ehci_iso_stream - groups all (s)itds for this endpoint.
+ * acts like a qh would, if EHCI had them for ISO.
+ */
+struct ehci_iso_stream {
+	/* first two fields match QH, but info1 == 0 */
+	__le32			hw_next;
+	__le32			hw_info1;
+
+	u32			refcount;
+	u8			bEndpointAddress;
+	u8			highspeed;
+	u16			depth;		/* depth in uframes */
+	struct list_head	td_list;	/* queued itds/sitds */
+	struct list_head	free_list;	/* list of unused itds/sitds */
+	struct usb_device	*udev;
+ 	struct usb_host_endpoint *ep;
+
+	/* output of (re)scheduling */
+	unsigned long		start;		/* jiffies */
+	unsigned long		rescheduled;
+	int			next_uframe;
+	__le32			splits;
+
+	/* the rest is derived from the endpoint descriptor,
+	 * trusting urb->interval == f(epdesc->bInterval) and
+	 * including the extra info for hw_bufp[0..2]
+	 */
+	u8			interval;
+	u8			usecs, c_usecs;
+	u16			maxp;
+	u16			raw_mask;
+	unsigned		bandwidth;
+
+	/* This is used to initialize iTD's hw_bufp fields */
+	__le32			buf0;		
+	__le32			buf1;		
+	__le32			buf2;
+
+	/* this is used to initialize sITD's tt info */
+	__le32			address;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.3
+ * Fig 3-4 "Isochronous Transaction Descriptor (iTD)"
+ *
+ * Schedule records for high speed iso xfers
+ */
+struct ehci_itd {
+	/* first part defined by EHCI spec */
+	__le32			hw_next;           /* see EHCI 3.3.1 */
+	__le32			hw_transaction [8]; /* see EHCI 3.3.2 */
+#define EHCI_ISOC_ACTIVE        (1<<31)        /* activate transfer this slot */
+#define EHCI_ISOC_BUF_ERR       (1<<30)        /* Data buffer error */
+#define EHCI_ISOC_BABBLE        (1<<29)        /* babble detected */
+#define EHCI_ISOC_XACTERR       (1<<28)        /* XactErr - transaction error */
+#define	EHCI_ITD_LENGTH(tok)	(((tok)>>16) & 0x0fff)
+#define	EHCI_ITD_IOC		(1 << 15)	/* interrupt on complete */
+
+#define ITD_ACTIVE	__constant_cpu_to_le32(EHCI_ISOC_ACTIVE)
+
+	__le32			hw_bufp [7];	/* see EHCI 3.3.3 */ 
+	__le32			hw_bufp_hi [7];	/* Appendix B */
+
+	/* the rest is HCD-private */
+	dma_addr_t		itd_dma;	/* for this itd */
+	union ehci_shadow	itd_next;	/* ptr to periodic q entry */
+
+	struct urb		*urb;
+	struct ehci_iso_stream	*stream;	/* endpoint's queue */
+	struct list_head	itd_list;	/* list of stream's itds */
+
+	/* any/all hw_transactions here may be used by that urb */
+	unsigned		frame;		/* where scheduled */
+	unsigned		pg;
+	unsigned		index[8];	/* in urb->iso_frame_desc */
+	u8			usecs[8];
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.4 
+ * siTD, aka split-transaction isochronous Transfer Descriptor
+ *       ... describe full speed iso xfers through TT in hubs
+ * see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD)
+ */
+struct ehci_sitd {
+	/* first part defined by EHCI spec */
+	__le32			hw_next;
+/* uses bit field macros above - see EHCI 0.95 Table 3-8 */
+	__le32			hw_fullspeed_ep;	/* EHCI table 3-9 */
+	__le32			hw_uframe;		/* EHCI table 3-10 */
+	__le32			hw_results;		/* EHCI table 3-11 */
+#define	SITD_IOC	(1 << 31)	/* interrupt on completion */
+#define	SITD_PAGE	(1 << 30)	/* buffer 0/1 */
+#define	SITD_LENGTH(x)	(0x3ff & ((x)>>16))
+#define	SITD_STS_ACTIVE	(1 << 7)	/* HC may execute this */
+#define	SITD_STS_ERR	(1 << 6)	/* error from TT */
+#define	SITD_STS_DBE	(1 << 5)	/* data buffer error (in HC) */
+#define	SITD_STS_BABBLE	(1 << 4)	/* device was babbling */
+#define	SITD_STS_XACT	(1 << 3)	/* illegal IN response */
+#define	SITD_STS_MMF	(1 << 2)	/* incomplete split transaction */
+#define	SITD_STS_STS	(1 << 1)	/* split transaction state */
+
+#define SITD_ACTIVE	__constant_cpu_to_le32(SITD_STS_ACTIVE)
+
+	__le32			hw_buf [2];		/* EHCI table 3-12 */
+	__le32			hw_backpointer;		/* EHCI table 3-13 */
+	__le32			hw_buf_hi [2];		/* Appendix B */
+
+	/* the rest is HCD-private */
+	dma_addr_t		sitd_dma;
+	union ehci_shadow	sitd_next;	/* ptr to periodic q entry */
+
+	struct urb		*urb;
+	struct ehci_iso_stream	*stream;	/* endpoint's queue */
+	struct list_head	sitd_list;	/* list of stream's sitds */
+	unsigned		frame;
+	unsigned		index;
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.96 Section 3.7
+ * Periodic Frame Span Traversal Node (FSTN)
+ *
+ * Manages split interrupt transactions (using TT) that span frame boundaries
+ * into uframes 0/1; see 4.12.2.2.  In those uframes, a "save place" FSTN
+ * makes the HC jump (back) to a QH to scan for fs/ls QH completions until
+ * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
+ */
+struct ehci_fstn {
+	__le32			hw_next;	/* any periodic q entry */
+	__le32			hw_prev;	/* qh or EHCI_LIST_END */
+
+	/* the rest is HCD-private */
+	dma_addr_t		fstn_dma;
+	union ehci_shadow	fstn_next;	/* ptr to periodic q entry */
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_USB_EHCI_ROOT_HUB_TT
+
+/*
+ * Some EHCI controllers have a Transaction Translator built into the
+ * root hub. This is a non-standard feature.  Each controller will need
+ * to add code to the following inline functions, and call them as
+ * needed (mostly in root hub code).
+ */
+
+#define	ehci_is_TDI(e)			((e)->is_tdi_rh_tt)
+
+/* Returns the speed of a device attached to a port on the root hub. */
+static inline unsigned int
+ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
+{
+	if (ehci_is_TDI(ehci)) {
+		switch ((portsc>>26)&3) {
+		case 0:
+			return 0;
+		case 1:
+			return (1<<USB_PORT_FEAT_LOWSPEED);
+		case 2:
+		default:
+			return (1<<USB_PORT_FEAT_HIGHSPEED);
+		}
+	}
+	return (1<<USB_PORT_FEAT_HIGHSPEED);
+}
+
+#else
+
+#define	ehci_is_TDI(e)			(0)
+
+#define	ehci_port_speed(ehci, portsc)	(1<<USB_PORT_FEAT_HIGHSPEED)
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#ifndef DEBUG
+#define STUB_DEBUG_FILES
+#endif	/* DEBUG */
+
+/*-------------------------------------------------------------------------*/
+
+#endif /* __LINUX_EHCI_HCD_H */
diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c
new file mode 100644
index 0000000..4b12be8
--- /dev/null
+++ b/drivers/usb/host/hc_crisv10.c
@@ -0,0 +1,4556 @@
+/*
+ * usb-host.c: ETRAX 100LX USB Host Controller Driver (HCD)
+ *
+ * Copyright (c) 2002, 2003 Axis Communications AB.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/arch/svinto.h>
+
+#include <linux/usb.h>
+/* Ugly include because we don't live with the other host drivers. */
+#include <../drivers/usb/core/hcd.h>
+#include <../drivers/usb/core/usb.h>
+
+#include "hc_crisv10.h"
+
+#define ETRAX_USB_HC_IRQ USB_HC_IRQ_NBR
+#define ETRAX_USB_RX_IRQ USB_DMA_RX_IRQ_NBR
+#define ETRAX_USB_TX_IRQ USB_DMA_TX_IRQ_NBR
+
+static const char *usb_hcd_version = "$Revision: 1.2 $";
+
+#undef KERN_DEBUG
+#define KERN_DEBUG ""
+
+
+#undef USB_DEBUG_RH
+#undef USB_DEBUG_EPID
+#undef USB_DEBUG_SB
+#undef USB_DEBUG_DESC
+#undef USB_DEBUG_URB
+#undef USB_DEBUG_TRACE
+#undef USB_DEBUG_BULK
+#undef USB_DEBUG_CTRL
+#undef USB_DEBUG_INTR
+#undef USB_DEBUG_ISOC
+
+#ifdef USB_DEBUG_RH
+#define dbg_rh(format, arg...) printk(KERN_DEBUG __FILE__ ": (RH) " format "\n" , ## arg)
+#else
+#define dbg_rh(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_EPID
+#define dbg_epid(format, arg...) printk(KERN_DEBUG __FILE__ ": (EPID) " format "\n" , ## arg)
+#else
+#define dbg_epid(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_SB
+#define dbg_sb(format, arg...) printk(KERN_DEBUG __FILE__ ": (SB) " format "\n" , ## arg)
+#else
+#define dbg_sb(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_CTRL
+#define dbg_ctrl(format, arg...) printk(KERN_DEBUG __FILE__ ": (CTRL) " format "\n" , ## arg)
+#else
+#define dbg_ctrl(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_BULK
+#define dbg_bulk(format, arg...) printk(KERN_DEBUG __FILE__ ": (BULK) " format "\n" , ## arg)
+#else
+#define dbg_bulk(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_INTR
+#define dbg_intr(format, arg...) printk(KERN_DEBUG __FILE__ ": (INTR) " format "\n" , ## arg)
+#else
+#define dbg_intr(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_ISOC
+#define dbg_isoc(format, arg...) printk(KERN_DEBUG __FILE__ ": (ISOC) " format "\n" , ## arg)
+#else
+#define dbg_isoc(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_TRACE
+#define DBFENTER (printk(": Entering: %s\n", __FUNCTION__))
+#define DBFEXIT  (printk(": Exiting:  %s\n", __FUNCTION__))
+#else
+#define DBFENTER do {} while (0)
+#define DBFEXIT  do {} while (0)
+#endif
+
+#define usb_pipeslow(pipe)	(((pipe) >> 26) & 1)
+
+/*-------------------------------------------------------------------
+ Virtual Root Hub
+ -------------------------------------------------------------------*/
+
+static __u8 root_hub_dev_des[] =
+{
+	0x12,  /*  __u8  bLength; */
+	0x01,  /*  __u8  bDescriptorType; Device */
+	0x00,  /*  __le16 bcdUSB; v1.0 */
+	0x01,
+	0x09,  /*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,  /*  __u8  bDeviceSubClass; */
+	0x00,  /*  __u8  bDeviceProtocol; */
+	0x08,  /*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x00,  /*  __le16 idVendor; */
+	0x00,
+	0x00,  /*  __le16 idProduct; */
+	0x00,
+	0x00,  /*  __le16 bcdDevice; */
+	0x00,
+	0x00,  /*  __u8  iManufacturer; */
+	0x02,  /*  __u8  iProduct; */
+	0x01,  /*  __u8  iSerialNumber; */
+	0x01   /*  __u8  bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+	0x09,  /*  __u8  bLength; */
+	0x02,  /*  __u8  bDescriptorType; Configuration */
+	0x19,  /*  __le16 wTotalLength; */
+	0x00,
+	0x01,  /*  __u8  bNumInterfaces; */
+	0x01,  /*  __u8  bConfigurationValue; */
+	0x00,  /*  __u8  iConfiguration; */
+	0x40,  /*  __u8  bmAttributes; Bit 7: Bus-powered */
+	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,  /*  __le16 ep_wMaxPacketSize; 8 Bytes */
+	0x00,
+	0xff   /*  __u8  ep_bInterval; 255 ms */
+};
+
+static __u8 root_hub_hub_des[] =
+{
+	0x09,  /*  __u8  bLength; */
+	0x29,  /*  __u8  bDescriptorType; Hub-descriptor */
+	0x02,  /*  __u8  bNbrPorts; */
+	0x00,  /* __u16  wHubCharacteristics; */
+	0x00,
+	0x01,  /*  __u8  bPwrOn2pwrGood; 2ms */
+	0x00,  /*  __u8  bHubContrCurrent; 0 mA */
+	0x00,  /*  __u8  DeviceRemovable; *** 7 Ports max *** */
+	0xff   /*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+static struct timer_list bulk_start_timer = TIMER_INITIALIZER(NULL, 0, 0);
+static struct timer_list bulk_eot_timer = TIMER_INITIALIZER(NULL, 0, 0);
+
+/* We want the start timer to expire before the eot timer, because the former might start
+   traffic, thus making it unnecessary for the latter to time out. */
+#define BULK_START_TIMER_INTERVAL (HZ/10) /* 100 ms */
+#define BULK_EOT_TIMER_INTERVAL (HZ/10+2) /* 120 ms */
+
+#define OK(x) len = (x); dbg_rh("OK(%d): line: %d", x, __LINE__); break
+#define CHECK_ALIGN(x) if (((__u32)(x)) & 0x00000003) \
+{panic("Alignment check (DWORD) failed at %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);}
+
+#define SLAB_FLAG     (in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL)
+#define KMALLOC_FLAG  (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)
+
+/* Most helpful debugging aid */
+#define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__))))
+
+/* Alternative assert define which stops after a failed assert. */
+/*
+#define assert(expr)                                      \
+{                                                         \
+        if (!(expr)) {                                    \
+                err("assert failed at line %d",__LINE__); \
+                while (1);                                \
+        }                                                 \
+}
+*/
+
+
+/* FIXME: Should RX_BUF_SIZE be a config option, or maybe we should adjust it dynamically?
+   To adjust it dynamically we would have to get an interrupt when we reach the end
+   of the rx descriptor list, or when we get close to the end, and then allocate more
+   descriptors. */
+
+#define NBR_OF_RX_DESC     512
+#define RX_DESC_BUF_SIZE   1024
+#define RX_BUF_SIZE        (NBR_OF_RX_DESC * RX_DESC_BUF_SIZE)
+
+/* The number of epids is, among other things, used for pre-allocating
+   ctrl, bulk and isoc EP descriptors (one for each epid).
+   Assumed to be > 1 when initiating the DMA lists. */
+#define NBR_OF_EPIDS       32
+
+/* Support interrupt traffic intervals up to 128 ms. */
+#define MAX_INTR_INTERVAL 128
+
+/* If periodic traffic (intr or isoc) is to be used, then one entry in the EP table
+   must be "invalid". By this we mean that we shouldn't care about epid attentions
+   for this epid, or at least handle them differently from epid attentions for "valid"
+   epids. This define determines which one to use (don't change it). */
+#define INVALID_EPID     31
+/* A special epid for the bulk dummys. */
+#define DUMMY_EPID       30
+
+/* This is just a software cache for the valid entries in R_USB_EPT_DATA. */
+static __u32 epid_usage_bitmask;
+
+/* A bitfield to keep information on in/out traffic is needed to uniquely identify
+   an endpoint on a device, since the most significant bit which indicates traffic
+   direction is lacking in the ep_id field (ETRAX epids can handle both in and
+   out traffic on endpoints that are otherwise identical). The USB framework, however,
+   relies on them to be handled separately.  For example, bulk IN and OUT urbs cannot
+   be queued in the same list, since they would block each other. */
+static __u32 epid_out_traffic;
+
+/* DMA IN cache bug. Align the DMA IN buffers to 32 bytes, i.e. a cache line.
+   Since RX_DESC_BUF_SIZE is 1024 is a multiple of 32, all rx buffers will be cache aligned. */
+static volatile unsigned char RxBuf[RX_BUF_SIZE] __attribute__ ((aligned (32)));
+static volatile USB_IN_Desc_t RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned (4)));
+
+/* Pointers into RxDescList. */
+static volatile USB_IN_Desc_t *myNextRxDesc;
+static volatile USB_IN_Desc_t *myLastRxDesc;
+static volatile USB_IN_Desc_t *myPrevRxDesc;
+
+/* EP descriptors must be 32-bit aligned. */
+static volatile USB_EP_Desc_t TxCtrlEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
+static volatile USB_EP_Desc_t TxBulkEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
+/* After each enabled bulk EP (IN or OUT) we put two disabled EP descriptors with the eol flag set,
+   causing the DMA to stop the DMA channel. The first of these two has the intr flag set, which
+   gives us a dma8_sub0_descr interrupt. When we receive this, we advance the DMA one step in the
+   EP list and then restart the bulk channel, thus forcing a switch between bulk EP descriptors
+   in each frame. */
+static volatile USB_EP_Desc_t TxBulkDummyEPList[NBR_OF_EPIDS][2] __attribute__ ((aligned (4)));
+
+static volatile USB_EP_Desc_t TxIsocEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
+static volatile USB_SB_Desc_t TxIsocSB_zout __attribute__ ((aligned (4)));
+
+static volatile USB_EP_Desc_t TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4)));
+static volatile USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4)));
+
+/* A zout transfer makes a memory access at the address of its buf pointer, which means that setting
+   this buf pointer to 0 will cause an access to the flash. In addition to this, setting sw_len to 0
+   results in a 16/32 bytes (depending on DMA burst size) transfer. Instead, we set it to 1, and point
+   it to this buffer. */
+static int zout_buffer[4] __attribute__ ((aligned (4)));
+
+/* Cache for allocating new EP and SB descriptors. */
+static kmem_cache_t *usb_desc_cache;
+
+/* Cache for the registers allocated in the top half. */
+static kmem_cache_t *top_half_reg_cache;
+
+/* Cache for the data allocated in the isoc descr top half. */
+static kmem_cache_t *isoc_compl_cache;
+
+static struct usb_bus *etrax_usb_bus;
+
+/* This is a circular (double-linked) list of the active urbs for each epid.
+   The head is never removed, and new urbs are linked onto the list as
+   urb_entry_t elements. Don't reference urb_list directly; use the wrapper
+   functions instead. Note that working with these lists might require spinlock
+   protection. */
+static struct list_head urb_list[NBR_OF_EPIDS];
+
+/* Read about the need and usage of this lock in submit_ctrl_urb. */
+static spinlock_t urb_list_lock;
+
+/* Used when unlinking asynchronously. */
+static struct list_head urb_unlink_list;
+
+/* for returning string descriptors in UTF-16LE */
+static int ascii2utf (char *ascii, __u8 *utf, int utfmax)
+{
+	int retval;
+
+	for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
+		*utf++ = *ascii++ & 0x7f;
+		*utf++ = 0;
+	}
+	return retval;
+}
+
+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;
+
+	data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
+	data [1] = 3;
+	return data [0];
+}
+
+/* Wrappers around the list functions (include/linux/list.h). */
+
+static inline int urb_list_empty(int epid)
+{
+	return list_empty(&urb_list[epid]);
+}
+
+/* Returns first urb for this epid, or NULL if list is empty. */
+static inline struct urb *urb_list_first(int epid)
+{
+	struct urb *first_urb = 0;
+
+	if (!urb_list_empty(epid)) {
+		/* Get the first urb (i.e. head->next). */
+		urb_entry_t *urb_entry = list_entry((&urb_list[epid])->next, urb_entry_t, list);
+		first_urb = urb_entry->urb;
+	}
+	return first_urb;
+}
+
+/* Adds an urb_entry last in the list for this epid. */
+static inline void urb_list_add(struct urb *urb, int epid)
+{
+	urb_entry_t *urb_entry = (urb_entry_t *)kmalloc(sizeof(urb_entry_t), KMALLOC_FLAG);
+	assert(urb_entry);
+
+	urb_entry->urb = urb;
+	list_add_tail(&urb_entry->list, &urb_list[epid]);
+}
+
+/* Search through the list for an element that contains this urb. (The list
+   is expected to be short and the one we are about to delete will often be
+   the first in the list.) */
+static inline urb_entry_t *__urb_list_entry(struct urb *urb, int epid)
+{
+	struct list_head *entry;
+	struct list_head *tmp;
+	urb_entry_t *urb_entry;
+
+	list_for_each_safe(entry, tmp, &urb_list[epid]) {
+		urb_entry = list_entry(entry, urb_entry_t, list);
+		assert(urb_entry);
+		assert(urb_entry->urb);
+
+		if (urb_entry->urb == urb) {
+			return urb_entry;
+		}
+	}
+	return 0;
+}
+
+/* Delete an urb from the list. */
+static inline void urb_list_del(struct urb *urb, int epid)
+{
+	urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
+	assert(urb_entry);
+
+	/* Delete entry and free. */
+	list_del(&urb_entry->list);
+	kfree(urb_entry);
+}
+
+/* Move an urb to the end of the list. */
+static inline void urb_list_move_last(struct urb *urb, int epid)
+{
+	urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
+	assert(urb_entry);
+
+	list_del(&urb_entry->list);
+	list_add_tail(&urb_entry->list, &urb_list[epid]);
+}
+
+/* Get the next urb in the list. */
+static inline struct urb *urb_list_next(struct urb *urb, int epid)
+{
+	urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
+
+	assert(urb_entry);
+
+	if (urb_entry->list.next != &urb_list[epid]) {
+		struct list_head *elem = urb_entry->list.next;
+		urb_entry = list_entry(elem, urb_entry_t, list);
+		return urb_entry->urb;
+	} else {
+		return NULL;
+	}
+}
+
+
+
+/* For debug purposes only. */
+static inline void urb_list_dump(int epid)
+{
+	struct list_head *entry;
+	struct list_head *tmp;
+	urb_entry_t *urb_entry;
+	int i = 0;
+
+	info("Dumping urb list for epid %d", epid);
+
+	list_for_each_safe(entry, tmp, &urb_list[epid]) {
+		urb_entry = list_entry(entry, urb_entry_t, list);
+		info("   entry %d, urb = 0x%lx", i, (unsigned long)urb_entry->urb);
+	}
+}
+
+static void init_rx_buffers(void);
+static int etrax_rh_unlink_urb(struct urb *urb);
+static void etrax_rh_send_irq(struct urb *urb);
+static void etrax_rh_init_int_timer(struct urb *urb);
+static void etrax_rh_int_timer_do(unsigned long ptr);
+
+static int etrax_usb_setup_epid(struct urb *urb);
+static int etrax_usb_lookup_epid(struct urb *urb);
+static int etrax_usb_allocate_epid(void);
+static void etrax_usb_free_epid(int epid);
+
+static int etrax_remove_from_sb_list(struct urb *urb);
+
+static void* etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, int mem_flags, dma_addr_t *dma);
+static void etrax_usb_buffer_free(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma);
+
+static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid);
+static void etrax_usb_add_to_ctrl_sb_list(struct urb *urb, int epid);
+static void etrax_usb_add_to_intr_sb_list(struct urb *urb, int epid);
+static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid);
+
+static int etrax_usb_submit_bulk_urb(struct urb *urb);
+static int etrax_usb_submit_ctrl_urb(struct urb *urb);
+static int etrax_usb_submit_intr_urb(struct urb *urb);
+static int etrax_usb_submit_isoc_urb(struct urb *urb);
+
+static int etrax_usb_submit_urb(struct urb *urb, int mem_flags);
+static int etrax_usb_unlink_urb(struct urb *urb, int status);
+static int etrax_usb_get_frame_number(struct usb_device *usb_dev);
+
+static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs);
+static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs);
+static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc, struct pt_regs *regs);
+static void etrax_usb_hc_interrupt_bottom_half(void *data);
+
+static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data);
+
+
+/* The following is a list of interrupt handlers for the host controller interrupts we use.
+   They are called from etrax_usb_hc_interrupt_bottom_half. */
+static void etrax_usb_hc_isoc_eof_interrupt(void);
+static void etrax_usb_hc_bulk_eot_interrupt(int timer_induced);
+static void etrax_usb_hc_epid_attn_interrupt(usb_interrupt_registers_t *reg);
+static void etrax_usb_hc_port_status_interrupt(usb_interrupt_registers_t *reg);
+static void etrax_usb_hc_ctl_status_interrupt(usb_interrupt_registers_t *reg);
+
+static int etrax_rh_submit_urb (struct urb *urb);
+
+/* Forward declaration needed because they are used in the rx interrupt routine. */
+static void etrax_usb_complete_urb(struct urb *urb, int status);
+static void etrax_usb_complete_bulk_urb(struct urb *urb, int status);
+static void etrax_usb_complete_ctrl_urb(struct urb *urb, int status);
+static void etrax_usb_complete_intr_urb(struct urb *urb, int status);
+static void etrax_usb_complete_isoc_urb(struct urb *urb, int status);
+
+static int etrax_usb_hc_init(void);
+static void etrax_usb_hc_cleanup(void);
+
+static struct usb_operations etrax_usb_device_operations =
+{
+	.get_frame_number = etrax_usb_get_frame_number,
+	.submit_urb = etrax_usb_submit_urb,
+	.unlink_urb = etrax_usb_unlink_urb,
+        .buffer_alloc = etrax_usb_buffer_alloc,
+        .buffer_free = etrax_usb_buffer_free
+};
+
+/* Note that these functions are always available in their "__" variants, for use in
+   error situations. The "__" missing variants are controlled by the USB_DEBUG_DESC/
+   USB_DEBUG_URB macros. */
+static void __dump_urb(struct urb* purb)
+{
+	printk("\nurb                  :0x%08lx\n", (unsigned long)purb);
+	printk("dev                   :0x%08lx\n", (unsigned long)purb->dev);
+	printk("pipe                  :0x%08x\n", purb->pipe);
+	printk("status                :%d\n", purb->status);
+	printk("transfer_flags        :0x%08x\n", purb->transfer_flags);
+	printk("transfer_buffer       :0x%08lx\n", (unsigned long)purb->transfer_buffer);
+	printk("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
+	printk("actual_length         :%d\n", purb->actual_length);
+	printk("setup_packet          :0x%08lx\n", (unsigned long)purb->setup_packet);
+	printk("start_frame           :%d\n", purb->start_frame);
+	printk("number_of_packets     :%d\n", purb->number_of_packets);
+	printk("interval              :%d\n", purb->interval);
+	printk("error_count           :%d\n", purb->error_count);
+	printk("context               :0x%08lx\n", (unsigned long)purb->context);
+	printk("complete              :0x%08lx\n\n", (unsigned long)purb->complete);
+}
+
+static void __dump_in_desc(volatile USB_IN_Desc_t *in)
+{
+	printk("\nUSB_IN_Desc at 0x%08lx\n", (unsigned long)in);
+	printk("  sw_len  : 0x%04x (%d)\n", in->sw_len, in->sw_len);
+	printk("  command : 0x%04x\n", in->command);
+	printk("  next    : 0x%08lx\n", in->next);
+	printk("  buf     : 0x%08lx\n", in->buf);
+	printk("  hw_len  : 0x%04x (%d)\n", in->hw_len, in->hw_len);
+	printk("  status  : 0x%04x\n\n", in->status);
+}
+
+static void __dump_sb_desc(volatile USB_SB_Desc_t *sb)
+{
+	char tt = (sb->command & 0x30) >> 4;
+	char *tt_string;
+
+	switch (tt) {
+	case 0:
+		tt_string = "zout";
+		break;
+	case 1:
+		tt_string = "in";
+		break;
+	case 2:
+		tt_string = "out";
+		break;
+	case 3:
+		tt_string = "setup";
+		break;
+	default:
+		tt_string = "unknown (weird)";
+	}
+
+	printk("\n   USB_SB_Desc at 0x%08lx\n", (unsigned long)sb);
+	printk("     command : 0x%04x\n", sb->command);
+	printk("        rem     : %d\n", (sb->command & 0x3f00) >> 8);
+	printk("        full    : %d\n", (sb->command & 0x40) >> 6);
+	printk("        tt      : %d (%s)\n", tt, tt_string);
+	printk("        intr    : %d\n", (sb->command & 0x8) >> 3);
+	printk("        eot     : %d\n", (sb->command & 0x2) >> 1);
+	printk("        eol     : %d\n", sb->command & 0x1);
+	printk("     sw_len  : 0x%04x (%d)\n", sb->sw_len, sb->sw_len);
+	printk("     next    : 0x%08lx\n", sb->next);
+	printk("     buf     : 0x%08lx\n\n", sb->buf);
+}
+
+
+static void __dump_ep_desc(volatile USB_EP_Desc_t *ep)
+{
+	printk("\nUSB_EP_Desc at 0x%08lx\n", (unsigned long)ep);
+	printk("  command : 0x%04x\n", ep->command);
+	printk("     ep_id   : %d\n", (ep->command & 0x1f00) >> 8);
+	printk("     enable  : %d\n", (ep->command & 0x10) >> 4);
+	printk("     intr    : %d\n", (ep->command & 0x8) >> 3);
+	printk("     eof     : %d\n", (ep->command & 0x2) >> 1);
+	printk("     eol     : %d\n", ep->command & 0x1);
+	printk("  hw_len  : 0x%04x (%d)\n", ep->hw_len, ep->hw_len);
+	printk("  next    : 0x%08lx\n", ep->next);
+	printk("  sub     : 0x%08lx\n\n", ep->sub);
+}
+
+static inline void __dump_ep_list(int pipe_type)
+{
+	volatile USB_EP_Desc_t *ep;
+	volatile USB_EP_Desc_t *first_ep;
+	volatile USB_SB_Desc_t *sb;
+
+	switch (pipe_type)
+	{
+	case PIPE_BULK:
+		first_ep = &TxBulkEPList[0];
+		break;
+	case PIPE_CONTROL:
+		first_ep = &TxCtrlEPList[0];
+		break;
+	case PIPE_INTERRUPT:
+		first_ep = &TxIntrEPList[0];
+		break;
+	case PIPE_ISOCHRONOUS:
+		first_ep = &TxIsocEPList[0];
+		break;
+	default:
+		warn("Cannot dump unknown traffic type");
+		return;
+	}
+	ep = first_ep;
+
+	printk("\n\nDumping EP list...\n\n");
+
+	do {
+		__dump_ep_desc(ep);
+		/* Cannot phys_to_virt on 0 as it turns into 80000000, which is != 0. */
+		sb = ep->sub ? phys_to_virt(ep->sub) : 0;
+		while (sb) {
+			__dump_sb_desc(sb);
+			sb = sb->next ? phys_to_virt(sb->next) : 0;
+		}
+		ep = (volatile USB_EP_Desc_t *)(phys_to_virt(ep->next));
+
+	} while (ep != first_ep);
+}
+
+static inline void __dump_ept_data(int epid)
+{
+	unsigned long flags;
+	__u32 r_usb_ept_data;
+
+	if (epid < 0 || epid > 31) {
+		printk("Cannot dump ept data for invalid epid %d\n", epid);
+		return;
+	}
+
+	save_flags(flags);
+	cli();
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+	nop();
+	r_usb_ept_data = *R_USB_EPT_DATA;
+	restore_flags(flags);
+
+	printk("\nR_USB_EPT_DATA = 0x%x for epid %d :\n", r_usb_ept_data, epid);
+	if (r_usb_ept_data == 0) {
+		/* No need for more detailed printing. */
+		return;
+	}
+	printk("  valid           : %d\n", (r_usb_ept_data & 0x80000000) >> 31);
+	printk("  hold            : %d\n", (r_usb_ept_data & 0x40000000) >> 30);
+	printk("  error_count_in  : %d\n", (r_usb_ept_data & 0x30000000) >> 28);
+	printk("  t_in            : %d\n", (r_usb_ept_data & 0x08000000) >> 27);
+	printk("  low_speed       : %d\n", (r_usb_ept_data & 0x04000000) >> 26);
+	printk("  port            : %d\n", (r_usb_ept_data & 0x03000000) >> 24);
+	printk("  error_code      : %d\n", (r_usb_ept_data & 0x00c00000) >> 22);
+	printk("  t_out           : %d\n", (r_usb_ept_data & 0x00200000) >> 21);
+	printk("  error_count_out : %d\n", (r_usb_ept_data & 0x00180000) >> 19);
+	printk("  max_len         : %d\n", (r_usb_ept_data & 0x0003f800) >> 11);
+	printk("  ep              : %d\n", (r_usb_ept_data & 0x00000780) >> 7);
+	printk("  dev             : %d\n", (r_usb_ept_data & 0x0000003f));
+}
+
+static inline void __dump_ept_data_list(void)
+{
+	int i;
+
+	printk("Dumping the whole R_USB_EPT_DATA list\n");
+
+	for (i = 0; i < 32; i++) {
+		__dump_ept_data(i);
+	}
+}
+#ifdef USB_DEBUG_DESC
+#define dump_in_desc(...) __dump_in_desc(...)
+#define dump_sb_desc(...) __dump_sb_desc(...)
+#define dump_ep_desc(...) __dump_ep_desc(...)
+#else
+#define dump_in_desc(...) do {} while (0)
+#define dump_sb_desc(...) do {} while (0)
+#define dump_ep_desc(...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_URB
+#define dump_urb(x)     __dump_urb(x)
+#else
+#define dump_urb(x)     do {} while (0)
+#endif
+
+static void init_rx_buffers(void)
+{
+	int i;
+
+	DBFENTER;
+
+	for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) {
+		RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
+		RxDescList[i].command = 0;
+		RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]);
+		RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE));
+		RxDescList[i].hw_len = 0;
+		RxDescList[i].status = 0;
+
+		/* DMA IN cache bug. (struct etrax_dma_descr has the same layout as USB_IN_Desc
+		   for the relevant fields.) */
+		prepare_rx_descriptor((struct etrax_dma_descr*)&RxDescList[i]);
+
+	}
+
+	RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
+	RxDescList[i].command = IO_STATE(USB_IN_command, eol, yes);
+	RxDescList[i].next = virt_to_phys(&RxDescList[0]);
+	RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE));
+	RxDescList[i].hw_len = 0;
+	RxDescList[i].status = 0;
+
+	myNextRxDesc = &RxDescList[0];
+	myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
+	myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
+
+	*R_DMA_CH9_FIRST = virt_to_phys(myNextRxDesc);
+	*R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, start);
+
+	DBFEXIT;
+}
+
+static void init_tx_bulk_ep(void)
+{
+	int i;
+
+	DBFENTER;
+
+	for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
+		CHECK_ALIGN(&TxBulkEPList[i]);
+		TxBulkEPList[i].hw_len = 0;
+		TxBulkEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
+		TxBulkEPList[i].sub = 0;
+		TxBulkEPList[i].next = virt_to_phys(&TxBulkEPList[i + 1]);
+
+		/* Initiate two EPs, disabled and with the eol flag set. No need for any
+		   preserved epid. */
+
+		/* The first one has the intr flag set so we get an interrupt when the DMA
+		   channel is about to become disabled. */
+		CHECK_ALIGN(&TxBulkDummyEPList[i][0]);
+		TxBulkDummyEPList[i][0].hw_len = 0;
+		TxBulkDummyEPList[i][0].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) |
+						   IO_STATE(USB_EP_command, eol, yes) |
+						   IO_STATE(USB_EP_command, intr, yes));
+		TxBulkDummyEPList[i][0].sub = 0;
+		TxBulkDummyEPList[i][0].next = virt_to_phys(&TxBulkDummyEPList[i][1]);
+
+		/* The second one. */
+		CHECK_ALIGN(&TxBulkDummyEPList[i][1]);
+		TxBulkDummyEPList[i][1].hw_len = 0;
+		TxBulkDummyEPList[i][1].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) |
+						   IO_STATE(USB_EP_command, eol, yes));
+		TxBulkDummyEPList[i][1].sub = 0;
+		/* The last dummy's next pointer is the same as the current EP's next pointer. */
+		TxBulkDummyEPList[i][1].next = virt_to_phys(&TxBulkEPList[i + 1]);
+	}
+
+	/* Configure the last one. */
+	CHECK_ALIGN(&TxBulkEPList[i]);
+	TxBulkEPList[i].hw_len = 0;
+	TxBulkEPList[i].command = (IO_STATE(USB_EP_command, eol, yes) |
+				   IO_FIELD(USB_EP_command, epid, i));
+	TxBulkEPList[i].sub = 0;
+	TxBulkEPList[i].next = virt_to_phys(&TxBulkEPList[0]);
+
+	/* No need configuring dummy EPs for the last one as it will never be used for
+	   bulk traffic (i == INVALD_EPID at this point). */
+
+	/* Set up to start on the last EP so we will enable it when inserting traffic
+	   for the first time (imitating the situation where the DMA has stopped
+	   because there was no more traffic). */
+	*R_DMA_CH8_SUB0_EP = virt_to_phys(&TxBulkEPList[i]);
+	/* No point in starting the bulk channel yet.
+	 *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); */
+	DBFEXIT;
+}
+
+static void init_tx_ctrl_ep(void)
+{
+	int i;
+
+	DBFENTER;
+
+	for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
+		CHECK_ALIGN(&TxCtrlEPList[i]);
+		TxCtrlEPList[i].hw_len = 0;
+		TxCtrlEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
+		TxCtrlEPList[i].sub = 0;
+		TxCtrlEPList[i].next = virt_to_phys(&TxCtrlEPList[i + 1]);
+	}
+
+	CHECK_ALIGN(&TxCtrlEPList[i]);
+	TxCtrlEPList[i].hw_len = 0;
+	TxCtrlEPList[i].command = (IO_STATE(USB_EP_command, eol, yes) |
+				   IO_FIELD(USB_EP_command, epid, i));
+
+	TxCtrlEPList[i].sub = 0;
+	TxCtrlEPList[i].next = virt_to_phys(&TxCtrlEPList[0]);
+
+	*R_DMA_CH8_SUB1_EP = virt_to_phys(&TxCtrlEPList[0]);
+	*R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start);
+
+	DBFEXIT;
+}
+
+
+static void init_tx_intr_ep(void)
+{
+	int i;
+
+	DBFENTER;
+
+	/* Read comment at zout_buffer declaration for an explanation to this. */
+	TxIntrSB_zout.sw_len = 1;
+	TxIntrSB_zout.next = 0;
+	TxIntrSB_zout.buf = virt_to_phys(&zout_buffer[0]);
+	TxIntrSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) |
+				 IO_STATE(USB_SB_command, tt, zout) |
+				 IO_STATE(USB_SB_command, full, yes) |
+				 IO_STATE(USB_SB_command, eot, yes) |
+				 IO_STATE(USB_SB_command, eol, yes));
+
+	for (i = 0; i < (MAX_INTR_INTERVAL - 1); i++) {
+		CHECK_ALIGN(&TxIntrEPList[i]);
+		TxIntrEPList[i].hw_len = 0;
+		TxIntrEPList[i].command =
+			(IO_STATE(USB_EP_command, eof, yes) |
+			 IO_STATE(USB_EP_command, enable, yes) |
+			 IO_FIELD(USB_EP_command, epid, INVALID_EPID));
+		TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout);
+		TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[i + 1]);
+	}
+
+	CHECK_ALIGN(&TxIntrEPList[i]);
+	TxIntrEPList[i].hw_len = 0;
+	TxIntrEPList[i].command =
+		(IO_STATE(USB_EP_command, eof, yes) |
+		 IO_STATE(USB_EP_command, eol, yes) |
+		 IO_STATE(USB_EP_command, enable, yes) |
+		 IO_FIELD(USB_EP_command, epid, INVALID_EPID));
+	TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout);
+	TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[0]);
+
+	*R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]);
+	*R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start);
+	DBFEXIT;
+}
+
+static void init_tx_isoc_ep(void)
+{
+	int i;
+
+	DBFENTER;
+
+	/* Read comment at zout_buffer declaration for an explanation to this. */
+	TxIsocSB_zout.sw_len = 1;
+	TxIsocSB_zout.next = 0;
+	TxIsocSB_zout.buf = virt_to_phys(&zout_buffer[0]);
+	TxIsocSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) |
+				 IO_STATE(USB_SB_command, tt, zout) |
+				 IO_STATE(USB_SB_command, full, yes) |
+				 IO_STATE(USB_SB_command, eot, yes) |
+				 IO_STATE(USB_SB_command, eol, yes));
+
+	/* The last isochronous EP descriptor is a dummy. */
+
+	for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
+		CHECK_ALIGN(&TxIsocEPList[i]);
+		TxIsocEPList[i].hw_len = 0;
+		TxIsocEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
+		TxIsocEPList[i].sub = 0;
+		TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[i + 1]);
+	}
+
+	CHECK_ALIGN(&TxIsocEPList[i]);
+	TxIsocEPList[i].hw_len = 0;
+
+	/* Must enable the last EP descr to get eof interrupt. */
+	TxIsocEPList[i].command = (IO_STATE(USB_EP_command, enable, yes) |
+				   IO_STATE(USB_EP_command, eof, yes) |
+				   IO_STATE(USB_EP_command, eol, yes) |
+				   IO_FIELD(USB_EP_command, epid, INVALID_EPID));
+	TxIsocEPList[i].sub = virt_to_phys(&TxIsocSB_zout);
+	TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[0]);
+
+	*R_DMA_CH8_SUB3_EP = virt_to_phys(&TxIsocEPList[0]);
+	*R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start);
+
+	DBFEXIT;
+}
+
+static void etrax_usb_unlink_intr_urb(struct urb *urb)
+{
+	volatile USB_EP_Desc_t *first_ep;  /* First EP in the list. */
+	volatile USB_EP_Desc_t *curr_ep;   /* Current EP, the iterator. */
+	volatile USB_EP_Desc_t *next_ep;   /* The EP after current. */
+	volatile USB_EP_Desc_t *unlink_ep; /* The one we should remove from the list. */
+
+	int epid;
+
+	/* Read 8.8.4 in Designer's Reference, "Removing an EP Descriptor from the List". */
+
+	DBFENTER;
+
+	epid = ((etrax_urb_priv_t *)urb->hcpriv)->epid;
+
+	first_ep = &TxIntrEPList[0];
+	curr_ep = first_ep;
+
+
+	/* Note that this loop removes all EP descriptors with this epid. This assumes
+	   that all EP descriptors belong to the one and only urb for this epid. */
+
+	do {
+		next_ep = (USB_EP_Desc_t *)phys_to_virt(curr_ep->next);
+
+		if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == epid) {
+
+			dbg_intr("Found EP to unlink for epid %d", epid);
+
+			/* This is the one we should unlink. */
+			unlink_ep = next_ep;
+
+			/* Actually unlink the EP from the DMA list. */
+			curr_ep->next = unlink_ep->next;
+
+			/* Wait until the DMA is no longer at this descriptor. */
+			while (*R_DMA_CH8_SUB2_EP == virt_to_phys(unlink_ep));
+
+			/* Now we are free to remove it and its SB descriptor.
+			   Note that it is assumed here that there is only one sb in the
+			   sb list for this ep. */
+			kmem_cache_free(usb_desc_cache, phys_to_virt(unlink_ep->sub));
+			kmem_cache_free(usb_desc_cache, (USB_EP_Desc_t *)unlink_ep);
+		}
+
+		curr_ep = phys_to_virt(curr_ep->next);
+
+	} while (curr_ep != first_ep);
+        urb->hcpriv = NULL;
+}
+
+void etrax_usb_do_intr_recover(int epid)
+{
+	USB_EP_Desc_t *first_ep, *tmp_ep;
+
+	DBFENTER;
+
+	first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP);
+	tmp_ep = first_ep;
+
+	/* What this does is simply to walk the list of interrupt
+	   ep descriptors and enable those that are disabled. */
+
+	do {
+		if (IO_EXTRACT(USB_EP_command, epid, tmp_ep->command) == epid &&
+		    !(tmp_ep->command & IO_MASK(USB_EP_command, enable))) {
+			tmp_ep->command |= IO_STATE(USB_EP_command, enable, yes);
+		}
+
+		tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->next);
+
+	} while (tmp_ep != first_ep);
+
+
+	DBFEXIT;
+}
+
+static int etrax_rh_unlink_urb (struct urb *urb)
+{
+	etrax_hc_t *hc;
+
+	DBFENTER;
+
+	hc = urb->dev->bus->hcpriv;
+
+	if (hc->rh.urb == urb) {
+		hc->rh.send = 0;
+		del_timer(&hc->rh.rh_int_timer);
+	}
+
+	DBFEXIT;
+	return 0;
+}
+
+static void etrax_rh_send_irq(struct urb *urb)
+{
+	__u16 data = 0;
+	etrax_hc_t *hc = urb->dev->bus->hcpriv;
+	DBFENTER;
+
+/*
+  dbg_rh("R_USB_FM_NUMBER   : 0x%08X", *R_USB_FM_NUMBER);
+  dbg_rh("R_USB_FM_REMAINING: 0x%08X", *R_USB_FM_REMAINING);
+*/
+
+	data |= (hc->rh.wPortChange_1) ? (1 << 1) : 0;
+	data |= (hc->rh.wPortChange_2) ? (1 << 2) : 0;
+
+	*((__u16 *)urb->transfer_buffer) = cpu_to_le16(data);
+	/* FIXME: Why is actual_length set to 1 when data is 2 bytes?
+	   Since only 1 byte is used, why not declare data as __u8? */
+	urb->actual_length = 1;
+	urb->status = 0;
+
+	if (hc->rh.send && urb->complete) {
+		dbg_rh("wPortChange_1: 0x%04X", hc->rh.wPortChange_1);
+		dbg_rh("wPortChange_2: 0x%04X", hc->rh.wPortChange_2);
+
+		urb->complete(urb, NULL);
+	}
+
+	DBFEXIT;
+}
+
+static void etrax_rh_init_int_timer(struct urb *urb)
+{
+	etrax_hc_t *hc;
+
+	DBFENTER;
+
+	hc = urb->dev->bus->hcpriv;
+	hc->rh.interval = urb->interval;
+	init_timer(&hc->rh.rh_int_timer);
+	hc->rh.rh_int_timer.function = etrax_rh_int_timer_do;
+	hc->rh.rh_int_timer.data = (unsigned long)urb;
+	/* FIXME: Is the jiffies resolution enough? All intervals < 10 ms will be mapped
+	   to 0, and the rest to the nearest lower 10 ms. */
+	hc->rh.rh_int_timer.expires = jiffies + ((HZ * hc->rh.interval) / 1000);
+	add_timer(&hc->rh.rh_int_timer);
+
+	DBFEXIT;
+}
+
+static void etrax_rh_int_timer_do(unsigned long ptr)
+{
+	struct urb *urb;
+	etrax_hc_t *hc;
+
+	DBFENTER;
+
+	urb = (struct urb*)ptr;
+	hc = urb->dev->bus->hcpriv;
+
+	if (hc->rh.send) {
+		etrax_rh_send_irq(urb);
+	}
+
+	DBFEXIT;
+}
+
+static int etrax_usb_setup_epid(struct urb *urb)
+{
+	int epid;
+	char devnum, endpoint, out_traffic, slow;
+	int maxlen;
+	unsigned long flags;
+
+	DBFENTER;
+
+	epid = etrax_usb_lookup_epid(urb);
+	if ((epid != -1)){
+		/* An epid that fits this urb has been found. */
+		DBFEXIT;
+		return epid;
+	}
+
+	/* We must find and initiate a new epid for this urb. */
+	epid = etrax_usb_allocate_epid();
+
+	if (epid == -1) {
+		/* Failed to allocate a new epid. */
+		DBFEXIT;
+		return epid;
+	}
+
+	/* We now have a new epid to use. Initiate it. */
+	set_bit(epid, (void *)&epid_usage_bitmask);
+
+	devnum = usb_pipedevice(urb->pipe);
+	endpoint = usb_pipeendpoint(urb->pipe);
+	slow = usb_pipeslow(urb->pipe);
+	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+		/* We want both IN and OUT control traffic to be put on the same EP/SB list. */
+		out_traffic = 1;
+	} else {
+		out_traffic = usb_pipeout(urb->pipe);
+	}
+
+	save_flags(flags);
+	cli();
+
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+	nop();
+
+	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+		*R_USB_EPT_DATA_ISO = IO_STATE(R_USB_EPT_DATA_ISO, valid, yes) |
+			/* FIXME: Change any to the actual port? */
+			IO_STATE(R_USB_EPT_DATA_ISO, port, any) |
+			IO_FIELD(R_USB_EPT_DATA_ISO, max_len, maxlen) |
+			IO_FIELD(R_USB_EPT_DATA_ISO, ep, endpoint) |
+			IO_FIELD(R_USB_EPT_DATA_ISO, dev, devnum);
+	} else {
+		*R_USB_EPT_DATA = IO_STATE(R_USB_EPT_DATA, valid, yes) |
+			IO_FIELD(R_USB_EPT_DATA, low_speed, slow) |
+			/* FIXME: Change any to the actual port? */
+			IO_STATE(R_USB_EPT_DATA, port, any) |
+			IO_FIELD(R_USB_EPT_DATA, max_len, maxlen) |
+			IO_FIELD(R_USB_EPT_DATA, ep, endpoint) |
+			IO_FIELD(R_USB_EPT_DATA, dev, devnum);
+	}
+
+	restore_flags(flags);
+
+	if (out_traffic) {
+		set_bit(epid, (void *)&epid_out_traffic);
+	} else {
+		clear_bit(epid, (void *)&epid_out_traffic);
+	}
+
+	dbg_epid("Setting up epid %d with devnum %d, endpoint %d and max_len %d (%s)",
+		 epid, devnum, endpoint, maxlen, out_traffic ? "OUT" : "IN");
+
+	DBFEXIT;
+	return epid;
+}
+
+static void etrax_usb_free_epid(int epid)
+{
+	unsigned long flags;
+
+	DBFENTER;
+
+	if (!test_bit(epid, (void *)&epid_usage_bitmask)) {
+		warn("Trying to free unused epid %d", epid);
+		DBFEXIT;
+		return;
+	}
+
+	save_flags(flags);
+	cli();
+
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+	nop();
+	while (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold));
+	/* This will, among other things, set the valid field to 0. */
+	*R_USB_EPT_DATA = 0;
+	restore_flags(flags);
+
+	clear_bit(epid, (void *)&epid_usage_bitmask);
+
+
+	dbg_epid("Freed epid %d", epid);
+
+	DBFEXIT;
+}
+
+static int etrax_usb_lookup_epid(struct urb *urb)
+{
+	int i;
+	__u32 data;
+	char devnum, endpoint, slow, out_traffic;
+	int maxlen;
+	unsigned long flags;
+
+	DBFENTER;
+
+	devnum = usb_pipedevice(urb->pipe);
+	endpoint = usb_pipeendpoint(urb->pipe);
+	slow = usb_pipeslow(urb->pipe);
+	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+		/* We want both IN and OUT control traffic to be put on the same EP/SB list. */
+		out_traffic = 1;
+	} else {
+		out_traffic = usb_pipeout(urb->pipe);
+	}
+
+	/* Step through att epids. */
+	for (i = 0; i < NBR_OF_EPIDS; i++) {
+		if (test_bit(i, (void *)&epid_usage_bitmask) &&
+		    test_bit(i, (void *)&epid_out_traffic) == out_traffic) {
+
+			save_flags(flags);
+			cli();
+			*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, i);
+			nop();
+
+			if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+				data = *R_USB_EPT_DATA_ISO;
+				restore_flags(flags);
+
+				if ((IO_MASK(R_USB_EPT_DATA_ISO, valid) & data) &&
+				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, dev, data) == devnum) &&
+				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, ep, data) == endpoint) &&
+				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, max_len, data) == maxlen)) {
+					dbg_epid("Found epid %d for devnum %d, endpoint %d (%s)",
+						 i, devnum, endpoint, out_traffic ? "OUT" : "IN");
+					DBFEXIT;
+					return i;
+				}
+			} else {
+				data = *R_USB_EPT_DATA;
+				restore_flags(flags);
+
+				if ((IO_MASK(R_USB_EPT_DATA, valid) & data) &&
+				    (IO_EXTRACT(R_USB_EPT_DATA, dev, data) == devnum) &&
+				    (IO_EXTRACT(R_USB_EPT_DATA, ep, data) == endpoint) &&
+				    (IO_EXTRACT(R_USB_EPT_DATA, low_speed, data) == slow) &&
+				    (IO_EXTRACT(R_USB_EPT_DATA, max_len, data) == maxlen)) {
+					dbg_epid("Found epid %d for devnum %d, endpoint %d (%s)",
+						 i, devnum, endpoint, out_traffic ? "OUT" : "IN");
+					DBFEXIT;
+					return i;
+				}
+			}
+		}
+	}
+
+	DBFEXIT;
+	return -1;
+}
+
+static int etrax_usb_allocate_epid(void)
+{
+	int i;
+
+	DBFENTER;
+
+	for (i = 0; i < NBR_OF_EPIDS; i++) {
+		if (!test_bit(i, (void *)&epid_usage_bitmask)) {
+			dbg_epid("Found free epid %d", i);
+			DBFEXIT;
+			return i;
+		}
+	}
+
+	dbg_epid("Found no free epids");
+	DBFEXIT;
+	return -1;
+}
+
+static int etrax_usb_submit_urb(struct urb *urb, int mem_flags)
+{
+	etrax_hc_t *hc;
+	int ret = -EINVAL;
+
+	DBFENTER;
+
+	if (!urb->dev || !urb->dev->bus) {
+		return -ENODEV;
+	}
+	if (usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)) <= 0) {
+		info("Submit urb to pipe with maxpacketlen 0, pipe 0x%X\n", urb->pipe);
+		return -EMSGSIZE;
+	}
+
+	if (urb->timeout) {
+		/* FIXME. */
+		warn("urb->timeout specified, ignoring.");
+	}
+
+	hc = (etrax_hc_t*)urb->dev->bus->hcpriv;
+
+	if (usb_pipedevice(urb->pipe) == hc->rh.devnum) {
+		/* This request is for the Virtual Root Hub. */
+		ret = etrax_rh_submit_urb(urb);
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+
+		ret = etrax_usb_submit_bulk_urb(urb);
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+
+		ret = etrax_usb_submit_ctrl_urb(urb);
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+		int bustime;
+
+		if (urb->bandwidth == 0) {
+			bustime = usb_check_bandwidth(urb->dev, urb);
+			if (bustime < 0) {
+				ret = bustime;
+			} else {
+				ret = etrax_usb_submit_intr_urb(urb);
+				if (ret == 0)
+					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
+			}
+		} else {
+			/* Bandwidth already set. */
+			ret = etrax_usb_submit_intr_urb(urb);
+		}
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+		int bustime;
+
+		if (urb->bandwidth == 0) {
+			bustime = usb_check_bandwidth(urb->dev, urb);
+			if (bustime < 0) {
+				ret = bustime;
+			} else {
+				ret = etrax_usb_submit_isoc_urb(urb);
+				if (ret == 0)
+					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
+			}
+		} else {
+			/* Bandwidth already set. */
+			ret = etrax_usb_submit_isoc_urb(urb);
+		}
+	}
+
+	DBFEXIT;
+
+        if (ret != 0)
+          printk("Submit URB error %d\n", ret);
+
+	return ret;
+}
+
+static int etrax_usb_unlink_urb(struct urb *urb, int status)
+{
+	etrax_hc_t *hc;
+	etrax_urb_priv_t *urb_priv;
+	int epid;
+	unsigned int flags;
+
+	DBFENTER;
+
+	if (!urb) {
+		return -EINVAL;
+	}
+
+	/* Disable interrupts here since a descriptor interrupt for the isoc epid
+	   will modify the sb list.  This could possibly be done more granular, but
+	   unlink_urb should not be used frequently anyway.
+	*/
+
+	save_flags(flags);
+	cli();
+
+	if (!urb->dev || !urb->dev->bus) {
+		restore_flags(flags);
+		return -ENODEV;
+	}
+	if (!urb->hcpriv) {
+		/* This happens if a device driver calls unlink on an urb that
+		   was never submitted (lazy driver) or if the urb was completed
+		   while unlink was being called. */
+		restore_flags(flags);
+		return 0;
+	}
+	if (urb->transfer_flags & URB_ASYNC_UNLINK) {
+		/* FIXME. */
+		/* If URB_ASYNC_UNLINK is set:
+		   unlink
+		   move to a separate urb list
+		   call complete at next sof with ECONNRESET
+
+		   If not:
+		   wait 1 ms
+		   unlink
+		   call complete with ENOENT
+		*/
+		warn("URB_ASYNC_UNLINK set, ignoring.");
+	}
+
+	/* One might think that urb->status = -EINPROGRESS would be a requirement for unlinking,
+	   but that doesn't work for interrupt and isochronous traffic since they are completed
+	   repeatedly, and urb->status is set then. That may in itself be a bug though. */
+
+	hc = urb->dev->bus->hcpriv;
+	urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+	epid = urb_priv->epid;
+
+	/* Set the urb status (synchronous unlink). */
+	urb->status = -ENOENT;
+	urb_priv->urb_state = UNLINK;
+
+	if (usb_pipedevice(urb->pipe) == hc->rh.devnum) {
+		int ret;
+		ret = etrax_rh_unlink_urb(urb);
+		DBFEXIT;
+		restore_flags(flags);
+		return ret;
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+
+		dbg_bulk("Unlink of bulk urb (0x%lx)", (unsigned long)urb);
+
+		if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
+			/* The EP was enabled, disable it and wait. */
+			TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
+
+			/* Ah, the luxury of busy-wait. */
+			while (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[epid]));
+		}
+		/* Kicking dummy list out of the party. */
+		TxBulkEPList[epid].next = virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]);
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+
+		dbg_ctrl("Unlink of ctrl urb (0x%lx)", (unsigned long)urb);
+
+		if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
+			/* The EP was enabled, disable it and wait. */
+			TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
+
+			/* Ah, the luxury of busy-wait. */
+			while (*R_DMA_CH8_SUB1_EP == virt_to_phys(&TxCtrlEPList[epid]));
+		}
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+
+		dbg_intr("Unlink of intr urb (0x%lx)", (unsigned long)urb);
+
+		/* Separate function because it's a tad more complicated. */
+		etrax_usb_unlink_intr_urb(urb);
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+
+		dbg_isoc("Unlink of isoc urb (0x%lx)", (unsigned long)urb);
+
+		if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
+			/* The EP was enabled, disable it and wait. */
+			TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
+
+			/* Ah, the luxury of busy-wait. */
+			while (*R_DMA_CH8_SUB3_EP == virt_to_phys(&TxIsocEPList[epid]));
+		}
+	}
+
+	/* Note that we need to remove the urb from the urb list *before* removing its SB
+	   descriptors. (This means that the isoc eof handler might get a null urb when we
+	   are unlinking the last urb.) */
+
+	if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+
+		urb_list_del(urb, epid);
+		TxBulkEPList[epid].sub = 0;
+		etrax_remove_from_sb_list(urb);
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+
+		urb_list_del(urb, epid);
+		TxCtrlEPList[epid].sub = 0;
+		etrax_remove_from_sb_list(urb);
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+
+		urb_list_del(urb, epid);
+		/* Sanity check (should never happen). */
+		assert(urb_list_empty(epid));
+
+		/* Release allocated bandwidth. */
+		usb_release_bandwidth(urb->dev, urb, 0);
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+
+		if (usb_pipeout(urb->pipe)) {
+
+			USB_SB_Desc_t *iter_sb, *prev_sb, *next_sb;
+
+			if (__urb_list_entry(urb, epid)) {
+
+				urb_list_del(urb, epid);
+				iter_sb = TxIsocEPList[epid].sub ? phys_to_virt(TxIsocEPList[epid].sub) : 0;
+				prev_sb = 0;
+				while (iter_sb && (iter_sb != urb_priv->first_sb)) {
+					prev_sb = iter_sb;
+					iter_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
+				}
+
+				if (iter_sb == 0) {
+					/* Unlink of the URB currently being transmitted. */
+					prev_sb = 0;
+					iter_sb = TxIsocEPList[epid].sub ? phys_to_virt(TxIsocEPList[epid].sub) : 0;
+				}
+
+				while (iter_sb && (iter_sb != urb_priv->last_sb)) {
+					iter_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
+				}
+				if (iter_sb) {
+					next_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
+				} else {
+					/* This should only happen if the DMA has completed
+					   processing the SB list for this EP while interrupts
+					   are disabled. */
+					dbg_isoc("Isoc urb not found, already sent?");
+					next_sb = 0;
+				}
+				if (prev_sb) {
+					prev_sb->next = next_sb ? virt_to_phys(next_sb) : 0;
+				} else {
+					TxIsocEPList[epid].sub = next_sb ? virt_to_phys(next_sb) : 0;
+				}
+
+				etrax_remove_from_sb_list(urb);
+				if (urb_list_empty(epid)) {
+					TxIsocEPList[epid].sub = 0;
+					dbg_isoc("Last isoc out urb epid %d", epid);
+				} else if (next_sb || prev_sb) {
+					dbg_isoc("Re-enable isoc out epid %d", epid);
+
+					TxIsocEPList[epid].hw_len = 0;
+					TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+				} else {
+					TxIsocEPList[epid].sub = 0;
+					dbg_isoc("URB list non-empty and no SB list, EP disabled");
+				}
+			} else {
+				dbg_isoc("Urb 0x%p not found, completed already?", urb);
+			}
+		} else {
+
+			urb_list_del(urb, epid);
+
+			/* For in traffic there is only one SB descriptor for each EP even
+			   though there may be several urbs (all urbs point at the same SB). */
+			if (urb_list_empty(epid)) {
+				/* No more urbs, remove the SB. */
+				TxIsocEPList[epid].sub = 0;
+				etrax_remove_from_sb_list(urb);
+			} else {
+				TxIsocEPList[epid].hw_len = 0;
+				TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+			}
+		}
+		/* Release allocated bandwidth. */
+		usb_release_bandwidth(urb->dev, urb, 1);
+	}
+	/* Free the epid if urb list is empty. */
+	if (urb_list_empty(epid)) {
+		etrax_usb_free_epid(epid);
+	}
+	restore_flags(flags);
+
+	/* Must be done before calling completion handler. */
+	kfree(urb_priv);
+	urb->hcpriv = 0;
+
+	if (urb->complete) {
+		urb->complete(urb, NULL);
+	}
+
+	DBFEXIT;
+	return 0;
+}
+
+static int etrax_usb_get_frame_number(struct usb_device *usb_dev)
+{
+	DBFENTER;
+	DBFEXIT;
+	return (*R_USB_FM_NUMBER & 0x7ff);
+}
+
+static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs)
+{
+	DBFENTER;
+
+	/* This interrupt handler could be used when unlinking EP descriptors. */
+
+	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub0_descr)) {
+		USB_EP_Desc_t *ep;
+
+		//dbg_bulk("dma8_sub0_descr (BULK) intr.");
+
+		/* It should be safe clearing the interrupt here, since we don't expect to get a new
+		   one until we restart the bulk channel. */
+		*R_DMA_CH8_SUB0_CLR_INTR = IO_STATE(R_DMA_CH8_SUB0_CLR_INTR, clr_descr, do);
+
+		/* Wait while the DMA is running (though we don't expect it to be). */
+		while (*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd));
+
+		/* Advance the DMA to the next EP descriptor. */
+		ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB0_EP);
+
+		//dbg_bulk("descr intr: DMA is at 0x%lx", (unsigned long)ep);
+
+		/* ep->next is already a physical address; no need for a virt_to_phys. */
+		*R_DMA_CH8_SUB0_EP = ep->next;
+
+		/* Start the DMA bulk channel again. */
+		*R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
+	}
+	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub1_descr)) {
+		struct urb *urb;
+		int epid;
+		etrax_urb_priv_t *urb_priv;
+		unsigned long int flags;
+
+		dbg_ctrl("dma8_sub1_descr (CTRL) intr.");
+		*R_DMA_CH8_SUB1_CLR_INTR = IO_STATE(R_DMA_CH8_SUB1_CLR_INTR, clr_descr, do);
+
+		/* The complete callback gets called so we cli. */
+		save_flags(flags);
+		cli();
+
+		for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
+			if ((TxCtrlEPList[epid].sub == 0) ||
+			    (epid == DUMMY_EPID) ||
+			    (epid == INVALID_EPID)) {
+				/* Nothing here to see. */
+				continue;
+			}
+
+			/* Get the first urb (if any). */
+			urb = urb_list_first(epid);
+
+			if (urb) {
+
+				/* Sanity check. */
+				assert(usb_pipetype(urb->pipe) == PIPE_CONTROL);
+
+				urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+				assert(urb_priv);
+
+				if (urb_priv->urb_state == WAITING_FOR_DESCR_INTR) {
+					assert(!(TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));
+
+					etrax_usb_complete_urb(urb, 0);
+				}
+			}
+		}
+		restore_flags(flags);
+	}
+	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub2_descr)) {
+		dbg_intr("dma8_sub2_descr (INTR) intr.");
+		*R_DMA_CH8_SUB2_CLR_INTR = IO_STATE(R_DMA_CH8_SUB2_CLR_INTR, clr_descr, do);
+	}
+	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub3_descr)) {
+		struct urb *urb;
+		int epid;
+		int epid_done;
+		etrax_urb_priv_t *urb_priv;
+		USB_SB_Desc_t *sb_desc;
+
+		usb_isoc_complete_data_t *comp_data = NULL;
+
+		/* One or more isoc out transfers are done. */
+		dbg_isoc("dma8_sub3_descr (ISOC) intr.");
+
+		/* For each isoc out EP search for the first sb_desc with the intr flag
+		   set.  This descriptor must be the last packet from an URB.  Then
+		   traverse the URB list for the EP until the URB with urb_priv->last_sb
+		   matching the intr-marked sb_desc is found.  All URBs before this have
+		   been sent.
+		*/
+
+		for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
+			/* Skip past epids with no SB lists, epids used for in traffic,
+			   and special (dummy, invalid) epids. */
+			if ((TxIsocEPList[epid].sub == 0) ||
+			    (test_bit(epid, (void *)&epid_out_traffic) == 0) ||
+			    (epid == DUMMY_EPID) ||
+			    (epid == INVALID_EPID)) {
+				/* Nothing here to see. */
+				continue;
+			}
+			sb_desc = phys_to_virt(TxIsocEPList[epid].sub);
+
+			/* Find the last descriptor of the currently active URB for this ep.
+			   This is the first descriptor in the sub list marked for a descriptor
+			   interrupt. */
+			while (sb_desc && !IO_EXTRACT(USB_SB_command, intr, sb_desc->command)) {
+				sb_desc = sb_desc->next ? phys_to_virt(sb_desc->next) : 0;
+			}
+			assert(sb_desc);
+
+			dbg_isoc("Check epid %d, sub 0x%p, SB 0x%p",
+				 epid,
+				 phys_to_virt(TxIsocEPList[epid].sub),
+				 sb_desc);
+
+			epid_done = 0;
+
+			/* Get the first urb (if any). */
+			urb = urb_list_first(epid);
+			assert(urb);
+
+			while (urb && !epid_done) {
+
+				/* Sanity check. */
+				assert(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
+
+				if (!usb_pipeout(urb->pipe)) {
+					/* descr interrupts are generated only for out pipes. */
+					epid_done = 1;
+					continue;
+				}
+
+				urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+				assert(urb_priv);
+
+				if (sb_desc != urb_priv->last_sb) {
+
+					/* This urb has been sent. */
+					dbg_isoc("out URB 0x%p sent", urb);
+
+					urb_priv->urb_state = TRANSFER_DONE;
+
+				} else if ((sb_desc == urb_priv->last_sb) &&
+					   !(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))) {
+
+					assert((sb_desc->command & IO_MASK(USB_SB_command, eol)) == IO_STATE(USB_SB_command, eol, yes));
+					assert(sb_desc->next == 0);
+
+					dbg_isoc("out URB 0x%p last in list, epid disabled", urb);
+					TxIsocEPList[epid].sub = 0;
+					TxIsocEPList[epid].hw_len = 0;
+					urb_priv->urb_state = TRANSFER_DONE;
+
+					epid_done = 1;
+
+				} else {
+					epid_done = 1;
+				}
+				if (!epid_done) {
+					urb = urb_list_next(urb, epid);
+				}
+			}
+
+		}
+
+		*R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do);
+
+		comp_data = (usb_isoc_complete_data_t*)kmem_cache_alloc(isoc_compl_cache, SLAB_ATOMIC);
+		assert(comp_data != NULL);
+
+                INIT_WORK(&comp_data->usb_bh, etrax_usb_isoc_descr_interrupt_bottom_half, comp_data);
+                schedule_work(&comp_data->usb_bh);
+	}
+
+	DBFEXIT;
+        return IRQ_HANDLED;
+}
+
+static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data)
+{
+	usb_isoc_complete_data_t *comp_data = (usb_isoc_complete_data_t*)data;
+
+	struct urb *urb;
+	int epid;
+	int epid_done;
+	etrax_urb_priv_t *urb_priv;
+
+	DBFENTER;
+
+	dbg_isoc("dma8_sub3_descr (ISOC) bottom half.");
+
+	for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
+		unsigned long flags;
+
+		save_flags(flags);
+		cli();
+
+		epid_done = 0;
+
+		/* The descriptor interrupt handler has marked all transmitted isoch. out
+		   URBs with TRANSFER_DONE.  Now we traverse all epids and for all that
+ 		   have isoch. out traffic traverse its URB list and complete the
+		   transmitted URB.
+		*/
+
+		while (!epid_done) {
+
+			/* Get the first urb (if any). */
+			urb = urb_list_first(epid);
+			if (urb == 0) {
+				epid_done = 1;
+				continue;
+			}
+
+			if (usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) {
+					epid_done = 1;
+					continue;
+			}
+
+			if (!usb_pipeout(urb->pipe)) {
+				/* descr interrupts are generated only for out pipes. */
+				epid_done = 1;
+				continue;
+			}
+
+			dbg_isoc("Check epid %d, SB 0x%p", epid, (char*)TxIsocEPList[epid].sub);
+
+			urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+			assert(urb_priv);
+
+			if (urb_priv->urb_state == TRANSFER_DONE) {
+				int i;
+				struct usb_iso_packet_descriptor *packet;
+
+				/* This urb has been sent. */
+				dbg_isoc("Completing isoc out URB 0x%p", urb);
+
+				for (i = 0; i < urb->number_of_packets; i++) {
+					packet = &urb->iso_frame_desc[i];
+					packet->status = 0;
+					packet->actual_length = packet->length;
+				}
+
+				etrax_usb_complete_isoc_urb(urb, 0);
+
+				if (urb_list_empty(epid)) {
+					etrax_usb_free_epid(epid);
+					epid_done = 1;
+				}
+			} else {
+				epid_done = 1;
+			}
+		}
+		restore_flags(flags);
+
+	}
+	kmem_cache_free(isoc_compl_cache, comp_data);
+
+	DBFEXIT;
+}
+
+
+
+static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs)
+{
+	struct urb *urb;
+	etrax_urb_priv_t *urb_priv;
+	int epid = 0;
+	unsigned long flags;
+
+	/* Isoc diagnostics. */
+	static int curr_fm = 0;
+	static int prev_fm = 0;
+
+	DBFENTER;
+
+	/* Clear this interrupt. */
+	*R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do);
+
+	/* Note that this while loop assumes that all packets span only
+	   one rx descriptor. */
+
+	/* The reason we cli here is that we call the driver's callback functions. */
+	save_flags(flags);
+	cli();
+
+	while (myNextRxDesc->status & IO_MASK(USB_IN_status, eop)) {
+
+		epid = IO_EXTRACT(USB_IN_status, epid, myNextRxDesc->status);
+		urb = urb_list_first(epid);
+
+		//printk("eop for epid %d, first urb 0x%lx\n", epid, (unsigned long)urb);
+
+		if (!urb) {
+			err("No urb for epid %d in rx interrupt", epid);
+			__dump_ept_data(epid);
+			goto skip_out;
+		}
+
+		/* Note that we cannot indescriminately assert(usb_pipein(urb->pipe)) since
+		   ctrl pipes are not. */
+
+		if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) {
+			__u32 r_usb_ept_data;
+			int no_error = 0;
+
+			assert(test_bit(epid, (void *)&epid_usage_bitmask));
+
+			*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+			nop();
+			if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+				r_usb_ept_data = *R_USB_EPT_DATA_ISO;
+
+				if ((r_usb_ept_data & IO_MASK(R_USB_EPT_DATA_ISO, valid)) &&
+				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data) == 0) &&
+				    (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata))) {
+					/* Not an error, just a failure to receive an expected iso
+					   in packet in this frame.  This is not documented
+					   in the designers reference.
+					*/
+					no_error++;
+				} else {
+					warn("R_USB_EPT_DATA_ISO for epid %d = 0x%x", epid, r_usb_ept_data);
+				}
+			} else {
+				r_usb_ept_data = *R_USB_EPT_DATA;
+				warn("R_USB_EPT_DATA for epid %d = 0x%x", epid, r_usb_ept_data);
+			}
+
+			if (!no_error){
+				warn("error in rx desc->status, epid %d, first urb = 0x%lx",
+				     epid, (unsigned long)urb);
+				__dump_in_desc(myNextRxDesc);
+
+				warn("R_USB_STATUS = 0x%x", *R_USB_STATUS);
+
+				/* Check that ept was disabled when error occurred. */
+				switch (usb_pipetype(urb->pipe)) {
+				case PIPE_BULK:
+					assert(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)));
+					break;
+				case PIPE_CONTROL:
+					assert(!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)));
+					break;
+				case PIPE_INTERRUPT:
+					assert(!(TxIntrEPList[epid].command & IO_MASK(USB_EP_command, enable)));
+					break;
+				case PIPE_ISOCHRONOUS:
+					assert(!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)));
+					break;
+				default:
+					warn("etrax_usb_rx_interrupt: bad pipetype %d in urb 0x%p",
+					     usb_pipetype(urb->pipe),
+					     urb);
+				}
+				etrax_usb_complete_urb(urb, -EPROTO);
+				goto skip_out;
+			}
+		}
+
+		urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+		assert(urb_priv);
+
+		if ((usb_pipetype(urb->pipe) == PIPE_BULK) ||
+		    (usb_pipetype(urb->pipe) == PIPE_CONTROL) ||
+		    (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
+
+			if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {
+				/* We get nodata for empty data transactions, and the rx descriptor's
+				   hw_len field is not valid in that case. No data to copy in other
+				   words. */
+			} else {
+				/* Make sure the data fits in the buffer. */
+				assert(urb_priv->rx_offset + myNextRxDesc->hw_len
+				       <= urb->transfer_buffer_length);
+
+				memcpy(urb->transfer_buffer + urb_priv->rx_offset,
+				       phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len);
+				urb_priv->rx_offset += myNextRxDesc->hw_len;
+			}
+
+			if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) {
+				if ((usb_pipetype(urb->pipe) == PIPE_CONTROL) &&
+				    ((TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)) ==
+				     IO_STATE(USB_EP_command, enable, yes))) {
+					/* The EP is still enabled, so the OUT packet used to ack
+					   the in data is probably not processed yet.  If the EP
+					   sub pointer has not moved beyond urb_priv->last_sb mark
+					   it for a descriptor interrupt and complete the urb in
+					   the descriptor interrupt handler.
+					*/
+					USB_SB_Desc_t *sub = TxCtrlEPList[urb_priv->epid].sub ? phys_to_virt(TxCtrlEPList[urb_priv->epid].sub) : 0;
+
+					while ((sub != NULL) && (sub != urb_priv->last_sb)) {
+						sub = sub->next ? phys_to_virt(sub->next) : 0;
+					}
+					if (sub != NULL) {
+						/* The urb has not been fully processed. */
+						urb_priv->urb_state = WAITING_FOR_DESCR_INTR;
+					} else {
+						warn("(CTRL) epid enabled and urb (0x%p) processed, ep->sub=0x%p", urb, (char*)TxCtrlEPList[urb_priv->epid].sub);
+						etrax_usb_complete_urb(urb, 0);
+					}
+				} else {
+					etrax_usb_complete_urb(urb, 0);
+				}
+			}
+
+		} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+
+			struct usb_iso_packet_descriptor *packet;
+
+			if (urb_priv->urb_state == UNLINK) {
+				info("Ignoring rx data for urb being unlinked.");
+				goto skip_out;
+			} else if (urb_priv->urb_state == NOT_STARTED) {
+				info("What? Got rx data for urb that isn't started?");
+				goto skip_out;
+			}
+
+			packet = &urb->iso_frame_desc[urb_priv->isoc_packet_counter];
+			packet->status = 0;
+
+			if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {
+				/* We get nodata for empty data transactions, and the rx descriptor's
+				   hw_len field is not valid in that case. We copy 0 bytes however to
+				   stay in synch. */
+				packet->actual_length = 0;
+			} else {
+				packet->actual_length = myNextRxDesc->hw_len;
+				/* Make sure the data fits in the buffer. */
+				assert(packet->actual_length <= packet->length);
+				memcpy(urb->transfer_buffer + packet->offset,
+				       phys_to_virt(myNextRxDesc->buf), packet->actual_length);
+			}
+
+			/* Increment the packet counter. */
+			urb_priv->isoc_packet_counter++;
+
+			/* Note that we don't care about the eot field in the rx descriptor's status.
+			   It will always be set for isoc traffic. */
+			if (urb->number_of_packets == urb_priv->isoc_packet_counter) {
+
+				/* Out-of-synch diagnostics. */
+				curr_fm = (*R_USB_FM_NUMBER & 0x7ff);
+				if (((prev_fm + urb_priv->isoc_packet_counter) % (0x7ff + 1)) != curr_fm) {
+					/* This test is wrong, if there is more than one isoc
+					   in endpoint active it will always calculate wrong
+					   since prev_fm is shared by all endpoints.
+
+					   FIXME Make this check per URB using urb->start_frame.
+					*/
+					dbg_isoc("Out of synch? Previous frame = %d, current frame = %d",
+						 prev_fm, curr_fm);
+
+				}
+				prev_fm = curr_fm;
+
+				/* Complete the urb with status OK. */
+				etrax_usb_complete_isoc_urb(urb, 0);
+			}
+		}
+
+	skip_out:
+
+		/* DMA IN cache bug. Flush the DMA IN buffer from the cache. (struct etrax_dma_descr
+		   has the same layout as USB_IN_Desc for the relevant fields.) */
+		prepare_rx_descriptor((struct etrax_dma_descr*)myNextRxDesc);
+
+		myPrevRxDesc = myNextRxDesc;
+		myPrevRxDesc->command |= IO_MASK(USB_IN_command, eol);
+		myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol);
+		myLastRxDesc = myPrevRxDesc;
+
+		myNextRxDesc->status = 0;
+		myNextRxDesc = phys_to_virt(myNextRxDesc->next);
+	}
+
+	restore_flags(flags);
+
+	DBFEXIT;
+
+        return IRQ_HANDLED;
+}
+
+
+/* This function will unlink the SB descriptors associated with this urb. */
+static int etrax_remove_from_sb_list(struct urb *urb)
+{
+	USB_SB_Desc_t *next_sb, *first_sb, *last_sb;
+	etrax_urb_priv_t *urb_priv;
+	int i = 0;
+
+	DBFENTER;
+
+	urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+	assert(urb_priv);
+
+	/* Just a sanity check. Since we don't fiddle with the DMA list the EP descriptor
+	   doesn't really need to be disabled, it's just that we expect it to be. */
+	if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+		assert(!(TxBulkEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));
+	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+		assert(!(TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));
+	}
+
+	first_sb = urb_priv->first_sb;
+	last_sb = urb_priv->last_sb;
+
+	assert(first_sb);
+	assert(last_sb);
+
+	while (first_sb != last_sb) {
+		next_sb = (USB_SB_Desc_t *)phys_to_virt(first_sb->next);
+		kmem_cache_free(usb_desc_cache, first_sb);
+		first_sb = next_sb;
+		i++;
+	}
+	kmem_cache_free(usb_desc_cache, last_sb);
+	i++;
+	dbg_sb("%d SB descriptors freed", i);
+	/* Compare i with urb->number_of_packets for Isoc traffic.
+	   Should be same when calling unlink_urb */
+
+	DBFEXIT;
+
+	return i;
+}
+
+static int etrax_usb_submit_bulk_urb(struct urb *urb)
+{
+	int epid;
+	int empty;
+	unsigned long flags;
+	etrax_urb_priv_t *urb_priv;
+
+	DBFENTER;
+
+	/* Epid allocation, empty check and list add must be protected.
+	   Read about this in etrax_usb_submit_ctrl_urb. */
+
+	spin_lock_irqsave(&urb_list_lock, flags);
+	epid = etrax_usb_setup_epid(urb);
+	if (epid == -1) {
+		DBFEXIT;
+		spin_unlock_irqrestore(&urb_list_lock, flags);
+		return -ENOMEM;
+	}
+	empty = urb_list_empty(epid);
+	urb_list_add(urb, epid);
+	spin_unlock_irqrestore(&urb_list_lock, flags);
+
+	dbg_bulk("Adding bulk %s urb 0x%lx to %s list, epid %d",
+		 usb_pipein(urb->pipe) ? "IN" : "OUT", (unsigned long)urb, empty ? "empty" : "", epid);
+
+	/* Mark the urb as being in progress. */
+	urb->status = -EINPROGRESS;
+
+	/* Setup the hcpriv data. */
+	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+	assert(urb_priv != NULL);
+	/* This sets rx_offset to 0. */
+	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
+	urb_priv->urb_state = NOT_STARTED;
+	urb->hcpriv = urb_priv;
+
+	if (empty) {
+		etrax_usb_add_to_bulk_sb_list(urb, epid);
+	}
+
+	DBFEXIT;
+
+	return 0;
+}
+
+static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid)
+{
+	USB_SB_Desc_t *sb_desc;
+	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+	unsigned long flags;
+	char maxlen;
+
+	DBFENTER;
+
+	dbg_bulk("etrax_usb_add_to_bulk_sb_list, urb 0x%lx", (unsigned long)urb);
+
+	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+
+	sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+	assert(sb_desc != NULL);
+	memset(sb_desc, 0, sizeof(USB_SB_Desc_t));
+
+
+	if (usb_pipeout(urb->pipe)) {
+
+		dbg_bulk("Grabbing bulk OUT, urb 0x%lx, epid %d", (unsigned long)urb, epid);
+
+		/* This is probably a sanity check of the bulk transaction length
+		   not being larger than 64 kB. */
+		if (urb->transfer_buffer_length > 0xffff) {
+			panic("urb->transfer_buffer_length > 0xffff");
+		}
+
+		sb_desc->sw_len = urb->transfer_buffer_length;
+
+		/* The rem field is don't care if it's not a full-length transfer, so setting
+		   it shouldn't hurt. Also, rem isn't used for OUT traffic. */
+		sb_desc->command = (IO_FIELD(USB_SB_command, rem, 0) |
+				    IO_STATE(USB_SB_command, tt, out) |
+				    IO_STATE(USB_SB_command, eot, yes) |
+				    IO_STATE(USB_SB_command, eol, yes));
+
+		/* The full field is set to yes, even if we don't actually check that this is
+		   a full-length transfer (i.e., that transfer_buffer_length % maxlen = 0).
+		   Setting full prevents the USB controller from sending an empty packet in
+		   that case.  However, if URB_ZERO_PACKET was set we want that. */
+		if (!(urb->transfer_flags & URB_ZERO_PACKET)) {
+			sb_desc->command |= IO_STATE(USB_SB_command, full, yes);
+		}
+
+		sb_desc->buf = virt_to_phys(urb->transfer_buffer);
+		sb_desc->next = 0;
+
+	} else if (usb_pipein(urb->pipe)) {
+
+		dbg_bulk("Grabbing bulk IN, urb 0x%lx, epid %d", (unsigned long)urb, epid);
+
+		sb_desc->sw_len = urb->transfer_buffer_length ?
+			(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
+
+		/* The rem field is don't care if it's not a full-length transfer, so setting
+		   it shouldn't hurt. */
+		sb_desc->command =
+			(IO_FIELD(USB_SB_command, rem,
+				  urb->transfer_buffer_length % maxlen) |
+			 IO_STATE(USB_SB_command, tt, in) |
+			 IO_STATE(USB_SB_command, eot, yes) |
+			 IO_STATE(USB_SB_command, eol, yes));
+
+		sb_desc->buf = 0;
+		sb_desc->next = 0;
+	}
+
+	urb_priv->first_sb = sb_desc;
+	urb_priv->last_sb = sb_desc;
+	urb_priv->epid = epid;
+
+	urb->hcpriv = urb_priv;
+
+	/* Reset toggle bits and reset error count. */
+	save_flags(flags);
+	cli();
+
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+	nop();
+
+	/* FIXME: Is this a special case since the hold field is checked,
+	   or should we check hold in a lot of other cases as well? */
+	if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) {
+		panic("Hold was set in %s", __FUNCTION__);
+	}
+
+	/* Reset error counters (regardless of which direction this traffic is). */
+	*R_USB_EPT_DATA &=
+		~(IO_MASK(R_USB_EPT_DATA, error_count_in) |
+		  IO_MASK(R_USB_EPT_DATA, error_count_out));
+
+	/* Software must preset the toggle bits. */
+	if (usb_pipeout(urb->pipe)) {
+		char toggle =
+			usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+		*R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_out);
+		*R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_out, toggle);
+	} else {
+		char toggle =
+			usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+		*R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_in);
+		*R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_in, toggle);
+	}
+
+	/* Assert that the EP descriptor is disabled. */
+	assert(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)));
+
+	/* The reason we set the EP's sub pointer directly instead of
+	   walking the SB list and linking it last in the list is that we only
+	   have one active urb at a time (the rest are queued). */
+
+	/* Note that we cannot have interrupts running when we have set the SB descriptor
+	   but the EP is not yet enabled.  If a bulk eot happens for another EP, we will
+	   find this EP disabled and with a SB != 0, which will make us think that it's done. */
+	TxBulkEPList[epid].sub = virt_to_phys(sb_desc);
+	TxBulkEPList[epid].hw_len = 0;
+	/* Note that we don't have to fill in the ep_id field since this
+	   was done when we allocated the EP descriptors in init_tx_bulk_ep. */
+
+	/* Check if the dummy list is already with us (if several urbs were queued). */
+	if (TxBulkEPList[epid].next != virt_to_phys(&TxBulkDummyEPList[epid][0])) {
+
+		dbg_bulk("Inviting dummy list to the party for urb 0x%lx, epid %d",
+			 (unsigned long)urb, epid);
+
+		/* The last EP in the dummy list already has its next pointer set to
+		   TxBulkEPList[epid].next. */
+
+		/* We don't need to check if the DMA is at this EP or not before changing the
+		   next pointer, since we will do it in one 32-bit write (EP descriptors are
+		   32-bit aligned). */
+		TxBulkEPList[epid].next = virt_to_phys(&TxBulkDummyEPList[epid][0]);
+	}
+	/* Enable the EP descr. */
+	dbg_bulk("Enabling bulk EP for urb 0x%lx, epid %d", (unsigned long)urb, epid);
+	TxBulkEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+
+	/* Everything is set up, safe to enable interrupts again. */
+	restore_flags(flags);
+
+	/* If the DMA bulk channel isn't running, we need to restart it if it
+	   has stopped at the last EP descriptor (DMA stopped because there was
+	   no more traffic) or if it has stopped at a dummy EP with the intr flag
+	   set (DMA stopped because we were too slow in inserting new traffic). */
+	if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) {
+
+		USB_EP_Desc_t *ep;
+		ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB0_EP);
+		dbg_bulk("DMA channel not running in add");
+		dbg_bulk("DMA is at 0x%lx", (unsigned long)ep);
+
+		if (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[NBR_OF_EPIDS - 1]) ||
+		    (ep->command & 0x8) >> 3) {
+			*R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
+			/* Update/restart the bulk start timer since we just started the channel. */
+			mod_timer(&bulk_start_timer, jiffies + BULK_START_TIMER_INTERVAL);
+			/* Update/restart the bulk eot timer since we just inserted traffic. */
+			mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
+		}
+	}
+
+	DBFEXIT;
+}
+
+static void etrax_usb_complete_bulk_urb(struct urb *urb, int status)
+{
+	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+	int epid = urb_priv->epid;
+	unsigned long flags;
+
+	DBFENTER;
+
+	if (status)
+		warn("Completing bulk urb with status %d.", status);
+
+	dbg_bulk("Completing bulk urb 0x%lx for epid %d", (unsigned long)urb, epid);
+
+	/* Update the urb list. */
+	urb_list_del(urb, epid);
+
+	/* For an IN pipe, we always set the actual length, regardless of whether there was
+	   an error or not (which means the device driver can use the data if it wants to). */
+	if (usb_pipein(urb->pipe)) {
+		urb->actual_length = urb_priv->rx_offset;
+	} else {
+		/* Set actual_length for OUT urbs also; the USB mass storage driver seems
+		   to want that. We wouldn't know of any partial writes if there was an error. */
+		if (status == 0) {
+			urb->actual_length = urb->transfer_buffer_length;
+		} else {
+			urb->actual_length = 0;
+		}
+	}
+
+	/* FIXME: Is there something of the things below we shouldn't do if there was an error?
+	   Like, maybe we shouldn't toggle the toggle bits, or maybe we shouldn't insert more traffic. */
+
+	save_flags(flags);
+	cli();
+
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+	nop();
+
+	/* We need to fiddle with the toggle bits because the hardware doesn't do it for us. */
+	if (usb_pipeout(urb->pipe)) {
+		char toggle =
+			IO_EXTRACT(R_USB_EPT_DATA, t_out, *R_USB_EPT_DATA);
+		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			      usb_pipeout(urb->pipe), toggle);
+	} else {
+		char toggle =
+			IO_EXTRACT(R_USB_EPT_DATA, t_in, *R_USB_EPT_DATA);
+		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			      usb_pipeout(urb->pipe), toggle);
+	}
+	restore_flags(flags);
+
+	/* Remember to free the SBs. */
+	etrax_remove_from_sb_list(urb);
+	kfree(urb_priv);
+	urb->hcpriv = 0;
+
+	/* If there are any more urb's in the list we'd better start sending */
+	if (!urb_list_empty(epid)) {
+
+		struct urb *new_urb;
+
+		/* Get the first urb. */
+		new_urb = urb_list_first(epid);
+		assert(new_urb);
+
+		dbg_bulk("More bulk for epid %d", epid);
+
+		etrax_usb_add_to_bulk_sb_list(new_urb, epid);
+	}
+
+	urb->status = status;
+
+	/* We let any non-zero status from the layer above have precedence. */
+	if (status == 0) {
+		/* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length)
+		   is to be treated as an error. */
+		if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+			if (usb_pipein(urb->pipe) &&
+			    (urb->actual_length !=
+			     usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))) {
+				urb->status = -EREMOTEIO;
+			}
+		}
+	}
+
+	if (urb->complete) {
+		urb->complete(urb, NULL);
+	}
+
+	if (urb_list_empty(epid)) {
+		/* This means that this EP is now free, deconfigure it. */
+		etrax_usb_free_epid(epid);
+
+		/* No more traffic; time to clean up.
+		   Must set sub pointer to 0, since we look at the sub pointer when handling
+		   the bulk eot interrupt. */
+
+		dbg_bulk("No bulk for epid %d", epid);
+
+		TxBulkEPList[epid].sub = 0;
+
+		/* Unlink the dummy list. */
+
+		dbg_bulk("Kicking dummy list out of party for urb 0x%lx, epid %d",
+			 (unsigned long)urb, epid);
+
+		/* No need to wait for the DMA before changing the next pointer.
+		   The modulo NBR_OF_EPIDS isn't actually necessary, since we will never use
+		   the last one (INVALID_EPID) for actual traffic. */
+		TxBulkEPList[epid].next =
+			virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]);
+	}
+
+	DBFEXIT;
+}
+
+static int etrax_usb_submit_ctrl_urb(struct urb *urb)
+{
+	int epid;
+	int empty;
+	unsigned long flags;
+	etrax_urb_priv_t *urb_priv;
+
+	DBFENTER;
+
+	/* FIXME: Return -ENXIO if there is already a queued urb for this endpoint? */
+
+	/* Epid allocation, empty check and list add must be protected.
+
+	   Epid allocation because if we find an existing epid for this endpoint an urb might be
+	   completed (emptying the list) before we add the new urb to the list, causing the epid
+	   to be de-allocated. We would then start the transfer with an invalid epid -> epid attn.
+
+	   Empty check and add because otherwise we might conclude that the list is not empty,
+	   after which it becomes empty before we add the new urb to the list, causing us not to
+	   insert the new traffic into the SB list. */
+
+	spin_lock_irqsave(&urb_list_lock, flags);
+	epid = etrax_usb_setup_epid(urb);
+	if (epid == -1) {
+		spin_unlock_irqrestore(&urb_list_lock, flags);
+		DBFEXIT;
+		return -ENOMEM;
+	}
+	empty = urb_list_empty(epid);
+	urb_list_add(urb, epid);
+	spin_unlock_irqrestore(&urb_list_lock, flags);
+
+	dbg_ctrl("Adding ctrl urb 0x%lx to %s list, epid %d",
+		 (unsigned long)urb, empty ? "empty" : "", epid);
+
+	/* Mark the urb as being in progress. */
+	urb->status = -EINPROGRESS;
+
+	/* Setup the hcpriv data. */
+	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+	assert(urb_priv != NULL);
+	/* This sets rx_offset to 0. */
+	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
+	urb_priv->urb_state = NOT_STARTED;
+	urb->hcpriv = urb_priv;
+
+	if (empty) {
+		etrax_usb_add_to_ctrl_sb_list(urb, epid);
+	}
+
+	DBFEXIT;
+
+	return 0;
+}
+
+static void etrax_usb_add_to_ctrl_sb_list(struct urb *urb, int epid)
+{
+	USB_SB_Desc_t *sb_desc_setup;
+	USB_SB_Desc_t *sb_desc_data;
+	USB_SB_Desc_t *sb_desc_status;
+
+	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+
+	unsigned long flags;
+	char maxlen;
+
+	DBFENTER;
+
+	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+
+	sb_desc_setup = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+	assert(sb_desc_setup != NULL);
+	sb_desc_status = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+	assert(sb_desc_status != NULL);
+
+	/* Initialize the mandatory setup SB descriptor (used only in control transfers) */
+	sb_desc_setup->sw_len = 8;
+	sb_desc_setup->command = (IO_FIELD(USB_SB_command, rem, 0) |
+				  IO_STATE(USB_SB_command, tt, setup) |
+				  IO_STATE(USB_SB_command, full, yes) |
+				  IO_STATE(USB_SB_command, eot, yes));
+
+	sb_desc_setup->buf = virt_to_phys(urb->setup_packet);
+
+	if (usb_pipeout(urb->pipe)) {
+		dbg_ctrl("Transfer for epid %d is OUT", epid);
+
+		/* If this Control OUT transfer has an optional data stage we add an OUT token
+		   before the mandatory IN (status) token, hence the reordered SB list */
+
+		sb_desc_setup->next = virt_to_phys(sb_desc_status);
+		if (urb->transfer_buffer) {
+
+			dbg_ctrl("This OUT transfer has an extra data stage");
+
+			sb_desc_data = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+			assert(sb_desc_data != NULL);
+
+			sb_desc_setup->next = virt_to_phys(sb_desc_data);
+
+			sb_desc_data->sw_len = urb->transfer_buffer_length;
+			sb_desc_data->command = (IO_STATE(USB_SB_command, tt, out) |
+						 IO_STATE(USB_SB_command, full, yes) |
+						 IO_STATE(USB_SB_command, eot, yes));
+			sb_desc_data->buf = virt_to_phys(urb->transfer_buffer);
+			sb_desc_data->next = virt_to_phys(sb_desc_status);
+		}
+
+		sb_desc_status->sw_len = 1;
+		sb_desc_status->command = (IO_FIELD(USB_SB_command, rem, 0) |
+					   IO_STATE(USB_SB_command, tt, in) |
+					   IO_STATE(USB_SB_command, eot, yes) |
+					   IO_STATE(USB_SB_command, intr, yes) |
+					   IO_STATE(USB_SB_command, eol, yes));
+
+		sb_desc_status->buf = 0;
+		sb_desc_status->next = 0;
+
+	} else if (usb_pipein(urb->pipe)) {
+
+		dbg_ctrl("Transfer for epid %d is IN", epid);
+		dbg_ctrl("transfer_buffer_length = %d", urb->transfer_buffer_length);
+		dbg_ctrl("rem is calculated to %d", urb->transfer_buffer_length % maxlen);
+
+		sb_desc_data = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+		assert(sb_desc_data != NULL);
+
+		sb_desc_setup->next = virt_to_phys(sb_desc_data);
+
+		sb_desc_data->sw_len = urb->transfer_buffer_length ?
+			(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
+		dbg_ctrl("sw_len got %d", sb_desc_data->sw_len);
+
+		sb_desc_data->command =
+			(IO_FIELD(USB_SB_command, rem,
+				  urb->transfer_buffer_length % maxlen) |
+			 IO_STATE(USB_SB_command, tt, in) |
+			 IO_STATE(USB_SB_command, eot, yes));
+
+		sb_desc_data->buf = 0;
+		sb_desc_data->next = virt_to_phys(sb_desc_status);
+
+		/* Read comment at zout_buffer declaration for an explanation to this. */
+		sb_desc_status->sw_len = 1;
+		sb_desc_status->command = (IO_FIELD(USB_SB_command, rem, 0) |
+					   IO_STATE(USB_SB_command, tt, zout) |
+					   IO_STATE(USB_SB_command, full, yes) |
+					   IO_STATE(USB_SB_command, eot, yes) |
+					   IO_STATE(USB_SB_command, intr, yes) |
+					   IO_STATE(USB_SB_command, eol, yes));
+
+		sb_desc_status->buf = virt_to_phys(&zout_buffer[0]);
+		sb_desc_status->next = 0;
+	}
+
+	urb_priv->first_sb = sb_desc_setup;
+	urb_priv->last_sb = sb_desc_status;
+	urb_priv->epid = epid;
+
+	urb_priv->urb_state = STARTED;
+
+	/* Reset toggle bits and reset error count, remember to di and ei */
+	/* Warning: it is possible that this locking doesn't work with bottom-halves */
+
+	save_flags(flags);
+	cli();
+
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+	nop();
+	if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) {
+		panic("Hold was set in %s", __FUNCTION__);
+	}
+
+
+	/* FIXME: Compare with etrax_usb_add_to_bulk_sb_list where the toggle bits
+	   are set to a specific value. Why the difference? Read "Transfer and Toggle Bits
+	   in Designer's Reference, p. 8 - 11. */
+	*R_USB_EPT_DATA &=
+		~(IO_MASK(R_USB_EPT_DATA, error_count_in) |
+		  IO_MASK(R_USB_EPT_DATA, error_count_out) |
+		  IO_MASK(R_USB_EPT_DATA, t_in) |
+		  IO_MASK(R_USB_EPT_DATA, t_out));
+
+	/* Since we use the rx interrupt to complete ctrl urbs, we can enable interrupts now
+	   (i.e. we don't check the sub pointer on an eot interrupt like we do for bulk traffic). */
+	restore_flags(flags);
+
+	/* Assert that the EP descriptor is disabled. */
+	assert(!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)));
+
+	/* Set up and enable the EP descriptor. */
+	TxCtrlEPList[epid].sub = virt_to_phys(sb_desc_setup);
+	TxCtrlEPList[epid].hw_len = 0;
+	TxCtrlEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+
+	/* We start the DMA sub channel without checking if it's running or not, because:
+	   1) If it's already running, issuing the start command is a nop.
+	   2) We avoid a test-and-set race condition. */
+	*R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start);
+
+	DBFEXIT;
+}
+
+static void etrax_usb_complete_ctrl_urb(struct urb *urb, int status)
+{
+	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+	int epid = urb_priv->epid;
+
+	DBFENTER;
+
+	if (status)
+		warn("Completing ctrl urb with status %d.", status);
+
+	dbg_ctrl("Completing ctrl epid %d, urb 0x%lx", epid, (unsigned long)urb);
+
+	/* Remove this urb from the list. */
+	urb_list_del(urb, epid);
+
+	/* For an IN pipe, we always set the actual length, regardless of whether there was
+	   an error or not (which means the device driver can use the data if it wants to). */
+	if (usb_pipein(urb->pipe)) {
+		urb->actual_length = urb_priv->rx_offset;
+	}
+
+	/* FIXME: Is there something of the things below we shouldn't do if there was an error?
+	   Like, maybe we shouldn't insert more traffic. */
+
+	/* Remember to free the SBs. */
+	etrax_remove_from_sb_list(urb);
+	kfree(urb_priv);
+	urb->hcpriv = 0;
+
+	/* If there are any more urbs in the list we'd better start sending. */
+	if (!urb_list_empty(epid)) {
+		struct urb *new_urb;
+
+		/* Get the first urb. */
+		new_urb = urb_list_first(epid);
+		assert(new_urb);
+
+		dbg_ctrl("More ctrl for epid %d, first urb = 0x%lx", epid, (unsigned long)new_urb);
+
+		etrax_usb_add_to_ctrl_sb_list(new_urb, epid);
+	}
+
+	urb->status = status;
+
+	/* We let any non-zero status from the layer above have precedence. */
+	if (status == 0) {
+		/* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length)
+		   is to be treated as an error. */
+		if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+			if (usb_pipein(urb->pipe) &&
+			    (urb->actual_length !=
+			     usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))) {
+				urb->status = -EREMOTEIO;
+			}
+		}
+	}
+
+	if (urb->complete) {
+		urb->complete(urb, NULL);
+	}
+
+	if (urb_list_empty(epid)) {
+		/* No more traffic. Time to clean up. */
+		etrax_usb_free_epid(epid);
+		/* Must set sub pointer to 0. */
+		dbg_ctrl("No ctrl for epid %d", epid);
+		TxCtrlEPList[epid].sub = 0;
+	}
+
+	DBFEXIT;
+}
+
+static int etrax_usb_submit_intr_urb(struct urb *urb)
+{
+
+	int epid;
+
+	DBFENTER;
+
+	if (usb_pipeout(urb->pipe)) {
+		/* Unsupported transfer type.
+		   We don't support interrupt out traffic. (If we do, we can't support
+		   intervals for neither in or out traffic, but are forced to schedule all
+		   interrupt traffic in one frame.) */
+		return -EINVAL;
+	}
+
+	epid = etrax_usb_setup_epid(urb);
+	if (epid == -1) {
+		DBFEXIT;
+		return -ENOMEM;
+	}
+
+	if (!urb_list_empty(epid)) {
+		/* There is already a queued urb for this endpoint. */
+		etrax_usb_free_epid(epid);
+		return -ENXIO;
+	}
+
+	urb->status = -EINPROGRESS;
+
+	dbg_intr("Add intr urb 0x%lx, to list, epid %d", (unsigned long)urb, epid);
+
+	urb_list_add(urb, epid);
+	etrax_usb_add_to_intr_sb_list(urb, epid);
+
+	return 0;
+
+	DBFEXIT;
+}
+
+static void etrax_usb_add_to_intr_sb_list(struct urb *urb, int epid)
+{
+
+	volatile USB_EP_Desc_t *tmp_ep;
+	volatile USB_EP_Desc_t *first_ep;
+
+	char maxlen;
+	int interval;
+	int i;
+
+	etrax_urb_priv_t *urb_priv;
+
+	DBFENTER;
+
+	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	interval = urb->interval;
+
+	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+	assert(urb_priv != NULL);
+	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
+	urb->hcpriv = urb_priv;
+
+	first_ep = &TxIntrEPList[0];
+
+	/* Round of the interval to 2^n, it is obvious that this code favours
+	   smaller numbers, but that is actually a good thing */
+	/* FIXME: The "rounding error" for larger intervals will be quite
+	   large. For in traffic this shouldn't be a problem since it will only
+	   mean that we "poll" more often. */
+	for (i = 0; interval; i++) {
+		interval = interval >> 1;
+	}
+	interval = 1 << (i - 1);
+
+	dbg_intr("Interval rounded to %d", interval);
+
+	tmp_ep = first_ep;
+	i = 0;
+	do {
+		if (tmp_ep->command & IO_MASK(USB_EP_command, eof)) {
+			if ((i % interval) == 0) {
+				/* Insert the traffic ep after tmp_ep */
+				USB_EP_Desc_t *ep_desc;
+				USB_SB_Desc_t *sb_desc;
+
+				dbg_intr("Inserting EP for epid %d", epid);
+
+				ep_desc = (USB_EP_Desc_t *)
+					kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+				sb_desc = (USB_SB_Desc_t *)
+					kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+				assert(ep_desc != NULL);
+				CHECK_ALIGN(ep_desc);
+				assert(sb_desc != NULL);
+
+				ep_desc->sub = virt_to_phys(sb_desc);
+				ep_desc->hw_len = 0;
+				ep_desc->command = (IO_FIELD(USB_EP_command, epid, epid) |
+						    IO_STATE(USB_EP_command, enable, yes));
+
+
+				/* Round upwards the number of packets of size maxlen
+				   that this SB descriptor should receive. */
+				sb_desc->sw_len = urb->transfer_buffer_length ?
+					(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
+				sb_desc->next = 0;
+				sb_desc->buf = 0;
+				sb_desc->command =
+					(IO_FIELD(USB_SB_command, rem, urb->transfer_buffer_length % maxlen) |
+					 IO_STATE(USB_SB_command, tt, in) |
+					 IO_STATE(USB_SB_command, eot, yes) |
+					 IO_STATE(USB_SB_command, eol, yes));
+
+				ep_desc->next = tmp_ep->next;
+				tmp_ep->next = virt_to_phys(ep_desc);
+			}
+			i++;
+		}
+		tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->next);
+	} while (tmp_ep != first_ep);
+
+
+	/* Note that first_sb/last_sb doesn't apply to interrupt traffic. */
+	urb_priv->epid = epid;
+
+	/* We start the DMA sub channel without checking if it's running or not, because:
+	   1) If it's already running, issuing the start command is a nop.
+	   2) We avoid a test-and-set race condition. */
+	*R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start);
+
+	DBFEXIT;
+}
+
+
+
+static void etrax_usb_complete_intr_urb(struct urb *urb, int status)
+{
+	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+	int epid = urb_priv->epid;
+
+	DBFENTER;
+
+	if (status)
+		warn("Completing intr urb with status %d.", status);
+
+	dbg_intr("Completing intr epid %d, urb 0x%lx", epid, (unsigned long)urb);
+
+	urb->status = status;
+	urb->actual_length = urb_priv->rx_offset;
+
+	dbg_intr("interrupt urb->actual_length = %d", urb->actual_length);
+
+	/* We let any non-zero status from the layer above have precedence. */
+	if (status == 0) {
+		/* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length)
+		   is to be treated as an error. */
+		if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+			if (urb->actual_length !=
+			    usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) {
+				urb->status = -EREMOTEIO;
+			}
+		}
+	}
+
+	/* The driver will resubmit the URB so we need to remove it first */
+        etrax_usb_unlink_urb(urb, 0);
+	if (urb->complete) {
+		urb->complete(urb, NULL);
+	}
+
+	DBFEXIT;
+}
+
+
+static int etrax_usb_submit_isoc_urb(struct urb *urb)
+{
+	int epid;
+	unsigned long flags;
+
+	DBFENTER;
+
+	dbg_isoc("Submitting isoc urb = 0x%lx", (unsigned long)urb);
+
+	/* Epid allocation, empty check and list add must be protected.
+	   Read about this in etrax_usb_submit_ctrl_urb. */
+
+	spin_lock_irqsave(&urb_list_lock, flags);
+	/* Is there an active epid for this urb ? */
+	epid = etrax_usb_setup_epid(urb);
+	if (epid == -1) {
+		DBFEXIT;
+		spin_unlock_irqrestore(&urb_list_lock, flags);
+		return -ENOMEM;
+	}
+
+	/* Ok, now we got valid endpoint, lets insert some traffic */
+
+	urb->status = -EINPROGRESS;
+
+	/* Find the last urb in the URB_List and add this urb after that one.
+	   Also add the traffic, that is do an etrax_usb_add_to_isoc_sb_list.  This
+	   is important to make this in "real time" since isochronous traffic is
+	   time sensitive. */
+
+	dbg_isoc("Adding isoc urb to (possibly empty) list");
+	urb_list_add(urb, epid);
+	etrax_usb_add_to_isoc_sb_list(urb, epid);
+	spin_unlock_irqrestore(&urb_list_lock, flags);
+
+	DBFEXIT;
+
+	return 0;
+}
+
+static void etrax_usb_check_error_isoc_ep(const int epid)
+{
+	unsigned long int flags;
+	int error_code;
+	__u32 r_usb_ept_data;
+
+	/* We can't read R_USB_EPID_ATTN here since it would clear the iso_eof,
+	   bulk_eot and epid_attn interrupts.  So we just check the status of
+	   the epid without testing if for it in R_USB_EPID_ATTN. */
+
+
+	save_flags(flags);
+	cli();
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+	nop();
+	/* Note that although there are separate R_USB_EPT_DATA and R_USB_EPT_DATA_ISO
+	   registers, they are located at the same address and are of the same size.
+	   In other words, this read should be ok for isoc also. */
+	r_usb_ept_data = *R_USB_EPT_DATA;
+	restore_flags(flags);
+
+	error_code = IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data);
+
+	if (r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, hold)) {
+		warn("Hold was set for epid %d.", epid);
+		return;
+	}
+
+	if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, no_error)) {
+
+		/* This indicates that the SB list of the ept was completed before
+		   new data was appended to it.  This is not an error, but indicates
+		   large system or USB load and could possibly cause trouble for
+		   very timing sensitive USB device drivers so we log it.
+		*/
+		info("Isoc. epid %d disabled with no error", epid);
+		return;
+
+	} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, stall)) {
+		/* Not really a protocol error, just says that the endpoint gave
+		   a stall response. Note that error_code cannot be stall for isoc. */
+		panic("Isoc traffic cannot stall");
+
+	} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, bus_error)) {
+		/* Two devices responded to a transaction request. Must be resolved
+		   by software. FIXME: Reset ports? */
+		panic("Bus error for epid %d."
+		      " Two devices responded to transaction request",
+		      epid);
+
+	} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, buffer_error)) {
+		/* DMA overrun or underrun. */
+		warn("Buffer overrun/underrun for epid %d. DMA too busy?", epid);
+
+		/* It seems that error_code = buffer_error in
+		   R_USB_EPT_DATA/R_USB_EPT_DATA_ISO and ourun = yes in R_USB_STATUS
+		   are the same error. */
+	}
+}
+
+
+static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid)
+{
+
+	int i = 0;
+
+	etrax_urb_priv_t *urb_priv;
+	USB_SB_Desc_t *prev_sb_desc,  *next_sb_desc, *temp_sb_desc;
+
+	DBFENTER;
+
+	prev_sb_desc = next_sb_desc = temp_sb_desc = NULL;
+
+	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC);
+	assert(urb_priv != NULL);
+	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
+
+	urb->hcpriv = urb_priv;
+	urb_priv->epid = epid;
+
+	if (usb_pipeout(urb->pipe)) {
+
+		if (urb->number_of_packets == 0) panic("etrax_usb_add_to_isoc_sb_list 0 packets\n");
+
+		dbg_isoc("Transfer for epid %d is OUT", epid);
+		dbg_isoc("%d packets in URB", urb->number_of_packets);
+
+		/* Create one SB descriptor for each packet and link them together. */
+		for (i = 0; i < urb->number_of_packets; i++) {
+			if (!urb->iso_frame_desc[i].length)
+				continue;
+
+			next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_ATOMIC);
+			assert(next_sb_desc != NULL);
+
+			if (urb->iso_frame_desc[i].length > 0) {
+
+				next_sb_desc->command = (IO_STATE(USB_SB_command, tt, out) |
+							 IO_STATE(USB_SB_command, eot, yes));
+
+				next_sb_desc->sw_len = urb->iso_frame_desc[i].length;
+				next_sb_desc->buf = virt_to_phys((char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset);
+
+				/* Check if full length transfer. */
+				if (urb->iso_frame_desc[i].length ==
+				    usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) {
+					next_sb_desc->command |= IO_STATE(USB_SB_command, full, yes);
+				}
+			} else {
+				dbg_isoc("zero len packet");
+				next_sb_desc->command = (IO_FIELD(USB_SB_command, rem, 0) |
+							 IO_STATE(USB_SB_command, tt, zout) |
+							 IO_STATE(USB_SB_command, eot, yes) |
+							 IO_STATE(USB_SB_command, full, yes));
+
+				next_sb_desc->sw_len = 1;
+				next_sb_desc->buf = virt_to_phys(&zout_buffer[0]);
+			}
+
+			/* First SB descriptor that belongs to this urb */
+			if (i == 0)
+				urb_priv->first_sb = next_sb_desc;
+			else
+				prev_sb_desc->next = virt_to_phys(next_sb_desc);
+
+			prev_sb_desc = next_sb_desc;
+		}
+
+		next_sb_desc->command |= (IO_STATE(USB_SB_command, intr, yes) |
+					  IO_STATE(USB_SB_command, eol, yes));
+		next_sb_desc->next = 0;
+		urb_priv->last_sb = next_sb_desc;
+
+	} else if (usb_pipein(urb->pipe)) {
+
+		dbg_isoc("Transfer for epid %d is IN", epid);
+		dbg_isoc("transfer_buffer_length = %d", urb->transfer_buffer_length);
+		dbg_isoc("rem is calculated to %d", urb->iso_frame_desc[urb->number_of_packets - 1].length);
+
+		/* Note that in descriptors for periodic traffic are not consumed. This means that
+		   the USB controller never propagates in the SB list. In other words, if there already
+		   is an SB descriptor in the list for this EP we don't have to do anything. */
+		if (TxIsocEPList[epid].sub == 0) {
+			dbg_isoc("Isoc traffic not already running, allocating SB");
+
+			next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_ATOMIC);
+			assert(next_sb_desc != NULL);
+
+			next_sb_desc->command = (IO_STATE(USB_SB_command, tt, in) |
+						 IO_STATE(USB_SB_command, eot, yes) |
+						 IO_STATE(USB_SB_command, eol, yes));
+
+			next_sb_desc->next = 0;
+			next_sb_desc->sw_len = 1; /* Actual number of packets is not relevant
+						     for periodic in traffic as long as it is more
+						     than zero.  Set to 1 always. */
+			next_sb_desc->buf = 0;
+
+			/* The rem field is don't care for isoc traffic, so we don't set it. */
+
+			/* Only one SB descriptor that belongs to this urb. */
+			urb_priv->first_sb = next_sb_desc;
+			urb_priv->last_sb = next_sb_desc;
+
+		} else {
+
+			dbg_isoc("Isoc traffic already running, just setting first/last_sb");
+
+			/* Each EP for isoc in will have only one SB descriptor, setup when submitting the
+			   already active urb. Note that even though we may have several first_sb/last_sb
+			   pointing at the same SB descriptor, they are freed only once (when the list has
+			   become empty). */
+			urb_priv->first_sb = phys_to_virt(TxIsocEPList[epid].sub);
+			urb_priv->last_sb = phys_to_virt(TxIsocEPList[epid].sub);
+			return;
+		}
+
+	}
+
+	/* Find the spot to insert this urb and add it. */
+	if (TxIsocEPList[epid].sub == 0) {
+		/* First SB descriptor inserted in this list (in or out). */
+		dbg_isoc("Inserting SB desc first in list");
+		TxIsocEPList[epid].hw_len = 0;
+		TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
+
+	} else {
+		/* Isochronous traffic is already running, insert new traffic last (only out). */
+		dbg_isoc("Inserting SB desc last in list");
+		temp_sb_desc = phys_to_virt(TxIsocEPList[epid].sub);
+		while ((temp_sb_desc->command & IO_MASK(USB_SB_command, eol)) !=
+		       IO_STATE(USB_SB_command, eol, yes)) {
+			assert(temp_sb_desc->next);
+			temp_sb_desc = phys_to_virt(temp_sb_desc->next);
+		}
+		dbg_isoc("Appending list on desc 0x%p", temp_sb_desc);
+
+		/* Next pointer must be set before eol is removed. */
+		temp_sb_desc->next = virt_to_phys(urb_priv->first_sb);
+		/* Clear the previous end of list flag since there is a new in the
+		   added SB descriptor list. */
+		temp_sb_desc->command &= ~IO_MASK(USB_SB_command, eol);
+
+		if (!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))) {
+			/* 8.8.5 in Designer's Reference says we should check for and correct
+			   any errors in the EP here.  That should not be necessary if epid_attn
+			   is handled correctly, so we assume all is ok. */
+			dbg_isoc("EP disabled");
+			etrax_usb_check_error_isoc_ep(epid);
+
+			/* The SB list was exhausted. */
+			if (virt_to_phys(urb_priv->last_sb) != TxIsocEPList[epid].sub) {
+				/* The new sublist did not get processed before the EP was
+				   disabled.  Setup the EP again. */
+				dbg_isoc("Set EP sub to new list");
+				TxIsocEPList[epid].hw_len = 0;
+				TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
+			}
+		}
+	}
+
+	if (urb->transfer_flags & URB_ISO_ASAP) {
+		/* The isoc transfer should be started as soon as possible. The start_frame
+		   field is a return value if URB_ISO_ASAP was set. Comparing R_USB_FM_NUMBER
+		   with a USB Chief trace shows that the first isoc IN token is sent 2 frames
+		   later. I'm not sure how this affects usage of the start_frame field by the
+		   device driver, or how it affects things when USB_ISO_ASAP is not set, so
+		   therefore there's no compensation for the 2 frame "lag" here. */
+		urb->start_frame = (*R_USB_FM_NUMBER & 0x7ff);
+		TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+		urb_priv->urb_state = STARTED;
+		dbg_isoc("URB_ISO_ASAP set, urb->start_frame set to %d", urb->start_frame);
+	} else {
+		/* Not started yet. */
+		urb_priv->urb_state = NOT_STARTED;
+		dbg_isoc("urb_priv->urb_state set to NOT_STARTED");
+	}
+
+       /* We start the DMA sub channel without checking if it's running or not, because:
+	  1) If it's already running, issuing the start command is a nop.
+	  2) We avoid a test-and-set race condition. */
+	*R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start);
+
+	DBFEXIT;
+}
+
+static void etrax_usb_complete_isoc_urb(struct urb *urb, int status)
+{
+	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+	int epid = urb_priv->epid;
+	int auto_resubmit = 0;
+
+	DBFENTER;
+	dbg_isoc("complete urb 0x%p, status %d", urb, status);
+
+	if (status)
+		warn("Completing isoc urb with status %d.", status);
+
+	if (usb_pipein(urb->pipe)) {
+		int i;
+
+		/* Make that all isoc packets have status and length set before
+		   completing the urb. */
+		for (i = urb_priv->isoc_packet_counter; i < urb->number_of_packets; i++) {
+			urb->iso_frame_desc[i].actual_length = 0;
+			urb->iso_frame_desc[i].status = -EPROTO;
+		}
+
+		urb_list_del(urb, epid);
+
+		if (!list_empty(&urb_list[epid])) {
+			((etrax_urb_priv_t *)(urb_list_first(epid)->hcpriv))->urb_state = STARTED;
+		} else {
+			unsigned long int flags;
+			if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
+				/* The EP was enabled, disable it and wait. */
+				TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
+
+				/* Ah, the luxury of busy-wait. */
+				while (*R_DMA_CH8_SUB3_EP == virt_to_phys(&TxIsocEPList[epid]));
+			}
+
+			etrax_remove_from_sb_list(urb);
+			TxIsocEPList[epid].sub = 0;
+			TxIsocEPList[epid].hw_len = 0;
+
+			save_flags(flags);
+			cli();
+			etrax_usb_free_epid(epid);
+			restore_flags(flags);
+		}
+
+		urb->hcpriv = 0;
+		kfree(urb_priv);
+
+		/* Release allocated bandwidth. */
+		usb_release_bandwidth(urb->dev, urb, 0);
+	} else if (usb_pipeout(urb->pipe)) {
+		int freed_descr;
+
+		dbg_isoc("Isoc out urb complete 0x%p", urb);
+
+		/* Update the urb list. */
+		urb_list_del(urb, epid);
+
+		freed_descr = etrax_remove_from_sb_list(urb);
+		dbg_isoc("freed %d descriptors of %d packets", freed_descr, urb->number_of_packets);
+		assert(freed_descr == urb->number_of_packets);
+		urb->hcpriv = 0;
+		kfree(urb_priv);
+
+		/* Release allocated bandwidth. */
+		usb_release_bandwidth(urb->dev, urb, 0);
+	}
+
+	urb->status = status;
+	if (urb->complete) {
+		urb->complete(urb, NULL);
+	}
+
+	if (auto_resubmit) {
+		/* Check that urb was not unlinked by the complete callback. */
+		if (__urb_list_entry(urb, epid)) {
+			/* Move this one down the list. */
+			urb_list_move_last(urb, epid);
+
+			/* Mark the now first urb as started (may already be). */
+			((etrax_urb_priv_t *)(urb_list_first(epid)->hcpriv))->urb_state = STARTED;
+
+			/* Must set this to 0 since this urb is still active after
+			   completion. */
+			urb_priv->isoc_packet_counter = 0;
+		} else {
+			warn("(ISOC) automatic resubmit urb 0x%p removed by complete.", urb);
+		}
+	}
+
+	DBFEXIT;
+}
+
+static void etrax_usb_complete_urb(struct urb *urb, int status)
+{
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_BULK:
+		etrax_usb_complete_bulk_urb(urb, status);
+		break;
+	case PIPE_CONTROL:
+		etrax_usb_complete_ctrl_urb(urb, status);
+		break;
+	case PIPE_INTERRUPT:
+		etrax_usb_complete_intr_urb(urb, status);
+		break;
+	case PIPE_ISOCHRONOUS:
+		etrax_usb_complete_isoc_urb(urb, status);
+		break;
+	default:
+		err("Unknown pipetype");
+	}
+}
+
+
+
+static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc, struct pt_regs *regs)
+{
+	usb_interrupt_registers_t *reg;
+	unsigned long flags;
+	__u32 irq_mask;
+	__u8 status;
+	__u32 epid_attn;
+	__u16 port_status_1;
+	__u16 port_status_2;
+	__u32 fm_number;
+
+	DBFENTER;
+
+	/* Read critical registers into local variables, do kmalloc afterwards. */
+	save_flags(flags);
+	cli();
+
+	irq_mask = *R_USB_IRQ_MASK_READ;
+	/* Reading R_USB_STATUS clears the ctl_status interrupt. Note that R_USB_STATUS
+	   must be read before R_USB_EPID_ATTN since reading the latter clears the
+	   ourun and perror fields of R_USB_STATUS. */
+	status = *R_USB_STATUS;
+
+	/* Reading R_USB_EPID_ATTN clears the iso_eof, bulk_eot and epid_attn interrupts. */
+	epid_attn = *R_USB_EPID_ATTN;
+
+	/* Reading R_USB_RH_PORT_STATUS_1 and R_USB_RH_PORT_STATUS_2 clears the
+	   port_status interrupt. */
+	port_status_1 = *R_USB_RH_PORT_STATUS_1;
+	port_status_2 = *R_USB_RH_PORT_STATUS_2;
+
+	/* Reading R_USB_FM_NUMBER clears the sof interrupt. */
+	/* Note: the lower 11 bits contain the actual frame number, sent with each sof. */
+	fm_number = *R_USB_FM_NUMBER;
+
+	restore_flags(flags);
+
+	reg = (usb_interrupt_registers_t *)kmem_cache_alloc(top_half_reg_cache, SLAB_ATOMIC);
+
+	assert(reg != NULL);
+
+	reg->hc = (etrax_hc_t *)vhc;
+
+	/* Now put register values into kmalloc'd area. */
+	reg->r_usb_irq_mask_read = irq_mask;
+	reg->r_usb_status = status;
+	reg->r_usb_epid_attn = epid_attn;
+	reg->r_usb_rh_port_status_1 = port_status_1;
+	reg->r_usb_rh_port_status_2 = port_status_2;
+	reg->r_usb_fm_number = fm_number;
+
+        INIT_WORK(&reg->usb_bh, etrax_usb_hc_interrupt_bottom_half, reg);
+        schedule_work(&reg->usb_bh);
+
+	DBFEXIT;
+
+        return IRQ_HANDLED;
+}
+
+static void etrax_usb_hc_interrupt_bottom_half(void *data)
+{
+	usb_interrupt_registers_t *reg = (usb_interrupt_registers_t *)data;
+	__u32 irq_mask = reg->r_usb_irq_mask_read;
+
+	DBFENTER;
+
+	/* Interrupts are handled in order of priority. */
+	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, epid_attn)) {
+		etrax_usb_hc_epid_attn_interrupt(reg);
+	}
+	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, port_status)) {
+		etrax_usb_hc_port_status_interrupt(reg);
+	}
+	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, ctl_status)) {
+		etrax_usb_hc_ctl_status_interrupt(reg);
+	}
+	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, iso_eof)) {
+		etrax_usb_hc_isoc_eof_interrupt();
+	}
+	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, bulk_eot)) {
+		/* Update/restart the bulk start timer since obviously the channel is running. */
+		mod_timer(&bulk_start_timer, jiffies + BULK_START_TIMER_INTERVAL);
+		/* Update/restart the bulk eot timer since we just received an bulk eot interrupt. */
+		mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
+
+		etrax_usb_hc_bulk_eot_interrupt(0);
+	}
+
+	kmem_cache_free(top_half_reg_cache, reg);
+
+	DBFEXIT;
+}
+
+
+void etrax_usb_hc_isoc_eof_interrupt(void)
+{
+	struct urb *urb;
+	etrax_urb_priv_t *urb_priv;
+	int epid;
+	unsigned long flags;
+
+	DBFENTER;
+
+	/* Do not check the invalid epid (it has a valid sub pointer). */
+	for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
+
+		/* Do not check the invalid epid (it has a valid sub pointer). */
+		if ((epid == DUMMY_EPID) || (epid == INVALID_EPID))
+			continue;
+
+		/* Disable interrupts to block the isoc out descriptor interrupt handler
+		   from being called while the isoc EPID list is being checked.
+		*/
+		save_flags(flags);
+		cli();
+
+		if (TxIsocEPList[epid].sub == 0) {
+			/* Nothing here to see. */
+			restore_flags(flags);
+			continue;
+		}
+
+		/* Get the first urb (if any). */
+		urb = urb_list_first(epid);
+		if (urb == 0) {
+			warn("Ignoring NULL urb");
+			restore_flags(flags);
+			continue;
+		}
+		if (usb_pipein(urb->pipe)) {
+
+			/* Sanity check. */
+			assert(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
+
+			urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+			assert(urb_priv);
+
+			if (urb_priv->urb_state == NOT_STARTED) {
+
+				/* If ASAP is not set and urb->start_frame is the current frame,
+				   start the transfer. */
+				if (!(urb->transfer_flags & URB_ISO_ASAP) &&
+				    (urb->start_frame == (*R_USB_FM_NUMBER & 0x7ff))) {
+
+					dbg_isoc("Enabling isoc IN EP descr for epid %d", epid);
+					TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+
+					/* This urb is now active. */
+					urb_priv->urb_state = STARTED;
+					continue;
+				}
+			}
+		}
+		restore_flags(flags);
+	}
+
+	DBFEXIT;
+
+}
+
+void etrax_usb_hc_bulk_eot_interrupt(int timer_induced)
+{
+ 	int epid;
+
+	/* The technique is to run one urb at a time, wait for the eot interrupt at which
+	   point the EP descriptor has been disabled. */
+
+	DBFENTER;
+	dbg_bulk("bulk eot%s", timer_induced ? ", called by timer" : "");
+
+	for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
+
+		if (!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) &&
+		    (TxBulkEPList[epid].sub != 0)) {
+
+			struct urb *urb;
+			etrax_urb_priv_t *urb_priv;
+			unsigned long flags;
+			__u32 r_usb_ept_data;
+
+			/* Found a disabled EP descriptor which has a non-null sub pointer.
+			   Verify that this ctrl EP descriptor got disabled no errors.
+			   FIXME: Necessary to check error_code? */
+			dbg_bulk("for epid %d?", epid);
+
+			/* Get the first urb. */
+			urb = urb_list_first(epid);
+
+			/* FIXME: Could this happen for valid reasons? Why did it disappear? Because of
+			   wrong unlinking? */
+			if (!urb) {
+				warn("NULL urb for epid %d", epid);
+				continue;
+			}
+
+			assert(urb);
+			urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+			assert(urb_priv);
+
+			/* Sanity checks. */
+			assert(usb_pipetype(urb->pipe) == PIPE_BULK);
+			if (phys_to_virt(TxBulkEPList[epid].sub) != urb_priv->last_sb) {
+				err("bulk endpoint got disabled before reaching last sb");
+			}
+
+			/* For bulk IN traffic, there seems to be a race condition between
+			   between the bulk eot and eop interrupts, or rather an uncertainty regarding
+			   the order in which they happen. Normally we expect the eop interrupt from
+			   DMA channel 9 to happen before the eot interrupt.
+
+			   Therefore, we complete the bulk IN urb in the rx interrupt handler instead. */
+
+			if (usb_pipein(urb->pipe)) {
+				dbg_bulk("in urb, continuing");
+				continue;
+			}
+
+			save_flags(flags);
+			cli();
+			*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+			nop();
+			r_usb_ept_data = *R_USB_EPT_DATA;
+			restore_flags(flags);
+
+			if (IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data) ==
+			    IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
+				/* This means that the endpoint has no error, is disabled
+				   and had inserted traffic, i.e. transfer successfully completed. */
+				etrax_usb_complete_bulk_urb(urb, 0);
+			} else {
+				/* Shouldn't happen. We expect errors to be caught by epid attention. */
+				err("Found disabled bulk EP desc, error_code != no_error");
+			}
+		}
+	}
+
+	/* Normally, we should find (at least) one disabled EP descriptor with a valid sub pointer.
+	   However, because of the uncertainty in the deliverance of the eop/eot interrupts, we may
+	   not.  Also, we might find two disabled EPs when handling an eot interrupt, and then find
+	   none the next time. */
+
+	DBFEXIT;
+
+}
+
+void etrax_usb_hc_epid_attn_interrupt(usb_interrupt_registers_t *reg)
+{
+	/* This function handles the epid attention interrupt.  There are a variety of reasons
+	   for this interrupt to happen (Designer's Reference, p. 8 - 22 for the details):
+
+	   invalid ep_id  - Invalid epid in an EP (EP disabled).
+	   stall	  - Not strictly an error condition (EP disabled).
+	   3rd error      - Three successive transaction errors  (EP disabled).
+	   buffer ourun   - Buffer overrun or underrun (EP disabled).
+	   past eof1      - Intr or isoc transaction proceeds past EOF1.
+	   near eof       - Intr or isoc transaction would not fit inside the frame.
+	   zout transfer  - If zout transfer for a bulk endpoint (EP disabled).
+	   setup transfer - If setup transfer for a non-ctrl endpoint (EP disabled). */
+
+	int epid;
+
+
+	DBFENTER;
+
+	assert(reg != NULL);
+
+	/* Note that we loop through all epids. We still want to catch errors for
+	   the invalid one, even though we might handle them differently. */
+	for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
+
+		if (test_bit(epid, (void *)&reg->r_usb_epid_attn)) {
+
+			struct urb *urb;
+			__u32 r_usb_ept_data;
+			unsigned long flags;
+			int error_code;
+
+			save_flags(flags);
+			cli();
+			*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+			nop();
+			/* Note that although there are separate R_USB_EPT_DATA and R_USB_EPT_DATA_ISO
+			   registers, they are located at the same address and are of the same size.
+			   In other words, this read should be ok for isoc also. */
+			r_usb_ept_data = *R_USB_EPT_DATA;
+			restore_flags(flags);
+
+			/* First some sanity checks. */
+			if (epid == INVALID_EPID) {
+				/* FIXME: What if it became disabled? Could seriously hurt interrupt
+				   traffic. (Use do_intr_recover.) */
+				warn("Got epid_attn for INVALID_EPID (%d).", epid);
+				err("R_USB_EPT_DATA = 0x%x", r_usb_ept_data);
+				err("R_USB_STATUS = 0x%x", reg->r_usb_status);
+				continue;
+			} else 	if (epid == DUMMY_EPID) {
+				/* We definitely don't care about these ones. Besides, they are
+				   always disabled, so any possible disabling caused by the
+				   epid attention interrupt is irrelevant. */
+				warn("Got epid_attn for DUMMY_EPID (%d).", epid);
+				continue;
+			}
+
+			/* Get the first urb in the urb list for this epid. We blatantly assume
+			   that only the first urb could have caused the epid attention.
+			   (For bulk and ctrl, only one urb is active at any one time. For intr
+			   and isoc we remove them once they are completed.) */
+			urb = urb_list_first(epid);
+
+			if (urb == NULL) {
+				err("Got epid_attn for epid %i with no urb.", epid);
+				err("R_USB_EPT_DATA = 0x%x", r_usb_ept_data);
+				err("R_USB_STATUS = 0x%x", reg->r_usb_status);
+				continue;
+			}
+
+			switch (usb_pipetype(urb->pipe)) {
+			case PIPE_BULK:
+				warn("Got epid attn for bulk endpoint, epid %d", epid);
+				break;
+			case PIPE_CONTROL:
+				warn("Got epid attn for control endpoint, epid %d", epid);
+				break;
+			case PIPE_INTERRUPT:
+				warn("Got epid attn for interrupt endpoint, epid %d", epid);
+				break;
+			case PIPE_ISOCHRONOUS:
+				warn("Got epid attn for isochronous endpoint, epid %d", epid);
+				break;
+			}
+
+			if (usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) {
+				if (r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, hold)) {
+					warn("Hold was set for epid %d.", epid);
+					continue;
+				}
+			}
+
+			/* Even though error_code occupies bits 22 - 23 in both R_USB_EPT_DATA and
+			   R_USB_EPT_DATA_ISOC, we separate them here so we don't forget in other places. */
+			if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+				error_code = IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data);
+			} else {
+				error_code = IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data);
+			}
+
+			/* Using IO_STATE_VALUE on R_USB_EPT_DATA should be ok for isoc also. */
+			if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
+
+				/* Isoc traffic doesn't have error_count_in/error_count_out. */
+				if ((usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) &&
+				    (IO_EXTRACT(R_USB_EPT_DATA, error_count_in, r_usb_ept_data) == 3 ||
+				     IO_EXTRACT(R_USB_EPT_DATA, error_count_out, r_usb_ept_data) == 3)) {
+					/* 3rd error. */
+					warn("3rd error for epid %i", epid);
+					etrax_usb_complete_urb(urb, -EPROTO);
+
+				} else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) {
+
+					warn("Perror for epid %d", epid);
+
+					if (!(r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, valid))) {
+						/* invalid ep_id */
+						panic("Perror because of invalid epid."
+						      " Deconfigured too early?");
+					} else {
+						/* past eof1, near eof, zout transfer, setup transfer */
+
+						/* Dump the urb and the relevant EP descriptor list. */
+
+						__dump_urb(urb);
+						__dump_ept_data(epid);
+						__dump_ep_list(usb_pipetype(urb->pipe));
+
+						panic("Something wrong with DMA descriptor contents."
+						      " Too much traffic inserted?");
+					}
+				} else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) {
+					/* buffer ourun */
+					panic("Buffer overrun/underrun for epid %d. DMA too busy?", epid);
+				}
+
+			} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, stall)) {
+				/* Not really a protocol error, just says that the endpoint gave
+				   a stall response. Note that error_code cannot be stall for isoc. */
+				if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+					panic("Isoc traffic cannot stall");
+				}
+
+				warn("Stall for epid %d", epid);
+				etrax_usb_complete_urb(urb, -EPIPE);
+
+			} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, bus_error)) {
+				/* Two devices responded to a transaction request. Must be resolved
+				   by software. FIXME: Reset ports? */
+				panic("Bus error for epid %d."
+				      " Two devices responded to transaction request",
+				      epid);
+
+			} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, buffer_error)) {
+				/* DMA overrun or underrun. */
+				warn("Buffer overrun/underrun for epid %d. DMA too busy?", epid);
+
+				/* It seems that error_code = buffer_error in
+				   R_USB_EPT_DATA/R_USB_EPT_DATA_ISO and ourun = yes in R_USB_STATUS
+				   are the same error. */
+				etrax_usb_complete_urb(urb, -EPROTO);
+			}
+		}
+	}
+
+	DBFEXIT;
+
+}
+
+void etrax_usb_bulk_start_timer_func(unsigned long dummy)
+{
+
+	/* We might enable an EP descriptor behind the current DMA position when it's about
+	   to decide that there are no more bulk traffic and it should stop the bulk channel.
+	   Therefore we periodically check if the bulk channel is stopped and there is an
+	   enabled bulk EP descriptor, in which case we start the bulk channel. */
+	dbg_bulk("bulk_start_timer timed out.");
+
+	if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) {
+		int epid;
+
+		dbg_bulk("Bulk DMA channel not running.");
+
+		for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
+			if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
+				dbg_bulk("Found enabled EP for epid %d, starting bulk channel.\n",
+					 epid);
+				*R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
+
+				/* Restart the bulk eot timer since we just started the bulk channel. */
+				mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
+
+				/* No need to search any further. */
+				break;
+			}
+		}
+	} else {
+		dbg_bulk("Bulk DMA channel running.");
+	}
+}
+
+void etrax_usb_hc_port_status_interrupt(usb_interrupt_registers_t *reg)
+{
+	etrax_hc_t *hc = reg->hc;
+	__u16 r_usb_rh_port_status_1 = reg->r_usb_rh_port_status_1;
+	__u16 r_usb_rh_port_status_2 = reg->r_usb_rh_port_status_2;
+
+	DBFENTER;
+
+	/* The Etrax RH does not include a wPortChange register, so this has to be handled in software
+	   (by saving the old port status value for comparison when the port status interrupt happens).
+	   See section 11.16.2.6.2 in the USB 1.1 spec for details. */
+
+	dbg_rh("hc->rh.prev_wPortStatus_1 = 0x%x", hc->rh.prev_wPortStatus_1);
+	dbg_rh("hc->rh.prev_wPortStatus_2 = 0x%x", hc->rh.prev_wPortStatus_2);
+	dbg_rh("r_usb_rh_port_status_1 = 0x%x", r_usb_rh_port_status_1);
+	dbg_rh("r_usb_rh_port_status_2 = 0x%x", r_usb_rh_port_status_2);
+
+	/* C_PORT_CONNECTION is set on any transition. */
+	hc->rh.wPortChange_1 |=
+		((r_usb_rh_port_status_1 & (1 << RH_PORT_CONNECTION)) !=
+		 (hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_CONNECTION))) ?
+		(1 << RH_PORT_CONNECTION) : 0;
+
+	hc->rh.wPortChange_2 |=
+		((r_usb_rh_port_status_2 & (1 << RH_PORT_CONNECTION)) !=
+		 (hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_CONNECTION))) ?
+		(1 << RH_PORT_CONNECTION) : 0;
+
+	/* C_PORT_ENABLE is _only_ set on a one to zero transition, i.e. when
+	   the port is disabled, not when it's enabled. */
+	hc->rh.wPortChange_1 |=
+		((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_ENABLE))
+		 && !(r_usb_rh_port_status_1 & (1 << RH_PORT_ENABLE))) ?
+		(1 << RH_PORT_ENABLE) : 0;
+
+	hc->rh.wPortChange_2 |=
+		((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_ENABLE))
+		 && !(r_usb_rh_port_status_2 & (1 << RH_PORT_ENABLE))) ?
+		(1 << RH_PORT_ENABLE) : 0;
+
+	/* C_PORT_SUSPEND is set to one when the device has transitioned out
+	   of the suspended state, i.e. when suspend goes from one to zero. */
+	hc->rh.wPortChange_1 |=
+		((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_SUSPEND))
+		 && !(r_usb_rh_port_status_1 & (1 << RH_PORT_SUSPEND))) ?
+		(1 << RH_PORT_SUSPEND) : 0;
+
+	hc->rh.wPortChange_2 |=
+		((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_SUSPEND))
+		 && !(r_usb_rh_port_status_2 & (1 << RH_PORT_SUSPEND))) ?
+		(1 << RH_PORT_SUSPEND) : 0;
+
+
+	/* C_PORT_RESET is set when reset processing on this port is complete. */
+	hc->rh.wPortChange_1 |=
+		((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_RESET))
+		 && !(r_usb_rh_port_status_1 & (1 << RH_PORT_RESET))) ?
+		(1 << RH_PORT_RESET) : 0;
+
+	hc->rh.wPortChange_2 |=
+		((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_RESET))
+		 && !(r_usb_rh_port_status_2 & (1 << RH_PORT_RESET))) ?
+		(1 << RH_PORT_RESET) : 0;
+
+	/* Save the new values for next port status change. */
+	hc->rh.prev_wPortStatus_1 = r_usb_rh_port_status_1;
+	hc->rh.prev_wPortStatus_2 = r_usb_rh_port_status_2;
+
+	dbg_rh("hc->rh.wPortChange_1 set to 0x%x", hc->rh.wPortChange_1);
+	dbg_rh("hc->rh.wPortChange_2 set to 0x%x", hc->rh.wPortChange_2);
+
+	DBFEXIT;
+
+}
+
+void etrax_usb_hc_ctl_status_interrupt(usb_interrupt_registers_t *reg)
+{
+	DBFENTER;
+
+	/* FIXME: What should we do if we get ourun or perror? Dump the EP and SB
+	   list for the corresponding epid? */
+	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) {
+		panic("USB controller got ourun.");
+	}
+	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) {
+
+		/* Before, etrax_usb_do_intr_recover was called on this epid if it was
+		   an interrupt pipe. I don't see how re-enabling all EP descriptors
+		   will help if there was a programming error. */
+		panic("USB controller got perror.");
+	}
+
+	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, device_mode)) {
+		/* We should never operate in device mode. */
+		panic("USB controller in device mode.");
+	}
+
+	/* These if-statements could probably be nested. */
+	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, host_mode)) {
+		info("USB controller in host mode.");
+	}
+	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, started)) {
+		info("USB controller started.");
+	}
+	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, running)) {
+		info("USB controller running.");
+	}
+
+	DBFEXIT;
+
+}
+
+
+static int etrax_rh_submit_urb(struct urb *urb)
+{
+	struct usb_device *usb_dev = urb->dev;
+	etrax_hc_t *hc = usb_dev->bus->hcpriv;
+	unsigned int pipe = urb->pipe;
+	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
+	void *data = urb->transfer_buffer;
+	int leni = urb->transfer_buffer_length;
+	int len = 0;
+	int stat = 0;
+
+	__u16 bmRType_bReq;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+
+	DBFENTER;
+
+	/* FIXME: What is this interrupt urb that is sent to the root hub? */
+	if (usb_pipetype (pipe) == PIPE_INTERRUPT) {
+		dbg_rh("Root-Hub submit IRQ: every %d ms", urb->interval);
+		hc->rh.urb = urb;
+		hc->rh.send = 1;
+		/* FIXME: We could probably remove this line since it's done
+		   in etrax_rh_init_int_timer. (Don't remove it from
+		   etrax_rh_init_int_timer though.) */
+		hc->rh.interval = urb->interval;
+		etrax_rh_init_int_timer(urb);
+		DBFEXIT;
+
+		return 0;
+	}
+
+	bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8);
+	wValue = le16_to_cpu(cmd->wValue);
+	wIndex = le16_to_cpu(cmd->wIndex);
+	wLength = le16_to_cpu(cmd->wLength);
+
+	dbg_rh("bmRType_bReq : 0x%04x (%d)", bmRType_bReq, bmRType_bReq);
+	dbg_rh("wValue       : 0x%04x (%d)", wValue, wValue);
+	dbg_rh("wIndex       : 0x%04x (%d)", wIndex, wIndex);
+	dbg_rh("wLength      : 0x%04x (%d)", wLength, 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 = cpu_to_le16 (1);
+		OK (2);
+
+	case RH_GET_STATUS | RH_INTERFACE:
+		*(__u16 *) data = cpu_to_le16 (0);
+		OK (2);
+
+	case RH_GET_STATUS | RH_ENDPOINT:
+		*(__u16 *) data = cpu_to_le16 (0);
+		OK (2);
+
+	case RH_GET_STATUS | RH_CLASS:
+		*(__u32 *) data = cpu_to_le32 (0);
+		OK (4);		/* hub power ** */
+
+	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+		if (wIndex == 1) {
+			*((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_1);
+			*((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_1);
+		} else if (wIndex == 2) {
+			*((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_2);
+			*((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_2);
+		} else {
+			dbg_rh("RH_GET_STATUS whith invalid wIndex!");
+			OK(0);
+		}
+
+		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_OVER_CURRENT):
+			OK (0);	/* hub power over current ** */
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_ENABLE):
+			if (wIndex == 1) {
+
+				dbg_rh("trying to do disable port 1");
+
+				*R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, yes);
+
+				while (hc->rh.prev_wPortStatus_1 &
+				       IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes));
+				*R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
+				dbg_rh("Port 1 is disabled");
+
+			} else if (wIndex == 2) {
+
+				dbg_rh("trying to do disable port 2");
+
+				*R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, yes);
+
+				while (hc->rh.prev_wPortStatus_2 &
+				       IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, yes));
+				*R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no);
+				dbg_rh("Port 2 is disabled");
+
+			} else {
+				dbg_rh("RH_CLEAR_FEATURE->RH_PORT_ENABLE "
+				       "with invalid wIndex == %d!", wIndex);
+			}
+
+			OK (0);
+		case (RH_PORT_SUSPEND):
+			/* Opposite to suspend should be resume, so we'll do a resume. */
+			/* FIXME: USB 1.1, 11.16.2.2 says:
+			   "Clearing the PORT_SUSPEND feature causes a host-initiated resume
+			   on the specified port. If the port is not in the Suspended state,
+			   the hub should treat this request as a functional no-operation."
+			   Shouldn't we check if the port is in a suspended state before
+			   resuming? */
+
+			/* Make sure the controller isn't busy. */
+			while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+			if (wIndex == 1) {
+				*R_USB_COMMAND =
+					IO_STATE(R_USB_COMMAND, port_sel, port1) |
+					IO_STATE(R_USB_COMMAND, port_cmd, resume) |
+					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+			} else if (wIndex == 2) {
+				*R_USB_COMMAND =
+					IO_STATE(R_USB_COMMAND, port_sel, port2) |
+					IO_STATE(R_USB_COMMAND, port_cmd, resume) |
+					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+			} else {
+				dbg_rh("RH_CLEAR_FEATURE->RH_PORT_SUSPEND "
+				       "with invalid wIndex == %d!", wIndex);
+			}
+
+			OK (0);
+		case (RH_PORT_POWER):
+			OK (0);	/* port power ** */
+		case (RH_C_PORT_CONNECTION):
+			if (wIndex == 1) {
+				hc->rh.wPortChange_1 &= ~(1 << RH_PORT_CONNECTION);
+			} else if (wIndex == 2) {
+				hc->rh.wPortChange_2 &= ~(1 << RH_PORT_CONNECTION);
+			} else {
+				dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_CONNECTION "
+				       "with invalid wIndex == %d!", wIndex);
+			}
+
+			OK (0);
+		case (RH_C_PORT_ENABLE):
+			if (wIndex == 1) {
+				hc->rh.wPortChange_1 &= ~(1 << RH_PORT_ENABLE);
+			} else if (wIndex == 2) {
+				hc->rh.wPortChange_2 &= ~(1 << RH_PORT_ENABLE);
+			} else {
+				dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_ENABLE "
+				       "with invalid wIndex == %d!", wIndex);
+			}
+			OK (0);
+		case (RH_C_PORT_SUSPEND):
+/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
+			OK (0);
+		case (RH_C_PORT_OVER_CURRENT):
+			OK (0);	/* port power over current ** */
+		case (RH_C_PORT_RESET):
+			if (wIndex == 1) {
+				hc->rh.wPortChange_1 &= ~(1 << RH_PORT_RESET);
+			} else if (wIndex == 2) {
+				hc->rh.wPortChange_2 &= ~(1 << RH_PORT_RESET);
+			} else {
+				dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_RESET "
+				       "with invalid index == %d!", wIndex);
+			}
+
+			OK (0);
+
+		}
+		break;
+
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_SUSPEND):
+
+			/* Make sure the controller isn't busy. */
+			while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+			if (wIndex == 1) {
+				*R_USB_COMMAND =
+					IO_STATE(R_USB_COMMAND, port_sel, port1) |
+					IO_STATE(R_USB_COMMAND, port_cmd, suspend) |
+					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+			} else if (wIndex == 2) {
+				*R_USB_COMMAND =
+					IO_STATE(R_USB_COMMAND, port_sel, port2) |
+					IO_STATE(R_USB_COMMAND, port_cmd, suspend) |
+					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+			} else {
+				dbg_rh("RH_SET_FEATURE->RH_PORT_SUSPEND "
+				       "with invalid wIndex == %d!", wIndex);
+			}
+
+			OK (0);
+		case (RH_PORT_RESET):
+			if (wIndex == 1) {
+
+			port_1_reset:
+				dbg_rh("Doing reset of port 1");
+
+				/* Make sure the controller isn't busy. */
+				while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+				*R_USB_COMMAND =
+					IO_STATE(R_USB_COMMAND, port_sel, port1) |
+					IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+
+				/* We must wait at least 10 ms for the device to recover.
+				   15 ms should be enough. */
+				udelay(15000);
+
+				/* Wait for reset bit to go low (should be done by now). */
+				while (hc->rh.prev_wPortStatus_1 &
+				       IO_STATE(R_USB_RH_PORT_STATUS_1, reset, yes));
+
+				/* If the port status is
+				   1) connected and enabled then there is a device and everything is fine
+				   2) neither connected nor enabled then there is no device, also fine
+				   3) connected and not enabled then we try again
+				   (Yes, there are other port status combinations besides these.) */
+
+				if ((hc->rh.prev_wPortStatus_1 &
+				     IO_STATE(R_USB_RH_PORT_STATUS_1, connected, yes)) &&
+				    (hc->rh.prev_wPortStatus_1 &
+				     IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, no))) {
+					dbg_rh("Connected device on port 1, but port not enabled?"
+					       " Trying reset again.");
+					goto port_2_reset;
+				}
+
+				/* Diagnostic printouts. */
+				if ((hc->rh.prev_wPortStatus_1 &
+				     IO_STATE(R_USB_RH_PORT_STATUS_1, connected, no)) &&
+				    (hc->rh.prev_wPortStatus_1 &
+				     IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, no))) {
+					dbg_rh("No connected device on port 1");
+				} else if ((hc->rh.prev_wPortStatus_1 &
+					    IO_STATE(R_USB_RH_PORT_STATUS_1, connected, yes)) &&
+					   (hc->rh.prev_wPortStatus_1 &
+					    IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes))) {
+					dbg_rh("Connected device on port 1, port 1 enabled");
+				}
+
+			} else if (wIndex == 2) {
+
+			port_2_reset:
+				dbg_rh("Doing reset of port 2");
+
+				/* Make sure the controller isn't busy. */
+				while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+				/* Issue the reset command. */
+				*R_USB_COMMAND =
+					IO_STATE(R_USB_COMMAND, port_sel, port2) |
+					IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+
+				/* We must wait at least 10 ms for the device to recover.
+				   15 ms should be enough. */
+				udelay(15000);
+
+				/* Wait for reset bit to go low (should be done by now). */
+				while (hc->rh.prev_wPortStatus_2 &
+				       IO_STATE(R_USB_RH_PORT_STATUS_2, reset, yes));
+
+				/* If the port status is
+				   1) connected and enabled then there is a device and everything is fine
+				   2) neither connected nor enabled then there is no device, also fine
+				   3) connected and not enabled then we try again
+				   (Yes, there are other port status combinations besides these.) */
+
+				if ((hc->rh.prev_wPortStatus_2 &
+				     IO_STATE(R_USB_RH_PORT_STATUS_2, connected, yes)) &&
+				    (hc->rh.prev_wPortStatus_2 &
+				     IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, no))) {
+					dbg_rh("Connected device on port 2, but port not enabled?"
+					       " Trying reset again.");
+					goto port_2_reset;
+				}
+
+				/* Diagnostic printouts. */
+				if ((hc->rh.prev_wPortStatus_2 &
+				     IO_STATE(R_USB_RH_PORT_STATUS_2, connected, no)) &&
+				    (hc->rh.prev_wPortStatus_2 &
+				     IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, no))) {
+					dbg_rh("No connected device on port 2");
+				} else if ((hc->rh.prev_wPortStatus_2 &
+					    IO_STATE(R_USB_RH_PORT_STATUS_2, connected, yes)) &&
+					   (hc->rh.prev_wPortStatus_2 &
+					    IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, yes))) {
+					dbg_rh("Connected device on port 2, port 2 enabled");
+				}
+
+			} else {
+				dbg_rh("RH_SET_FEATURE->RH_PORT_RESET with invalid wIndex = %d", wIndex);
+			}
+
+			/* Make sure the controller isn't busy. */
+			while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+			/* If all enabled ports were disabled the host controller goes down into
+			   started mode, so we need to bring it back into the running state.
+			   (This is safe even if it's already in the running state.) */
+			*R_USB_COMMAND =
+				IO_STATE(R_USB_COMMAND, port_sel, nop) |
+				IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+				IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run);
+
+			dbg_rh("...Done");
+			OK(0);
+
+		case (RH_PORT_POWER):
+			OK (0);	/* port power ** */
+		case (RH_PORT_ENABLE):
+			/* There is no port enable command in the host controller, so if the
+			   port is already enabled, we do nothing. If not, we reset the port
+			   (with an ugly goto). */
+
+			if (wIndex == 1) {
+				if (hc->rh.prev_wPortStatus_1 &
+				    IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, no)) {
+					goto port_1_reset;
+				}
+			} else if (wIndex == 2) {
+				if (hc->rh.prev_wPortStatus_2 &
+				    IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, no)) {
+					goto port_2_reset;
+				}
+			} else {
+				dbg_rh("RH_SET_FEATURE->RH_GET_STATUS with invalid wIndex = %d", wIndex);
+			}
+			OK (0);
+		}
+		break;
+
+	case RH_SET_ADDRESS:
+		hc->rh.devnum = wValue;
+		dbg_rh("RH address set to: %d", hc->rh.devnum);
+		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));
+			memcpy (data, root_hub_dev_des, len);
+			OK (len);
+		case (0x02):	/* configuration descriptor */
+			len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_config_des), wLength));
+			memcpy (data, root_hub_config_des, len);
+			OK (len);
+		case (0x03):	/* string descriptors */
+			len = usb_root_hub_string (wValue & 0xff,
+						   0xff, "ETRAX 100LX",
+						   data, wLength);
+			if (len > 0) {
+				OK(min(leni, len));
+			} else {
+				stat = -EPIPE;
+			}
+
+		}
+		break;
+
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+		root_hub_hub_des[2] = hc->rh.numports;
+		len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_hub_des), wLength));
+		memcpy (data, root_hub_hub_des, len);
+		OK (len);
+
+	case RH_GET_CONFIGURATION:
+		*(__u8 *) data = 0x01;
+		OK (1);
+
+	case RH_SET_CONFIGURATION:
+		OK (0);
+
+	default:
+		stat = -EPIPE;
+	}
+
+	urb->actual_length = len;
+	urb->status = stat;
+	urb->dev = NULL;
+	if (urb->complete) {
+		urb->complete(urb, NULL);
+	}
+	DBFEXIT;
+
+	return 0;
+}
+
+static void
+etrax_usb_bulk_eot_timer_func(unsigned long dummy)
+{
+	/* Because of a race condition in the top half, we might miss a bulk eot.
+	   This timer "simulates" a bulk eot if we don't get one for a while, hopefully
+	   correcting the situation. */
+	dbg_bulk("bulk_eot_timer timed out.");
+	etrax_usb_hc_bulk_eot_interrupt(1);
+}
+
+static void*
+etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, int mem_flags, dma_addr_t *dma)
+{
+  return kmalloc(size, mem_flags);
+}
+
+static void
+etrax_usb_buffer_free(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma)
+{
+  kfree(addr);
+}
+
+
+static struct device fake_device;
+
+static int __init etrax_usb_hc_init(void)
+{
+	static etrax_hc_t *hc;
+	struct usb_bus *bus;
+	struct usb_device *usb_rh;
+	int i;
+
+	DBFENTER;
+
+	info("ETRAX 100LX USB-HCD %s (c) 2001-2003 Axis Communications AB\n", usb_hcd_version);
+
+ 	hc = kmalloc(sizeof(etrax_hc_t), GFP_KERNEL);
+	assert(hc != NULL);
+
+	/* We use kmem_cache_* to make sure that all DMA desc. are dword aligned */
+	/* Note that we specify sizeof(USB_EP_Desc_t) as the size, but also allocate
+	   SB descriptors from this cache. This is ok since sizeof(USB_EP_Desc_t) ==
+	   sizeof(USB_SB_Desc_t). */
+
+	usb_desc_cache = kmem_cache_create("usb_desc_cache", sizeof(USB_EP_Desc_t), 0,
+					   SLAB_HWCACHE_ALIGN, 0, 0);
+	assert(usb_desc_cache != NULL);
+
+	top_half_reg_cache = kmem_cache_create("top_half_reg_cache",
+					       sizeof(usb_interrupt_registers_t),
+					       0, SLAB_HWCACHE_ALIGN, 0, 0);
+	assert(top_half_reg_cache != NULL);
+
+	isoc_compl_cache = kmem_cache_create("isoc_compl_cache",
+						sizeof(usb_isoc_complete_data_t),
+						0, SLAB_HWCACHE_ALIGN, 0, 0);
+	assert(isoc_compl_cache != NULL);
+
+	etrax_usb_bus = bus = usb_alloc_bus(&etrax_usb_device_operations);
+	hc->bus = bus;
+	bus->bus_name="ETRAX 100LX";
+	bus->hcpriv = hc;
+
+	/* Initalize RH to the default address.
+	   And make sure that we have no status change indication */
+	hc->rh.numports = 2;  /* The RH has two ports */
+	hc->rh.devnum = 1;
+	hc->rh.wPortChange_1 = 0;
+	hc->rh.wPortChange_2 = 0;
+
+	/* Also initate the previous values to zero */
+	hc->rh.prev_wPortStatus_1 = 0;
+	hc->rh.prev_wPortStatus_2 = 0;
+
+	/* Initialize the intr-traffic flags */
+	/* FIXME: This isn't used. (Besides, the error field isn't initialized.) */
+	hc->intr.sleeping = 0;
+	hc->intr.wq = NULL;
+
+	epid_usage_bitmask = 0;
+	epid_out_traffic = 0;
+
+	/* Mark the invalid epid as being used. */
+	set_bit(INVALID_EPID, (void *)&epid_usage_bitmask);
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, INVALID_EPID);
+	nop();
+	/* The valid bit should still be set ('invalid' is in our world; not the hardware's). */
+	*R_USB_EPT_DATA = (IO_STATE(R_USB_EPT_DATA, valid, yes) |
+			   IO_FIELD(R_USB_EPT_DATA, max_len, 1));
+
+	/* Mark the dummy epid as being used. */
+	set_bit(DUMMY_EPID, (void *)&epid_usage_bitmask);
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, DUMMY_EPID);
+	nop();
+	*R_USB_EPT_DATA = (IO_STATE(R_USB_EPT_DATA, valid, no) |
+			   IO_FIELD(R_USB_EPT_DATA, max_len, 1));
+
+	/* Initialize the urb list by initiating a head for each list. */
+	for (i = 0; i < NBR_OF_EPIDS; i++) {
+		INIT_LIST_HEAD(&urb_list[i]);
+	}
+	spin_lock_init(&urb_list_lock);
+
+	INIT_LIST_HEAD(&urb_unlink_list);
+
+
+	/* Initiate the bulk start timer. */
+	init_timer(&bulk_start_timer);
+	bulk_start_timer.expires = jiffies + BULK_START_TIMER_INTERVAL;
+	bulk_start_timer.function = etrax_usb_bulk_start_timer_func;
+	add_timer(&bulk_start_timer);
+
+
+	/* Initiate the bulk eot timer. */
+	init_timer(&bulk_eot_timer);
+	bulk_eot_timer.expires = jiffies + BULK_EOT_TIMER_INTERVAL;
+	bulk_eot_timer.function = etrax_usb_bulk_eot_timer_func;
+	add_timer(&bulk_eot_timer);
+
+	/* Set up the data structures for USB traffic. Note that this must be done before
+	   any interrupt that relies on sane DMA list occurrs. */
+	init_rx_buffers();
+	init_tx_bulk_ep();
+	init_tx_ctrl_ep();
+	init_tx_intr_ep();
+	init_tx_isoc_ep();
+
+        device_initialize(&fake_device);
+        kobject_set_name(&fake_device.kobj, "etrax_usb");
+        kobject_add(&fake_device.kobj);
+        hc->bus->controller = &fake_device;
+	usb_register_bus(hc->bus);
+
+	*R_IRQ_MASK2_SET =
+		/* Note that these interrupts are not used. */
+		IO_STATE(R_IRQ_MASK2_SET, dma8_sub0_descr, set) |
+		/* Sub channel 1 (ctrl) descr. interrupts are used. */
+		IO_STATE(R_IRQ_MASK2_SET, dma8_sub1_descr, set) |
+		IO_STATE(R_IRQ_MASK2_SET, dma8_sub2_descr, set) |
+		/* Sub channel 3 (isoc) descr. interrupts are used. */
+		IO_STATE(R_IRQ_MASK2_SET, dma8_sub3_descr, set);
+
+	/* Note that the dma9_descr interrupt is not used. */
+	*R_IRQ_MASK2_SET =
+		IO_STATE(R_IRQ_MASK2_SET, dma9_eop, set) |
+		IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set);
+
+	/* FIXME: Enable iso_eof only when isoc traffic is running. */
+	*R_USB_IRQ_MASK_SET =
+		IO_STATE(R_USB_IRQ_MASK_SET, iso_eof, set) |
+		IO_STATE(R_USB_IRQ_MASK_SET, bulk_eot, set) |
+		IO_STATE(R_USB_IRQ_MASK_SET, epid_attn, set) |
+		IO_STATE(R_USB_IRQ_MASK_SET, port_status, set) |
+		IO_STATE(R_USB_IRQ_MASK_SET, ctl_status, set);
+
+
+	if (request_irq(ETRAX_USB_HC_IRQ, etrax_usb_hc_interrupt_top_half, 0,
+			"ETRAX 100LX built-in USB (HC)", hc)) {
+		err("Could not allocate IRQ %d for USB", ETRAX_USB_HC_IRQ);
+		etrax_usb_hc_cleanup();
+		DBFEXIT;
+		return -1;
+	}
+
+	if (request_irq(ETRAX_USB_RX_IRQ, etrax_usb_rx_interrupt, 0,
+			"ETRAX 100LX built-in USB (Rx)", hc)) {
+		err("Could not allocate IRQ %d for USB", ETRAX_USB_RX_IRQ);
+		etrax_usb_hc_cleanup();
+		DBFEXIT;
+		return -1;
+	}
+
+	if (request_irq(ETRAX_USB_TX_IRQ, etrax_usb_tx_interrupt, 0,
+			"ETRAX 100LX built-in USB (Tx)", hc)) {
+		err("Could not allocate IRQ %d for USB", ETRAX_USB_TX_IRQ);
+		etrax_usb_hc_cleanup();
+		DBFEXIT;
+		return -1;
+	}
+
+	/* R_USB_COMMAND:
+	   USB commands in host mode. The fields in this register should all be
+	   written to in one write. Do not read-modify-write one field at a time. A
+	   write to this register will trigger events in the USB controller and an
+	   incomplete command may lead to unpredictable results, and in worst case
+	   even to a deadlock in the controller.
+	   (Note however that the busy field is read-only, so no need to write to it.) */
+
+	/* Check the busy bit before writing to R_USB_COMMAND. */
+
+	while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+	/* Reset the USB interface. */
+	*R_USB_COMMAND =
+		IO_STATE(R_USB_COMMAND, port_sel, nop) |
+		IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+		IO_STATE(R_USB_COMMAND, ctrl_cmd, reset);
+
+	/* Designer's Reference, p. 8 - 10 says we should Initate R_USB_FM_PSTART to 0x2A30 (10800),
+	   to guarantee that control traffic gets 10% of the bandwidth, and periodic transfer may
+	   allocate the rest (90%). This doesn't work though. Read on for a lenghty explanation.
+
+	   While there is a difference between rev. 2 and rev. 3 of the ETRAX 100LX regarding the NAK
+	   behaviour, it doesn't solve this problem. What happens is that a control transfer will not
+	   be interrupted in its data stage when PSTART happens (the point at which periodic traffic
+	   is started). Thus, if PSTART is set to 10800 and its IN or OUT token is NAKed until just before
+	   PSTART happens, it will continue the IN/OUT transfer as long as it's ACKed. After it's done,
+	   there may be too little time left for an isochronous transfer, causing an epid attention
+	   interrupt due to perror. The work-around for this is to let the control transfers run at the
+	   end of the frame instead of at the beginning, and will be interrupted just fine if it doesn't
+	   fit into the frame. However, since there will *always* be a control transfer at the beginning
+	   of the frame, regardless of what we set PSTART to, that transfer might be a 64-byte transfer
+	   which consumes up to 15% of the frame, leaving only 85% for periodic traffic. The solution to
+	   this would be to 'dummy allocate' 5% of the frame with the usb_claim_bandwidth function to make
+	   sure that the periodic transfers that are inserted will always fit in the frame.
+
+	   The idea was suggested that a control transfer could be split up into several 8 byte transfers,
+	   so that it would be interrupted by PSTART, but since this can't be done for an IN transfer this
+	   hasn't been implemented.
+
+	   The value 11960 is chosen to be just after the SOF token, with a couple of bit times extra
+	   for possible bit stuffing. */
+
+	*R_USB_FM_PSTART = IO_FIELD(R_USB_FM_PSTART, value, 11960);
+
+#ifdef CONFIG_ETRAX_USB_HOST_PORT1
+	*R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
+#endif
+
+#ifdef CONFIG_ETRAX_USB_HOST_PORT2
+	*R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no);
+#endif
+
+	while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+	/* Configure the USB interface as a host controller. */
+	*R_USB_COMMAND =
+		IO_STATE(R_USB_COMMAND, port_sel, nop) |
+		IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+		IO_STATE(R_USB_COMMAND, ctrl_cmd, host_config);
+
+	/* Note: Do not reset any ports here. Await the port status interrupts, to have a controlled
+	   sequence of resetting the ports. If we reset both ports now, and there are devices
+	   on both ports, we will get a bus error because both devices will answer the set address
+	   request. */
+
+	while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+	/* Start processing of USB traffic. */
+	*R_USB_COMMAND =
+		IO_STATE(R_USB_COMMAND, port_sel, nop) |
+		IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+		IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run);
+
+	while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+	usb_rh = usb_alloc_dev(NULL, hc->bus, 0);
+	hc->bus->root_hub = usb_rh;
+        usb_rh->state = USB_STATE_ADDRESS;
+        usb_rh->speed = USB_SPEED_FULL;
+        usb_rh->devnum = 1;
+        hc->bus->devnum_next = 2;
+        usb_rh->ep0.desc.wMaxPacketSize = __const_cpu_to_le16(64);
+        usb_get_device_descriptor(usb_rh, USB_DT_DEVICE_SIZE);
+	usb_new_device(usb_rh);
+
+	DBFEXIT;
+
+	return 0;
+}
+
+static void etrax_usb_hc_cleanup(void)
+{
+	DBFENTER;
+
+	free_irq(ETRAX_USB_HC_IRQ, NULL);
+	free_irq(ETRAX_USB_RX_IRQ, NULL);
+	free_irq(ETRAX_USB_TX_IRQ, NULL);
+
+	usb_deregister_bus(etrax_usb_bus);
+
+	/* FIXME: call kmem_cache_destroy here? */
+
+	DBFEXIT;
+}
+
+module_init(etrax_usb_hc_init);
+module_exit(etrax_usb_hc_cleanup);
diff --git a/drivers/usb/host/hc_crisv10.h b/drivers/usb/host/hc_crisv10.h
new file mode 100644
index 0000000..62f7711
--- /dev/null
+++ b/drivers/usb/host/hc_crisv10.h
@@ -0,0 +1,289 @@
+#ifndef __LINUX_ETRAX_USB_H
+#define __LINUX_ETRAX_USB_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+typedef struct USB_IN_Desc {
+	volatile __u16 sw_len;
+	volatile __u16 command;
+	volatile unsigned long next;
+	volatile unsigned long buf;
+	volatile __u16 hw_len;
+	volatile __u16 status;
+} USB_IN_Desc_t;
+
+typedef struct USB_SB_Desc {
+	volatile __u16 sw_len;
+	volatile __u16 command;
+	volatile unsigned long next;
+	volatile unsigned long buf;
+	__u32 dummy;
+} USB_SB_Desc_t;
+
+typedef struct USB_EP_Desc {
+	volatile __u16 hw_len;
+	volatile __u16 command;
+	volatile unsigned long sub;
+	volatile unsigned long next;
+	__u32 dummy;
+} USB_EP_Desc_t;
+
+struct virt_root_hub {
+	int devnum;
+	void *urb;
+	void *int_addr;
+	int send;
+	int interval;
+	int numports;
+	struct timer_list rh_int_timer;
+	volatile __u16 wPortChange_1;
+	volatile __u16 wPortChange_2;
+	volatile __u16 prev_wPortStatus_1;
+	volatile __u16 prev_wPortStatus_2;
+};
+
+struct etrax_usb_intr_traffic {
+	int sleeping;
+	int error;
+	struct wait_queue *wq;
+};
+
+typedef struct etrax_usb_hc {
+	struct usb_bus *bus;
+	struct virt_root_hub rh;
+	struct etrax_usb_intr_traffic intr;
+} etrax_hc_t;
+
+typedef enum {
+	STARTED,
+	NOT_STARTED,
+	UNLINK,
+	TRANSFER_DONE,
+	WAITING_FOR_DESCR_INTR
+} etrax_usb_urb_state_t;
+
+
+
+typedef struct etrax_usb_urb_priv {
+	/* The first_sb field is used for freeing all SB descriptors belonging
+	   to an urb. The corresponding ep descriptor's sub pointer cannot be
+	   used for this since the DMA advances the sub pointer as it processes
+	   the sb list. */
+	USB_SB_Desc_t *first_sb;
+	/* The last_sb field referes to the last SB descriptor that belongs to
+	   this urb. This is important to know so we can free the SB descriptors
+	   that ranges between first_sb and last_sb. */
+	USB_SB_Desc_t *last_sb;
+
+	/* The rx_offset field is used in ctrl and bulk traffic to keep track
+	   of the offset in the urb's transfer_buffer where incoming data should be
+	   copied to. */
+	__u32 rx_offset;
+
+	/* Counter used in isochronous transfers to keep track of the
+	   number of packets received/transmitted.  */
+	__u32 isoc_packet_counter;
+
+	/* This field is used to pass information about the urb's current state between
+	   the various interrupt handlers (thus marked volatile). */
+	volatile etrax_usb_urb_state_t urb_state;
+
+	/* Connection between the submitted urb and ETRAX epid number */
+	__u8 epid;
+
+	/* The rx_data_list field is used for periodic traffic, to hold
+	   received data for later processing in the the complete_urb functions,
+	   where the data us copied to the urb's transfer_buffer. Basically, we
+	   use this intermediate storage because we don't know when it's safe to
+	   reuse the transfer_buffer (FIXME?). */
+	struct list_head rx_data_list;
+} etrax_urb_priv_t;
+
+/* This struct is for passing data from the top half to the bottom half. */
+typedef struct usb_interrupt_registers
+{
+	etrax_hc_t *hc;
+	__u32 r_usb_epid_attn;
+	__u8 r_usb_status;
+	__u16 r_usb_rh_port_status_1;
+	__u16 r_usb_rh_port_status_2;
+	__u32 r_usb_irq_mask_read;
+	__u32 r_usb_fm_number;
+	struct work_struct usb_bh;
+} usb_interrupt_registers_t;
+
+/* This struct is for passing data from the isoc top half to the isoc bottom half. */
+typedef struct usb_isoc_complete_data
+{
+	struct urb *urb;
+	struct work_struct usb_bh;
+} usb_isoc_complete_data_t;
+
+/* This struct holds data we get from the rx descriptors for DMA channel 9
+   for periodic traffic (intr and isoc). */
+typedef struct rx_data
+{
+	void *data;
+	int length;
+	struct list_head list;
+} rx_data_t;
+
+typedef struct urb_entry
+{
+	struct urb *urb;
+	struct list_head list;
+} urb_entry_t;
+
+/* ---------------------------------------------------------------------------
+   Virtual Root HUB
+   ------------------------------------------------------------------------- */
+/* 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
+
+/* Our Vendor Specific feature */
+#define RH_REMOVE_EP               0x00
+
+
+#define RH_ACK                     0x01
+#define RH_REQ_ERR                 -1
+#define RH_NACK                    0x00
+
+/* Field definitions for */
+
+#define USB_IN_command__eol__BITNR      0 /* command macros */
+#define USB_IN_command__eol__WIDTH      1
+#define USB_IN_command__eol__no         0
+#define USB_IN_command__eol__yes        1
+
+#define USB_IN_command__intr__BITNR     3
+#define USB_IN_command__intr__WIDTH     1
+#define USB_IN_command__intr__no        0
+#define USB_IN_command__intr__yes       1
+
+#define USB_IN_status__eop__BITNR       1 /* status macros. */
+#define USB_IN_status__eop__WIDTH       1
+#define USB_IN_status__eop__no          0
+#define USB_IN_status__eop__yes         1
+
+#define USB_IN_status__eot__BITNR       5
+#define USB_IN_status__eot__WIDTH       1
+#define USB_IN_status__eot__no          0
+#define USB_IN_status__eot__yes         1
+
+#define USB_IN_status__error__BITNR     6
+#define USB_IN_status__error__WIDTH     1
+#define USB_IN_status__error__no        0
+#define USB_IN_status__error__yes       1
+
+#define USB_IN_status__nodata__BITNR    7
+#define USB_IN_status__nodata__WIDTH    1
+#define USB_IN_status__nodata__no       0
+#define USB_IN_status__nodata__yes      1
+
+#define USB_IN_status__epid__BITNR      8
+#define USB_IN_status__epid__WIDTH      5
+
+#define USB_EP_command__eol__BITNR      0
+#define USB_EP_command__eol__WIDTH      1
+#define USB_EP_command__eol__no         0
+#define USB_EP_command__eol__yes        1
+
+#define USB_EP_command__eof__BITNR      1
+#define USB_EP_command__eof__WIDTH      1
+#define USB_EP_command__eof__no         0
+#define USB_EP_command__eof__yes        1
+
+#define USB_EP_command__intr__BITNR     3
+#define USB_EP_command__intr__WIDTH     1
+#define USB_EP_command__intr__no        0
+#define USB_EP_command__intr__yes       1
+
+#define USB_EP_command__enable__BITNR   4
+#define USB_EP_command__enable__WIDTH   1
+#define USB_EP_command__enable__no      0
+#define USB_EP_command__enable__yes     1
+
+#define USB_EP_command__hw_valid__BITNR 5
+#define USB_EP_command__hw_valid__WIDTH 1
+#define USB_EP_command__hw_valid__no    0
+#define USB_EP_command__hw_valid__yes   1
+
+#define USB_EP_command__epid__BITNR     8
+#define USB_EP_command__epid__WIDTH     5
+
+#define USB_SB_command__eol__BITNR      0 /* command macros. */
+#define USB_SB_command__eol__WIDTH      1
+#define USB_SB_command__eol__no         0
+#define USB_SB_command__eol__yes        1
+
+#define USB_SB_command__eot__BITNR      1
+#define USB_SB_command__eot__WIDTH      1
+#define USB_SB_command__eot__no         0
+#define USB_SB_command__eot__yes        1
+
+#define USB_SB_command__intr__BITNR     3
+#define USB_SB_command__intr__WIDTH     1
+#define USB_SB_command__intr__no        0
+#define USB_SB_command__intr__yes       1
+
+#define USB_SB_command__tt__BITNR       4
+#define USB_SB_command__tt__WIDTH       2
+#define USB_SB_command__tt__zout        0
+#define USB_SB_command__tt__in          1
+#define USB_SB_command__tt__out         2
+#define USB_SB_command__tt__setup       3
+
+
+#define USB_SB_command__rem__BITNR      8
+#define USB_SB_command__rem__WIDTH      6
+
+#define USB_SB_command__full__BITNR     6
+#define USB_SB_command__full__WIDTH     1
+#define USB_SB_command__full__no        0
+#define USB_SB_command__full__yes       1
+
+#endif
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
new file mode 100644
index 0000000..3981bf1
--- /dev/null
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -0,0 +1,284 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ *
+ * Bus Glue for AMD Alchemy Au1xxx
+ *
+ * Written by Christopher Hoover <ch@hpl.hp.com>
+ * Based on fragments of previous driver by Rusell King et al.
+ *
+ * Modified for LH7A404 from ohci-sa1111.c
+ *  by Durgesh Pattamatta <pattamattad@sharpsec.com>
+ * Modified for AMD Alchemy Au1xxx
+ *  by Matt Porter <mporter@kernel.crashing.org>
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <asm/mach-au1x00/au1000.h>
+
+#define USBH_ENABLE_BE (1<<0)
+#define USBH_ENABLE_C  (1<<1)
+#define USBH_ENABLE_E  (1<<2)
+#define USBH_ENABLE_CE (1<<3)
+#define USBH_ENABLE_RD (1<<4)
+
+#ifdef __LITTLE_ENDIAN
+#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C)
+#elif __BIG_ENDIAN
+#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C | USBH_ENABLE_BE)
+#else
+#error not byte order defined
+#endif
+
+extern int usb_disabled(void);
+
+/*-------------------------------------------------------------------------*/
+
+static void au1xxx_start_hc(struct platform_device *dev)
+{
+	printk(KERN_DEBUG __FILE__
+		": starting Au1xxx OHCI USB Controller\n");
+
+	/* enable host controller */
+	au_writel(USBH_ENABLE_CE, USB_HOST_CONFIG);
+	udelay(1000);
+	au_writel(USBH_ENABLE_INIT, USB_HOST_CONFIG);
+	udelay(1000);
+
+	/* wait for reset complete (read register twice; see au1500 errata) */
+	while (au_readl(USB_HOST_CONFIG),
+		!(au_readl(USB_HOST_CONFIG) & USBH_ENABLE_RD))
+		udelay(1000);
+
+	printk(KERN_DEBUG __FILE__
+	": Clock to USB host has been enabled \n");
+}
+
+static void au1xxx_stop_hc(struct platform_device *dev)
+{
+	printk(KERN_DEBUG __FILE__
+	       ": stopping Au1xxx OHCI USB Controller\n");
+
+	/* Disable clock */
+	au_writel(readl((void *)USB_HOST_CONFIG) & ~USBH_ENABLE_CE, USB_HOST_CONFIG);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+
+/**
+ * usb_hcd_au1xxx_probe - initialize Au1xxx-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ */
+int usb_hcd_au1xxx_probe (const struct hc_driver *driver,
+			  struct platform_device *dev)
+{
+	int retval;
+	struct usb_hcd *hcd;
+
+	if(dev->resource[1].flags != IORESOURCE_IRQ) {
+		pr_debug ("resource[1] is not IORESOURCE_IRQ");
+		return -ENOMEM;
+	}
+
+	hcd = usb_create_hcd(driver, &dev->dev, "au1xxx");
+	if (!hcd)
+		return -ENOMEM;
+	hcd->rsrc_start = dev->resource[0].start;
+	hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		pr_debug("request_mem_region failed");
+		retval = -EBUSY;
+		goto err1;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		pr_debug("ioremap failed");
+		retval = -ENOMEM;
+		goto err2;
+	}
+
+	au1xxx_start_hc(dev);
+	ohci_hcd_init(hcd_to_ohci(hcd));
+
+	retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
+	if (retval == 0)
+		return retval;
+
+	au1xxx_stop_hc(dev);
+	iounmap(hcd->regs);
+ err2:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ err1:
+	usb_put_hcd(hcd);
+	return retval;
+}
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_au1xxx_remove - shutdown processing for Au1xxx-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_au1xxx_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+void usb_hcd_au1xxx_remove (struct usb_hcd *hcd, struct platform_device *dev)
+{
+	usb_remove_hcd(hcd);
+	au1xxx_stop_hc(dev);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_au1xxx_start (struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int		ret;
+
+	ohci_dbg (ohci, "ohci_au1xxx_start, ohci:%p", ohci);
+
+	if ((ret = ohci_init (ohci)) < 0)
+		return ret;
+
+	if ((ret = ohci_run (ohci)) < 0) {
+		err ("can't start %s", hcd->self.bus_name);
+		ohci_stop (hcd);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_au1xxx_hc_driver = {
+	.description =		hcd_name,
+	.product_desc =		"Au1xxx OHCI",
+	.hcd_priv_size =	sizeof(struct ohci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ohci_irq,
+	.flags =		HCD_USB11 | HCD_MEMORY,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.start =		ohci_au1xxx_start,
+#ifdef	CONFIG_PM
+	/* suspend:		ohci_au1xxx_suspend,  -- tbd */
+	/* resume:		ohci_au1xxx_resume,   -- tbd */
+#endif /*CONFIG_PM*/
+	.stop =			ohci_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ohci_urb_enqueue,
+	.urb_dequeue =		ohci_urb_dequeue,
+	.endpoint_disable =	ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ohci_hub_status_data,
+	.hub_control =		ohci_hub_control,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hcd_au1xxx_drv_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	int ret;
+
+	pr_debug ("In ohci_hcd_au1xxx_drv_probe");
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	ret = usb_hcd_au1xxx_probe(&ohci_au1xxx_hc_driver, pdev);
+	return ret;
+}
+
+static int ohci_hcd_au1xxx_drv_remove(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	usb_hcd_au1xxx_remove(hcd, pdev);
+	return 0;
+}
+	/*TBD*/
+/*static int ohci_hcd_au1xxx_drv_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	return 0;
+}
+static int ohci_hcd_au1xxx_drv_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	return 0;
+}
+*/
+
+static struct device_driver ohci_hcd_au1xxx_driver = {
+	.name		= "au1xxx-ohci",
+	.bus		= &platform_bus_type,
+	.probe		= ohci_hcd_au1xxx_drv_probe,
+	.remove		= ohci_hcd_au1xxx_drv_remove,
+	/*.suspend	= ohci_hcd_au1xxx_drv_suspend, */
+	/*.resume	= ohci_hcd_au1xxx_drv_resume, */
+};
+
+static int __init ohci_hcd_au1xxx_init (void)
+{
+	pr_debug (DRIVER_INFO " (Au1xxx)");
+	pr_debug ("block sizes: ed %d td %d\n",
+		sizeof (struct ed), sizeof (struct td));
+
+	return driver_register(&ohci_hcd_au1xxx_driver);
+}
+
+static void __exit ohci_hcd_au1xxx_cleanup (void)
+{
+	driver_unregister(&ohci_hcd_au1xxx_driver);
+}
+
+module_init (ohci_hcd_au1xxx_init);
+module_exit (ohci_hcd_au1xxx_cleanup);
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
new file mode 100644
index 0000000..62f53a2
--- /dev/null
+++ b/drivers/usb/host/ohci-dbg.c
@@ -0,0 +1,707 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * This file is licenced under the GPL.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+
+#define edstring(ed_type) ({ char *temp; \
+	switch (ed_type) { \
+	case PIPE_CONTROL:	temp = "ctrl"; break; \
+	case PIPE_BULK:		temp = "bulk"; break; \
+	case PIPE_INTERRUPT:	temp = "intr"; break; \
+	default: 		temp = "isoc"; break; \
+	}; temp;})
+#define pipestring(pipe) edstring(usb_pipetype(pipe))
+
+/* debug| print the main components of an URB
+ * small: 0) header + data packets 1) just header
+ */
+static void __attribute__((unused))
+urb_print (struct urb * urb, char * str, int small)
+{
+	unsigned int pipe= urb->pipe;
+
+	if (!urb->dev || !urb->dev->bus) {
+		dbg("%s URB: no dev", str);
+		return;
+	}
+
+#ifndef	OHCI_VERBOSE_DEBUG
+	if (urb->status != 0)
+#endif
+	dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d",
+		    str,
+		    urb,
+		    usb_pipedevice (pipe),
+		    usb_pipeendpoint (pipe),
+		    usb_pipeout (pipe)? "out" : "in",
+		    pipestring (pipe),
+		    urb->transfer_flags,
+		    urb->actual_length,
+		    urb->transfer_buffer_length,
+		    urb->status);
+
+#ifdef	OHCI_VERBOSE_DEBUG
+	if (!small) {
+		int i, len;
+
+		if (usb_pipecontrol (pipe)) {
+			printk (KERN_DEBUG __FILE__ ": setup(8):");
+			for (i = 0; i < 8 ; i++)
+				printk (" %02x", ((__u8 *) urb->setup_packet) [i]);
+			printk ("\n");
+		}
+		if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
+			printk (KERN_DEBUG __FILE__ ": data(%d/%d):",
+				urb->actual_length,
+				urb->transfer_buffer_length);
+			len = usb_pipeout (pipe)?
+						urb->transfer_buffer_length: urb->actual_length;
+			for (i = 0; i < 16 && i < len; i++)
+				printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
+			printk ("%s stat:%d\n", i < len? "...": "", urb->status);
+		}
+	}
+#endif
+}
+
+#define ohci_dbg_sw(ohci, next, size, format, arg...) \
+	do { \
+	if (next) { \
+		unsigned s_len; \
+		s_len = scnprintf (*next, *size, format, ## arg ); \
+		*size -= s_len; *next += s_len; \
+	} else \
+		ohci_dbg(ohci,format, ## arg ); \
+	} while (0);
+
+
+static void ohci_dump_intr_mask (
+	struct ohci_hcd *ohci,
+	char *label,
+	u32 mask,
+	char **next,
+	unsigned *size)
+{
+	ohci_dbg_sw (ohci, next, size, "%s 0x%08x%s%s%s%s%s%s%s%s%s\n",
+		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 (
+	struct ohci_hcd *ohci,
+	char *label,
+	u32 value,
+	char **next,
+	unsigned *size)
+{
+	if (value)
+		ohci_dbg_sw (ohci, next, size, "%s %08x\n", label, value);
+}
+
+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 (struct ohci_hcd *controller, char **next, unsigned *size)
+{
+	struct ohci_regs __iomem *regs = controller->regs;
+	u32			temp;
+
+	temp = ohci_readl (controller, &regs->revision) & 0xff;
+	ohci_dbg_sw (controller, next, size,
+		"OHCI %d.%d, %s legacy support registers\n",
+		0x03 & (temp >> 4), (temp & 0x0f),
+		(temp & 0x0100) ? "with" : "NO");
+
+	temp = ohci_readl (controller, &regs->control);
+	ohci_dbg_sw (controller, next, size,
+		"control 0x%03x%s%s%s HCFS=%s%s%s%s%s CBSR=%d\n",
+		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 = ohci_readl (controller, &regs->cmdstatus);
+	ohci_dbg_sw (controller, next, size,
+		"cmdstatus 0x%05x SOC=%d%s%s%s%s\n", 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 (controller, "intrstatus",
+			ohci_readl (controller, &regs->intrstatus),
+			next, size);
+	ohci_dump_intr_mask (controller, "intrenable",
+			ohci_readl (controller, &regs->intrenable),
+			next, size);
+	// intrdisable always same as intrenable
+
+	maybe_print_eds (controller, "ed_periodcurrent",
+			ohci_readl (controller, &regs->ed_periodcurrent),
+			next, size);
+
+	maybe_print_eds (controller, "ed_controlhead",
+			ohci_readl (controller, &regs->ed_controlhead),
+			next, size);
+	maybe_print_eds (controller, "ed_controlcurrent",
+			ohci_readl (controller, &regs->ed_controlcurrent),
+			next, size);
+
+	maybe_print_eds (controller, "ed_bulkhead",
+			ohci_readl (controller, &regs->ed_bulkhead),
+			next, size);
+	maybe_print_eds (controller, "ed_bulkcurrent",
+			ohci_readl (controller, &regs->ed_bulkcurrent),
+			next, size);
+
+	maybe_print_eds (controller, "donehead",
+			ohci_readl (controller, &regs->donehead), next, size);
+
+	/* broken fminterval means traffic won't flow! */ 
+	ohci_dbg (controller, "fminterval %08x\n", 
+			ohci_readl (controller, &regs->fminterval));
+}
+
+#define dbg_port_sw(hc,num,value,next,size) \
+	ohci_dbg_sw (hc, next, size, \
+		"roothub.portstatus [%d] " \
+		"0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \
+		num, 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_roothub (
+	struct ohci_hcd *controller,
+	int verbose,
+	char **next,
+	unsigned *size)
+{
+	u32			temp, ndp, i;
+
+	temp = roothub_a (controller);
+	if (temp == ~(u32)0)
+		return;
+	ndp = (temp & RH_A_NDP);
+
+	if (verbose) {
+		ohci_dbg_sw (controller, next, size,
+			"roothub.a %08x POTPGT=%d%s%s%s%s%s NDP=%d\n", 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);
+		ohci_dbg_sw (controller, next, size,
+			"roothub.b %08x PPCM=%04x DR=%04x\n",
+			temp,
+			(temp & RH_B_PPCM) >> 16,
+			(temp & RH_B_DR)
+			);
+		temp = roothub_status (controller);
+		ohci_dbg_sw (controller, next, size,
+			"roothub.status %08x%s%s%s%s%s%s\n",
+			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_port_sw (controller, i, temp, next, size);
+	}
+}
+
+static void ohci_dump (struct ohci_hcd *controller, int verbose)
+{
+	ohci_dbg (controller, "OHCI controller state\n");
+
+	// dumps some of the state we know about
+	ohci_dump_status (controller, NULL, NULL);
+	if (controller->hcca)
+		ohci_dbg (controller,
+			"hcca frame #%04x\n", ohci_frame_no(controller));
+	ohci_dump_roothub (controller, 1, NULL, NULL);
+}
+
+static const char data0 [] = "DATA0";
+static const char data1 [] = "DATA1";
+
+static void ohci_dump_td (const struct ohci_hcd *ohci, const char *label,
+		const struct td *td)
+{
+	u32	tmp = hc32_to_cpup (ohci, &td->hwINFO);
+
+	ohci_dbg (ohci, "%s td %p%s; urb %p index %d; hw next td %08x\n",
+		label, td,
+		(tmp & TD_DONE) ? " (DONE)" : "",
+		td->urb, td->index,
+		hc32_to_cpup (ohci, &td->hwNextTD));
+	if ((tmp & TD_ISO) == 0) {
+		const char	*toggle, *pid;
+		u32	cbp, be;
+
+		switch (tmp & TD_T) {
+		case TD_T_DATA0: toggle = data0; break;
+		case TD_T_DATA1: toggle = data1; break;
+		case TD_T_TOGGLE: toggle = "(CARRY)"; break;
+		default: toggle = "(?)"; break;
+		}
+		switch (tmp & TD_DP) {
+		case TD_DP_SETUP: pid = "SETUP"; break;
+		case TD_DP_IN: pid = "IN"; break;
+		case TD_DP_OUT: pid = "OUT"; break;
+		default: pid = "(bad pid)"; break;
+		}
+		ohci_dbg (ohci, "     info %08x CC=%x %s DI=%d %s %s\n", tmp,
+			TD_CC_GET(tmp), /* EC, */ toggle,
+			(tmp & TD_DI) >> 21, pid,
+			(tmp & TD_R) ? "R" : "");
+		cbp = hc32_to_cpup (ohci, &td->hwCBP);
+		be = hc32_to_cpup (ohci, &td->hwBE);
+		ohci_dbg (ohci, "     cbp %08x be %08x (len %d)\n", cbp, be,
+			cbp ? (be + 1 - cbp) : 0);
+	} else {
+		unsigned	i;
+		ohci_dbg (ohci, "  info %08x CC=%x FC=%d DI=%d SF=%04x\n", tmp,
+			TD_CC_GET(tmp),
+			(tmp >> 24) & 0x07,
+			(tmp & TD_DI) >> 21,
+			tmp & 0x0000ffff);
+		ohci_dbg (ohci, "  bp0 %08x be %08x\n",
+			hc32_to_cpup (ohci, &td->hwCBP) & ~0x0fff,
+			hc32_to_cpup (ohci, &td->hwBE));
+		for (i = 0; i < MAXPSW; i++) {
+			u16	psw = ohci_hwPSW (ohci, td, i);
+			int	cc = (psw >> 12) & 0x0f;
+			ohci_dbg (ohci, "    psw [%d] = %2x, CC=%x %s=%d\n", i,
+				psw, cc,
+				(cc >= 0x0e) ? "OFFSET" : "SIZE",
+				psw & 0x0fff);
+		}
+	}
+}
+
+/* caller MUST own hcd spinlock if verbose is set! */
+static void __attribute__((unused))
+ohci_dump_ed (const struct ohci_hcd *ohci, const char *label,
+		const struct ed *ed, int verbose)
+{
+	u32	tmp = hc32_to_cpu (ohci, ed->hwINFO);
+	char	*type = "";
+
+	ohci_dbg (ohci, "%s, ed %p state 0x%x type %s; next ed %08x\n",
+		label,
+		ed, ed->state, edstring (ed->type),
+		hc32_to_cpup (ohci, &ed->hwNextED));
+	switch (tmp & (ED_IN|ED_OUT)) {
+	case ED_OUT: type = "-OUT"; break;
+	case ED_IN: type = "-IN"; break;
+	/* else from TDs ... control */
+	}
+	ohci_dbg (ohci,
+		"  info %08x MAX=%d%s%s%s%s EP=%d%s DEV=%d\n", tmp,
+		0x03ff & (tmp >> 16),
+		(tmp & ED_DEQUEUE) ? " DQ" : "",
+		(tmp & ED_ISO) ? " ISO" : "",
+		(tmp & ED_SKIP) ? " SKIP" : "",
+		(tmp & ED_LOWSPEED) ? " LOW" : "",
+		0x000f & (tmp >> 7),
+		type,
+		0x007f & tmp);
+	tmp = hc32_to_cpup (ohci, &ed->hwHeadP);
+	ohci_dbg (ohci, "  tds: head %08x %s%s tail %08x%s\n",
+		tmp,
+		(tmp & ED_C) ? data1 : data0,
+		(tmp & ED_H) ? " HALT" : "",
+		hc32_to_cpup (ohci, &ed->hwTailP),
+		verbose ? "" : " (not listing)");
+	if (verbose) {
+		struct list_head	*tmp;
+
+		/* use ed->td_list because HC concurrently modifies
+		 * hwNextTD as it accumulates ed_donelist.
+		 */
+		list_for_each (tmp, &ed->td_list) {
+			struct td		*td;
+			td = list_entry (tmp, struct td, td_list);
+			ohci_dump_td (ohci, "  ->", td);
+		}
+	}
+}
+
+#else
+static inline void ohci_dump (struct ohci_hcd *controller, int verbose) {}
+
+#undef OHCI_VERBOSE_DEBUG
+
+#endif /* DEBUG */
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef STUB_DEBUG_FILES
+
+static inline void create_debug_files (struct ohci_hcd *bus) { }
+static inline void remove_debug_files (struct ohci_hcd *bus) { }
+
+#else
+
+static ssize_t
+show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed)
+{
+	unsigned		temp, size = count;
+
+	if (!ed)
+		return 0;
+
+	/* print first --> last */
+	while (ed->ed_prev)
+		ed = ed->ed_prev;
+
+	/* dump a snapshot of the bulk or control schedule */
+	while (ed) {
+		u32		info = hc32_to_cpu (ohci, ed->hwINFO);
+		u32		headp = hc32_to_cpu (ohci, ed->hwHeadP);
+		struct list_head *entry;
+		struct td	*td;
+
+		temp = scnprintf (buf, size,
+			"ed/%p %cs dev%d ep%d%s max %d %08x%s%s %s",
+			ed,
+			(info & ED_LOWSPEED) ? 'l' : 'f',
+			info & 0x7f,
+			(info >> 7) & 0xf,
+			(info & ED_IN) ? "in" : "out",
+			0x03ff & (info >> 16),
+			info,
+			(info & ED_SKIP) ? " s" : "",
+			(headp & ED_H) ? " H" : "",
+			(headp & ED_C) ? data1 : data0);
+		size -= temp;
+		buf += temp;
+
+		list_for_each (entry, &ed->td_list) {
+			u32		cbp, be;
+
+			td = list_entry (entry, struct td, td_list);
+			info = hc32_to_cpup (ohci, &td->hwINFO);
+			cbp = hc32_to_cpup (ohci, &td->hwCBP);
+			be = hc32_to_cpup (ohci, &td->hwBE);
+			temp = scnprintf (buf, size,
+					"\n\ttd %p %s %d cc=%x urb %p (%08x)",
+					td,
+					({ char *pid;
+					switch (info & TD_DP) {
+					case TD_DP_SETUP: pid = "setup"; break;
+					case TD_DP_IN: pid = "in"; break;
+					case TD_DP_OUT: pid = "out"; break;
+					default: pid = "(?)"; break;
+					 } pid;}),
+					cbp ? (be + 1 - cbp) : 0,
+					TD_CC_GET (info), td->urb, info);
+			size -= temp;
+			buf += temp;
+		}
+
+		temp = scnprintf (buf, size, "\n");
+		size -= temp;
+		buf += temp;
+
+		ed = ed->ed_next;
+	}
+	return count - size;
+}
+
+static ssize_t
+show_async (struct class_device *class_dev, char *buf)
+{
+	struct usb_bus		*bus;
+	struct usb_hcd		*hcd;
+	struct ohci_hcd		*ohci;
+	size_t			temp;
+	unsigned long		flags;
+
+	bus = to_usb_bus(class_dev);
+	hcd = bus->hcpriv;
+	ohci = hcd_to_ohci(hcd);
+
+	/* display control and bulk lists together, for simplicity */
+	spin_lock_irqsave (&ohci->lock, flags);
+	temp = show_list (ohci, buf, PAGE_SIZE, ohci->ed_controltail);
+	temp += show_list (ohci, buf + temp, PAGE_SIZE - temp, ohci->ed_bulktail);
+	spin_unlock_irqrestore (&ohci->lock, flags);
+
+	return temp;
+}
+static CLASS_DEVICE_ATTR (async, S_IRUGO, show_async, NULL);
+
+
+#define DBG_SCHED_LIMIT 64
+
+static ssize_t
+show_periodic (struct class_device *class_dev, char *buf)
+{
+	struct usb_bus		*bus;
+	struct usb_hcd		*hcd;
+	struct ohci_hcd		*ohci;
+	struct ed		**seen, *ed;
+	unsigned long		flags;
+	unsigned		temp, size, seen_count;
+	char			*next;
+	unsigned		i;
+
+	if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, SLAB_ATOMIC)))
+		return 0;
+	seen_count = 0;
+
+	bus = to_usb_bus(class_dev);
+	hcd = bus->hcpriv;
+	ohci = hcd_to_ohci(hcd);
+	next = buf;
+	size = PAGE_SIZE;
+
+	temp = scnprintf (next, size, "size = %d\n", NUM_INTS);
+	size -= temp;
+	next += temp;
+
+	/* dump a snapshot of the periodic schedule (and load) */
+	spin_lock_irqsave (&ohci->lock, flags);
+	for (i = 0; i < NUM_INTS; i++) {
+		if (!(ed = ohci->periodic [i]))
+			continue;
+
+		temp = scnprintf (next, size, "%2d [%3d]:", i, ohci->load [i]);
+		size -= temp;
+		next += temp;
+
+		do {
+			temp = scnprintf (next, size, " ed%d/%p",
+				ed->interval, ed);
+			size -= temp;
+			next += temp;
+			for (temp = 0; temp < seen_count; temp++) {
+				if (seen [temp] == ed)
+					break;
+			}
+
+			/* show more info the first time around */
+			if (temp == seen_count) {
+				u32	info = hc32_to_cpu (ohci, ed->hwINFO);
+				struct list_head	*entry;
+				unsigned		qlen = 0;
+
+				/* qlen measured here in TDs, not urbs */
+				list_for_each (entry, &ed->td_list)
+					qlen++;
+
+				temp = scnprintf (next, size,
+					" (%cs dev%d ep%d%s-%s qlen %u"
+					" max %d %08x%s%s)",
+					(info & ED_LOWSPEED) ? 'l' : 'f',
+					info & 0x7f,
+					(info >> 7) & 0xf,
+					(info & ED_IN) ? "in" : "out",
+					(info & ED_ISO) ? "iso" : "int",
+					qlen,
+					0x03ff & (info >> 16),
+					info,
+					(info & ED_SKIP) ? " K" : "",
+					(ed->hwHeadP &
+						cpu_to_hc32(ohci, ED_H)) ?
+ 							" H" : "");
+				size -= temp;
+				next += temp;
+
+				if (seen_count < DBG_SCHED_LIMIT)
+					seen [seen_count++] = ed;
+
+				ed = ed->ed_next;
+
+			} else {
+				/* we've seen it and what's after */
+				temp = 0;
+				ed = NULL;
+			}
+
+		} while (ed);
+
+		temp = scnprintf (next, size, "\n");
+		size -= temp;
+		next += temp;
+	}
+	spin_unlock_irqrestore (&ohci->lock, flags);
+	kfree (seen);
+
+	return PAGE_SIZE - size;
+}
+static CLASS_DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);
+
+
+#undef DBG_SCHED_LIMIT
+
+static ssize_t
+show_registers (struct class_device *class_dev, char *buf)
+{
+	struct usb_bus		*bus;
+	struct usb_hcd		*hcd;
+	struct ohci_hcd		*ohci;
+	struct ohci_regs __iomem *regs;
+	unsigned long		flags;
+	unsigned		temp, size;
+	char			*next;
+	u32			rdata;
+
+	bus = to_usb_bus(class_dev);
+	hcd = bus->hcpriv;
+	ohci = hcd_to_ohci(hcd);
+	regs = ohci->regs;
+	next = buf;
+	size = PAGE_SIZE;
+
+	spin_lock_irqsave (&ohci->lock, flags);
+
+	/* dump driver info, then registers in spec order */
+
+	ohci_dbg_sw (ohci, &next, &size,
+		"bus %s, device %s\n"
+		"%s\n"
+		"%s version " DRIVER_VERSION "\n",
+		hcd->self.controller->bus->name,
+		hcd->self.controller->bus_id,
+		hcd->product_desc,
+		hcd_name);
+
+	if (bus->controller->power.power_state) {
+		size -= scnprintf (next, size,
+			"SUSPENDED (no register access)\n");
+		goto done;
+	}
+
+	ohci_dump_status(ohci, &next, &size);
+
+	/* hcca */
+	if (ohci->hcca)
+		ohci_dbg_sw (ohci, &next, &size,
+			"hcca frame 0x%04x\n", ohci_frame_no(ohci));
+
+	/* other registers mostly affect frame timings */
+	rdata = ohci_readl (ohci, &regs->fminterval);
+	temp = scnprintf (next, size,
+			"fmintvl 0x%08x %sFSMPS=0x%04x FI=0x%04x\n",
+			rdata, (rdata >> 31) ? "FIT " : "",
+			(rdata >> 16) & 0xefff, rdata & 0xffff);
+	size -= temp;
+	next += temp;
+
+	rdata = ohci_readl (ohci, &regs->fmremaining);
+	temp = scnprintf (next, size, "fmremaining 0x%08x %sFR=0x%04x\n",
+			rdata, (rdata >> 31) ? "FRT " : "",
+			rdata & 0x3fff);
+	size -= temp;
+	next += temp;
+
+	rdata = ohci_readl (ohci, &regs->periodicstart);
+	temp = scnprintf (next, size, "periodicstart 0x%04x\n",
+			rdata & 0x3fff);
+	size -= temp;
+	next += temp;
+
+	rdata = ohci_readl (ohci, &regs->lsthresh);
+	temp = scnprintf (next, size, "lsthresh 0x%04x\n",
+			rdata & 0x3fff);
+	size -= temp;
+	next += temp;
+
+	/* roothub */
+	ohci_dump_roothub (ohci, 1, &next, &size);
+
+done:
+	spin_unlock_irqrestore (&ohci->lock, flags);
+	return PAGE_SIZE - size;
+}
+static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
+
+
+static inline void create_debug_files (struct ohci_hcd *ohci)
+{
+	struct class_device *cldev = &ohci_to_hcd(ohci)->self.class_dev;
+
+	class_device_create_file(cldev, &class_device_attr_async);
+	class_device_create_file(cldev, &class_device_attr_periodic);
+	class_device_create_file(cldev, &class_device_attr_registers);
+	ohci_dbg (ohci, "created debug files\n");
+}
+
+static inline void remove_debug_files (struct ohci_hcd *ohci)
+{
+	struct class_device *cldev = &ohci_to_hcd(ohci)->self.class_dev;
+
+	class_device_remove_file(cldev, &class_device_attr_async);
+	class_device_remove_file(cldev, &class_device_attr_periodic);
+	class_device_remove_file(cldev, &class_device_attr_registers);
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
new file mode 100644
index 0000000..1e27f10
--- /dev/null
+++ b/drivers/usb/host/ohci-hcd.c
@@ -0,0 +1,925 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * [ Initialisation is based on Linus'  ]
+ * [ uhci code and gregs ohci fragments ]
+ * [ (C) Copyright 1999 Linus Torvalds  ]
+ * [ (C) Copyright 1999 Gregory P. Smith]
+ * 
+ * 
+ * OHCI is the main "non-Intel/VIA" standard for USB 1.1 host controller
+ * interfaces (though some non-x86 Intel chips use it).  It supports
+ * smarter hardware than UHCI.  A download link for the spec available
+ * through the http://www.usb.org website.
+ *
+ * History:
+ * 
+ * 2004/03/24 LH7A404 support (Durgesh Pattamatta & Marc Singer)
+ * 2004/02/04 use generic dma_* functions instead of pci_* (dsaxena@plexity.net)
+ * 2003/02/24 show registers in sysfs (Kevin Brosius)
+ *
+ * 2002/09/03 get rid of ed hashtables, rework periodic scheduling and
+ * 	bandwidth accounting; if debugging, show schedules in driverfs
+ * 2002/07/19 fixes to management of ED and schedule state.
+ * 2002/06/09 SA-1111 support (Christopher Hoover)
+ * 2002/06/01 remember frame when HC won't see EDs any more; use that info
+ *	to fix urb unlink races caused by interrupt latency assumptions;
+ *	minor ED field and function naming updates
+ * 2002/01/18 package as a patch for 2.5.3; this should match the
+ *	2.4.17 kernel modulo some bugs being fixed.
+ *
+ * 2001/10/18 merge pmac cleanup (Benjamin Herrenschmidt) and bugfixes
+ *	from post-2.4.5 patches.
+ * 2001/09/20 URB_ZERO_PACKET support; hcca_dma portability, OPTi warning
+ * 2001/09/07 match PCI PM changes, errnos from Linus' tree
+ * 2001/05/05 fork 2.4.5 version into "hcd" framework, cleanup, simplify;
+ *	pbook pci quirks gone (please fix pbook pci sw!) (db)
+ *
+ * 2001/04/08 Identify version on module load (gb)
+ * 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam);
+ 	pci_map_single (db)
+ * 2001/03/21 td and dev/ed allocation uses new pci_pool API (db)
+ * 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam)
+ *
+ * 2000/09/26 fixed races in removing the private portion of the urb
+ * 2000/09/07 disable bulk and control lists when unlinking the last
+ *	endpoint descriptor in order to avoid unrecoverable errors on
+ *	the Lucent chips. (rwc@sgi)
+ * 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some
+ *	urb unlink probs, indentation fixes
+ * 2000/08/11 various oops fixes mostly affecting iso and cleanup from
+ *	device unplugs.
+ * 2000/06/28 use PCI hotplug framework, for better power management
+ *	and for Cardbus support (David Brownell)
+ * 2000/earlier:  fixes for NEC/Lucent chips; suspend/resume handling
+ *	when the controller loses power; handle UE; cleanup; ...
+ *
+ * v5.2 1999/12/07 URB 3rd preview, 
+ * v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi)
+ * v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume 
+ * 	i386: HUB, Keyboard, Mouse, Printer 
+ *
+ * v4.3 1999/10/27 multiple HCs, bulk_request
+ * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes
+ * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl.
+ * v4.0 1999/08/18 
+ * v3.0 1999/06/25 
+ * v2.1 1999/05/09  code clean up
+ * v2.0 1999/05/04 
+ * v1.0 1999/04/27 initial release
+ *
+ * This file is licenced under the GPL.
+ */
+ 
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_DEBUG
+#	define DEBUG
+#else
+#	undef DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>  /* for in_interrupt () */
+#include <linux/usb.h>
+#include <linux/usb_otg.h>
+#include "../core/hcd.h"
+#include <linux/dma-mapping.h> 
+#include <linux/dmapool.h>    /* needed by ohci-mem.c when no PCI */
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+
+#define DRIVER_VERSION "2004 Nov 08"
+#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
+#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
+
+/*-------------------------------------------------------------------------*/
+
+// #define OHCI_VERBOSE_DEBUG	/* not always helpful */
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define	OHCI_CONTROL_INIT 	OHCI_CTRL_CBSR
+#define	OHCI_INTR_INIT \
+	(OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_WDH)
+
+#ifdef __hppa__
+/* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */
+#define	IR_DISABLE
+#endif
+
+#ifdef CONFIG_ARCH_OMAP
+/* OMAP doesn't support IR (no SMM; not needed) */
+#define	IR_DISABLE
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static const char	hcd_name [] = "ohci_hcd";
+
+#include "ohci.h"
+
+static void ohci_dump (struct ohci_hcd *ohci, int verbose);
+static int ohci_init (struct ohci_hcd *ohci);
+static void ohci_stop (struct usb_hcd *hcd);
+
+#include "ohci-hub.c"
+#include "ohci-dbg.c"
+#include "ohci-mem.c"
+#include "ohci-q.c"
+
+
+/*
+ * On architectures with edge-triggered interrupts we must never return
+ * IRQ_NONE.
+ */
+#if defined(CONFIG_SA1111)  /* ... or other edge-triggered systems */
+#define IRQ_NOTMINE	IRQ_HANDLED
+#else
+#define IRQ_NOTMINE	IRQ_NONE
+#endif
+
+
+/* Some boards misreport power switching/overcurrent */
+static int distrust_firmware = 1;
+module_param (distrust_firmware, bool, 0);
+MODULE_PARM_DESC (distrust_firmware,
+	"true to distrust firmware power/overcurrent setup");
+
+/* Some boards leave IR set wrongly, since they fail BIOS/SMM handshakes */
+static int no_handshake = 0;
+module_param (no_handshake, bool, 0);
+MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake");
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * queue up an urb for anything except the root hub
+ */
+static int ohci_urb_enqueue (
+	struct usb_hcd	*hcd,
+	struct usb_host_endpoint *ep,
+	struct urb	*urb,
+	int		mem_flags
+) {
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	struct ed	*ed;
+	urb_priv_t	*urb_priv;
+	unsigned int	pipe = urb->pipe;
+	int		i, size = 0;
+	unsigned long	flags;
+	int		retval = 0;
+	
+#ifdef OHCI_VERBOSE_DEBUG
+	urb_print (urb, "SUB", usb_pipein (pipe));
+#endif
+	
+	/* every endpoint has a ed, locate and maybe (re)initialize it */
+	if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval)))
+		return -ENOMEM;
+
+	/* for the private part of the URB we need the number of TDs (size) */
+	switch (ed->type) {
+		case PIPE_CONTROL:
+			/* td_submit_urb() doesn't yet handle these */
+			if (urb->transfer_buffer_length > 4096)
+				return -EMSGSIZE;
+
+			/* 1 TD for setup, 1 for ACK, plus ... */
+			size = 2;
+			/* FALLTHROUGH */
+		// case PIPE_INTERRUPT:
+		// case PIPE_BULK:
+		default:
+			/* one TD for every 4096 Bytes (can be upto 8K) */
+			size += urb->transfer_buffer_length / 4096;
+			/* ... and for any remaining bytes ... */
+			if ((urb->transfer_buffer_length % 4096) != 0)
+				size++;
+			/* ... and maybe a zero length packet to wrap it up */
+			if (size == 0)
+				size++;
+			else if ((urb->transfer_flags & URB_ZERO_PACKET) != 0
+				&& (urb->transfer_buffer_length
+					% usb_maxpacket (urb->dev, pipe,
+						usb_pipeout (pipe))) == 0)
+				size++;
+			break;
+		case PIPE_ISOCHRONOUS: /* number of packets from URB */
+			size = urb->number_of_packets;
+			break;
+	}
+
+	/* allocate the private part of the URB */
+	urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),
+			mem_flags);
+	if (!urb_priv)
+		return -ENOMEM;
+	memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));
+	INIT_LIST_HEAD (&urb_priv->pending);
+	urb_priv->length = size;
+	urb_priv->ed = ed;	
+
+	/* allocate the TDs (deferring hash chain updates) */
+	for (i = 0; i < size; i++) {
+		urb_priv->td [i] = td_alloc (ohci, mem_flags);
+		if (!urb_priv->td [i]) {
+			urb_priv->length = i;
+			urb_free_priv (ohci, urb_priv);
+			return -ENOMEM;
+		}
+	}	
+
+	spin_lock_irqsave (&ohci->lock, flags);
+
+	/* don't submit to a dead HC */
+	if (!HC_IS_RUNNING(hcd->state)) {
+		retval = -ENODEV;
+		goto fail;
+	}
+
+	/* in case of unlink-during-submit */
+	spin_lock (&urb->lock);
+	if (urb->status != -EINPROGRESS) {
+		spin_unlock (&urb->lock);
+		urb->hcpriv = urb_priv;
+		finish_urb (ohci, urb, NULL);
+		retval = 0;
+		goto fail;
+	}
+
+	/* schedule the ed if needed */
+	if (ed->state == ED_IDLE) {
+		retval = ed_schedule (ohci, ed);
+		if (retval < 0)
+			goto fail0;
+		if (ed->type == PIPE_ISOCHRONOUS) {
+			u16	frame = ohci_frame_no(ohci);
+
+			/* delay a few frames before the first TD */
+			frame += max_t (u16, 8, ed->interval);
+			frame &= ~(ed->interval - 1);
+			frame |= ed->branch;
+			urb->start_frame = frame;
+
+			/* yes, only URB_ISO_ASAP is supported, and
+			 * urb->start_frame is never used as input.
+			 */
+		}
+	} else if (ed->type == PIPE_ISOCHRONOUS)
+		urb->start_frame = ed->last_iso + ed->interval;
+
+	/* fill the TDs and link them to the ed; and
+	 * enable that part of the schedule, if needed
+	 * and update count of queued periodic urbs
+	 */
+	urb->hcpriv = urb_priv;
+	td_submit_urb (ohci, urb);
+
+fail0:
+	spin_unlock (&urb->lock);
+fail:
+	if (retval)
+		urb_free_priv (ohci, urb_priv);
+	spin_unlock_irqrestore (&ohci->lock, flags);
+	return retval;
+}
+
+/*
+ * decouple the URB from the HC queues (TDs, urb_priv); it's
+ * already marked using urb->status.  reporting is always done
+ * asynchronously, and we might be dealing with an urb that's
+ * partially transferred, or an ED with other urbs being unlinked.
+ */
+static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+{
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+	unsigned long		flags;
+	
+#ifdef OHCI_VERBOSE_DEBUG
+	urb_print (urb, "UNLINK", 1);
+#endif		  
+
+	spin_lock_irqsave (&ohci->lock, flags);
+ 	if (HC_IS_RUNNING(hcd->state)) {
+		urb_priv_t  *urb_priv;
+
+		/* Unless an IRQ completed the unlink while it was being
+		 * handed to us, flag it for unlink and giveback, and force
+		 * some upcoming INTR_SF to call finish_unlinks()
+		 */
+		urb_priv = urb->hcpriv;
+		if (urb_priv) {
+			if (urb_priv->ed->state == ED_OPER)
+				start_ed_unlink (ohci, urb_priv->ed);
+		}
+	} else {
+		/*
+		 * with HC dead, we won't respect hc queue pointers
+		 * any more ... just clean up every urb's memory.
+		 */
+		if (urb->hcpriv)
+			finish_urb (ohci, urb, NULL);
+	}
+	spin_unlock_irqrestore (&ohci->lock, flags);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* frees config/altsetting state for endpoints,
+ * including ED memory, dummy TD, and bulk/intr data toggle
+ */
+
+static void
+ohci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+	unsigned long		flags;
+	struct ed		*ed = ep->hcpriv;
+	unsigned		limit = 1000;
+
+	/* ASSERT:  any requests/urbs are being unlinked */
+	/* ASSERT:  nobody can be submitting urbs for this any more */
+
+	if (!ed)
+		return;
+
+rescan:
+	spin_lock_irqsave (&ohci->lock, flags);
+
+	if (!HC_IS_RUNNING (hcd->state)) {
+sanitize:
+		ed->state = ED_IDLE;
+		finish_unlinks (ohci, 0, NULL);
+	}
+
+	switch (ed->state) {
+	case ED_UNLINK:		/* wait for hw to finish? */
+		/* major IRQ delivery trouble loses INTR_SF too... */
+		if (limit-- == 0) {
+			ohci_warn (ohci, "IRQ INTR_SF lossage\n");
+			goto sanitize;
+		}
+		spin_unlock_irqrestore (&ohci->lock, flags);
+		set_current_state (TASK_UNINTERRUPTIBLE);
+		schedule_timeout (1);
+		goto rescan;
+	case ED_IDLE:		/* fully unlinked */
+		if (list_empty (&ed->td_list)) {
+			td_free (ohci, ed->dummy);
+			ed_free (ohci, ed);
+			break;
+		}
+		/* else FALL THROUGH */
+	default:
+		/* caller was supposed to have unlinked any requests;
+		 * that's not our job.  can't recover; must leak ed.
+		 */
+		ohci_err (ohci, "leak ed %p (#%02x) state %d%s\n",
+			ed, ep->desc.bEndpointAddress, ed->state,
+			list_empty (&ed->td_list) ? "" : " (has tds)");
+		td_free (ohci, ed->dummy);
+		break;
+	}
+	ep->hcpriv = NULL;
+	spin_unlock_irqrestore (&ohci->lock, flags);
+	return;
+}
+
+static int ohci_get_frame (struct usb_hcd *hcd)
+{
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+
+	return ohci_frame_no(ohci);
+}
+
+static void ohci_usb_reset (struct ohci_hcd *ohci)
+{
+	ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
+	ohci->hc_control &= OHCI_CTRL_RWC;
+	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+}
+
+/*-------------------------------------------------------------------------*
+ * HC functions
+ *-------------------------------------------------------------------------*/
+
+/* init memory, and kick BIOS/SMM off */
+
+static int ohci_init (struct ohci_hcd *ohci)
+{
+	int ret;
+
+	disable (ohci);
+	ohci->regs = ohci_to_hcd(ohci)->regs;
+	ohci->next_statechange = jiffies;
+
+#ifndef IR_DISABLE
+	/* SMM owns the HC?  not for long! */
+	if (!no_handshake && ohci_readl (ohci,
+					&ohci->regs->control) & OHCI_CTRL_IR) {
+		u32 temp;
+
+		ohci_dbg (ohci, "USB HC TakeOver from BIOS/SMM\n");
+
+		/* this timeout is arbitrary.  we make it long, so systems
+		 * depending on usb keyboards may be usable even if the
+		 * BIOS/SMM code seems pretty broken.
+		 */
+		temp = 500;	/* arbitrary: five seconds */
+
+		ohci_writel (ohci, OHCI_INTR_OC, &ohci->regs->intrenable);
+		ohci_writel (ohci, OHCI_OCR, &ohci->regs->cmdstatus);
+		while (ohci_readl (ohci, &ohci->regs->control) & OHCI_CTRL_IR) {
+			msleep (10);
+			if (--temp == 0) {
+				ohci_err (ohci, "USB HC takeover failed!"
+					"  (BIOS/SMM bug)\n");
+				return -EBUSY;
+			}
+		}
+		ohci_usb_reset (ohci);
+	}
+#endif
+
+	/* Disable HC interrupts */
+	ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+	// flush the writes
+	(void) ohci_readl (ohci, &ohci->regs->control);
+
+	if (ohci->hcca)
+		return 0;
+
+	ohci->hcca = dma_alloc_coherent (ohci_to_hcd(ohci)->self.controller,
+			sizeof *ohci->hcca, &ohci->hcca_dma, 0);
+	if (!ohci->hcca)
+		return -ENOMEM;
+
+	if ((ret = ohci_mem_init (ohci)) < 0)
+		ohci_stop (ohci_to_hcd(ohci));
+
+	return ret;
+
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Start an OHCI controller, set the BUS operational
+ * resets USB and controller
+ * enable interrupts 
+ * connect the virtual root hub
+ */
+static int ohci_run (struct ohci_hcd *ohci)
+{
+  	u32			mask, temp;
+  	struct usb_device	*udev;
+  	struct usb_bus		*bus;
+	int			first = ohci->fminterval == 0;
+
+	disable (ohci);
+
+	/* boot firmware should have set this up (5.1.1.3.1) */
+	if (first) {
+
+		temp = ohci_readl (ohci, &ohci->regs->fminterval);
+		ohci->fminterval = temp & 0x3fff;
+		if (ohci->fminterval != FI)
+			ohci_dbg (ohci, "fminterval delta %d\n",
+				ohci->fminterval - FI);
+		ohci->fminterval |= FSMP (ohci->fminterval) << 16;
+		/* also: power/overcurrent flags in roothub.a */
+	}
+
+  	/* Reset USB nearly "by the book".  RemoteWakeupConnected
+	 * saved if boot firmware (BIOS/SMM/...) told us it's connected
+	 * (for OHCI integrated on mainboard, it normally is)
+	 */
+	ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
+	ohci_dbg (ohci, "resetting from state '%s', control = 0x%x\n",
+			hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
+			ohci->hc_control);
+
+	if (ohci->hc_control & OHCI_CTRL_RWC
+			&& !(ohci->flags & OHCI_QUIRK_AMD756))
+		ohci_to_hcd(ohci)->can_wakeup = 1;
+
+	switch (ohci->hc_control & OHCI_CTRL_HCFS) {
+	case OHCI_USB_OPER:
+		temp = 0;
+		break;
+	case OHCI_USB_SUSPEND:
+	case OHCI_USB_RESUME:
+		ohci->hc_control &= OHCI_CTRL_RWC;
+		ohci->hc_control |= OHCI_USB_RESUME;
+		temp = 10 /* msec wait */;
+		break;
+	// case OHCI_USB_RESET:
+	default:
+		ohci->hc_control &= OHCI_CTRL_RWC;
+		ohci->hc_control |= OHCI_USB_RESET;
+		temp = 50 /* msec wait */;
+		break;
+	}
+	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+	// flush the writes
+	(void) ohci_readl (ohci, &ohci->regs->control);
+	msleep(temp);
+	temp = roothub_a (ohci);
+	if (!(temp & RH_A_NPS)) {
+		unsigned ports = temp & RH_A_NDP; 
+
+		/* power down each port */
+		for (temp = 0; temp < ports; temp++)
+			ohci_writel (ohci, RH_PS_LSDA,
+				&ohci->regs->roothub.portstatus [temp]);
+	}
+	// flush those writes
+	(void) ohci_readl (ohci, &ohci->regs->control);
+	memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
+
+	/* 2msec timelimit here means no irqs/preempt */
+	spin_lock_irq (&ohci->lock);
+
+retry:
+	/* HC Reset requires max 10 us delay */
+	ohci_writel (ohci, OHCI_HCR,  &ohci->regs->cmdstatus);
+	temp = 30;	/* ... allow extra time */
+	while ((ohci_readl (ohci, &ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+		if (--temp == 0) {
+			spin_unlock_irq (&ohci->lock);
+			ohci_err (ohci, "USB HC reset timed out!\n");
+			return -1;
+		}
+		udelay (1);
+	}
+
+	/* now we're in the SUSPEND state ... must go OPERATIONAL
+	 * within 2msec else HC enters RESUME
+	 *
+	 * ... but some hardware won't init fmInterval "by the book"
+	 * (SiS, OPTi ...), so reset again instead.  SiS doesn't need
+	 * this if we write fmInterval after we're OPERATIONAL.
+	 * Unclear about ALi, ServerWorks, and others ... this could
+	 * easily be a longstanding bug in chip init on Linux.
+	 */
+	if (ohci->flags & OHCI_QUIRK_INITRESET) {
+		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+		// flush those writes
+		(void) ohci_readl (ohci, &ohci->regs->control);
+	}
+
+	/* Tell the controller where the control and bulk lists are
+	 * The lists are empty now. */
+	ohci_writel (ohci, 0, &ohci->regs->ed_controlhead);
+	ohci_writel (ohci, 0, &ohci->regs->ed_bulkhead);
+
+	/* a reset clears this */
+	ohci_writel (ohci, (u32) ohci->hcca_dma, &ohci->regs->hcca);
+
+	periodic_reinit (ohci);
+
+	/* some OHCI implementations are finicky about how they init.
+	 * bogus values here mean not even enumeration could work.
+	 */
+	if ((ohci_readl (ohci, &ohci->regs->fminterval) & 0x3fff0000) == 0
+			|| !ohci_readl (ohci, &ohci->regs->periodicstart)) {
+		if (!(ohci->flags & OHCI_QUIRK_INITRESET)) {
+			ohci->flags |= OHCI_QUIRK_INITRESET;
+			ohci_dbg (ohci, "enabling initreset quirk\n");
+			goto retry;
+		}
+		spin_unlock_irq (&ohci->lock);
+		ohci_err (ohci, "init err (%08x %04x)\n",
+			ohci_readl (ohci, &ohci->regs->fminterval),
+			ohci_readl (ohci, &ohci->regs->periodicstart));
+		return -EOVERFLOW;
+	}
+
+ 	/* start controller operations */
+	ohci->hc_control &= OHCI_CTRL_RWC;
+ 	ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ 	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+	ohci_to_hcd(ohci)->state = HC_STATE_RUNNING;
+
+	/* wake on ConnectStatusChange, matching external hubs */
+	ohci_writel (ohci, RH_HS_DRWE, &ohci->regs->roothub.status);
+
+	/* Choose the interrupts we care about now, others later on demand */
+	mask = OHCI_INTR_INIT;
+	ohci_writel (ohci, mask, &ohci->regs->intrstatus);
+	ohci_writel (ohci, mask, &ohci->regs->intrenable);
+
+	/* handle root hub init quirks ... */
+	temp = roothub_a (ohci);
+	temp &= ~(RH_A_PSM | RH_A_OCPM);
+	if (ohci->flags & OHCI_QUIRK_SUPERIO) {
+		/* NSC 87560 and maybe others */
+		temp |= RH_A_NOCP;
+		temp &= ~(RH_A_POTPGT | RH_A_NPS);
+		ohci_writel (ohci, temp, &ohci->regs->roothub.a);
+	} else if ((ohci->flags & OHCI_QUIRK_AMD756) || distrust_firmware) {
+		/* hub power always on; required for AMD-756 and some
+		 * Mac platforms.  ganged overcurrent reporting, if any.
+		 */
+		temp |= RH_A_NPS;
+		ohci_writel (ohci, temp, &ohci->regs->roothub.a);
+	}
+	ohci_writel (ohci, RH_HS_LPSC, &ohci->regs->roothub.status);
+	ohci_writel (ohci, (temp & RH_A_NPS) ? 0 : RH_B_PPCM,
+						&ohci->regs->roothub.b);
+	// flush those writes
+	(void) ohci_readl (ohci, &ohci->regs->control);
+
+	spin_unlock_irq (&ohci->lock);
+
+	// POTPGT delay is bits 24-31, in 2 ms units.
+	mdelay ((temp >> 23) & 0x1fe);
+	bus = &ohci_to_hcd(ohci)->self;
+	ohci_to_hcd(ohci)->state = HC_STATE_RUNNING;
+
+	ohci_dump (ohci, 1);
+
+	udev = bus->root_hub;
+	if (udev) {
+		return 0;
+	}
+ 
+	/* connect the virtual root hub */
+	udev = usb_alloc_dev (NULL, bus, 0);
+	if (!udev) {
+		disable (ohci);
+		ohci->hc_control &= ~OHCI_CTRL_HCFS;
+		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+		return -ENOMEM;
+	}
+
+	udev->speed = USB_SPEED_FULL;
+	if (usb_hcd_register_root_hub (udev, ohci_to_hcd(ohci)) != 0) {
+		usb_put_dev (udev);
+		disable (ohci);
+		ohci->hc_control &= ~OHCI_CTRL_HCFS;
+		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+		return -ENODEV;
+	}
+	if (ohci->power_budget)
+		hub_set_power_budget(udev, ohci->power_budget);
+
+	create_debug_files (ohci);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* an interrupt happens */
+
+static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
+{
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+	struct ohci_regs __iomem *regs = ohci->regs;
+ 	int			ints; 
+
+	/* we can eliminate a (slow) ohci_readl()
+	   if _only_ WDH caused this irq */
+	if ((ohci->hcca->done_head != 0)
+			&& ! (hc32_to_cpup (ohci, &ohci->hcca->done_head)
+				& 0x01)) {
+		ints =  OHCI_INTR_WDH;
+
+	/* cardbus/... hardware gone before remove() */
+	} else if ((ints = ohci_readl (ohci, &regs->intrstatus)) == ~(u32)0) {
+		disable (ohci);
+		ohci_dbg (ohci, "device removed!\n");
+		return IRQ_HANDLED;
+
+	/* interrupt for some other device? */
+	} else if ((ints &= ohci_readl (ohci, &regs->intrenable)) == 0) {
+		return IRQ_NOTMINE;
+	} 
+
+	if (ints & OHCI_INTR_UE) {
+		disable (ohci);
+		ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
+		// e.g. due to PCI Master/Target Abort
+
+		ohci_dump (ohci, 1);
+		ohci_usb_reset (ohci);
+	}
+
+	if (ints & OHCI_INTR_RD) {
+		ohci_vdbg (ohci, "resume detect\n");
+		if (hcd->state != HC_STATE_QUIESCING)
+			schedule_work(&ohci->rh_resume);
+	}
+
+	if (ints & OHCI_INTR_WDH) {
+		if (HC_IS_RUNNING(hcd->state))
+			ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrdisable);	
+		spin_lock (&ohci->lock);
+		dl_done_list (ohci, ptregs);
+		spin_unlock (&ohci->lock);
+		if (HC_IS_RUNNING(hcd->state))
+			ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrenable); 
+	}
+  
+	/* could track INTR_SO to reduce available PCI/... bandwidth */
+
+	/* handle any pending URB/ED unlinks, leaving INTR_SF enabled
+	 * when there's still unlinking to be done (next frame).
+	 */
+	spin_lock (&ohci->lock);
+	if (ohci->ed_rm_list)
+		finish_unlinks (ohci, ohci_frame_no(ohci), ptregs);
+	if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
+			&& HC_IS_RUNNING(hcd->state))
+		ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);	
+	spin_unlock (&ohci->lock);
+
+	if (HC_IS_RUNNING(hcd->state)) {
+		ohci_writel (ohci, ints, &regs->intrstatus);
+		ohci_writel (ohci, OHCI_INTR_MIE, &regs->intrenable);	
+		// flush those writes
+		(void) ohci_readl (ohci, &ohci->regs->control);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void ohci_stop (struct usb_hcd *hcd)
+{	
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+
+	ohci_dbg (ohci, "stop %s controller (state 0x%02x)\n",
+		hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
+		hcd->state);
+	ohci_dump (ohci, 1);
+
+	flush_scheduled_work();
+
+	ohci_usb_reset (ohci);
+	ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+	
+	remove_debug_files (ohci);
+	ohci_mem_cleanup (ohci);
+	if (ohci->hcca) {
+		dma_free_coherent (hcd->self.controller, 
+				sizeof *ohci->hcca, 
+				ohci->hcca, ohci->hcca_dma);
+		ohci->hcca = NULL;
+		ohci->hcca_dma = 0;
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* must not be called from interrupt context */
+
+#if	defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM)
+
+static int ohci_restart (struct ohci_hcd *ohci)
+{
+	int temp;
+	int i;
+	struct urb_priv *priv;
+	struct usb_device *root = ohci_to_hcd(ohci)->self.root_hub;
+
+	/* mark any devices gone, so they do nothing till khubd disconnects.
+	 * recycle any "live" eds/tds (and urbs) right away.
+	 * later, khubd disconnect processing will recycle the other state,
+	 * (either as disconnect/reconnect, or maybe someday as a reset).
+	 */ 
+	spin_lock_irq(&ohci->lock);
+	disable (ohci);
+	for (i = 0; i < root->maxchild; i++) {
+		if (root->children [i])
+			usb_set_device_state (root->children[i],
+				USB_STATE_NOTATTACHED);
+	}
+	if (!list_empty (&ohci->pending))
+		ohci_dbg(ohci, "abort schedule...\n");
+	list_for_each_entry (priv, &ohci->pending, pending) {
+		struct urb	*urb = priv->td[0]->urb;
+		struct ed	*ed = priv->ed;
+
+		switch (ed->state) {
+		case ED_OPER:
+			ed->state = ED_UNLINK;
+			ed->hwINFO |= cpu_to_hc32(ohci, ED_DEQUEUE);
+			ed_deschedule (ohci, ed);
+
+			ed->ed_next = ohci->ed_rm_list;
+			ed->ed_prev = NULL;
+			ohci->ed_rm_list = ed;
+			/* FALLTHROUGH */
+		case ED_UNLINK:
+			break;
+		default:
+			ohci_dbg(ohci, "bogus ed %p state %d\n",
+					ed, ed->state);
+		}
+
+		spin_lock (&urb->lock);
+		urb->status = -ESHUTDOWN;
+		spin_unlock (&urb->lock);
+	}
+	finish_unlinks (ohci, 0, NULL);
+	spin_unlock_irq(&ohci->lock);
+
+	/* paranoia, in case that didn't work: */
+
+	/* empty the interrupt branches */
+	for (i = 0; i < NUM_INTS; i++) ohci->load [i] = 0;
+	for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table [i] = 0;
+	
+	/* no EDs to remove */
+	ohci->ed_rm_list = NULL;
+
+	/* empty control and bulk lists */	 
+	ohci->ed_controltail = NULL;
+	ohci->ed_bulktail    = NULL;
+
+	if ((temp = ohci_run (ohci)) < 0) {
+		ohci_err (ohci, "can't restart, %d\n", temp);
+		return temp;
+	} else {
+		/* here we "know" root ports should always stay powered,
+		 * and that if we try to turn them back on the root hub
+		 * will respond to CSC processing.
+		 */
+		i = roothub_a (ohci) & RH_A_NDP;
+		while (i--)
+			ohci_writel (ohci, RH_PS_PSS,
+				&ohci->regs->roothub.portstatus [temp]);
+		ohci_dbg (ohci, "restart complete\n");
+	}
+	return 0;
+}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
+
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_DESCRIPTION (DRIVER_INFO);
+MODULE_LICENSE ("GPL");
+
+#ifdef CONFIG_PCI
+#include "ohci-pci.c"
+#endif
+
+#ifdef CONFIG_SA1111
+#include "ohci-sa1111.c"
+#endif
+
+#ifdef CONFIG_ARCH_OMAP
+#include "ohci-omap.c"
+#endif
+
+#ifdef CONFIG_ARCH_LH7A404
+#include "ohci-lh7a404.c"
+#endif
+
+#ifdef CONFIG_PXA27x
+#include "ohci-pxa27x.c"
+#endif
+
+#ifdef CONFIG_SOC_AU1X00
+#include "ohci-au1xxx.c"
+#endif
+
+#ifdef CONFIG_USB_OHCI_HCD_PPC_SOC
+#include "ohci-ppc-soc.c"
+#endif
+
+#if !(defined(CONFIG_PCI) \
+      || defined(CONFIG_SA1111) \
+      || defined(CONFIG_ARCH_OMAP) \
+      || defined (CONFIG_ARCH_LH7A404) \
+      || defined (CONFIG_PXA27x) \
+      || defined (CONFIG_SOC_AU1X00) \
+      || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
+	)
+#error "missing bus glue for ohci-hcd"
+#endif
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
new file mode 100644
index 0000000..e2fc412
--- /dev/null
+++ b/drivers/usb/host/ohci-hub.c
@@ -0,0 +1,643 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ * 
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * This file is licenced under GPL
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * OHCI Root Hub ... the nonsharable stuff
+ */
+
+#define dbg_port(hc,label,num,value) \
+	ohci_dbg (hc, \
+		"%s roothub.portstatus [%d] " \
+		"= 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \
+		label, num, 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" : "" \
+		);
+
+/*-------------------------------------------------------------------------*/
+
+#if	defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM)
+
+#define OHCI_SCHED_ENABLES \
+	(OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
+
+static void dl_done_list (struct ohci_hcd *, struct pt_regs *);
+static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *);
+static int ohci_restart (struct ohci_hcd *ohci);
+
+static int ohci_hub_suspend (struct usb_hcd *hcd)
+{
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+	int			status = 0;
+	unsigned long		flags;
+
+	spin_lock_irqsave (&ohci->lock, flags);
+
+	ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
+	switch (ohci->hc_control & OHCI_CTRL_HCFS) {
+	case OHCI_USB_RESUME:
+		ohci_dbg (ohci, "resume/suspend?\n");
+		ohci->hc_control &= ~OHCI_CTRL_HCFS;
+		ohci->hc_control |= OHCI_USB_RESET;
+		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+		(void) ohci_readl (ohci, &ohci->regs->control);
+		/* FALL THROUGH */
+	case OHCI_USB_RESET:
+		status = -EBUSY;
+		ohci_dbg (ohci, "needs reinit!\n");
+		goto done;
+	case OHCI_USB_SUSPEND:
+		ohci_dbg (ohci, "already suspended\n");
+		goto done;
+	}
+	ohci_dbg (ohci, "suspend root hub\n");
+
+	/* First stop any processing */
+	hcd->state = HC_STATE_QUIESCING;
+	if (ohci->hc_control & OHCI_SCHED_ENABLES) {
+		int		limit;
+
+		ohci->hc_control &= ~OHCI_SCHED_ENABLES;
+		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+		ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
+		ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrstatus);
+
+		/* sched disables take effect on the next frame,
+		 * then the last WDH could take 6+ msec
+		 */
+		ohci_dbg (ohci, "stopping schedules ...\n");
+		limit = 2000;
+		while (limit > 0) {
+			udelay (250);
+			limit =- 250;
+			if (ohci_readl (ohci, &ohci->regs->intrstatus)
+					& OHCI_INTR_SF)
+				break;
+		}
+		dl_done_list (ohci, NULL);
+		mdelay (7);
+	}
+	dl_done_list (ohci, NULL);
+	finish_unlinks (ohci, ohci_frame_no(ohci), NULL);
+	ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus),
+			&ohci->regs->intrstatus);
+
+	/* maybe resume can wake root hub */
+	if (hcd->remote_wakeup)
+		ohci->hc_control |= OHCI_CTRL_RWE;
+	else
+		ohci->hc_control &= ~OHCI_CTRL_RWE;
+
+	/* Suspend hub */
+	ohci->hc_control &= ~OHCI_CTRL_HCFS;
+	ohci->hc_control |= OHCI_USB_SUSPEND;
+	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+	(void) ohci_readl (ohci, &ohci->regs->control);
+
+	/* no resumes until devices finish suspending */
+	ohci->next_statechange = jiffies + msecs_to_jiffies (5);
+
+done:
+	if (status == 0)
+		hcd->state = HC_STATE_SUSPENDED;
+	spin_unlock_irqrestore (&ohci->lock, flags);
+	return status;
+}
+
+static inline struct ed *find_head (struct ed *ed)
+{
+	/* for bulk and control lists */
+	while (ed->ed_prev)
+		ed = ed->ed_prev;
+	return ed;
+}
+
+/* caller has locked the root hub */
+static int ohci_hub_resume (struct usb_hcd *hcd)
+{
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+	u32			temp, enables;
+	int			status = -EINPROGRESS;
+
+	if (time_before (jiffies, ohci->next_statechange))
+		msleep(5);
+
+	spin_lock_irq (&ohci->lock);
+	ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
+
+	if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
+		/* this can happen after suspend-to-disk */
+		if (hcd->state == HC_STATE_RESUMING) {
+			ohci_dbg (ohci, "BIOS/SMM active, control %03x\n",
+					ohci->hc_control);
+			status = -EBUSY;
+		/* this happens when pmcore resumes HC then root */
+		} else {
+			ohci_dbg (ohci, "duplicate resume\n");
+			status = 0;
+		}
+	} else switch (ohci->hc_control & OHCI_CTRL_HCFS) {
+	case OHCI_USB_SUSPEND:
+		ohci->hc_control &= ~(OHCI_CTRL_HCFS|OHCI_SCHED_ENABLES);
+		ohci->hc_control |= OHCI_USB_RESUME;
+		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+		(void) ohci_readl (ohci, &ohci->regs->control);
+		ohci_dbg (ohci, "resume root hub\n");
+		break;
+	case OHCI_USB_RESUME:
+		/* HCFS changes sometime after INTR_RD */
+		ohci_info (ohci, "wakeup\n");
+		break;
+	case OHCI_USB_OPER:
+		ohci_dbg (ohci, "already resumed\n");
+		status = 0;
+		break;
+	default:		/* RESET, we lost power */
+		ohci_dbg (ohci, "root hub hardware reset\n");
+		status = -EBUSY;
+	}
+	spin_unlock_irq (&ohci->lock);
+	if (status == -EBUSY) {
+		(void) ohci_init (ohci);
+		return ohci_restart (ohci);
+	}
+	if (status != -EINPROGRESS)
+		return status;
+
+	temp = roothub_a (ohci) & RH_A_NDP;
+	enables = 0;
+	while (temp--) {
+		u32 stat = ohci_readl (ohci,
+				       &ohci->regs->roothub.portstatus [temp]);
+
+		/* force global, not selective, resume */
+		if (!(stat & RH_PS_PSS))
+			continue;
+		ohci_writel (ohci, RH_PS_POCI,
+				&ohci->regs->roothub.portstatus [temp]);
+	}
+
+	/* Some controllers (lucent erratum) need extra-long delays */
+	hcd->state = HC_STATE_RESUMING;
+	mdelay (20 /* usb 11.5.1.10 */ + 15);
+
+	temp = ohci_readl (ohci, &ohci->regs->control);
+	temp &= OHCI_CTRL_HCFS;
+	if (temp != OHCI_USB_RESUME) {
+		ohci_err (ohci, "controller won't resume\n");
+		return -EBUSY;
+	}
+
+	/* disable old schedule state, reinit from scratch */
+	ohci_writel (ohci, 0, &ohci->regs->ed_controlhead);
+	ohci_writel (ohci, 0, &ohci->regs->ed_controlcurrent);
+	ohci_writel (ohci, 0, &ohci->regs->ed_bulkhead);
+	ohci_writel (ohci, 0, &ohci->regs->ed_bulkcurrent);
+	ohci_writel (ohci, 0, &ohci->regs->ed_periodcurrent);
+	ohci_writel (ohci, (u32) ohci->hcca_dma, &ohci->regs->hcca);
+
+	/* Sometimes PCI D3 suspend trashes frame timings ... */
+	periodic_reinit (ohci);
+
+	/* interrupts might have been disabled */
+	ohci_writel (ohci, OHCI_INTR_INIT, &ohci->regs->intrenable);
+	if (ohci->ed_rm_list)
+		ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrenable);
+	ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus),
+			&ohci->regs->intrstatus);
+
+	/* Then re-enable operations */
+	ohci_writel (ohci, OHCI_USB_OPER, &ohci->regs->control);
+	(void) ohci_readl (ohci, &ohci->regs->control);
+	msleep (3);
+
+	temp = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+	if (hcd->can_wakeup)
+		temp |= OHCI_CTRL_RWC;
+	ohci->hc_control = temp;
+	ohci_writel (ohci, temp, &ohci->regs->control);
+	(void) ohci_readl (ohci, &ohci->regs->control);
+
+	/* TRSMRCY */
+	msleep (10);
+
+	/* keep it alive for ~5x suspend + resume costs */
+	ohci->next_statechange = jiffies + msecs_to_jiffies (250);
+
+	/* maybe turn schedules back on */
+	enables = 0;
+	temp = 0;
+	if (!ohci->ed_rm_list) {
+		if (ohci->ed_controltail) {
+			ohci_writel (ohci,
+					find_head (ohci->ed_controltail)->dma,
+					&ohci->regs->ed_controlhead);
+			enables |= OHCI_CTRL_CLE;
+			temp |= OHCI_CLF;
+		}
+		if (ohci->ed_bulktail) {
+			ohci_writel (ohci, find_head (ohci->ed_bulktail)->dma,
+				&ohci->regs->ed_bulkhead);
+			enables |= OHCI_CTRL_BLE;
+			temp |= OHCI_BLF;
+		}
+	}
+	if (hcd->self.bandwidth_isoc_reqs || hcd->self.bandwidth_int_reqs)
+		enables |= OHCI_CTRL_PLE|OHCI_CTRL_IE;
+	if (enables) {
+		ohci_dbg (ohci, "restarting schedules ... %08x\n", enables);
+		ohci->hc_control |= enables;
+		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+		if (temp)
+			ohci_writel (ohci, temp, &ohci->regs->cmdstatus);
+		(void) ohci_readl (ohci, &ohci->regs->control);
+	}
+
+	hcd->state = HC_STATE_RUNNING;
+	return 0;
+}
+
+static void ohci_rh_resume (void *_hcd)
+{
+	struct usb_hcd	*hcd = _hcd;
+
+	usb_lock_device (hcd->self.root_hub);
+	(void) ohci_hub_resume (hcd);
+	usb_unlock_device (hcd->self.root_hub);
+}
+
+#else
+
+static void ohci_rh_resume (void *_hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (_hcd);
+	ohci_dbg(ohci, "rh_resume ??\n");
+}
+
+#endif	/* CONFIG_USB_SUSPEND || CONFIG_PM */
+
+/*-------------------------------------------------------------------------*/
+
+/* build "status change" packet (one or two bytes) from HC registers */
+
+static int
+ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int		ports, i, changed = 0, length = 1;
+	int		can_suspend = hcd->can_wakeup;
+	unsigned long	flags;
+
+	spin_lock_irqsave (&ohci->lock, flags);
+
+	/* handle autosuspended root:  finish resuming before
+	 * letting khubd or root hub timer see state changes.
+	 */
+	if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER
+			|| !HC_IS_RUNNING(hcd->state)) {
+		can_suspend = 0;
+		goto done;
+	}
+
+	ports = roothub_a (ohci) & RH_A_NDP; 
+	if (ports > MAX_ROOT_PORTS) {
+		ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n", ports,
+			  ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP);
+		/* retry later; "should not happen" */
+		goto done;
+	}
+
+	/* init status */
+	if (roothub_status (ohci) & (RH_HS_LPSC | RH_HS_OCIC))
+		buf [0] = changed = 1;
+	else
+		buf [0] = 0;
+	if (ports > 7) {
+		buf [1] = 0;
+		length++;
+	}
+
+	/* look at each port */
+	for (i = 0; i < ports; i++) {
+		u32	status = roothub_portstatus (ohci, i);
+
+		if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
+				| RH_PS_OCIC | RH_PS_PRSC)) {
+			changed = 1;
+			if (i < 7)
+			    buf [0] |= 1 << (i + 1);
+			else
+			    buf [1] |= 1 << (i - 7);
+			continue;
+		}
+
+		/* can suspend if no ports are enabled; or if all all
+		 * enabled ports are suspended AND remote wakeup is on.
+		 */
+		if (!(status & RH_PS_CCS))
+			continue;
+		if ((status & RH_PS_PSS) && hcd->remote_wakeup)
+			continue;
+		can_suspend = 0;
+	}
+done:
+	spin_unlock_irqrestore (&ohci->lock, flags);
+
+#ifdef CONFIG_PM
+	/* save power by suspending idle root hubs;
+	 * INTR_RD wakes us when there's work
+	 * NOTE: if we can do this, we don't need a root hub timer!
+	 */
+	if (can_suspend
+			&& !changed
+			&& !ohci->ed_rm_list
+			&& ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES)
+					& ohci->hc_control)
+				== OHCI_USB_OPER
+			&& time_after (jiffies, ohci->next_statechange)
+			&& usb_trylock_device (hcd->self.root_hub)
+			) {
+		ohci_vdbg (ohci, "autosuspend\n");
+		(void) ohci_hub_suspend (hcd);
+		hcd->state = HC_STATE_RUNNING;
+		usb_unlock_device (hcd->self.root_hub);
+	}
+#endif
+
+	return changed ? length : 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+ohci_hub_descriptor (
+	struct ohci_hcd			*ohci,
+	struct usb_hub_descriptor	*desc
+) {
+	u32		rh = roothub_a (ohci);
+	int		ports = rh & RH_A_NDP; 
+	u16		temp;
+
+	desc->bDescriptorType = 0x29;
+	desc->bPwrOn2PwrGood = (rh & RH_A_POTPGT) >> 24;
+	desc->bHubContrCurrent = 0;
+
+	desc->bNbrPorts = ports;
+	temp = 1 + (ports / 8);
+	desc->bDescLength = 7 + 2 * temp;
+
+	temp = 0;
+	if (rh & RH_A_NPS)		/* no power switching? */
+	    temp |= 0x0002;
+	if (rh & RH_A_PSM) 		/* per-port power switching? */
+	    temp |= 0x0001;
+	if (rh & RH_A_NOCP)		/* no overcurrent reporting? */
+	    temp |= 0x0010;
+	else if (rh & RH_A_OCPM)	/* per-port overcurrent reporting? */
+	    temp |= 0x0008;
+	desc->wHubCharacteristics = (__force __u16)cpu_to_hc16(ohci, temp);
+
+	/* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+	rh = roothub_b (ohci);
+	desc->bitmap [0] = rh & RH_B_DR;
+	if (ports > 7) {
+		desc->bitmap [1] = (rh & RH_B_DR) >> 8;
+		desc->bitmap [2] = desc->bitmap [3] = 0xff;
+	} else
+		desc->bitmap [1] = 0xff;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	CONFIG_USB_OTG
+
+static int ohci_start_port_reset (struct usb_hcd *hcd, unsigned port)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	u32			status;
+
+	if (!port)
+		return -EINVAL;
+	port--;
+
+	/* start port reset before HNP protocol times out */
+	status = ohci_readl(ohci, &ohci->regs->roothub.portstatus [port]);
+	if (!(status & RH_PS_CCS))
+		return -ENODEV;
+
+	/* khubd will finish the reset later */
+	ohci_writel(ohci, RH_PS_PRS, &ohci->regs->roothub.portstatus [port]);
+	return 0;
+}
+
+static void start_hnp(struct ohci_hcd *ohci);
+
+#else
+
+#define	ohci_start_port_reset		NULL
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+
+/* See usb 7.1.7.5:  root hubs must issue at least 50 msec reset signaling,
+ * not necessarily continuous ... to guard against resume signaling.
+ * The short timeout is safe for non-root hubs, and is backward-compatible
+ * with earlier Linux hosts.
+ */
+#ifdef	CONFIG_USB_SUSPEND
+#define	PORT_RESET_MSEC		50
+#else
+#define	PORT_RESET_MSEC		10
+#endif
+
+/* this timer value might be vendor-specific ... */
+#define	PORT_RESET_HW_MSEC	10
+
+/* wrap-aware logic morphed from <linux/jiffies.h> */
+#define tick_before(t1,t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0)
+
+/* called from some task, normally khubd */
+static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port)
+{
+	__hc32 __iomem *portstat = &ohci->regs->roothub.portstatus [port];
+	u32	temp;
+	u16	now = ohci_readl(ohci, &ohci->regs->fmnumber);
+	u16	reset_done = now + PORT_RESET_MSEC;
+
+	/* build a "continuous enough" reset signal, with up to
+	 * 3msec gap between pulses.  scheduler HZ==100 must work;
+	 * this might need to be deadline-scheduled.
+	 */
+	do {
+		/* spin until any current reset finishes */
+		for (;;) {
+			temp = ohci_readl (ohci, portstat);
+			if (!(temp & RH_PS_PRS))
+				break;
+			udelay (500);
+		} 
+
+		if (!(temp & RH_PS_CCS))
+			break;
+		if (temp & RH_PS_PRSC)
+			ohci_writel (ohci, RH_PS_PRSC, portstat);
+
+		/* start the next reset, sleep till it's probably done */
+		ohci_writel (ohci, RH_PS_PRS, portstat);
+		msleep(PORT_RESET_HW_MSEC);
+		now = ohci_readl(ohci, &ohci->regs->fmnumber);
+	} while (tick_before(now, reset_done));
+	/* caller synchronizes using PRSC */
+}
+
+static int ohci_hub_control (
+	struct usb_hcd	*hcd,
+	u16		typeReq,
+	u16		wValue,
+	u16		wIndex,
+	char		*buf,
+	u16		wLength
+) {
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int		ports = hcd_to_bus (hcd)->root_hub->maxchild;
+	u32		temp;
+	int		retval = 0;
+
+	switch (typeReq) {
+	case ClearHubFeature:
+		switch (wValue) {
+		case C_HUB_OVER_CURRENT:
+			ohci_writel (ohci, RH_HS_OCIC,
+					&ohci->regs->roothub.status);
+		case C_HUB_LOCAL_POWER:
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case ClearPortFeature:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+
+		switch (wValue) {
+		case USB_PORT_FEAT_ENABLE:
+			temp = RH_PS_CCS;
+			break;
+		case USB_PORT_FEAT_C_ENABLE:
+			temp = RH_PS_PESC;
+			break;
+		case USB_PORT_FEAT_SUSPEND:
+			temp = RH_PS_POCI;
+			if ((ohci->hc_control & OHCI_CTRL_HCFS)
+					!= OHCI_USB_OPER)
+				schedule_work (&ohci->rh_resume);
+			break;
+		case USB_PORT_FEAT_C_SUSPEND:
+			temp = RH_PS_PSSC;
+			break;
+		case USB_PORT_FEAT_POWER:
+			temp = RH_PS_LSDA;
+			break;
+		case USB_PORT_FEAT_C_CONNECTION:
+			temp = RH_PS_CSC;
+			break;
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+			temp = RH_PS_OCIC;
+			break;
+		case USB_PORT_FEAT_C_RESET:
+			temp = RH_PS_PRSC;
+			break;
+		default:
+			goto error;
+		}
+		ohci_writel (ohci, temp,
+				&ohci->regs->roothub.portstatus [wIndex]);
+		// ohci_readl (ohci, &ohci->regs->roothub.portstatus [wIndex]);
+		break;
+	case GetHubDescriptor:
+		ohci_hub_descriptor (ohci, (struct usb_hub_descriptor *) buf);
+		break;
+	case GetHubStatus:
+		temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE);
+		*(__le32 *) buf = cpu_to_le32 (temp);
+		break;
+	case GetPortStatus:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		temp = roothub_portstatus (ohci, wIndex);
+		*(__le32 *) buf = cpu_to_le32 (temp);
+
+#ifndef	OHCI_VERBOSE_DEBUG
+	if (*(u16*)(buf+2))	/* only if wPortChange is interesting */
+#endif
+		dbg_port (ohci, "GetStatus", wIndex, temp);
+		break;
+	case SetHubFeature:
+		switch (wValue) {
+		case C_HUB_OVER_CURRENT:
+			// FIXME:  this can be cleared, yes?
+		case C_HUB_LOCAL_POWER:
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case SetPortFeature:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+#ifdef	CONFIG_USB_OTG
+			if (hcd->self.otg_port == (wIndex + 1)
+					&& hcd->self.b_hnp_enable)
+				start_hnp(ohci);
+			else
+#endif
+			ohci_writel (ohci, RH_PS_PSS,
+				&ohci->regs->roothub.portstatus [wIndex]);
+			break;
+		case USB_PORT_FEAT_POWER:
+			ohci_writel (ohci, RH_PS_PPS,
+				&ohci->regs->roothub.portstatus [wIndex]);
+			break;
+		case USB_PORT_FEAT_RESET:
+			root_port_reset (ohci, wIndex);
+			break;
+		default:
+			goto error;
+		}
+		break;
+
+	default:
+error:
+		/* "protocol stall" on error */
+		retval = -EPIPE;
+	}
+	return retval;
+}
+
diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
new file mode 100644
index 0000000..817620d
--- /dev/null
+++ b/drivers/usb/host/ohci-lh7a404.c
@@ -0,0 +1,266 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ *
+ * Bus Glue for Sharp LH7A404
+ *
+ * Written by Christopher Hoover <ch@hpl.hp.com>
+ * Based on fragments of previous driver by Rusell King et al.
+ *
+ * Modified for LH7A404 from ohci-sa1111.c
+ *  by Durgesh Pattamatta <pattamattad@sharpsec.com>
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/arch/hardware.h>
+
+
+extern int usb_disabled(void);
+
+/*-------------------------------------------------------------------------*/
+
+static void lh7a404_start_hc(struct platform_device *dev)
+{
+	printk(KERN_DEBUG __FILE__
+	       ": starting LH7A404 OHCI USB Controller\n");
+
+	/*
+	 * Now, carefully enable the USB clock, and take
+	 * the USB host controller out of reset.
+	 */
+	CSC_PWRCNT |= CSC_PWRCNT_USBH_EN; /* Enable clock */
+	udelay(1000);
+	USBH_CMDSTATUS = OHCI_HCR;
+	
+	printk(KERN_DEBUG __FILE__
+		   ": Clock to USB host has been enabled \n");
+}
+
+static void lh7a404_stop_hc(struct platform_device *dev)
+{
+	printk(KERN_DEBUG __FILE__
+	       ": stopping LH7A404 OHCI USB Controller\n");
+
+	CSC_PWRCNT &= ~CSC_PWRCNT_USBH_EN; /* Disable clock */
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+
+/**
+ * usb_hcd_lh7a404_probe - initialize LH7A404-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ */
+int usb_hcd_lh7a404_probe (const struct hc_driver *driver,
+			  struct platform_device *dev)
+{
+	int retval;
+	struct usb_hcd *hcd;
+
+	if (dev->resource[1].flags != IORESOURCE_IRQ) {
+		pr_debug("resource[1] is not IORESOURCE_IRQ");
+		return -ENOMEM;
+	}
+
+	hcd = usb_create_hcd(driver, &dev->dev, "lh7a404");
+	if (!hcd)
+		return -ENOMEM;
+	hcd->rsrc_start = dev->resource[0].start;
+	hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		pr_debug("request_mem_region failed");
+		retval = -EBUSY;
+		goto err1;
+	}
+	
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		pr_debug("ioremap failed");
+		retval = -ENOMEM;
+		goto err2;
+	}
+
+	lh7a404_start_hc(dev);
+	ohci_hcd_init(hcd_to_ohci(hcd));
+
+	retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
+	if (retval == 0)
+		return retval;
+
+	lh7a404_stop_hc(dev);
+	iounmap(hcd->regs);
+ err2:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ err1:
+	usb_put_hcd(hcd);
+	return retval;
+}
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_lh7a404_remove - shutdown processing for LH7A404-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_lh7a404_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+void usb_hcd_lh7a404_remove (struct usb_hcd *hcd, struct platform_device *dev)
+{
+	usb_remove_hcd(hcd);
+	lh7a404_stop_hc(dev);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_lh7a404_start (struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int		ret;
+
+	ohci_dbg (ohci, "ohci_lh7a404_start, ohci:%p", ohci);
+	if ((ret = ohci_init(ohci)) < 0)
+		return ret;
+
+	if ((ret = ohci_run (ohci)) < 0) {
+		err ("can't start %s", hcd->self.bus_name);
+		ohci_stop (hcd);
+		return ret;
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_lh7a404_hc_driver = {
+	.description =		hcd_name,
+	.product_desc =		"LH7A404 OHCI",
+	.hcd_priv_size =	sizeof(struct ohci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ohci_irq,
+	.flags =		HCD_USB11 | HCD_MEMORY,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.start =		ohci_lh7a404_start,
+#ifdef	CONFIG_PM
+	/* suspend:		ohci_lh7a404_suspend,  -- tbd */
+	/* resume:		ohci_lh7a404_resume,   -- tbd */
+#endif /*CONFIG_PM*/
+	.stop =			ohci_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ohci_urb_enqueue,
+	.urb_dequeue =		ohci_urb_dequeue,
+	.endpoint_disable =	ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ohci_hub_status_data,
+	.hub_control =		ohci_hub_control,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hcd_lh7a404_drv_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	int ret;
+
+	pr_debug ("In ohci_hcd_lh7a404_drv_probe");
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	ret = usb_hcd_lh7a404_probe(&ohci_lh7a404_hc_driver, pdev);
+	return ret;
+}
+
+static int ohci_hcd_lh7a404_drv_remove(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	usb_hcd_lh7a404_remove(hcd, pdev);
+	return 0;
+}
+	/*TBD*/
+/*static int ohci_hcd_lh7a404_drv_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	return 0;
+}
+static int ohci_hcd_lh7a404_drv_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+
+	return 0;
+}
+*/
+
+static struct device_driver ohci_hcd_lh7a404_driver = {
+	.name		= "lh7a404-ohci",
+	.bus		= &platform_bus_type,
+	.probe		= ohci_hcd_lh7a404_drv_probe,
+	.remove		= ohci_hcd_lh7a404_drv_remove,
+	/*.suspend	= ohci_hcd_lh7a404_drv_suspend, */
+	/*.resume	= ohci_hcd_lh7a404_drv_resume, */
+};
+
+static int __init ohci_hcd_lh7a404_init (void)
+{
+	pr_debug (DRIVER_INFO " (LH7A404)");
+	pr_debug ("block sizes: ed %d td %d\n",
+		sizeof (struct ed), sizeof (struct td));
+
+	return driver_register(&ohci_hcd_lh7a404_driver);
+}
+
+static void __exit ohci_hcd_lh7a404_cleanup (void)
+{
+	driver_unregister(&ohci_hcd_lh7a404_driver);
+}
+
+module_init (ohci_hcd_lh7a404_init);
+module_exit (ohci_hcd_lh7a404_cleanup);
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
new file mode 100644
index 0000000..e55682b
--- /dev/null
+++ b/drivers/usb/host/ohci-mem.c
@@ -0,0 +1,139 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ * 
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * This file is licenced under the GPL.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * There's basically three types of memory:
+ *	- data used only by the HCD ... kmalloc is fine
+ *	- async and periodic schedules, shared by HC and HCD ... these
+ *	  need to use dma_pool or dma_alloc_coherent
+ *	- driver buffers, read/written by HC ... the hcd glue or the
+ *	  device driver provides us with dma addresses
+ *
+ * There's also PCI "register" data, which is memory mapped.
+ * No memory seen by this driver is pagable.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+static void ohci_hcd_init (struct ohci_hcd *ohci)
+{
+	ohci->next_statechange = jiffies;
+	spin_lock_init (&ohci->lock);
+	INIT_LIST_HEAD (&ohci->pending);
+	INIT_WORK (&ohci->rh_resume, ohci_rh_resume, ohci_to_hcd(ohci));
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_mem_init (struct ohci_hcd *ohci)
+{
+	ohci->td_cache = dma_pool_create ("ohci_td",
+		ohci_to_hcd(ohci)->self.controller,
+		sizeof (struct td),
+		32 /* byte alignment */,
+		0 /* no page-crossing issues */);
+	if (!ohci->td_cache)
+		return -ENOMEM;
+	ohci->ed_cache = dma_pool_create ("ohci_ed",
+		ohci_to_hcd(ohci)->self.controller,
+		sizeof (struct ed),
+		16 /* byte alignment */,
+		0 /* no page-crossing issues */);
+	if (!ohci->ed_cache) {
+		dma_pool_destroy (ohci->td_cache);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void ohci_mem_cleanup (struct ohci_hcd *ohci)
+{
+	if (ohci->td_cache) {
+		dma_pool_destroy (ohci->td_cache);
+		ohci->td_cache = NULL;
+	}
+	if (ohci->ed_cache) {
+		dma_pool_destroy (ohci->ed_cache);
+		ohci->ed_cache = NULL;
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* ohci "done list" processing needs this mapping */
+static inline struct td *
+dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma)
+{
+	struct td *td;
+
+	td_dma &= TD_MASK;
+	td = hc->td_hash [TD_HASH_FUNC(td_dma)];
+	while (td && td->td_dma != td_dma)
+		td = td->td_hash;
+	return td;
+}
+
+/* TDs ... */
+static struct td *
+td_alloc (struct ohci_hcd *hc, int mem_flags)
+{
+	dma_addr_t	dma;
+	struct td	*td;
+
+	td = dma_pool_alloc (hc->td_cache, mem_flags, &dma);
+	if (td) {
+		/* in case hc fetches it, make it look dead */
+		memset (td, 0, sizeof *td);
+		td->hwNextTD = cpu_to_hc32 (hc, dma);
+		td->td_dma = dma;
+		/* hashed in td_fill */
+	}
+	return td;
+}
+
+static void
+td_free (struct ohci_hcd *hc, struct td *td)
+{
+	struct td	**prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)];
+
+	while (*prev && *prev != td)
+		prev = &(*prev)->td_hash;
+	if (*prev)
+		*prev = td->td_hash;
+	else if ((td->hwINFO & cpu_to_hc32(hc, TD_DONE)) != 0)
+		ohci_dbg (hc, "no hash for td %p\n", td);
+	dma_pool_free (hc->td_cache, td, td->td_dma);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* EDs ... */
+static struct ed *
+ed_alloc (struct ohci_hcd *hc, int mem_flags)
+{
+	dma_addr_t	dma;
+	struct ed	*ed;
+
+	ed = dma_pool_alloc (hc->ed_cache, mem_flags, &dma);
+	if (ed) {
+		memset (ed, 0, sizeof (*ed));
+		INIT_LIST_HEAD (&ed->td_list);
+		ed->dma = dma;
+	}
+	return ed;
+}
+
+static void
+ed_free (struct ohci_hcd *hc, struct ed *ed)
+{
+	dma_pool_free (hc->ed_cache, ed, ed->dma);
+}
+
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
new file mode 100644
index 0000000..90285f1
--- /dev/null
+++ b/drivers/usb/host/ohci-omap.c
@@ -0,0 +1,560 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2005 David Brownell
+ * (C) Copyright 2002 Hewlett-Packard Company
+ * 
+ * OMAP Bus Glue
+ *
+ * Modified for OMAP by Tony Lindgren <tony@atomide.com>
+ * Based on the 2.4 OMAP OHCI driver originally done by MontaVista Software Inc.
+ * and on ohci-sa1111.c by Christopher Hoover <ch@hpl.hp.com>
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/fpga.h>
+#include <asm/arch/usb.h>
+#include <asm/hardware/clock.h>
+
+
+/* OMAP-1510 OHCI has its own MMU for DMA */
+#define OMAP1510_LB_MEMSIZE	32	/* Should be same as SDRAM size */
+#define OMAP1510_LB_CLOCK_DIV	0xfffec10c
+#define OMAP1510_LB_MMU_CTL	0xfffec208
+#define OMAP1510_LB_MMU_LCK	0xfffec224
+#define OMAP1510_LB_MMU_LD_TLB	0xfffec228
+#define OMAP1510_LB_MMU_CAM_H	0xfffec22c
+#define OMAP1510_LB_MMU_CAM_L	0xfffec230
+#define OMAP1510_LB_MMU_RAM_H	0xfffec234
+#define OMAP1510_LB_MMU_RAM_L	0xfffec238
+
+
+#ifndef CONFIG_ARCH_OMAP
+#error "This file is OMAP bus glue.  CONFIG_OMAP must be defined."
+#endif
+
+#ifdef CONFIG_TPS65010
+#include <asm/arch/tps65010.h>
+#else
+
+#define LOW	0
+#define HIGH	1
+
+#define GPIO1	1
+
+static inline int tps65010_set_gpio_out_value(unsigned gpio, unsigned value)
+{
+	return 0;
+}
+
+#endif
+
+extern int usb_disabled(void);
+extern int ocpi_enable(void);
+
+static struct clk *usb_host_ck;
+
+static void omap_ohci_clock_power(int on)
+{
+	if (on) {
+		clk_enable(usb_host_ck);
+		/* guesstimate for T5 == 1x 32K clock + APLL lock time */
+		udelay(100);
+	} else {
+		clk_disable(usb_host_ck);
+	}
+}
+
+/*
+ * Board specific gang-switched transceiver power on/off.
+ * NOTE:  OSK supplies power from DC, not battery.
+ */
+static int omap_ohci_transceiver_power(int on)
+{
+	if (on) {
+		if (machine_is_omap_innovator() && cpu_is_omap1510())
+			fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL)
+				| ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), 
+			       INNOVATOR_FPGA_CAM_USB_CONTROL);
+		else if (machine_is_omap_osk())
+			tps65010_set_gpio_out_value(GPIO1, LOW);
+	} else {
+		if (machine_is_omap_innovator() && cpu_is_omap1510())
+			fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL)
+				& ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), 
+			       INNOVATOR_FPGA_CAM_USB_CONTROL);
+		else if (machine_is_omap_osk())
+			tps65010_set_gpio_out_value(GPIO1, HIGH);
+	}
+
+	return 0;
+}
+
+/*
+ * OMAP-1510 specific Local Bus clock on/off
+ */
+static int omap_1510_local_bus_power(int on)
+{
+	if (on) {
+		omap_writel((1 << 1) | (1 << 0), OMAP1510_LB_MMU_CTL);
+		udelay(200);
+	} else {
+		omap_writel(0, OMAP1510_LB_MMU_CTL);
+	}
+
+	return 0;
+}
+
+/*
+ * OMAP-1510 specific Local Bus initialization
+ * NOTE: This assumes 32MB memory size in OMAP1510LB_MEMSIZE.
+ *       See also arch/mach-omap/memory.h for __virt_to_dma() and 
+ *       __dma_to_virt() which need to match with the physical 
+ *       Local Bus address below.
+ */
+static int omap_1510_local_bus_init(void)
+{
+	unsigned int tlb;
+	unsigned long lbaddr, physaddr;
+
+	omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4, 
+	       OMAP1510_LB_CLOCK_DIV);
+
+	/* Configure the Local Bus MMU table */
+	for (tlb = 0; tlb < OMAP1510_LB_MEMSIZE; tlb++) {
+		lbaddr = tlb * 0x00100000 + OMAP1510_LB_OFFSET;
+		physaddr = tlb * 0x00100000 + PHYS_OFFSET;
+		omap_writel((lbaddr & 0x0fffffff) >> 22, OMAP1510_LB_MMU_CAM_H);
+		omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc, 
+		       OMAP1510_LB_MMU_CAM_L);
+		omap_writel(physaddr >> 16, OMAP1510_LB_MMU_RAM_H);
+		omap_writel((physaddr & 0x0000fc00) | 0x300, OMAP1510_LB_MMU_RAM_L);
+		omap_writel(tlb << 4, OMAP1510_LB_MMU_LCK);
+		omap_writel(0x1, OMAP1510_LB_MMU_LD_TLB);
+	}
+
+	/* Enable the walking table */
+	omap_writel(omap_readl(OMAP1510_LB_MMU_CTL) | (1 << 3), OMAP1510_LB_MMU_CTL);
+	udelay(200);
+
+	return 0;
+}
+
+#ifdef	CONFIG_USB_OTG
+
+static void start_hnp(struct ohci_hcd *ohci)
+{
+	const unsigned	port = ohci_to_hcd(ohci)->self.otg_port - 1;
+	unsigned long	flags;
+
+	otg_start_hnp(ohci->transceiver);
+
+	local_irq_save(flags);
+	ohci->transceiver->state = OTG_STATE_A_SUSPEND;
+	writel (RH_PS_PSS, &ohci->regs->roothub.portstatus [port]);
+	OTG_CTRL_REG &= ~OTG_A_BUSREQ;
+	local_irq_restore(flags);
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
+{
+	struct omap_usb_config	*config = pdev->dev.platform_data;
+	int			need_transceiver = (config->otg != 0);
+	int			ret;
+
+	dev_dbg(&pdev->dev, "starting USB Controller\n");
+
+	if (config->otg) {
+		ohci_to_hcd(ohci)->self.otg_port = config->otg;
+		/* default/minimum OTG power budget:  8 mA */
+		ohci->power_budget = 8;
+	}
+
+	/* boards can use OTG transceivers in non-OTG modes */
+	need_transceiver = need_transceiver
+			|| machine_is_omap_h2() || machine_is_omap_h3();
+
+	if (cpu_is_omap16xx())
+		ocpi_enable();
+
+#ifdef	CONFIG_ARCH_OMAP_OTG
+	if (need_transceiver) {
+		ohci->transceiver = otg_get_transceiver();
+		if (ohci->transceiver) {
+			int	status = otg_set_host(ohci->transceiver,
+						&ohci_to_hcd(ohci)->self);
+			dev_dbg(&pdev->dev, "init %s transceiver, status %d\n",
+					ohci->transceiver->label, status);
+			if (status) {
+				if (ohci->transceiver)
+					put_device(ohci->transceiver->dev);
+				return status;
+			}
+		} else {
+			dev_err(&pdev->dev, "can't find transceiver\n");
+			return -ENODEV;
+		}
+	}
+#endif
+
+	omap_ohci_clock_power(1);
+
+	if (cpu_is_omap1510()) {
+		omap_1510_local_bus_power(1);
+		omap_1510_local_bus_init();
+	}
+
+	if ((ret = ohci_init(ohci)) < 0)
+		return ret;
+
+	/* board-specific power switching and overcurrent support */
+	if (machine_is_omap_osk() || machine_is_omap_innovator()) {
+		u32	rh = roothub_a (ohci);
+
+		/* power switching (ganged by default) */
+		rh &= ~RH_A_NPS;
+
+		/* TPS2045 switch for internal transceiver (port 1) */
+		if (machine_is_omap_osk()) {
+			ohci->power_budget = 250;
+
+			rh &= ~RH_A_NOCP;
+
+			/* gpio9 for overcurrent detction */
+			omap_cfg_reg(W8_1610_GPIO9);
+			omap_request_gpio(9);
+			omap_set_gpio_direction(9, 1 /* IN */);
+
+			/* for paranoia's sake:  disable USB.PUEN */
+			omap_cfg_reg(W4_USB_HIGHZ);
+		}
+		ohci_writel(ohci, rh, &ohci->regs->roothub.a);
+		distrust_firmware = 0;
+	}
+
+	/* FIXME khubd hub requests should manage power switching */
+	omap_ohci_transceiver_power(1);
+
+	/* board init will have already handled HMC and mux setup.
+	 * any external transceiver should already be initialized
+	 * too, so all configured ports use the right signaling now.
+	 */
+
+	return 0;
+}
+
+static void omap_stop_hc(struct platform_device *pdev)
+{
+	dev_dbg(&pdev->dev, "stopping USB Controller\n");
+	omap_ohci_clock_power(0);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *);
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+
+/**
+ * usb_hcd_omap_probe - initialize OMAP-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ */
+int usb_hcd_omap_probe (const struct hc_driver *driver,
+			  struct platform_device *pdev)
+{
+	int retval;
+	struct usb_hcd *hcd = 0;
+	struct ohci_hcd *ohci;
+
+	if (pdev->num_resources != 2) {
+		printk(KERN_ERR "hcd probe: invalid num_resources: %i\n", 
+		       pdev->num_resources);
+		return -ENODEV;
+	}
+
+	if (pdev->resource[0].flags != IORESOURCE_MEM 
+			|| pdev->resource[1].flags != IORESOURCE_IRQ) {
+		printk(KERN_ERR "hcd probe: invalid resource type\n");
+		return -ENODEV;
+	}
+
+	usb_host_ck = clk_get(0, "usb_hhc_ck");
+	if (IS_ERR(usb_host_ck))
+		return PTR_ERR(usb_host_ck);
+
+	hcd = usb_create_hcd (driver, &pdev->dev, pdev->dev.bus_id);
+	if (!hcd) {
+		retval = -ENOMEM;
+		goto err0;
+	}
+	hcd->rsrc_start = pdev->resource[0].start;
+	hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		dev_dbg(&pdev->dev, "request_mem_region failed\n");
+		retval = -EBUSY;
+		goto err1;
+	}
+
+	hcd->regs = (void __iomem *) (int) IO_ADDRESS(hcd->rsrc_start);
+
+	ohci = hcd_to_ohci(hcd);
+	ohci_hcd_init(ohci);
+
+	retval = omap_start_hc(ohci, pdev);
+	if (retval < 0)
+		goto err2;
+
+	retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), SA_INTERRUPT);
+	if (retval == 0)
+		return retval;
+
+	omap_stop_hc(pdev);
+err2:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err1:
+	usb_put_hcd(hcd);
+err0:
+	clk_put(usb_host_ck);
+	return retval;
+}
+
+
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_omap_remove - shutdown processing for OMAP-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_omap_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+void usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
+{
+	usb_remove_hcd(hcd);
+	if (machine_is_omap_osk())
+		omap_free_gpio(9);
+	omap_stop_hc(pdev);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+	clk_put(usb_host_ck);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_omap_start (struct usb_hcd *hcd)
+{
+	struct omap_usb_config *config;
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int		ret;
+
+	config = hcd->self.controller->platform_data;
+	if (config->otg || config->rwc)
+		writel(OHCI_CTRL_RWC, &ohci->regs->control);
+
+	if ((ret = ohci_run (ohci)) < 0) {
+		dev_err(hcd->self.controller, "can't start\n");
+		ohci_stop (hcd);
+		return ret;
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_omap_hc_driver = {
+	.description =		hcd_name,
+	.product_desc =		"OMAP OHCI",
+	.hcd_priv_size =	sizeof(struct ohci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ohci_irq,
+	.flags =		HCD_USB11 | HCD_MEMORY,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.start =		ohci_omap_start,
+	.stop =			ohci_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ohci_urb_enqueue,
+	.urb_dequeue =		ohci_urb_dequeue,
+	.endpoint_disable =	ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ohci_hub_status_data,
+	.hub_control =		ohci_hub_control,
+#ifdef	CONFIG_USB_SUSPEND
+	.hub_suspend =		ohci_hub_suspend,
+	.hub_resume =		ohci_hub_resume,
+#endif
+	.start_port_reset =	ohci_start_port_reset,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hcd_omap_drv_probe(struct device *dev)
+{
+	return usb_hcd_omap_probe(&ohci_omap_hc_driver,
+				to_platform_device(dev));
+}
+
+static int ohci_hcd_omap_drv_remove(struct device *dev)
+{
+	struct platform_device	*pdev = to_platform_device(dev);
+	struct usb_hcd		*hcd = dev_get_drvdata(dev);
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+
+	usb_hcd_omap_remove(hcd, pdev);
+	if (ohci->transceiver) {
+		(void) otg_set_host(ohci->transceiver, 0);
+		put_device(ohci->transceiver->dev);
+	}
+	dev_set_drvdata(dev, NULL);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	CONFIG_PM
+
+/* states match PCI usage, always suspending the root hub except that
+ * 4 ~= D3cold (ACPI D3) with clock off (resume sees reset).
+ */
+
+static int ohci_omap_suspend(struct device *dev, u32 state, u32 level)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci(dev_get_drvdata(dev));
+	int		status = -EINVAL;
+
+	if (level != SUSPEND_POWER_DOWN)
+		return 0;
+	if (state <= dev->power.power_state)
+		return 0;
+
+	dev_dbg(dev, "suspend to %d\n", state);
+	down(&ohci_to_hcd(ohci)->self.root_hub->serialize);
+	status = ohci_hub_suspend(ohci_to_hcd(ohci));
+	if (status == 0) {
+		if (state >= 4) {
+			omap_ohci_clock_power(0);
+			ohci_to_hcd(ohci)->self.root_hub->state =
+					USB_STATE_SUSPENDED;
+			state = 4;
+		}
+		ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
+		dev->power.power_state = state;
+	}
+	up(&ohci_to_hcd(ohci)->self.root_hub->serialize);
+	return status;
+}
+
+static int ohci_omap_resume(struct device *dev, u32 level)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci(dev_get_drvdata(dev));
+	int		status = 0;
+
+	if (level != RESUME_POWER_ON)
+		return 0;
+
+	switch (dev->power.power_state) {
+	case 0:
+		break;
+	case 4:
+		if (time_before(jiffies, ohci->next_statechange))
+			msleep(5);
+		ohci->next_statechange = jiffies;
+		omap_ohci_clock_power(1);
+		/* FALLTHROUGH */
+	default:
+		dev_dbg(dev, "resume from %d\n", dev->power.power_state);
+#ifdef	CONFIG_USB_SUSPEND
+		/* get extra cleanup even if remote wakeup isn't in use */
+		status = usb_resume_device(ohci_to_hcd(ohci)->self.root_hub);
+#else
+		down(&ohci_to_hcd(ohci)->self.root_hub->serialize);
+		status = ohci_hub_resume(ohci_to_hcd(ohci));
+		up(&ohci_to_hcd(ohci)->self.root_hub->serialize);
+#endif
+		if (status == 0)
+			dev->power.power_state = 0;
+		break;
+	}
+	return status;
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Driver definition to register with the OMAP bus
+ */
+static struct device_driver ohci_hcd_omap_driver = {
+	.name		= "ohci",
+	.bus		= &platform_bus_type,
+	.probe		= ohci_hcd_omap_drv_probe,
+	.remove		= ohci_hcd_omap_drv_remove,
+#ifdef	CONFIG_PM
+	.suspend	= ohci_omap_suspend,
+	.resume		= ohci_omap_resume,
+#endif
+};
+
+static int __init ohci_hcd_omap_init (void)
+{
+	printk (KERN_DEBUG "%s: " DRIVER_INFO " (OMAP)\n", hcd_name);
+	if (usb_disabled())
+		return -ENODEV;
+
+	pr_debug("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
+		sizeof (struct ed), sizeof (struct td));
+
+	return driver_register(&ohci_hcd_omap_driver);
+}
+
+static void __exit ohci_hcd_omap_cleanup (void)
+{
+	driver_unregister(&ohci_hcd_omap_driver);
+}
+
+module_init (ohci_hcd_omap_init);
+module_exit (ohci_hcd_omap_cleanup);
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
new file mode 100644
index 0000000..b611582
--- /dev/null
+++ b/drivers/usb/host/ohci-pci.c
@@ -0,0 +1,264 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * [ Initialisation is based on Linus'  ]
+ * [ uhci code and gregs ohci fragments ]
+ * [ (C) Copyright 1999 Linus Torvalds  ]
+ * [ (C) Copyright 1999 Gregory P. Smith]
+ * 
+ * PCI Bus Glue
+ *
+ * This file is licenced under the GPL.
+ */
+ 
+#ifdef CONFIG_PMAC_PBOOK
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/pci-bridge.h>
+#include <asm/prom.h>
+#ifndef CONFIG_PM
+#	define CONFIG_PM
+#endif
+#endif
+
+#ifndef CONFIG_PCI
+#error "This file is PCI bus glue.  CONFIG_PCI must be defined."
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static int
+ohci_pci_reset (struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+
+	ohci_hcd_init (ohci);
+	return ohci_init (ohci);
+}
+
+static int __devinit
+ohci_pci_start (struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int		ret;
+
+	if(hcd->self.controller && hcd->self.controller->bus == &pci_bus_type) {
+		struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+
+		/* AMD 756, for most chips (early revs), corrupts register
+		 * values on read ... so enable the vendor workaround.
+		 */
+		if (pdev->vendor == PCI_VENDOR_ID_AMD
+				&& pdev->device == 0x740c) {
+			ohci->flags = OHCI_QUIRK_AMD756;
+			ohci_info (ohci, "AMD756 erratum 4 workaround\n");
+			// also somewhat erratum 10 (suspend/resume issues)
+		}
+
+		/* FIXME for some of the early AMD 760 southbridges, OHCI
+		 * won't work at all.  blacklist them.
+		 */
+
+		/* Apple's OHCI driver has a lot of bizarre workarounds
+		 * for this chip.  Evidently control and bulk lists
+		 * can get confused.  (B&W G3 models, and ...)
+		 */
+		else if (pdev->vendor == PCI_VENDOR_ID_OPTI
+				&& pdev->device == 0xc861) {
+			ohci_info (ohci,
+				"WARNING: OPTi workarounds unavailable\n");
+		}
+
+		/* Check for NSC87560. We have to look at the bridge (fn1) to
+		 * identify the USB (fn2). This quirk might apply to more or
+		 * even all NSC stuff.
+		 */
+		else if (pdev->vendor == PCI_VENDOR_ID_NS) {
+			struct pci_dev	*b;
+
+			b  = pci_find_slot (pdev->bus->number,
+					PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
+			if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
+					&& b->vendor == PCI_VENDOR_ID_NS) {
+				ohci->flags |= OHCI_QUIRK_SUPERIO;
+				ohci_info (ohci, "Using NSC SuperIO setup\n");
+			}
+		}
+	}
+
+	/* NOTE: there may have already been a first reset, to
+	 * keep bios/smm irqs from making trouble
+	 */
+	if ((ret = ohci_run (ohci)) < 0) {
+		ohci_err (ohci, "can't start\n");
+		ohci_stop (hcd);
+		return ret;
+	}
+	return 0;
+}
+
+#ifdef	CONFIG_PM
+
+static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
+{
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+
+	/* suspend root hub, hoping it keeps power during suspend */
+	if (time_before (jiffies, ohci->next_statechange))
+		msleep (100);
+
+#ifdef	CONFIG_USB_SUSPEND
+	(void) usb_suspend_device (hcd->self.root_hub, state);
+#else
+	usb_lock_device (hcd->self.root_hub);
+	(void) ohci_hub_suspend (hcd);
+	usb_unlock_device (hcd->self.root_hub);
+#endif
+
+	/* let things settle down a bit */
+	msleep (100);
+	
+#ifdef CONFIG_PMAC_PBOOK
+	if (_machine == _MACH_Pmac) {
+	   	struct device_node	*of_node;
+ 
+		/* Disable USB PAD & cell clock */
+		of_node = pci_device_to_OF_node (to_pci_dev(hcd->self.controller));
+		if (of_node)
+			pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
+	}
+#endif /* CONFIG_PMAC_PBOOK */
+	return 0;
+}
+
+
+static int ohci_pci_resume (struct usb_hcd *hcd)
+{
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+	int			retval = 0;
+
+#ifdef CONFIG_PMAC_PBOOK
+	if (_machine == _MACH_Pmac) {
+		struct device_node *of_node;
+
+		/* Re-enable USB PAD & cell clock */
+		of_node = pci_device_to_OF_node (to_pci_dev(hcd->self.controller));
+		if (of_node)
+			pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);
+	}
+#endif /* CONFIG_PMAC_PBOOK */
+
+	/* resume root hub */
+	if (time_before (jiffies, ohci->next_statechange))
+		msleep (100);
+#ifdef	CONFIG_USB_SUSPEND
+	/* get extra cleanup even if remote wakeup isn't in use */
+	retval = usb_resume_device (hcd->self.root_hub);
+#else
+	usb_lock_device (hcd->self.root_hub);
+	retval = ohci_hub_resume (hcd);
+	usb_unlock_device (hcd->self.root_hub);
+#endif
+
+	return retval;
+}
+
+#endif	/* CONFIG_PM */
+
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_pci_hc_driver = {
+	.description =		hcd_name,
+	.product_desc =		"OHCI Host Controller",
+	.hcd_priv_size =	sizeof(struct ohci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ohci_irq,
+	.flags =		HCD_MEMORY | HCD_USB11,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset =		ohci_pci_reset,
+	.start =		ohci_pci_start,
+#ifdef	CONFIG_PM
+	.suspend =		ohci_pci_suspend,
+	.resume =		ohci_pci_resume,
+#endif
+	.stop =			ohci_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ohci_urb_enqueue,
+	.urb_dequeue =		ohci_urb_dequeue,
+	.endpoint_disable =	ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ohci_hub_status_data,
+	.hub_control =		ohci_hub_control,
+#ifdef	CONFIG_USB_SUSPEND
+	.hub_suspend =		ohci_hub_suspend,
+	.hub_resume =		ohci_hub_resume,
+#endif
+	.start_port_reset =	ohci_start_port_reset,
+};
+
+/*-------------------------------------------------------------------------*/
+
+
+static const struct pci_device_id pci_ids [] = { {
+	/* handle any USB OHCI controller */
+	PCI_DEVICE_CLASS((PCI_CLASS_SERIAL_USB << 8) | 0x10, ~0),
+	.driver_data =	(unsigned long) &ohci_pci_hc_driver,
+	}, { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE (pci, pci_ids);
+
+/* pci driver glue; this is a "new style" PCI driver module */
+static struct pci_driver ohci_pci_driver = {
+	.name =		(char *) hcd_name,
+	.id_table =	pci_ids,
+
+	.probe =	usb_hcd_pci_probe,
+	.remove =	usb_hcd_pci_remove,
+
+#ifdef	CONFIG_PM
+	.suspend =	usb_hcd_pci_suspend,
+	.resume =	usb_hcd_pci_resume,
+#endif
+};
+
+ 
+static int __init ohci_hcd_pci_init (void) 
+{
+	printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name);
+	if (usb_disabled())
+		return -ENODEV;
+
+	pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
+		sizeof (struct ed), sizeof (struct td));
+	return pci_register_driver (&ohci_pci_driver);
+}
+module_init (ohci_hcd_pci_init);
+
+/*-------------------------------------------------------------------------*/
+
+static void __exit ohci_hcd_pci_cleanup (void) 
+{	
+	pci_unregister_driver (&ohci_pci_driver);
+}
+module_exit (ohci_hcd_pci_cleanup);
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
new file mode 100644
index 0000000..17964c3
--- /dev/null
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -0,0 +1,234 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ * (C) Copyright 2003-2005 MontaVista Software Inc.
+ * 
+ * Bus Glue for PPC On-Chip OHCI driver
+ * Tested on Freescale MPC5200 and IBM STB04xxx
+ *
+ * Modified by Dale Farnsworth <dale@farnsworth.org> from ohci-sa1111.c
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <asm/usb.h>
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * usb_hcd_ppc_soc_probe - initialize On-Chip HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ * Store this function in the HCD's struct pci_driver as probe().
+ */
+static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
+			  struct platform_device *pdev)
+{
+	int retval;
+	struct usb_hcd *hcd;
+	struct ohci_hcd	*ohci;
+	struct resource *res;
+	int irq;
+	struct usb_hcd_platform_data *pd = pdev->dev.platform_data;
+
+	pr_debug("initializing PPC-SOC USB Controller\n");
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		pr_debug(__FILE__ ": no irq\n");
+		return -ENODEV;
+	}
+	irq = res->start;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		pr_debug(__FILE__ ": no reg addr\n");
+		return -ENODEV;
+	}
+
+	hcd = usb_create_hcd(driver, &pdev->dev, "PPC-SOC USB");
+	if (!hcd)
+		return -ENOMEM;
+	hcd->rsrc_start = res->start;
+	hcd->rsrc_len = res->end - res->start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		pr_debug(__FILE__ ": request_mem_region failed\n");
+		retval = -EBUSY;
+		goto err1;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		pr_debug(__FILE__ ": ioremap failed\n");
+		retval = -ENOMEM;
+		goto err2;
+	}
+
+	if (pd->start && (retval = pd->start(pdev)))
+		goto err3;
+
+	ohci = hcd_to_ohci(hcd);
+	ohci->flags |= OHCI_BIG_ENDIAN;
+	ohci_hcd_init(ohci);
+
+	retval = usb_add_hcd(hcd, irq, SA_INTERRUPT);
+	if (retval == 0)
+		return retval;
+
+	pr_debug("Removing PPC-SOC USB Controller\n");
+	if (pd && pd->stop)
+		pd->stop(pdev);
+ err3:
+	iounmap(hcd->regs);
+ err2:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ err1:
+ 	usb_put_hcd(hcd);
+	return retval;
+}
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_ppc_soc_remove - shutdown processing for On-Chip HCDs
+ * @pdev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_ppc_soc_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+static void usb_hcd_ppc_soc_remove(struct usb_hcd *hcd,
+		struct platform_device *pdev)
+{
+	struct usb_hcd_platform_data *pd = pdev->dev.platform_data;
+
+	usb_remove_hcd(hcd);
+
+	pr_debug("stopping PPC-SOC USB Controller\n");
+	if (pd && pd->stop)
+		pd->stop(pdev);
+
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_hcd_put(hcd);
+}
+
+static int __devinit
+ohci_ppc_soc_start(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
+	int		ret;
+
+	if ((ret = ohci_init(ohci)) < 0)
+		return ret;
+
+	if ((ret = ohci_run(ohci)) < 0) {
+		err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
+		ohci_stop(hcd);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct hc_driver ohci_ppc_soc_hc_driver = {
+	.description =		hcd_name,
+	.hcd_priv_size =	sizeof(struct ohci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ohci_irq,
+	.flags =		HCD_USB11 | HCD_MEMORY,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.start =		ohci_ppc_soc_start,
+	.stop =			ohci_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ohci_urb_enqueue,
+	.urb_dequeue =		ohci_urb_dequeue,
+	.endpoint_disable =	ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ohci_hub_status_data,
+	.hub_control =		ohci_hub_control,
+#ifdef	CONFIG_USB_SUSPEND
+	.hub_suspend =		ohci_hub_suspend,
+	.hub_resume =		ohci_hub_resume,
+#endif
+	.start_port_reset =	ohci_start_port_reset,
+};
+
+static int ohci_hcd_ppc_soc_drv_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	int ret;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	ret = usb_hcd_ppc_soc_probe(&ohci_ppc_soc_hc_driver, pdev);
+	return ret;
+}
+
+static int ohci_hcd_ppc_soc_drv_remove(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	usb_hcd_ppc_soc_remove(hcd, pdev);
+	return 0;
+}
+
+static struct device_driver ohci_hcd_ppc_soc_driver = {
+	.name		= "ppc-soc-ohci",
+	.bus		= &platform_bus_type,
+	.probe		= ohci_hcd_ppc_soc_drv_probe,
+	.remove		= ohci_hcd_ppc_soc_drv_remove,
+#if	defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM)
+	/*.suspend	= ohci_hcd_ppc_soc_drv_suspend,*/
+	/*.resume	= ohci_hcd_ppc_soc_drv_resume,*/
+#endif
+};
+
+static int __init ohci_hcd_ppc_soc_init(void)
+{
+	pr_debug(DRIVER_INFO " (PPC SOC)\n");
+	pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed),
+							sizeof(struct td));
+
+	return driver_register(&ohci_hcd_ppc_soc_driver);
+}
+
+static void __exit ohci_hcd_ppc_soc_cleanup(void)
+{
+	driver_unregister(&ohci_hcd_ppc_soc_driver);
+}
+
+module_init(ohci_hcd_ppc_soc_init);
+module_exit(ohci_hcd_ppc_soc_cleanup);
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
new file mode 100644
index 0000000..6f3464a
--- /dev/null
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -0,0 +1,383 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ *
+ * Bus Glue for pxa27x
+ *
+ * Written by Christopher Hoover <ch@hpl.hp.com>
+ * Based on fragments of previous driver by Russell King et al.
+ *
+ * Modified for LH7A404 from ohci-sa1111.c
+ *  by Durgesh Pattamatta <pattamattad@sharpsec.com>
+ *
+ * Modified for pxa27x from ohci-lh7a404.c
+ *  by Nick Bane <nick@cecomputing.co.uk> 26-8-2004
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/device.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+
+
+#define PMM_NPS_MODE           1
+#define PMM_GLOBAL_MODE        2
+#define PMM_PERPORT_MODE       3
+
+#define PXA_UHC_MAX_PORTNUM    3
+
+#define UHCRHPS(x)              __REG2( 0x4C000050, (x)<<2 )
+
+static int pxa27x_ohci_pmm_state;
+
+/*
+  PMM_NPS_MODE -- PMM Non-power switching mode
+      Ports are powered continuously.
+
+  PMM_GLOBAL_MODE -- PMM global switching mode
+      All ports are powered at the same time.
+
+  PMM_PERPORT_MODE -- PMM per port switching mode
+      Ports are powered individually.
+ */
+static int pxa27x_ohci_select_pmm( int mode )
+{
+	pxa27x_ohci_pmm_state = mode;
+
+	switch ( mode ) {
+	case PMM_NPS_MODE:
+		UHCRHDA |= RH_A_NPS;
+		break; 
+	case PMM_GLOBAL_MODE:
+		UHCRHDA &= ~(RH_A_NPS & RH_A_PSM);
+		break;
+	case PMM_PERPORT_MODE:
+		UHCRHDA &= ~(RH_A_NPS);
+		UHCRHDA |= RH_A_PSM;
+
+		/* Set port power control mask bits, only 3 ports. */
+		UHCRHDB |= (0x7<<17);
+		break;
+	default:
+		printk( KERN_ERR
+			"Invalid mode %d, set to non-power switch mode.\n", 
+			mode );
+
+		pxa27x_ohci_pmm_state = PMM_NPS_MODE;
+		UHCRHDA |= RH_A_NPS;
+	}
+
+	return 0;
+}
+
+/*
+  If you select PMM_PERPORT_MODE, you should set the port power
+ */
+static int pxa27x_ohci_set_port_power( int port )
+{
+	if ( (pxa27x_ohci_pmm_state==PMM_PERPORT_MODE)
+	     && (port>0) && (port<PXA_UHC_MAX_PORTNUM) ) {
+		UHCRHPS(port) |= 0x100;
+		return 0;
+	}
+	return -1;
+}
+
+/*
+  If you select PMM_PERPORT_MODE, you should set the port power
+ */
+static int pxa27x_ohci_clear_port_power( int port )
+{
+	if ( (pxa27x_ohci_pmm_state==PMM_PERPORT_MODE) 
+	     && (port>0) && (port<PXA_UHC_MAX_PORTNUM) ) {
+		UHCRHPS(port) |= 0x200;
+		return 0;
+	}
+	 
+	return -1;
+}
+
+extern int usb_disabled(void);
+
+/*-------------------------------------------------------------------------*/
+
+static void pxa27x_start_hc(struct platform_device *dev)
+{
+	pxa_set_cken(CKEN10_USBHOST, 1);
+
+	UHCHR |= UHCHR_FHR;
+	udelay(11);
+	UHCHR &= ~UHCHR_FHR;
+
+	UHCHR |= UHCHR_FSBIR;
+	while (UHCHR & UHCHR_FSBIR)
+		cpu_relax();
+
+	/* This could be properly abstracted away through the
+	   device data the day more machines are supported and
+	   their differences can be figured out correctly. */
+	if (machine_is_mainstone()) {
+		/* setup Port1 GPIO pin. */
+		pxa_gpio_mode( 88 | GPIO_ALT_FN_1_IN);	/* USBHPWR1 */
+		pxa_gpio_mode( 89 | GPIO_ALT_FN_2_OUT);	/* USBHPEN1 */
+
+		/* Set the Power Control Polarity Low and Power Sense
+		   Polarity Low to active low. Supply power to USB ports. */
+		UHCHR = (UHCHR | UHCHR_PCPL | UHCHR_PSPL) &
+			~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE);
+	}
+
+	UHCHR &= ~UHCHR_SSE;
+
+	UHCHIE = (UHCHIE_UPRIE | UHCHIE_RWIE);
+}
+
+static void pxa27x_stop_hc(struct platform_device *dev)
+{
+	UHCHR |= UHCHR_FHR;
+	udelay(11);
+	UHCHR &= ~UHCHR_FHR;
+
+	UHCCOMS |= 1;
+	udelay(10);
+
+	pxa_set_cken(CKEN10_USBHOST, 0);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+
+/**
+ * usb_hcd_pxa27x_probe - initialize pxa27x-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ */
+int usb_hcd_pxa27x_probe (const struct hc_driver *driver,
+			  struct platform_device *dev)
+{
+	int retval;
+	struct usb_hcd *hcd;
+
+	if (dev->resource[1].flags != IORESOURCE_IRQ) {
+		pr_debug ("resource[1] is not IORESOURCE_IRQ");
+		return -ENOMEM;
+	}
+
+	hcd = usb_create_hcd (driver, &dev->dev, "pxa27x");
+	if (!hcd)
+		return -ENOMEM;
+	hcd->rsrc_start = dev->resource[0].start;
+	hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		pr_debug("request_mem_region failed");
+		retval = -EBUSY;
+		goto err1;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		pr_debug("ioremap failed");
+		retval = -ENOMEM;
+		goto err2;
+	}
+
+	pxa27x_start_hc(dev);
+
+	/* Select Power Management Mode */
+	pxa27x_ohci_select_pmm( PMM_PERPORT_MODE );
+
+	/* If choosing PMM_PERPORT_MODE, we should set the port power before we use it. */
+	if (pxa27x_ohci_set_port_power(1) < 0)
+		printk(KERN_ERR "Setting port 1 power failed.\n");
+
+	if (pxa27x_ohci_clear_port_power(2) < 0)
+		printk(KERN_ERR "Setting port 2 power failed.\n");
+
+	if (pxa27x_ohci_clear_port_power(3) < 0)
+		printk(KERN_ERR "Setting port 3 power failed.\n");
+
+	ohci_hcd_init(hcd_to_ohci(hcd));
+
+	retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
+	if (retval == 0)
+		return retval;
+
+	pxa27x_stop_hc(dev);
+	iounmap(hcd->regs);
+ err2:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ err1:
+	usb_put_hcd(hcd);
+	return retval;
+}
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_pxa27x_remove - shutdown processing for pxa27x-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_pxa27x_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *dev)
+{
+	usb_remove_hcd(hcd);
+	pxa27x_stop_hc(dev);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_pxa27x_start (struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int		ret;
+
+	ohci_dbg (ohci, "ohci_pxa27x_start, ohci:%p", ohci);
+
+	if ((ret = ohci_init(ohci)) < 0)
+		return ret;
+
+	if ((ret = ohci_run (ohci)) < 0) {
+		err ("can't start %s", hcd->self.bus_name);
+		ohci_stop (hcd);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_pxa27x_hc_driver = {
+	.description =		hcd_name,
+	.product_desc =		"PXA27x OHCI",
+	.hcd_priv_size =	sizeof(struct ohci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ohci_irq,
+	.flags =		HCD_USB11 | HCD_MEMORY,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.start =		ohci_pxa27x_start,
+	.stop =			ohci_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ohci_urb_enqueue,
+	.urb_dequeue =		ohci_urb_dequeue,
+	.endpoint_disable =	ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ohci_hub_status_data,
+	.hub_control =		ohci_hub_control,
+#ifdef  CONFIG_USB_SUSPEND
+	.hub_suspend =		ohci_hub_suspend,
+	.hub_resume =		ohci_hub_resume,
+#endif
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hcd_pxa27x_drv_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	int ret;
+
+	pr_debug ("In ohci_hcd_pxa27x_drv_probe");
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	ret = usb_hcd_pxa27x_probe(&ohci_pxa27x_hc_driver, pdev);
+	return ret;
+}
+
+static int ohci_hcd_pxa27x_drv_remove(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	usb_hcd_pxa27x_remove(hcd, pdev);
+	return 0;
+}
+
+static int ohci_hcd_pxa27x_drv_suspend(struct device *dev, u32 state, u32 level)
+{
+//	struct platform_device *pdev = to_platform_device(dev);
+//	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	printk("%s: not implemented yet\n", __FUNCTION__);
+
+	return 0;
+}
+
+static int ohci_hcd_pxa27x_drv_resume(struct device *dev, u32 state)
+{
+//	struct platform_device *pdev = to_platform_device(dev);
+//	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	printk("%s: not implemented yet\n", __FUNCTION__);
+
+	return 0;
+}
+
+
+static struct device_driver ohci_hcd_pxa27x_driver = {
+	.name		= "pxa27x-ohci",
+	.bus		= &platform_bus_type,
+	.probe		= ohci_hcd_pxa27x_drv_probe,
+	.remove		= ohci_hcd_pxa27x_drv_remove,
+	.suspend	= ohci_hcd_pxa27x_drv_suspend, 
+	.resume		= ohci_hcd_pxa27x_drv_resume, 
+};
+
+static int __init ohci_hcd_pxa27x_init (void)
+{
+	pr_debug (DRIVER_INFO " (pxa27x)");
+	pr_debug ("block sizes: ed %d td %d\n",
+		sizeof (struct ed), sizeof (struct td));
+
+	return driver_register(&ohci_hcd_pxa27x_driver);
+}
+
+static void __exit ohci_hcd_pxa27x_cleanup (void)
+{
+	driver_unregister(&ohci_hcd_pxa27x_driver);
+}
+
+module_init (ohci_hcd_pxa27x_init);
+module_exit (ohci_hcd_pxa27x_cleanup);
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
new file mode 100644
index 0000000..c90114a
--- /dev/null
+++ b/drivers/usb/host/ohci-q.c
@@ -0,0 +1,1107 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ * 
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * This file is licenced under the GPL.
+ */
+
+static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
+{
+	int		last = urb_priv->length - 1;
+
+	if (last >= 0) {
+		int		i;
+		struct td	*td;
+
+		for (i = 0; i <= last; i++) {
+			td = urb_priv->td [i];
+			if (td)
+				td_free (hc, td);
+		}
+	}
+
+	list_del (&urb_priv->pending);
+	kfree (urb_priv);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * URB goes back to driver, and isn't reissued.
+ * It's completely gone from HC data structures.
+ * PRECONDITION:  ohci lock held, irqs blocked.
+ */
+static void
+finish_urb (struct ohci_hcd *ohci, struct urb *urb, struct pt_regs *regs)
+__releases(ohci->lock)
+__acquires(ohci->lock)
+{
+	// ASSERT (urb->hcpriv != 0);
+
+	urb_free_priv (ohci, urb->hcpriv);
+	urb->hcpriv = NULL;
+
+	spin_lock (&urb->lock);
+	if (likely (urb->status == -EINPROGRESS))
+		urb->status = 0;
+	/* report short control reads right even though the data TD always
+	 * has TD_R set.  (much simpler, but creates the 1-td limit.)
+	 */
+	if (unlikely (urb->transfer_flags & URB_SHORT_NOT_OK)
+			&& unlikely (usb_pipecontrol (urb->pipe))
+			&& urb->actual_length < urb->transfer_buffer_length
+			&& usb_pipein (urb->pipe)
+			&& urb->status == 0) {
+		urb->status = -EREMOTEIO;
+	}
+	spin_unlock (&urb->lock);
+
+	switch (usb_pipetype (urb->pipe)) {
+	case PIPE_ISOCHRONOUS:
+		ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs--;
+		break;
+	case PIPE_INTERRUPT:
+		ohci_to_hcd(ohci)->self.bandwidth_int_reqs--;
+		break;
+	}
+
+#ifdef OHCI_VERBOSE_DEBUG
+	urb_print (urb, "RET", usb_pipeout (urb->pipe));
+#endif
+
+	/* urb->complete() can reenter this HCD */
+	spin_unlock (&ohci->lock);
+	usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb, regs);
+	spin_lock (&ohci->lock);
+
+	/* stop periodic dma if it's not needed */
+	if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0
+			&& ohci_to_hcd(ohci)->self.bandwidth_int_reqs == 0) {
+		ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_IE);
+		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+	}
+}
+
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/  
+
+/* search for the right schedule branch to use for a periodic ed.
+ * does some load balancing; returns the branch, or negative errno.
+ */
+static int balance (struct ohci_hcd *ohci, int interval, int load)
+{
+	int	i, branch = -ENOSPC;
+
+	/* iso periods can be huge; iso tds specify frame numbers */
+	if (interval > NUM_INTS)
+		interval = NUM_INTS;
+
+	/* search for the least loaded schedule branch of that period
+	 * that has enough bandwidth left unreserved.
+	 */
+	for (i = 0; i < interval ; i++) {
+		if (branch < 0 || ohci->load [branch] > ohci->load [i]) {
+#if 1	/* CONFIG_USB_BANDWIDTH */
+			int	j;
+
+			/* usb 1.1 says 90% of one frame */
+			for (j = i; j < NUM_INTS; j += interval) {
+				if ((ohci->load [j] + load) > 900)
+					break;
+			}
+			if (j < NUM_INTS)
+				continue;
+#endif
+			branch = i; 
+		}
+	}
+	return branch;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* both iso and interrupt requests have periods; this routine puts them
+ * into the schedule tree in the apppropriate place.  most iso devices use
+ * 1msec periods, but that's not required.
+ */
+static void periodic_link (struct ohci_hcd *ohci, struct ed *ed)
+{
+	unsigned	i;
+
+	ohci_vdbg (ohci, "link %sed %p branch %d [%dus.], interval %d\n",
+		(ed->hwINFO & cpu_to_hc32 (ohci, ED_ISO)) ? "iso " : "",
+		ed, ed->branch, ed->load, ed->interval);
+
+	for (i = ed->branch; i < NUM_INTS; i += ed->interval) {
+		struct ed	**prev = &ohci->periodic [i];
+		__hc32		*prev_p = &ohci->hcca->int_table [i];
+		struct ed	*here = *prev;
+
+		/* sorting each branch by period (slow before fast)
+		 * lets us share the faster parts of the tree.
+		 * (plus maybe: put interrupt eds before iso)
+		 */
+		while (here && ed != here) {
+			if (ed->interval > here->interval)
+				break;
+			prev = &here->ed_next;
+			prev_p = &here->hwNextED;
+			here = *prev;
+		}
+		if (ed != here) {
+			ed->ed_next = here;
+			if (here)
+				ed->hwNextED = *prev_p;
+			wmb ();
+			*prev = ed;
+			*prev_p = cpu_to_hc32(ohci, ed->dma);
+			wmb();
+		}
+		ohci->load [i] += ed->load;
+	}
+	ohci_to_hcd(ohci)->self.bandwidth_allocated += ed->load / ed->interval;
+}
+
+/* link an ed into one of the HC chains */
+
+static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
+{	 
+	int	branch;
+
+	if (ohci_to_hcd(ohci)->state == HC_STATE_QUIESCING)
+		return -EAGAIN;
+
+	ed->state = ED_OPER;
+	ed->ed_prev = NULL;
+	ed->ed_next = NULL;
+	ed->hwNextED = 0;
+	wmb ();
+
+	/* we care about rm_list when setting CLE/BLE in case the HC was at
+	 * work on some TD when CLE/BLE was turned off, and isn't quiesced
+	 * yet.  finish_unlinks() restarts as needed, some upcoming INTR_SF.
+	 *
+	 * control and bulk EDs are doubly linked (ed_next, ed_prev), but
+	 * periodic ones are singly linked (ed_next). that's because the
+	 * periodic schedule encodes a tree like figure 3-5 in the ohci
+	 * spec:  each qh can have several "previous" nodes, and the tree
+	 * doesn't have unused/idle descriptors.
+	 */
+	switch (ed->type) {
+	case PIPE_CONTROL:
+		if (ohci->ed_controltail == NULL) {
+			WARN_ON (ohci->hc_control & OHCI_CTRL_CLE);
+			ohci_writel (ohci, ed->dma,
+					&ohci->regs->ed_controlhead);
+		} else {
+			ohci->ed_controltail->ed_next = ed;
+			ohci->ed_controltail->hwNextED = cpu_to_hc32 (ohci,
+								ed->dma);
+		}
+		ed->ed_prev = ohci->ed_controltail;
+		if (!ohci->ed_controltail && !ohci->ed_rm_list) {
+			wmb();
+			ohci->hc_control |= OHCI_CTRL_CLE;
+			ohci_writel (ohci, 0, &ohci->regs->ed_controlcurrent);
+			ohci_writel (ohci, ohci->hc_control,
+					&ohci->regs->control);
+		}
+		ohci->ed_controltail = ed;
+		break;
+
+	case PIPE_BULK:
+		if (ohci->ed_bulktail == NULL) {
+			WARN_ON (ohci->hc_control & OHCI_CTRL_BLE);
+			ohci_writel (ohci, ed->dma, &ohci->regs->ed_bulkhead);
+		} else {
+			ohci->ed_bulktail->ed_next = ed;
+			ohci->ed_bulktail->hwNextED = cpu_to_hc32 (ohci,
+								ed->dma);
+		}
+		ed->ed_prev = ohci->ed_bulktail;
+		if (!ohci->ed_bulktail && !ohci->ed_rm_list) {
+			wmb();
+			ohci->hc_control |= OHCI_CTRL_BLE;
+			ohci_writel (ohci, 0, &ohci->regs->ed_bulkcurrent);
+			ohci_writel (ohci, ohci->hc_control,
+					&ohci->regs->control);
+		}
+		ohci->ed_bulktail = ed;
+		break;
+
+	// case PIPE_INTERRUPT:
+	// case PIPE_ISOCHRONOUS:
+	default:
+		branch = balance (ohci, ed->interval, ed->load);
+		if (branch < 0) {
+			ohci_dbg (ohci,
+				"ERR %d, interval %d msecs, load %d\n",
+				branch, ed->interval, ed->load);
+			// FIXME if there are TDs queued, fail them!
+			return branch;
+		}
+		ed->branch = branch;
+		periodic_link (ohci, ed);
+	}	 	
+
+	/* the HC may not see the schedule updates yet, but if it does
+	 * then they'll be properly ordered.
+	 */
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* scan the periodic table to find and unlink this ED */
+static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)
+{
+	int	i;
+
+	for (i = ed->branch; i < NUM_INTS; i += ed->interval) {
+		struct ed	*temp;
+		struct ed	**prev = &ohci->periodic [i];
+		__hc32		*prev_p = &ohci->hcca->int_table [i];
+
+		while (*prev && (temp = *prev) != ed) {
+			prev_p = &temp->hwNextED;
+			prev = &temp->ed_next;
+		}
+		if (*prev) {
+			*prev_p = ed->hwNextED;
+			*prev = ed->ed_next;
+		}
+		ohci->load [i] -= ed->load;
+	}	
+	ohci_to_hcd(ohci)->self.bandwidth_allocated -= ed->load / ed->interval;
+
+	ohci_vdbg (ohci, "unlink %sed %p branch %d [%dus.], interval %d\n",
+		(ed->hwINFO & cpu_to_hc32 (ohci, ED_ISO)) ? "iso " : "",
+		ed, ed->branch, ed->load, ed->interval);
+}
+
+/* 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
+ * (assuming it already started that, which needn't be true).
+ *
+ * ED_UNLINK is a transient state: the HC may still see this ED, but soon
+ * it won't.  ED_SKIP means the HC will finish its current transaction,
+ * but won't start anything new.  The TD queue may still grow; device
+ * drivers don't know about this HCD-internal state.
+ *
+ * When the HC can't see the ED, something changes ED_UNLINK to one of:
+ *
+ *  - ED_OPER: when there's any request queued, the ED gets rescheduled
+ *    immediately.  HC should be working on them.
+ *
+ *  - ED_IDLE:  when there's no TD queue. there's no reason for the HC
+ *    to care about this ED; safe to disable the endpoint.
+ *
+ * When finish_unlinks() runs later, after SOF interrupt, it will often
+ * complete one or more URB unlinks before making that state change.
+ */
+static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) 
+{
+	ed->hwINFO |= cpu_to_hc32 (ohci, ED_SKIP);
+	wmb ();
+	ed->state = ED_UNLINK;
+
+	/* To deschedule something from the control or bulk list, just
+	 * clear CLE/BLE and wait.  There's no safe way to scrub out list
+	 * head/current registers until later, and "later" isn't very
+	 * tightly specified.  Figure 6-5 and Section 6.4.2.2 show how
+	 * the HC is reading the ED queues (while we modify them).
+	 *
+	 * For now, ed_schedule() is "later".  It might be good paranoia
+	 * to scrub those registers in finish_unlinks(), in case of bugs
+	 * that make the HC try to use them.
+	 */
+	switch (ed->type) {
+	case PIPE_CONTROL:
+		/* remove ED from the HC's list: */
+		if (ed->ed_prev == NULL) {
+			if (!ed->hwNextED) {
+				ohci->hc_control &= ~OHCI_CTRL_CLE;
+				ohci_writel (ohci, ohci->hc_control,
+						&ohci->regs->control);
+				// a ohci_readl() later syncs CLE with the HC
+			} else
+				ohci_writel (ohci,
+					hc32_to_cpup (ohci, &ed->hwNextED),
+					&ohci->regs->ed_controlhead);
+		} else {
+			ed->ed_prev->ed_next = ed->ed_next;
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		}
+		/* remove ED from the HCD's list: */
+		if (ohci->ed_controltail == ed) {
+			ohci->ed_controltail = ed->ed_prev;
+			if (ohci->ed_controltail)
+				ohci->ed_controltail->ed_next = NULL;
+		} else if (ed->ed_next) {
+			ed->ed_next->ed_prev = ed->ed_prev;
+		}
+		break;
+
+	case PIPE_BULK:
+		/* remove ED from the HC's list: */
+		if (ed->ed_prev == NULL) {
+			if (!ed->hwNextED) {
+				ohci->hc_control &= ~OHCI_CTRL_BLE;
+				ohci_writel (ohci, ohci->hc_control,
+						&ohci->regs->control);
+				// a ohci_readl() later syncs BLE with the HC
+			} else
+				ohci_writel (ohci,
+					hc32_to_cpup (ohci, &ed->hwNextED),
+					&ohci->regs->ed_bulkhead);
+		} else {
+			ed->ed_prev->ed_next = ed->ed_next;
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		}
+		/* remove ED from the HCD's list: */
+		if (ohci->ed_bulktail == ed) {
+			ohci->ed_bulktail = ed->ed_prev;
+			if (ohci->ed_bulktail)
+				ohci->ed_bulktail->ed_next = NULL;
+		} else if (ed->ed_next) {
+			ed->ed_next->ed_prev = ed->ed_prev;
+		}
+		break;
+
+	// case PIPE_INTERRUPT:
+	// case PIPE_ISOCHRONOUS:
+	default:
+		periodic_unlink (ohci, ed);
+		break;
+	}
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* get and maybe (re)init an endpoint. init _should_ be done only as part
+ * of enumeration, usb_set_configuration() or usb_set_interface().
+ */
+static struct ed *ed_get (
+	struct ohci_hcd		*ohci,
+	struct usb_host_endpoint *ep,
+	struct usb_device	*udev,
+	unsigned int		pipe,
+	int			interval
+) {
+	struct ed		*ed; 
+	unsigned long		flags;
+
+	spin_lock_irqsave (&ohci->lock, flags);
+
+	if (!(ed = ep->hcpriv)) {
+		struct td	*td;
+		int		is_out;
+		u32		info;
+
+		ed = ed_alloc (ohci, GFP_ATOMIC);
+		if (!ed) {
+			/* out of memory */
+			goto done;
+		}
+
+  		/* dummy td; end of td list for ed */
+		td = td_alloc (ohci, GFP_ATOMIC);
+ 		if (!td) {
+			/* out of memory */
+			ed_free (ohci, ed);
+			ed = NULL;
+			goto done;
+		}
+		ed->dummy = td;
+		ed->hwTailP = cpu_to_hc32 (ohci, td->td_dma);
+		ed->hwHeadP = ed->hwTailP;	/* ED_C, ED_H zeroed */
+		ed->state = ED_IDLE;
+
+		is_out = !(ep->desc.bEndpointAddress & USB_DIR_IN);
+
+		/* FIXME usbcore changes dev->devnum before SET_ADDRESS
+		 * suceeds ... otherwise we wouldn't need "pipe".
+		 */
+		info = usb_pipedevice (pipe);
+		ed->type = usb_pipetype(pipe);
+
+		info |= (ep->desc.bEndpointAddress & ~USB_DIR_IN) << 7;
+		info |= le16_to_cpu(ep->desc.wMaxPacketSize) << 16;
+		if (udev->speed == USB_SPEED_LOW)
+			info |= ED_LOWSPEED;
+		/* only control transfers store pids in tds */
+		if (ed->type != PIPE_CONTROL) {
+			info |= is_out ? ED_OUT : ED_IN;
+			if (ed->type != PIPE_BULK) {
+				/* periodic transfers... */
+				if (ed->type == PIPE_ISOCHRONOUS)
+					info |= ED_ISO;
+				else if (interval > 32)	/* iso can be bigger */
+					interval = 32;
+				ed->interval = interval;
+				ed->load = usb_calc_bus_time (
+					udev->speed, !is_out,
+					ed->type == PIPE_ISOCHRONOUS,
+					le16_to_cpu(ep->desc.wMaxPacketSize))
+						/ 1000;
+			}
+		}
+		ed->hwINFO = cpu_to_hc32(ohci, info);
+
+		ep->hcpriv = ed;
+	}
+
+done:
+	spin_unlock_irqrestore (&ohci->lock, flags);
+	return ed; 
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* request unlinking of an endpoint from an operational HC.
+ * put the ep on the rm_list
+ * real work is done at the next start frame (SF) hardware interrupt
+ * caller guarantees HCD is running, so hardware access is safe,
+ * and that ed->state is ED_OPER
+ */
+static void start_ed_unlink (struct ohci_hcd *ohci, struct ed *ed)
+{    
+	ed->hwINFO |= cpu_to_hc32 (ohci, ED_DEQUEUE);
+	ed_deschedule (ohci, ed);
+
+	/* rm_list is just singly linked, for simplicity */
+	ed->ed_next = ohci->ed_rm_list;
+	ed->ed_prev = NULL;
+	ohci->ed_rm_list = ed;
+
+	/* enable SOF interrupt */
+	ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrstatus);
+	ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrenable);
+	// flush those writes, and get latest HCCA contents
+	(void) ohci_readl (ohci, &ohci->regs->control);
+
+	/* SF interrupt might get delayed; record the frame counter value that
+	 * indicates when the HC isn't looking at it, so concurrent unlinks
+	 * behave.  frame_no wraps every 2^16 msec, and changes right before
+	 * SF is triggered.
+	 */
+	ed->tick = ohci_frame_no(ohci) + 1;
+
+}
+
+/*-------------------------------------------------------------------------*
+ * TD handling functions
+ *-------------------------------------------------------------------------*/
+
+/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
+
+static void
+td_fill (struct ohci_hcd *ohci, u32 info,
+	dma_addr_t data, int len,
+	struct urb *urb, int index)
+{
+	struct td		*td, *td_pt;
+	struct urb_priv		*urb_priv = urb->hcpriv;
+	int			is_iso = info & TD_ISO;
+	int			hash;
+
+	// ASSERT (index < urb_priv->length);
+
+	/* aim for only one interrupt per urb.  mostly applies to control
+	 * and iso; other urbs rarely need more than one TD per urb.
+	 * this way, only final tds (or ones with an error) cause IRQs.
+	 * at least immediately; use DI=6 in case any control request is
+	 * tempted to die part way through.  (and to force the hc to flush
+	 * its donelist soonish, even on unlink paths.)
+	 *
+	 * NOTE: could delay interrupts even for the last TD, and get fewer
+	 * interrupts ... increasing per-urb latency by sharing interrupts.
+	 * Drivers that queue bulk urbs may request that behavior.
+	 */
+	if (index != (urb_priv->length - 1)
+			|| (urb->transfer_flags & URB_NO_INTERRUPT))
+		info |= TD_DI_SET (6);
+
+	/* use this td as the next dummy */
+	td_pt = urb_priv->td [index];
+
+	/* fill the old dummy TD */
+	td = urb_priv->td [index] = urb_priv->ed->dummy;
+	urb_priv->ed->dummy = td_pt;
+
+	td->ed = urb_priv->ed;
+	td->next_dl_td = NULL;
+	td->index = index;
+	td->urb = urb; 
+	td->data_dma = data;
+	if (!len)
+		data = 0;
+
+	td->hwINFO = cpu_to_hc32 (ohci, info);
+	if (is_iso) {
+		td->hwCBP = cpu_to_hc32 (ohci, data & 0xFFFFF000);
+		*ohci_hwPSWp(ohci, td, 0) = cpu_to_hc16 (ohci,
+						(data & 0x0FFF) | 0xE000);
+		td->ed->last_iso = info & 0xffff;
+	} else {
+		td->hwCBP = cpu_to_hc32 (ohci, data); 
+	}			
+	if (data)
+		td->hwBE = cpu_to_hc32 (ohci, data + len - 1);
+	else
+		td->hwBE = 0;
+	td->hwNextTD = cpu_to_hc32 (ohci, td_pt->td_dma);
+
+	/* append to queue */
+	list_add_tail (&td->td_list, &td->ed->td_list);
+
+	/* hash it for later reverse mapping */
+	hash = TD_HASH_FUNC (td->td_dma);
+	td->td_hash = ohci->td_hash [hash];
+	ohci->td_hash [hash] = td;
+
+	/* HC might read the TD (or cachelines) right away ... */
+	wmb ();
+	td->ed->hwTailP = td->hwNextTD;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Prepare all TDs of a transfer, and queue them onto the ED.
+ * Caller guarantees HC is active.
+ * Usually the ED is already on the schedule, so TDs might be
+ * processed as soon as they're queued.
+ */
+static void td_submit_urb (
+	struct ohci_hcd	*ohci,
+	struct urb	*urb
+) {
+	struct urb_priv	*urb_priv = urb->hcpriv;
+	dma_addr_t	data;
+	int		data_len = urb->transfer_buffer_length;
+	int		cnt = 0;
+	u32		info = 0;
+	int		is_out = usb_pipeout (urb->pipe);
+	int		periodic = 0;
+
+	/* OHCI handles the bulk/interrupt data toggles itself.  We just
+	 * use the device toggle bits for resetting, and rely on the fact
+	 * that resetting toggle is meaningless if the endpoint is active.
+	 */
+  	if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) {
+		usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+			is_out, 1);
+		urb_priv->ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_C);
+	}
+
+	urb_priv->td_cnt = 0;
+	list_add (&urb_priv->pending, &ohci->pending);
+
+	if (data_len)
+		data = urb->transfer_dma;
+	else
+		data = 0;
+
+	/* NOTE:  TD_CC is set so we can tell which TDs the HC processed by
+	 * using TD_CC_GET, as well as by seeing them on the done list.
+	 * (CC = NotAccessed ... 0x0F, or 0x0E in PSWs for ISO.)
+	 */
+	switch (urb_priv->ed->type) {
+
+	/* Bulk and interrupt are identical except for where in the schedule
+	 * their EDs live.
+	 */
+	case PIPE_INTERRUPT:
+		/* ... and periodic urbs have extra accounting */
+		periodic = ohci_to_hcd(ohci)->self.bandwidth_int_reqs++ == 0
+			&& ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0;
+		/* FALLTHROUGH */
+	case PIPE_BULK:
+		info = is_out
+			? TD_T_TOGGLE | TD_CC | TD_DP_OUT
+			: TD_T_TOGGLE | TD_CC | TD_DP_IN;
+		/* TDs _could_ transfer up to 8K each */
+		while (data_len > 4096) {
+			td_fill (ohci, info, data, 4096, urb, cnt);
+			data += 4096;
+			data_len -= 4096;
+			cnt++;
+		}
+		/* maybe avoid ED halt on final TD short read */
+		if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
+			info |= TD_R;
+		td_fill (ohci, info, data, data_len, urb, cnt);
+		cnt++;
+		if ((urb->transfer_flags & URB_ZERO_PACKET)
+				&& cnt < urb_priv->length) {
+			td_fill (ohci, info, 0, 0, urb, cnt);
+			cnt++;
+		}
+		/* maybe kickstart bulk list */
+		if (urb_priv->ed->type == PIPE_BULK) {
+			wmb ();
+			ohci_writel (ohci, OHCI_BLF, &ohci->regs->cmdstatus);
+		}
+		break;
+
+	/* control manages DATA0/DATA1 toggle per-request; SETUP resets it,
+	 * any DATA phase works normally, and the STATUS ack is special.
+	 */
+	case PIPE_CONTROL:
+		info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+		td_fill (ohci, info, urb->setup_dma, 8, urb, cnt++);
+		if (data_len > 0) {
+			info = TD_CC | TD_R | TD_T_DATA1;
+			info |= is_out ? TD_DP_OUT : TD_DP_IN;
+			/* NOTE:  mishandles transfers >8K, some >4K */
+			td_fill (ohci, info, data, data_len, urb, cnt++);
+		}
+		info = (is_out || data_len == 0)
+			? TD_CC | TD_DP_IN | TD_T_DATA1
+			: TD_CC | TD_DP_OUT | TD_T_DATA1;
+		td_fill (ohci, info, data, 0, urb, cnt++);
+		/* maybe kickstart control list */
+		wmb ();
+		ohci_writel (ohci, OHCI_CLF, &ohci->regs->cmdstatus);
+		break;
+
+	/* ISO has no retransmit, so no toggle; and it uses special TDs.
+	 * Each TD could handle multiple consecutive frames (interval 1);
+	 * we could often reduce the number of TDs here.
+	 */
+	case PIPE_ISOCHRONOUS:
+		for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
+			int	frame = urb->start_frame;
+
+			// FIXME scheduling should handle frame counter
+			// roll-around ... exotic case (and OHCI has
+			// a 2^16 iso range, vs other HCs max of 2^10)
+			frame += cnt * urb->interval;
+			frame &= 0xffff;
+			td_fill (ohci, TD_CC | TD_ISO | frame,
+				data + urb->iso_frame_desc [cnt].offset,
+				urb->iso_frame_desc [cnt].length, urb, cnt);
+		}
+		periodic = ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs++ == 0
+			&& ohci_to_hcd(ohci)->self.bandwidth_int_reqs == 0;
+		break;
+	}
+
+	/* start periodic dma if needed */
+	if (periodic) {
+		wmb ();
+		ohci->hc_control |= OHCI_CTRL_PLE|OHCI_CTRL_IE;
+		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+	}
+
+	// ASSERT (urb_priv->length == cnt);
+}
+
+/*-------------------------------------------------------------------------*
+ * Done List handling functions
+ *-------------------------------------------------------------------------*/
+
+/* calculate transfer length/status and update the urb
+ * PRECONDITION:  irqsafe (only for urb->status locking)
+ */
+static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
+{
+	u32	tdINFO = hc32_to_cpup (ohci, &td->hwINFO);
+	int	cc = 0;
+
+	list_del (&td->td_list);
+
+	/* ISO ... drivers see per-TD length/status */
+  	if (tdINFO & TD_ISO) {
+ 		u16	tdPSW = ohci_hwPSW (ohci, td, 0);
+		int	dlen = 0;
+
+		/* NOTE:  assumes FC in tdINFO == 0, and that
+		 * only the first of 0..MAXPSW psws is used.
+		 */
+
+ 		cc = (tdPSW >> 12) & 0xF;
+  		if (tdINFO & TD_CC)	/* hc didn't touch? */
+			return;
+
+		if (usb_pipeout (urb->pipe))
+			dlen = urb->iso_frame_desc [td->index].length;
+		else {
+			/* short reads are always OK for ISO */
+			if (cc == TD_DATAUNDERRUN)
+				cc = TD_CC_NOERROR;
+			dlen = tdPSW & 0x3ff;
+		}
+		urb->actual_length += dlen;
+		urb->iso_frame_desc [td->index].actual_length = dlen;
+		urb->iso_frame_desc [td->index].status = cc_to_error [cc];
+
+		if (cc != TD_CC_NOERROR)
+			ohci_vdbg (ohci,
+				"urb %p iso td %p (%d) len %d cc %d\n",
+				urb, td, 1 + td->index, dlen, cc);
+
+	/* BULK, INT, CONTROL ... drivers see aggregate length/status,
+	 * except that "setup" bytes aren't counted and "short" transfers
+	 * might not be reported as errors.
+	 */
+	} else {
+		int	type = usb_pipetype (urb->pipe);
+		u32	tdBE = hc32_to_cpup (ohci, &td->hwBE);
+
+  		cc = TD_CC_GET (tdINFO);
+
+		/* update packet status if needed (short is normally ok) */
+		if (cc == TD_DATAUNDERRUN
+				&& !(urb->transfer_flags & URB_SHORT_NOT_OK))
+			cc = TD_CC_NOERROR;
+		if (cc != TD_CC_NOERROR && cc < 0x0E) {
+			spin_lock (&urb->lock);
+			if (urb->status == -EINPROGRESS)
+				urb->status = cc_to_error [cc];
+			spin_unlock (&urb->lock);
+		}
+
+		/* count all non-empty packets except control SETUP packet */
+		if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) {
+			if (td->hwCBP == 0)
+				urb->actual_length += tdBE - td->data_dma + 1;
+			else
+				urb->actual_length +=
+					  hc32_to_cpup (ohci, &td->hwCBP)
+					- td->data_dma;
+		}
+
+		if (cc != TD_CC_NOERROR && cc < 0x0E)
+			ohci_vdbg (ohci,
+				"urb %p td %p (%d) cc %d, len=%d/%d\n",
+				urb, td, 1 + td->index, cc,
+				urb->actual_length,
+				urb->transfer_buffer_length);
+  	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline struct td *
+ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
+{
+  	struct urb		*urb = td->urb;
+	struct ed		*ed = td->ed;
+	struct list_head	*tmp = td->td_list.next;
+	__hc32			toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C);
+
+	/* clear ed halt; this is the td that caused it, but keep it inactive
+	 * until its urb->complete() has a chance to clean up.
+	 */
+	ed->hwINFO |= cpu_to_hc32 (ohci, ED_SKIP);
+	wmb ();
+	ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H); 
+
+	/* put any later tds from this urb onto the donelist, after 'td',
+	 * order won't matter here: no errors, and nothing was transferred.
+	 * also patch the ed so it looks as if those tds completed normally.
+	 */
+	while (tmp != &ed->td_list) {
+		struct td	*next;
+		__hc32		info;
+
+		next = list_entry (tmp, struct td, td_list);
+		tmp = next->td_list.next;
+
+		if (next->urb != urb)
+			break;
+
+		/* NOTE: if multi-td control DATA segments get supported,
+		 * this urb had one of them, this td wasn't the last td
+		 * in that segment (TD_R clear), this ed halted because
+		 * of a short read, _and_ URB_SHORT_NOT_OK is clear ...
+		 * then we need to leave the control STATUS packet queued
+		 * and clear ED_SKIP.
+		 */
+		info = next->hwINFO;
+		info |= cpu_to_hc32 (ohci, TD_DONE);
+		info &= ~cpu_to_hc32 (ohci, TD_CC);
+		next->hwINFO = info;
+
+		next->next_dl_td = rev;	
+		rev = next;
+
+		ed->hwHeadP = next->hwNextTD | toggle;
+	}
+
+	/* help for troubleshooting:  report anything that
+	 * looks odd ... that doesn't include protocol stalls
+	 * (or maybe some other things)
+	 */
+	switch (cc) {
+	case TD_DATAUNDERRUN:
+		if ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)
+			break;
+		/* fallthrough */
+	case TD_CC_STALL:
+		if (usb_pipecontrol (urb->pipe))
+			break;
+		/* fallthrough */
+	default:
+		ohci_dbg (ohci,
+			"urb %p path %s ep%d%s %08x cc %d --> status %d\n",
+			urb, urb->dev->devpath,
+			usb_pipeendpoint (urb->pipe),
+			usb_pipein (urb->pipe) ? "in" : "out",
+			hc32_to_cpu (ohci, td->hwINFO),
+			cc, cc_to_error [cc]);
+	}
+
+	return rev;
+}
+
+/* replies to the request have to be on a FIFO basis so
+ * we unreverse the hc-reversed done-list
+ */
+static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
+{
+	u32		td_dma;
+	struct td	*td_rev = NULL;
+	struct td	*td = NULL;
+
+	td_dma = hc32_to_cpup (ohci, &ohci->hcca->done_head);
+	ohci->hcca->done_head = 0;
+	wmb();
+
+	/* get TD from hc's singly linked list, and
+	 * prepend to ours.  ed->td_list changes later.
+	 */
+	while (td_dma) {		
+	    	int		cc;
+
+		td = dma_to_td (ohci, td_dma);
+		if (!td) {
+			ohci_err (ohci, "bad entry %8x\n", td_dma);
+			break;
+		}
+
+		td->hwINFO |= cpu_to_hc32 (ohci, TD_DONE);
+		cc = TD_CC_GET (hc32_to_cpup (ohci, &td->hwINFO));
+
+		/* Non-iso endpoints can halt on error; un-halt,
+		 * and dequeue any other TDs from this urb.
+		 * No other TD could have caused the halt.
+		 */
+		if (cc != TD_CC_NOERROR
+				&& (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H)))
+			td_rev = ed_halted (ohci, td, cc, td_rev);
+
+		td->next_dl_td = td_rev;	
+		td_rev = td;
+		td_dma = hc32_to_cpup (ohci, &td->hwNextTD);
+	}	
+	return td_rev;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* there are some urbs/eds to unlink; called in_irq(), with HCD locked */
+static void
+finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs)
+{
+	struct ed	*ed, **last;
+
+rescan_all:
+	for (last = &ohci->ed_rm_list, ed = *last; ed != NULL; ed = *last) {
+		struct list_head	*entry, *tmp;
+		int			completed, modified;
+		__hc32			*prev;
+
+		/* only take off EDs that the HC isn't using, accounting for
+		 * frame counter wraps and EDs with partially retired TDs
+		 */
+		if (likely (regs && HC_IS_RUNNING(ohci_to_hcd(ohci)->state))) {
+			if (tick_before (tick, ed->tick)) {
+skip_ed:
+				last = &ed->ed_next;
+				continue;
+			}
+
+			if (!list_empty (&ed->td_list)) {
+				struct td	*td;
+				u32		head;
+
+				td = list_entry (ed->td_list.next, struct td,
+							td_list);
+				head = hc32_to_cpu (ohci, ed->hwHeadP) &
+								TD_MASK;
+
+				/* INTR_WDH may need to clean up first */
+				if (td->td_dma != head)
+					goto skip_ed;
+			}
+		}
+
+		/* reentrancy:  if we drop the schedule lock, someone might
+		 * have modified this list.  normally it's just prepending
+		 * entries (which we'd ignore), but paranoia won't hurt.
+		 */
+		*last = ed->ed_next;
+		ed->ed_next = NULL;
+		modified = 0;
+
+		/* unlink urbs as requested, but rescan the list after
+		 * we call a completion since it might have unlinked
+		 * another (earlier) urb
+		 *
+		 * When we get here, the HC doesn't see this ed.  But it
+		 * must not be rescheduled until all completed URBs have
+		 * been given back to the driver.
+		 */
+rescan_this:
+		completed = 0;
+		prev = &ed->hwHeadP;
+		list_for_each_safe (entry, tmp, &ed->td_list) {
+			struct td	*td;
+			struct urb	*urb;
+			urb_priv_t	*urb_priv;
+			__hc32		savebits;
+
+			td = list_entry (entry, struct td, td_list);
+			urb = td->urb;
+			urb_priv = td->urb->hcpriv;
+
+			if (urb->status == -EINPROGRESS) {
+				prev = &td->hwNextTD;
+				continue;
+			}
+
+			/* patch pointer hc uses */
+			savebits = *prev & ~cpu_to_hc32 (ohci, TD_MASK);
+			*prev = td->hwNextTD | savebits;
+
+			/* HC may have partly processed this TD */
+			td_done (ohci, urb, td);
+			urb_priv->td_cnt++;
+
+			/* if URB is done, clean up */
+			if (urb_priv->td_cnt == urb_priv->length) {
+				modified = completed = 1;
+				finish_urb (ohci, urb, regs);
+			}
+		}
+		if (completed && !list_empty (&ed->td_list))
+			goto rescan_this;
+
+		/* ED's now officially unlinked, hc doesn't see */
+		ed->state = ED_IDLE;
+		ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
+		ed->hwNextED = 0;
+		wmb ();
+		ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP | ED_DEQUEUE);
+
+		/* but if there's work queued, reschedule */
+		if (!list_empty (&ed->td_list)) {
+			if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state))
+				ed_schedule (ohci, ed);
+		}
+
+		if (modified)
+			goto rescan_all;
+   	}
+
+	/* maybe reenable control and bulk lists */ 
+	if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state)
+			&& ohci_to_hcd(ohci)->state != HC_STATE_QUIESCING
+			&& !ohci->ed_rm_list) {
+		u32	command = 0, control = 0;
+
+		if (ohci->ed_controltail) {
+			command |= OHCI_CLF;
+			if (!(ohci->hc_control & OHCI_CTRL_CLE)) {
+				control |= OHCI_CTRL_CLE;
+				ohci_writel (ohci, 0,
+					&ohci->regs->ed_controlcurrent);
+			}
+		}
+		if (ohci->ed_bulktail) {
+			command |= OHCI_BLF;
+			if (!(ohci->hc_control & OHCI_CTRL_BLE)) {
+				control |= OHCI_CTRL_BLE;
+				ohci_writel (ohci, 0,
+					&ohci->regs->ed_bulkcurrent);
+			}
+		}
+		
+		/* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */
+		if (control) {
+			ohci->hc_control |= control;
+ 			ohci_writel (ohci, ohci->hc_control,
+					&ohci->regs->control);   
+ 		}
+		if (command)
+			ohci_writel (ohci, command, &ohci->regs->cmdstatus);   
+ 	}
+}
+
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Process normal completions (error or success) and clean the schedules.
+ *
+ * This is the main path for handing urbs back to drivers.  The only other
+ * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of
+ * scanning the (re-reversed) donelist as this does.
+ */
+static void
+dl_done_list (struct ohci_hcd *ohci, struct pt_regs *regs)
+{
+	struct td	*td = dl_reverse_done_list (ohci);
+
+  	while (td) {
+		struct td	*td_next = td->next_dl_td;
+		struct urb	*urb = td->urb;
+		urb_priv_t	*urb_priv = urb->hcpriv;
+		struct ed	*ed = td->ed;
+
+		/* update URB's length and status from TD */
+   		td_done (ohci, urb, td);
+  		urb_priv->td_cnt++;
+
+		/* If all this urb's TDs are done, call complete() */
+  		if (urb_priv->td_cnt == urb_priv->length)
+  			finish_urb (ohci, urb, regs);
+
+		/* clean schedule:  unlink EDs that are no longer busy */
+		if (list_empty (&ed->td_list)) {
+			if (ed->state == ED_OPER)
+				start_ed_unlink (ohci, ed);
+
+		/* ... reenabling halted EDs only after fault cleanup */
+		} else if ((ed->hwINFO & cpu_to_hc32 (ohci, ED_SKIP | ED_DEQUEUE))
+					== cpu_to_hc32 (ohci, ED_SKIP)) {
+			td = list_entry (ed->td_list.next, struct td, td_list);
+ 			if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) {
+				ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP);
+				/* ... hc may need waking-up */
+				switch (ed->type) {
+				case PIPE_CONTROL:
+					ohci_writel (ohci, OHCI_CLF,
+						&ohci->regs->cmdstatus);   
+					break;
+				case PIPE_BULK:
+					ohci_writel (ohci, OHCI_BLF,
+						&ohci->regs->cmdstatus);   
+					break;
+				}
+			}
+		}
+
+    		td = td_next;
+  	}  
+}
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
new file mode 100644
index 0000000..814d2be
--- /dev/null
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -0,0 +1,289 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ * 
+ * SA1111 Bus Glue
+ *
+ * Written by Christopher Hoover <ch@hpl.hp.com>
+ * Based on fragments of previous driver by Rusell King et al.
+ *
+ * This file is licenced under the GPL.
+ */
+ 
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/arch/assabet.h>
+#include <asm/arch/badge4.h>
+#include <asm/hardware/sa1111.h>
+
+#ifndef CONFIG_SA1111
+#error "This file is SA-1111 bus glue.  CONFIG_SA1111 must be defined."
+#endif
+
+extern int usb_disabled(void);
+
+/*-------------------------------------------------------------------------*/
+
+static void sa1111_start_hc(struct sa1111_dev *dev)
+{
+	unsigned int usb_rst = 0;
+
+	printk(KERN_DEBUG __FILE__ 
+	       ": starting SA-1111 OHCI USB Controller\n");
+
+#ifdef CONFIG_SA1100_BADGE4
+	if (machine_is_badge4()) {
+		badge4_set_5V(BADGE4_5V_USB, 1);
+	}
+#endif
+
+	if (machine_is_xp860() ||
+	    machine_has_neponset() ||
+	    machine_is_pfs168() ||
+	    machine_is_badge4())
+		usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW;
+
+	/*
+	 * Configure the power sense and control lines.  Place the USB
+	 * host controller in reset.
+	 */
+	sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
+		      dev->mapbase + SA1111_USB_RESET);
+
+	/*
+	 * Now, carefully enable the USB clock, and take
+	 * the USB host controller out of reset.
+	 */
+	sa1111_enable_device(dev);
+	udelay(11);
+	sa1111_writel(usb_rst, dev->mapbase + SA1111_USB_RESET);
+}
+
+static void sa1111_stop_hc(struct sa1111_dev *dev)
+{
+	unsigned int usb_rst;
+	printk(KERN_DEBUG __FILE__ 
+	       ": stopping SA-1111 OHCI USB Controller\n");
+
+	/*
+	 * Put the USB host controller into reset.
+	 */
+	usb_rst = sa1111_readl(dev->mapbase + SA1111_USB_RESET);
+	sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
+		      dev->mapbase + SA1111_USB_RESET);
+
+	/*
+	 * Stop the USB clock.
+	 */
+	sa1111_disable_device(dev);
+
+#ifdef CONFIG_SA1100_BADGE4
+	if (machine_is_badge4()) {
+		/* Disable power to the USB bus */
+		badge4_set_5V(BADGE4_5V_USB, 0);
+	}
+#endif
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+#if 0
+static void dump_hci_status(struct usb_hcd *hcd, const char *label)
+{
+	unsigned long status = sa1111_readl(hcd->regs + SA1111_USB_STATUS);
+
+	dbg ("%s USB_STATUS = { %s%s%s%s%s}", label,
+	     ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),
+	     ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""),
+	     ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "),
+	     ((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "),
+	     ((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : ""));
+}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+
+/**
+ * usb_hcd_sa1111_probe - initialize SA-1111-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ * Store this function in the HCD's struct pci_driver as probe().
+ */
+int usb_hcd_sa1111_probe (const struct hc_driver *driver,
+			  struct sa1111_dev *dev)
+{
+	struct usb_hcd *hcd;
+	int retval;
+
+	hcd = usb_create_hcd (driver, &dev->dev, "sa1111");
+	if (!hcd)
+		return -ENOMEM;
+	hcd->rsrc_start = dev->res.start;
+	hcd->rsrc_len = dev->res.end - dev->res.start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		dbg("request_mem_region failed");
+		retval = -EBUSY;
+		goto err1;
+	}
+	hcd->regs = dev->mapbase;
+
+	sa1111_start_hc(dev);
+	ohci_hcd_init(hcd_to_ohci(hcd));
+
+	retval = usb_add_hcd(hcd, dev->irq[1], SA_INTERRUPT);
+	if (retval == 0)
+		return retval;
+
+	sa1111_stop_hc(dev);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ err1:
+	usb_put_hcd(hcd);
+	return retval;
+}
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_sa1111_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *dev)
+{
+	usb_remove_hcd(hcd);
+	sa1111_stop_hc(dev);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_sa1111_start (struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int		ret;
+
+	if ((ret = ohci_init(ohci)) < 0)
+		return ret;
+
+	if ((ret = ohci_run (ohci)) < 0) {
+		err ("can't start %s", hcd->self.bus_name);
+		ohci_stop (hcd);
+		return ret;
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_sa1111_hc_driver = {
+	.description =		hcd_name,
+	.product_desc =		"SA-1111 OHCI",
+	.hcd_priv_size =	sizeof(struct ohci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ohci_irq,
+	.flags =		HCD_USB11 | HCD_MEMORY,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.start =		ohci_sa1111_start,
+#ifdef	CONFIG_PM
+	/* suspend:		ohci_sa1111_suspend,  -- tbd */
+	/* resume:		ohci_sa1111_resume,   -- tbd */
+#endif
+	.stop =			ohci_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ohci_urb_enqueue,
+	.urb_dequeue =		ohci_urb_dequeue,
+	.endpoint_disable =	ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ohci_hub_status_data,
+	.hub_control =		ohci_hub_control,
+#ifdef	CONFIG_USB_SUSPEND
+	.hub_suspend =		ohci_hub_suspend,
+	.hub_resume =		ohci_hub_resume,
+#endif
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hcd_sa1111_drv_probe(struct sa1111_dev *dev)
+{
+	int ret;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, dev);
+	return ret;
+}
+
+static int ohci_hcd_sa1111_drv_remove(struct sa1111_dev *dev)
+{
+	struct usb_hcd *hcd = sa1111_get_drvdata(dev);
+
+	usb_hcd_sa1111_remove(hcd, dev);
+	return 0;
+}
+
+static struct sa1111_driver ohci_hcd_sa1111_driver = {
+	.drv = {
+		.name	= "sa1111-ohci",
+	},
+	.devid		= SA1111_DEVID_USB,
+	.probe		= ohci_hcd_sa1111_drv_probe,
+	.remove		= ohci_hcd_sa1111_drv_remove,
+};
+
+static int __init ohci_hcd_sa1111_init (void)
+{
+	dbg (DRIVER_INFO " (SA-1111)");
+	dbg ("block sizes: ed %d td %d",
+		sizeof (struct ed), sizeof (struct td));
+
+	return sa1111_driver_register(&ohci_hcd_sa1111_driver);
+}
+
+static void __exit ohci_hcd_sa1111_cleanup (void)
+{
+	sa1111_driver_unregister(&ohci_hcd_sa1111_driver);
+}
+
+module_init (ohci_hcd_sa1111_init);
+module_exit (ohci_hcd_sa1111_cleanup);
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
new file mode 100644
index 0000000..2ba6e2b
--- /dev/null
+++ b/drivers/usb/host/ohci.h
@@ -0,0 +1,636 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ * 
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * This file is licenced under the GPL.
+ */
+
+/*
+ * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
+ * __leXX (normally) or __beXX (given OHCI_BIG_ENDIAN), depending on the
+ * host controller implementation.
+ */
+typedef __u32 __bitwise __hc32;
+typedef __u16 __bitwise __hc16;
+ 
+/*
+ * OHCI Endpoint Descriptor (ED) ... holds TD queue
+ * See OHCI spec, section 4.2
+ *
+ * This is a "Queue Head" for those transfers, which is why
+ * both EHCI and UHCI call similar structures a "QH".
+ */
+struct ed {
+	/* first fields are hardware-specified */
+	__hc32			hwINFO;       	/* endpoint config bitmap */
+	/* info bits defined by hcd */
+#define ED_DEQUEUE	(1 << 27)
+	/* info bits defined by the hardware */
+#define ED_ISO		(1 << 15)
+#define ED_SKIP		(1 << 14)
+#define ED_LOWSPEED	(1 << 13)
+#define ED_OUT		(0x01 << 11)
+#define ED_IN		(0x02 << 11)
+	__hc32			hwTailP;	/* tail of TD list */
+	__hc32			hwHeadP;	/* head of TD list (hc r/w) */
+#define ED_C		(0x02)			/* toggle carry */
+#define ED_H		(0x01)			/* halted */
+	__hc32			hwNextED;	/* next ED in list */
+
+	/* rest are purely for the driver's use */
+	dma_addr_t		dma;		/* addr of ED */
+	struct td		*dummy;		/* next TD to activate */
+
+	/* host's view of schedule */
+	struct ed		*ed_next;	/* on schedule or rm_list */
+	struct ed		*ed_prev;	/* for non-interrupt EDs */
+	struct list_head	td_list;	/* "shadow list" of our TDs */
+
+	/* create --> IDLE --> OPER --> ... --> IDLE --> destroy
+	 * usually:  OPER --> UNLINK --> (IDLE | OPER) --> ...
+	 */
+	u8			state;		/* ED_{IDLE,UNLINK,OPER} */
+#define ED_IDLE 	0x00		/* NOT linked to HC */
+#define ED_UNLINK 	0x01		/* being unlinked from hc */
+#define ED_OPER		0x02		/* IS linked to hc */
+
+	u8			type; 		/* PIPE_{BULK,...} */
+
+	/* periodic scheduling params (for intr and iso) */
+	u8			branch;
+	u16			interval;
+	u16			load;
+	u16			last_iso;	/* iso only */
+
+	/* HC may see EDs on rm_list until next frame (frame_no == tick) */
+	u16			tick;
+} __attribute__ ((aligned(16)));
+
+#define ED_MASK	((u32)~0x0f)		/* strip hw status in low addr bits */
+
+ 
+/*
+ * OHCI Transfer Descriptor (TD) ... one per transfer segment
+ * See OHCI spec, sections 4.3.1 (general = control/bulk/interrupt)
+ * and 4.3.2 (iso)
+ */
+struct td {
+	/* first fields are hardware-specified */
+	__hc32		hwINFO;		/* transfer info bitmask */
+
+	/* hwINFO bits for both general and iso tds: */
+#define TD_CC       0xf0000000			/* condition code */
+#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_DI       0x00E00000			/* frames before interrupt */
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+	/* these two bits are available for definition/use by HCDs in both
+	 * general and iso tds ... others are available for only one type
+	 */
+#define TD_DONE     0x00020000			/* retired to donelist */
+#define TD_ISO      0x00010000			/* copy of ED_ISO */
+
+	/* hwINFO bits for general tds: */
+#define TD_EC       0x0C000000			/* error count */
+#define TD_T        0x03000000			/* data toggle state */
+#define TD_T_DATA0  0x02000000				/* DATA0 */
+#define TD_T_DATA1  0x03000000				/* DATA1 */
+#define TD_T_TOGGLE 0x00000000				/* uses ED_C */
+#define TD_DP       0x00180000			/* direction/pid */
+#define TD_DP_SETUP 0x00000000			/* SETUP pid */
+#define TD_DP_IN    0x00100000				/* IN pid */
+#define TD_DP_OUT   0x00080000				/* OUT pid */
+							/* 0x00180000 rsvd */
+#define TD_R        0x00040000			/* round: short packets OK? */
+
+	/* (no hwINFO #defines yet for iso tds) */
+
+  	__hc32		hwCBP;		/* Current Buffer Pointer (or 0) */
+  	__hc32		hwNextTD;	/* Next TD Pointer */
+  	__hc32		hwBE;		/* Memory Buffer End Pointer */
+
+	/* PSW is only for ISO.  Only 1 PSW entry is used, but on
+	 * big-endian PPC hardware that's the second entry.
+	 */
+#define MAXPSW	2
+  	__hc16		hwPSW [MAXPSW];
+
+	/* rest are purely for the driver's use */
+  	__u8		index;
+  	struct ed	*ed;
+  	struct td	*td_hash;	/* dma-->td hashtable */
+  	struct td	*next_dl_td;
+  	struct urb	*urb;
+
+	dma_addr_t	td_dma;		/* addr of this TD */
+	dma_addr_t	data_dma;	/* addr of data it points to */
+
+	struct list_head td_list;	/* "shadow list", TDs on same ED */
+} __attribute__ ((aligned(32)));	/* c/b/i need 16; only iso needs 32 */
+
+#define TD_MASK	((u32)~0x1f)		/* strip hw status in low addr bits */
+
+/*
+ * Hardware transfer status codes -- CC from td->hwINFO or td->hwPSW
+ */
+#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
+
+
+/* map OHCI TD status codes (CC) to errno values */ 
+static const int cc_to_error [16] = { 
+	/* No  Error  */               0,
+	/* CRC Error  */               -EILSEQ,
+	/* Bit Stuff  */               -EPROTO,
+	/* Data Togg  */               -EILSEQ,
+	/* Stall      */               -EPIPE,
+	/* DevNotResp */               -ETIMEDOUT,
+	/* PIDCheck   */               -EPROTO,
+	/* UnExpPID   */               -EPROTO,
+	/* DataOver   */               -EOVERFLOW,
+	/* DataUnder  */               -EREMOTEIO,
+	/* (for hw)   */               -EIO,
+	/* (for hw)   */               -EIO,
+	/* BufferOver */               -ECOMM,
+	/* BuffUnder  */               -ENOSR,
+	/* (for HCD)  */               -EALREADY,
+	/* (for HCD)  */               -EALREADY 
+};
+
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined section 4.4.1 of the OHCI spec. The HC is
+ * told the base address of it.  It must be 256-byte aligned.
+ */
+struct ohci_hcca {
+#define NUM_INTS 32
+	__hc32	int_table [NUM_INTS];	/* periodic schedule */
+
+	/* 
+	 * OHCI defines u16 frame_no, followed by u16 zero pad.
+	 * Since some processors can't do 16 bit bus accesses,
+	 * portable access must be a 32 bits wide.
+	 */
+	__hc32	frame_no;		/* current frame number */
+	__hc32	done_head;		/* info returned for an interrupt */
+	u8	reserved_for_hc [116];
+	u8	what [4];		/* spec only identifies 252 bytes :) */
+} __attribute__ ((aligned(256)));
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O region.
+ * You must use readl() and writel() (in <asm/io.h>) to access these fields!!
+ * Layout is in section 7 (and appendix B) of the spec.
+ */
+struct ohci_regs {
+	/* control and status registers (section 7.1) */
+	__hc32	revision;
+	__hc32	control;
+	__hc32	cmdstatus;
+	__hc32	intrstatus;
+	__hc32	intrenable;
+	__hc32	intrdisable;
+
+	/* memory pointers (section 7.2) */
+	__hc32	hcca;
+	__hc32	ed_periodcurrent;
+	__hc32	ed_controlhead;
+	__hc32	ed_controlcurrent;
+	__hc32	ed_bulkhead;
+	__hc32	ed_bulkcurrent;
+	__hc32	donehead;
+
+	/* frame counters (section 7.3) */
+	__hc32	fminterval;
+	__hc32	fmremaining;
+	__hc32	fmnumber;
+	__hc32	periodicstart;
+	__hc32	lsthresh;
+
+	/* Root hub ports (section 7.4) */
+	struct	ohci_roothub_regs {
+		__hc32	a;
+		__hc32	b;
+		__hc32	status;
+#define MAX_ROOT_PORTS	15	/* maximum OHCI root hub ports (RH_A_NDP) */
+		__hc32	portstatus [MAX_ROOT_PORTS];
+	} roothub;
+
+	/* and optional "legacy support" registers (appendix B) at 0x0100 */
+
+} __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 */
+
+
+/* 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 */
+
+
+/* hcd-private per-urb state */
+typedef struct urb_priv {
+	struct ed		*ed;
+	u16			length;		// # tds in this request
+	u16			td_cnt;		// tds already serviced
+	struct list_head	pending;
+	struct td		*td [0];	// all TDs in this request
+
+} urb_priv_t;
+
+#define TD_HASH_SIZE    64    /* power'o'two */
+// sizeof (struct td) ~= 64 == 2^6 ... 
+#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 6)) % TD_HASH_SIZE)
+
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+struct ohci_hcd {
+	spinlock_t		lock;
+
+	/*
+	 * I/O memory used to communicate with the HC (dma-consistent)
+	 */
+	struct ohci_regs __iomem *regs;
+
+	/*
+	 * main memory used to communicate with the HC (dma-consistent).
+	 * hcd adds to schedule for a live hc any time, but removals finish
+	 * only at the start of the next frame.
+	 */
+	struct ohci_hcca	*hcca;
+	dma_addr_t		hcca_dma;
+
+	struct ed		*ed_rm_list;		/* to be removed */
+
+	struct ed		*ed_bulktail;		/* last in bulk list */
+	struct ed		*ed_controltail;	/* last in ctrl list */
+ 	struct ed		*periodic [NUM_INTS];	/* shadow int_table */
+
+	/*
+	 * OTG controllers and transceivers need software interaction;
+	 * other external transceivers should be software-transparent 
+	 */
+	struct otg_transceiver	*transceiver;
+	unsigned		power_budget;
+
+	/*
+	 * memory management for queue data structures
+	 */
+	struct dma_pool		*td_cache;
+	struct dma_pool		*ed_cache;
+	struct td		*td_hash [TD_HASH_SIZE];
+	struct list_head	pending;
+
+	/*
+	 * driver state
+	 */
+	int			load [NUM_INTS];
+	u32 			hc_control;	/* copy of hc control reg */
+	unsigned long		next_statechange;	/* suspend/resume */
+	u32			fminterval;		/* saved register */
+
+	struct work_struct	rh_resume;
+
+	unsigned long		flags;		/* for HC bugs */
+#define	OHCI_QUIRK_AMD756	0x01			/* erratum #4 */
+#define	OHCI_QUIRK_SUPERIO	0x02			/* natsemi */
+#define	OHCI_QUIRK_INITRESET	0x04			/* SiS, OPTi, ... */
+#define	OHCI_BIG_ENDIAN		0x08			/* big endian HC */
+	// there are also chip quirks/bugs in init logic
+
+};
+
+/* convert between an hcd pointer and the corresponding ohci_hcd */
+static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *hcd)
+{
+	return (struct ohci_hcd *) (hcd->hcd_priv);
+}
+static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci)
+{
+	return container_of ((void *) ohci, struct usb_hcd, hcd_priv);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifndef DEBUG
+#define STUB_DEBUG_FILES
+#endif	/* DEBUG */
+
+#define ohci_dbg(ohci, fmt, args...) \
+	dev_dbg (ohci_to_hcd(ohci)->self.controller , fmt , ## args )
+#define ohci_err(ohci, fmt, args...) \
+	dev_err (ohci_to_hcd(ohci)->self.controller , fmt , ## args )
+#define ohci_info(ohci, fmt, args...) \
+	dev_info (ohci_to_hcd(ohci)->self.controller , fmt , ## args )
+#define ohci_warn(ohci, fmt, args...) \
+	dev_warn (ohci_to_hcd(ohci)->self.controller , fmt , ## args )
+
+#ifdef OHCI_VERBOSE_DEBUG
+#	define ohci_vdbg ohci_dbg
+#else
+#	define ohci_vdbg(ohci, fmt, args...) do { } while (0)
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * While most USB host controllers implement their registers and
+ * in-memory communication descriptors in little-endian format,
+ * a minority (notably the IBM STB04XXX and the Motorola MPC5200
+ * processors) implement them in big endian format.
+ *
+ * This attempts to support either format at compile time without a
+ * runtime penalty, or both formats with the additional overhead
+ * of checking a flag bit.
+ */
+
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN
+
+#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
+#define big_endian(ohci)	(ohci->flags & OHCI_BIG_ENDIAN) /* either */
+#else
+#define big_endian(ohci)	1		/* only big endian */
+#endif
+
+/*
+ * Big-endian read/write functions are arch-specific.
+ * Other arches can be added if/when they're needed.
+ */
+#if defined(CONFIG_PPC)
+#define readl_be(addr)		in_be32((__force unsigned *)addr)
+#define writel_be(val, addr)	out_be32((__force unsigned *)addr, val)
+#endif
+
+static inline unsigned int ohci_readl (const struct ohci_hcd *ohci,
+							__hc32 __iomem * regs)
+{
+	return big_endian(ohci) ? readl_be (regs) : readl ((__force u32 *)regs);
+}
+
+static inline void ohci_writel (const struct ohci_hcd *ohci,
+				const unsigned int val, __hc32 __iomem *regs)
+{
+	big_endian(ohci) ? writel_be (val, regs) :
+			   writel (val, (__force u32 *)regs);
+}
+
+#else	/* !CONFIG_USB_OHCI_BIG_ENDIAN */
+
+#define big_endian(ohci)	0		/* only little endian */
+
+#ifdef CONFIG_ARCH_LH7A404
+	/* Marc Singer: at the time this code was written, the LH7A404
+	 * had a problem reading the USB host registers.  This
+	 * implementation of the ohci_readl function performs the read
+	 * twice as a work-around.
+	 */
+static inline unsigned int
+ohci_readl (const struct ohci_hcd *ohci, const __hc32 *regs)
+{
+	*(volatile __force unsigned int*) regs;
+	return *(volatile __force unsigned int*) regs;
+}
+#else
+	/* Standard version of ohci_readl uses standard, platform
+	 * specific implementation. */
+static inline unsigned int
+ohci_readl (const struct ohci_hcd *ohci, __hc32 __iomem * regs)
+{
+	return readl(regs);
+}
+#endif
+
+static inline void ohci_writel (const struct ohci_hcd *ohci,
+				const unsigned int val, __hc32 __iomem *regs)
+{
+	writel (val, regs);
+}
+
+#endif	/* !CONFIG_USB_OHCI_BIG_ENDIAN */
+
+/*-------------------------------------------------------------------------*/
+
+/* cpu to ohci */
+static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x)
+{
+	return big_endian(ohci) ? (__force __hc16)cpu_to_be16(x) : (__force __hc16)cpu_to_le16(x);
+}
+
+static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x)
+{
+	return big_endian(ohci) ? cpu_to_be16p(x) : cpu_to_le16p(x);
+}
+
+static inline __hc32 cpu_to_hc32 (const struct ohci_hcd *ohci, const u32 x)
+{
+	return big_endian(ohci) ? (__force __hc32)cpu_to_be32(x) : (__force __hc32)cpu_to_le32(x);
+}
+
+static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x)
+{
+	return big_endian(ohci) ? cpu_to_be32p(x) : cpu_to_le32p(x);
+}
+
+/* ohci to cpu */
+static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x)
+{
+	return big_endian(ohci) ? be16_to_cpu((__force __be16)x) : le16_to_cpu((__force __le16)x);
+}
+
+static inline u16 hc16_to_cpup (const struct ohci_hcd *ohci, const __hc16 *x)
+{
+	return big_endian(ohci) ? be16_to_cpup((__force __be16 *)x) : le16_to_cpup((__force __le16 *)x);
+}
+
+static inline u32 hc32_to_cpu (const struct ohci_hcd *ohci, const __hc32 x)
+{
+	return big_endian(ohci) ? be32_to_cpu((__force __be32)x) : le32_to_cpu((__force __le32)x);
+}
+
+static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
+{
+	return big_endian(ohci) ? be32_to_cpup((__force __be32 *)x) : le32_to_cpup((__force __le32 *)x);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
+ * hardware handles 16 bit reads.  That creates a different confusion on
+ * some big-endian SOC implementations.  Same thing happens with PSW access.
+ */
+
+#ifdef CONFIG_STB03xxx
+#define OHCI_BE_FRAME_NO_SHIFT	16
+#else
+#define OHCI_BE_FRAME_NO_SHIFT	0
+#endif
+
+static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
+{
+	u32 tmp;
+	if (big_endian(ohci)) {
+		tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
+		tmp >>= OHCI_BE_FRAME_NO_SHIFT;
+	} else
+		tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no);
+
+	return (u16)tmp;
+}
+
+static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci,
+                                 const struct td *td, int index)
+{
+	return (__hc16 *)(big_endian(ohci) ?
+			&td->hwPSW[index ^ 1] : &td->hwPSW[index]);
+}
+
+static inline u16 ohci_hwPSW(const struct ohci_hcd *ohci,
+                               const struct td *td, int index)
+{
+	return hc16_to_cpup(ohci, ohci_hwPSWp(ohci, td, index));
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline void disable (struct ohci_hcd *ohci)
+{
+	ohci_to_hcd(ohci)->state = HC_STATE_HALT;
+}
+
+#define	FI			0x2edf		/* 12000 bits per frame (-1) */
+#define	FSMP(fi) 		(0x7fff & ((6 * ((fi) - 210)) / 7))
+#define	FIT			(1 << 31)
+#define LSTHRESH		0x628		/* lowspeed bit threshold */
+
+static void periodic_reinit (struct ohci_hcd *ohci)
+{
+	u32	fi = ohci->fminterval & 0x03fff;
+	u32	fit = ohci_readl(ohci, &ohci->regs->fminterval) & FIT;
+
+	ohci_writel (ohci, (fit ^ FIT) | ohci->fminterval,
+						&ohci->regs->fminterval);
+	ohci_writel (ohci, ((9 * fi) / 10) & 0x3fff,
+						&ohci->regs->periodicstart);
+}
+
+/* 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 read_roothub(hc, register, mask) ({ \
+	u32 temp = ohci_readl (hc, &hc->regs->roothub.register); \
+	if (temp == -1) \
+		disable (hc); \
+	else if (hc->flags & OHCI_QUIRK_AMD756) \
+		while (temp & mask) \
+			temp = ohci_readl (hc, &hc->regs->roothub.register); \
+	temp; })
+
+static u32 roothub_a (struct ohci_hcd *hc)
+	{ return read_roothub (hc, a, 0xfc0fe000); }
+static inline u32 roothub_b (struct ohci_hcd *hc)
+	{ return ohci_readl (hc, &hc->regs->roothub.b); }
+static inline u32 roothub_status (struct ohci_hcd *hc)
+	{ return ohci_readl (hc, &hc->regs->roothub.status); }
+static u32 roothub_portstatus (struct ohci_hcd *hc, int i)
+	{ return read_roothub (hc, portstatus [i], 0xffe0fce0); }
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
new file mode 100644
index 0000000..d309e29
--- /dev/null
+++ b/drivers/usb/host/sl811-hcd.c
@@ -0,0 +1,1851 @@
+/*
+ * SL811HS HCD (Host Controller Driver) for USB.
+ *
+ * Copyright (C) 2004 Psion Teklogix (for NetBook PRO)
+ * Copyright (C) 2004 David Brownell
+ * 
+ * Periodic scheduling is based on Roman's OHCI code
+ * 	Copyright (C) 1999 Roman Weissgaerber
+ *
+ * The SL811HS controller handles host side USB (like the SL11H, but with
+ * another register set and SOF generation) as well as peripheral side USB
+ * (like the SL811S).  This driver version doesn't implement the Gadget API
+ * for the peripheral role; or OTG (that'd need much external circuitry).
+ *
+ * For documentation, see the SL811HS spec and the "SL811HS Embedded Host"
+ * document (providing significant pieces missing from that spec); plus
+ * the SL811S spec if you want peripheral side info.
+ */ 
+
+/*
+ * Status:  Passed basic stress testing, works with hubs, mice, keyboards,
+ * and usb-storage.
+ *
+ * TODO:
+ * - usb suspend/resume triggered by sl811 (with USB_SUSPEND)
+ * - various issues noted in the code
+ * - performance work; use both register banks; ...
+ * - use urb->iso_frame_desc[] with ISO transfers
+ */
+
+#undef	VERBOSE
+#undef	PACKET_TRACE
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_DEBUG
+#	define DEBUG
+#else
+#	undef DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/usb_sl811.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+
+#include "../core/hcd.h"
+#include "sl811.h"
+
+
+MODULE_DESCRIPTION("SL811HS USB Host Controller Driver");
+MODULE_LICENSE("GPL");
+
+#define DRIVER_VERSION	"15 Dec 2004"
+
+
+#ifndef DEBUG
+#	define	STUB_DEBUG_FILE
+#endif
+
+/* for now, use only one transfer register bank */
+#undef	USE_B
+
+/* this doesn't understand urb->iso_frame_desc[], but if you had a driver
+ * that just queued one ISO frame per URB then iso transfers "should" work
+ * using the normal urb status fields.
+ */
+#define	DISABLE_ISO
+
+// #define	QUIRK2
+#define	QUIRK3
+
+static const char hcd_name[] = "sl811-hcd";
+
+/*-------------------------------------------------------------------------*/
+
+static void port_power(struct sl811 *sl811, int is_on)
+{
+	struct usb_hcd	*hcd = sl811_to_hcd(sl811);
+
+	/* hub is inactive unless the port is powered */
+	if (is_on) {
+		if (sl811->port1 & (1 << USB_PORT_FEAT_POWER))
+			return;
+
+		sl811->port1 = (1 << USB_PORT_FEAT_POWER);
+		sl811->irq_enable = SL11H_INTMASK_INSRMV;
+		hcd->self.controller->power.power_state = PMSG_ON;
+	} else {
+		sl811->port1 = 0;
+		sl811->irq_enable = 0;
+		hcd->state = HC_STATE_HALT;
+		hcd->self.controller->power.power_state = PMSG_SUSPEND;
+	}
+	sl811->ctrl1 = 0;
+	sl811_write(sl811, SL11H_IRQ_ENABLE, 0);
+	sl811_write(sl811, SL11H_IRQ_STATUS, ~0);
+
+	if (sl811->board && sl811->board->port_power) {
+		/* switch VBUS, at 500mA unless hub power budget gets set */
+		DBG("power %s\n", is_on ? "on" : "off");
+		sl811->board->port_power(hcd->self.controller, is_on);
+	}
+
+	/* reset as thoroughly as we can */
+	if (sl811->board && sl811->board->reset)
+		sl811->board->reset(hcd->self.controller);
+
+	sl811_write(sl811, SL11H_IRQ_ENABLE, 0);
+	sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
+	sl811_write(sl811, SL811HS_CTLREG2, SL811HS_CTL2_INIT);
+	sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
+
+	// if !is_on, put into lowpower mode now
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* This is a PIO-only HCD.  Queueing appends URBs to the endpoint's queue,
+ * and may start I/O.  Endpoint queues are scanned during completion irq
+ * handlers (one per packet: ACK, NAK, faults, etc) and urb cancelation.
+ *
+ * Using an external DMA engine to copy a packet at a time could work,
+ * though setup/teardown costs may be too big to make it worthwhile.
+ */
+
+/* SETUP starts a new control request.  Devices are not allowed to
+ * STALL or NAK these; they must cancel any pending control requests.
+ */
+static void setup_packet(
+	struct sl811		*sl811,
+	struct sl811h_ep	*ep,
+	struct urb		*urb,
+	u8			bank,
+	u8			control
+)
+{
+	u8			addr;
+	u8			len;
+	void __iomem		*data_reg;
+
+	addr = SL811HS_PACKET_BUF(bank == 0);
+	len = sizeof(struct usb_ctrlrequest);
+	data_reg = sl811->data_reg;
+	sl811_write_buf(sl811, addr, urb->setup_packet, len);
+
+	/* autoincrementing */
+	sl811_write(sl811, bank + SL11H_BUFADDRREG, addr);
+	writeb(len, data_reg);
+	writeb(SL_SETUP /* | ep->epnum */, data_reg);
+	writeb(usb_pipedevice(urb->pipe), data_reg);
+
+	/* always OUT/data0 */ ;
+	sl811_write(sl811, bank + SL11H_HOSTCTLREG,
+			control | SL11H_HCTLMASK_OUT);
+	ep->length = 0;
+	PACKET("SETUP qh%p\n", ep);
+}
+
+/* STATUS finishes control requests, often after IN or OUT data packets */
+static void status_packet(
+	struct sl811		*sl811,
+	struct sl811h_ep	*ep,
+	struct urb		*urb,
+	u8			bank,
+	u8			control
+)
+{
+	int			do_out;
+	void __iomem		*data_reg;
+
+	do_out = urb->transfer_buffer_length && usb_pipein(urb->pipe);
+	data_reg = sl811->data_reg;
+
+	/* autoincrementing */
+	sl811_write(sl811, bank + SL11H_BUFADDRREG, 0);
+	writeb(0, data_reg);
+	writeb((do_out ? SL_OUT : SL_IN) /* | ep->epnum */, data_reg);
+	writeb(usb_pipedevice(urb->pipe), data_reg);
+
+	/* always data1; sometimes IN */
+	control |= SL11H_HCTLMASK_TOGGLE;
+	if (do_out)
+		control |= SL11H_HCTLMASK_OUT;
+	sl811_write(sl811, bank + SL11H_HOSTCTLREG, control);
+	ep->length = 0;
+	PACKET("STATUS%s/%s qh%p\n", ep->nak_count ? "/retry" : "",
+			do_out ? "out" : "in", ep);
+}
+
+/* IN packets can be used with any type of endpoint. here we just
+ * start the transfer, data from the peripheral may arrive later.
+ * urb->iso_frame_desc is currently ignored here...
+ */
+static void in_packet(
+	struct sl811		*sl811,
+	struct sl811h_ep	*ep,
+	struct urb		*urb,
+	u8			bank,
+	u8			control
+)
+{
+	u8			addr;
+	u8			len;
+	void __iomem		*data_reg;
+
+	/* avoid losing data on overflow */
+	len = ep->maxpacket;
+	addr = SL811HS_PACKET_BUF(bank == 0);
+	if (!(control & SL11H_HCTLMASK_ISOCH)
+			&& usb_gettoggle(urb->dev, ep->epnum, 0))
+		control |= SL11H_HCTLMASK_TOGGLE;
+	data_reg = sl811->data_reg;
+
+	/* autoincrementing */
+	sl811_write(sl811, bank + SL11H_BUFADDRREG, addr);
+	writeb(len, data_reg);
+	writeb(SL_IN | ep->epnum, data_reg);
+	writeb(usb_pipedevice(urb->pipe), data_reg);
+
+	sl811_write(sl811, bank + SL11H_HOSTCTLREG, control);
+	ep->length = min((int)len,
+			urb->transfer_buffer_length - urb->actual_length);
+	PACKET("IN%s/%d qh%p len%d\n", ep->nak_count ? "/retry" : "",
+			!!usb_gettoggle(urb->dev, ep->epnum, 0), ep, len);
+}
+
+/* OUT packets can be used with any type of endpoint.
+ * urb->iso_frame_desc is currently ignored here...
+ */
+static void out_packet(
+	struct sl811		*sl811,
+	struct sl811h_ep	*ep,
+	struct urb		*urb,
+	u8			bank,
+	u8			control
+)
+{
+	void			*buf;
+	u8			addr;
+	u8			len;
+	void __iomem		*data_reg;
+
+	buf = urb->transfer_buffer + urb->actual_length;
+	prefetch(buf);
+
+	len = min((int)ep->maxpacket,
+			urb->transfer_buffer_length - urb->actual_length);
+
+	if (!(control & SL11H_HCTLMASK_ISOCH)
+			&& usb_gettoggle(urb->dev, ep->epnum, 1))
+		control |= SL11H_HCTLMASK_TOGGLE;
+	addr = SL811HS_PACKET_BUF(bank == 0);
+	data_reg = sl811->data_reg;
+
+	sl811_write_buf(sl811, addr, buf, len);
+
+	/* autoincrementing */
+	sl811_write(sl811, bank + SL11H_BUFADDRREG, addr);
+	writeb(len, data_reg);
+	writeb(SL_OUT | ep->epnum, data_reg);
+	writeb(usb_pipedevice(urb->pipe), data_reg);
+
+	sl811_write(sl811, bank + SL11H_HOSTCTLREG,
+			control | SL11H_HCTLMASK_OUT);
+	ep->length = len;
+	PACKET("OUT%s/%d qh%p len%d\n", ep->nak_count ? "/retry" : "",
+			!!usb_gettoggle(urb->dev, ep->epnum, 1), ep, len);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* caller updates on-chip enables later */
+
+static inline void sofirq_on(struct sl811 *sl811)
+{
+	if (sl811->irq_enable & SL11H_INTMASK_SOFINTR)
+		return;
+	VDBG("sof irq on\n");
+	sl811->irq_enable |= SL11H_INTMASK_SOFINTR;
+}
+
+static inline void sofirq_off(struct sl811 *sl811)
+{
+	if (!(sl811->irq_enable & SL11H_INTMASK_SOFINTR))
+		return;
+	VDBG("sof irq off\n");
+	sl811->irq_enable &= ~SL11H_INTMASK_SOFINTR;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* pick the next endpoint for a transaction, and issue it.
+ * frames start with periodic transfers (after whatever is pending
+ * from the previous frame), and the rest of the time is async
+ * transfers, scheduled round-robin.
+ */
+static struct sl811h_ep	*start(struct sl811 *sl811, u8 bank)
+{
+	struct sl811h_ep	*ep;
+	struct urb		*urb;
+	int			fclock;
+	u8			control;
+
+	/* use endpoint at schedule head */
+	if (sl811->next_periodic) {
+		ep = sl811->next_periodic;
+		sl811->next_periodic = ep->next;
+	} else {
+		if (sl811->next_async)
+			ep = sl811->next_async;
+		else if (!list_empty(&sl811->async))
+			ep = container_of(sl811->async.next,
+					struct sl811h_ep, schedule);
+		else {
+			/* could set up the first fullspeed periodic
+			 * transfer for the next frame ...
+			 */
+			return NULL;
+		}
+
+#ifdef USE_B
+		if ((bank && sl811->active_b == ep) || sl811->active_a == ep)
+			return NULL;
+#endif
+
+		if (ep->schedule.next == &sl811->async)
+			sl811->next_async = NULL;
+		else
+			sl811->next_async = container_of(ep->schedule.next,
+					struct sl811h_ep, schedule);
+	}
+
+	if (unlikely(list_empty(&ep->hep->urb_list))) {
+		DBG("empty %p queue?\n", ep);
+		return NULL;
+	}
+
+	urb = container_of(ep->hep->urb_list.next, struct urb, urb_list);
+	control = ep->defctrl;
+
+	/* if this frame doesn't have enough time left to transfer this
+	 * packet, wait till the next frame.  too-simple algorithm...
+	 */
+	fclock = sl811_read(sl811, SL11H_SOFTMRREG) << 6;
+	fclock -= 100;		/* setup takes not much time */
+	if (urb->dev->speed == USB_SPEED_LOW) {
+		if (control & SL11H_HCTLMASK_PREAMBLE) {
+			/* also note erratum 1: some hubs won't work */
+			fclock -= 800;
+		}
+		fclock -= ep->maxpacket << 8;
+
+		/* erratum 2: AFTERSOF only works for fullspeed */
+		if (fclock < 0) {
+			if (ep->period)
+				sl811->stat_overrun++;
+			sofirq_on(sl811);
+			return NULL;
+		}
+	} else {
+		fclock -= 12000 / 19;	/* 19 64byte packets/msec */
+		if (fclock < 0) {
+			if (ep->period)
+				sl811->stat_overrun++;
+			control |= SL11H_HCTLMASK_AFTERSOF;
+
+		/* throttle bulk/control irq noise */
+		} else if (ep->nak_count)
+			control |= SL11H_HCTLMASK_AFTERSOF;
+	}
+
+
+	switch (ep->nextpid) {
+	case USB_PID_IN:
+		in_packet(sl811, ep, urb, bank, control);
+		break;
+	case USB_PID_OUT:
+		out_packet(sl811, ep, urb, bank, control);
+		break;
+	case USB_PID_SETUP:
+		setup_packet(sl811, ep, urb, bank, control);
+		break;
+	case USB_PID_ACK:		/* for control status */
+		status_packet(sl811, ep, urb, bank, control);
+		break;
+	default:
+		DBG("bad ep%p pid %02x\n", ep, ep->nextpid);
+		ep = NULL;
+	}
+	return ep;
+}
+
+#define MIN_JIFFIES	((msecs_to_jiffies(2) > 1) ? msecs_to_jiffies(2) : 2)
+
+static inline void start_transfer(struct sl811 *sl811)
+{
+	if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND))
+		return;
+	if (sl811->active_a == NULL) {
+		sl811->active_a = start(sl811, SL811_EP_A(SL811_HOST_BUF));
+		if (sl811->active_a != NULL)
+			sl811->jiffies_a = jiffies + MIN_JIFFIES;
+	}
+#ifdef USE_B
+	if (sl811->active_b == NULL) {
+		sl811->active_b = start(sl811, SL811_EP_B(SL811_HOST_BUF));
+		if (sl811->active_b != NULL)
+			sl811->jiffies_b = jiffies + MIN_JIFFIES;
+	}
+#endif
+}
+
+static void finish_request(
+	struct sl811		*sl811,
+	struct sl811h_ep	*ep,
+	struct urb		*urb,
+	struct pt_regs		*regs,
+	int			status
+) __releases(sl811->lock) __acquires(sl811->lock)
+{
+	unsigned		i;
+
+	if (usb_pipecontrol(urb->pipe))
+		ep->nextpid = USB_PID_SETUP;
+
+	spin_lock(&urb->lock);
+	if (urb->status == -EINPROGRESS)
+		urb->status = status;
+	spin_unlock(&urb->lock);
+
+	spin_unlock(&sl811->lock);
+	usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, regs);
+	spin_lock(&sl811->lock);
+
+	/* leave active endpoints in the schedule */
+	if (!list_empty(&ep->hep->urb_list))
+		return;
+
+	/* async deschedule? */
+	if (!list_empty(&ep->schedule)) {
+		list_del_init(&ep->schedule);
+		if (ep == sl811->next_async)
+			sl811->next_async = NULL;
+		return;
+	}
+
+	/* periodic deschedule */
+	DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+	for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
+		struct sl811h_ep	*temp;
+		struct sl811h_ep	**prev = &sl811->periodic[i];
+
+		while (*prev && ((temp = *prev) != ep))
+			prev = &temp->next;
+		if (*prev)
+			*prev = ep->next;
+		sl811->load[i] -= ep->load;
+	}	
+	ep->branch = PERIODIC_SIZE;
+	sl811->periodic_count--;
+	sl811_to_hcd(sl811)->self.bandwidth_allocated
+		-= ep->load / ep->period;
+	if (ep == sl811->next_periodic)
+		sl811->next_periodic = ep->next;
+
+	/* we might turn SOFs back on again for the async schedule */
+	if (sl811->periodic_count == 0)
+		sofirq_off(sl811);
+}
+
+static void
+done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank, struct pt_regs *regs)
+{
+	u8			status;
+	struct urb		*urb;
+	int			urbstat = -EINPROGRESS;
+
+	if (unlikely(!ep))
+		return;
+
+	status = sl811_read(sl811, bank + SL11H_PKTSTATREG);
+
+	urb = container_of(ep->hep->urb_list.next, struct urb, urb_list);
+
+	/* we can safely ignore NAKs */
+	if (status & SL11H_STATMASK_NAK) {
+		// PACKET("...NAK_%02x qh%p\n", bank, ep);
+		if (!ep->period)
+			ep->nak_count++;
+		ep->error_count = 0;
+
+	/* ACK advances transfer, toggle, and maybe queue */
+	} else if (status & SL11H_STATMASK_ACK) {
+		struct usb_device	*udev = urb->dev;
+		int			len;
+		unsigned char		*buf;
+
+		/* urb->iso_frame_desc is currently ignored here... */
+
+		ep->nak_count = ep->error_count = 0;
+		switch (ep->nextpid) {
+		case USB_PID_OUT:
+			// PACKET("...ACK/out_%02x qh%p\n", bank, ep);
+			urb->actual_length += ep->length;
+			usb_dotoggle(udev, ep->epnum, 1);
+			if (urb->actual_length
+					== urb->transfer_buffer_length) {
+				if (usb_pipecontrol(urb->pipe))
+					ep->nextpid = USB_PID_ACK;
+
+				/* some bulk protocols terminate OUT transfers
+				 * by a short packet, using ZLPs not padding.
+				 */
+				else if (ep->length < ep->maxpacket
+						|| !(urb->transfer_flags
+							& URB_ZERO_PACKET))
+					urbstat = 0;
+			}
+			break;
+		case USB_PID_IN:
+			// PACKET("...ACK/in_%02x qh%p\n", bank, ep);
+			buf = urb->transfer_buffer + urb->actual_length;
+			prefetchw(buf);
+			len = ep->maxpacket - sl811_read(sl811,
+						bank + SL11H_XFERCNTREG);
+			if (len > ep->length) {
+				len = ep->length;
+				urb->status = -EOVERFLOW;
+			}
+			urb->actual_length += len;
+			sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0),
+					buf, len);
+			usb_dotoggle(udev, ep->epnum, 0);
+			if (urb->actual_length == urb->transfer_buffer_length)
+				urbstat = 0;
+			else if (len < ep->maxpacket) {
+				if (urb->transfer_flags & URB_SHORT_NOT_OK)
+					urbstat = -EREMOTEIO;
+				else
+					urbstat = 0;
+			}
+			if (usb_pipecontrol(urb->pipe)
+					&& (urbstat == -EREMOTEIO
+						|| urbstat == 0)) {
+
+				/* NOTE if the status stage STALLs (why?),
+				 * this reports the wrong urb status.
+				 */
+				spin_lock(&urb->lock);
+				if (urb->status == -EINPROGRESS)
+					urb->status = urbstat;
+				spin_unlock(&urb->lock);
+
+				urb = NULL;
+				ep->nextpid = USB_PID_ACK;
+			}
+			break;
+		case USB_PID_SETUP:
+			// PACKET("...ACK/setup_%02x qh%p\n", bank, ep);
+			if (urb->transfer_buffer_length == urb->actual_length)
+				ep->nextpid = USB_PID_ACK;
+			else if (usb_pipeout(urb->pipe)) {
+				usb_settoggle(udev, 0, 1, 1);
+				ep->nextpid = USB_PID_OUT;
+			} else {
+				usb_settoggle(udev, 0, 0, 1);
+				ep->nextpid = USB_PID_IN;
+			}
+			break;
+		case USB_PID_ACK:
+			// PACKET("...ACK/status_%02x qh%p\n", bank, ep);
+			urbstat = 0;
+			break;
+		}
+
+	/* STALL stops all transfers */
+	} else if (status & SL11H_STATMASK_STALL) {
+		PACKET("...STALL_%02x qh%p\n", bank, ep);
+		ep->nak_count = ep->error_count = 0;
+		urbstat = -EPIPE;
+
+	/* error? retry, until "3 strikes" */
+	} else if (++ep->error_count >= 3) {
+		if (status & SL11H_STATMASK_TMOUT)
+			urbstat = -ETIMEDOUT;
+		else if (status & SL11H_STATMASK_OVF)
+			urbstat = -EOVERFLOW;
+		else
+			urbstat = -EPROTO;
+		ep->error_count = 0;
+		PACKET("...3STRIKES_%02x %02x qh%p stat %d\n",
+				bank, status, ep, urbstat);
+	}
+
+	if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS))
+		finish_request(sl811, ep, urb, regs, urbstat);
+}
+
+static inline u8 checkdone(struct sl811 *sl811)
+{
+	u8	ctl;
+	u8	irqstat = 0;
+
+	if (sl811->active_a && time_before_eq(sl811->jiffies_a, jiffies)) {
+		ctl = sl811_read(sl811, SL811_EP_A(SL11H_HOSTCTLREG));
+		if (ctl & SL11H_HCTLMASK_ARM)
+			sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0);
+		DBG("%s DONE_A: ctrl %02x sts %02x\n",
+			(ctl & SL11H_HCTLMASK_ARM) ? "timeout" : "lost",
+			ctl,
+			sl811_read(sl811, SL811_EP_A(SL11H_PKTSTATREG)));
+		irqstat |= SL11H_INTMASK_DONE_A;
+	}
+#ifdef	USE_B
+	if (sl811->active_b && time_before_eq(sl811->jiffies_b, jiffies)) {
+		ctl = sl811_read(sl811, SL811_EP_B(SL11H_HOSTCTLREG));
+		if (ctl & SL11H_HCTLMASK_ARM)
+			sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0);
+		DBG("%s DONE_B: ctrl %02x sts %02x\n",
+			(ctl & SL11H_HCTLMASK_ARM) ? "timeout" : "lost",
+			ctl,
+			sl811_read(sl811, SL811_EP_B(SL11H_PKTSTATREG)));
+		irqstat |= SL11H_INTMASK_DONE_A;
+	}
+#endif
+	return irqstat;
+}
+
+static irqreturn_t sl811h_irq(struct usb_hcd *hcd, struct pt_regs *regs)
+{
+	struct sl811	*sl811 = hcd_to_sl811(hcd);
+	u8		irqstat;
+	irqreturn_t	ret = IRQ_NONE;
+	unsigned	retries = 5;
+
+	spin_lock(&sl811->lock);
+
+retry:
+	irqstat = sl811_read(sl811, SL11H_IRQ_STATUS) & ~SL11H_INTMASK_DP;
+	if (irqstat) {
+		sl811_write(sl811, SL11H_IRQ_STATUS, irqstat);
+		irqstat &= sl811->irq_enable;
+	}
+
+#ifdef	QUIRK2
+	/* this may no longer be necessary ... */
+	if (irqstat == 0 && ret == IRQ_NONE) {
+		irqstat = checkdone(sl811);
+		if (irqstat /* && irq != ~0 */ )
+			sl811->stat_lost++;
+	}
+#endif
+
+	/* USB packets, not necessarily handled in the order they're
+	 * issued ... that's fine if they're different endpoints.
+	 */
+	if (irqstat & SL11H_INTMASK_DONE_A) {
+		done(sl811, sl811->active_a, SL811_EP_A(SL811_HOST_BUF), regs);
+		sl811->active_a = NULL;
+		sl811->stat_a++;
+	}
+#ifdef USE_B
+	if (irqstat & SL11H_INTMASK_DONE_B) {
+		done(sl811, sl811->active_b, SL811_EP_B(SL811_HOST_BUF), regs);
+		sl811->active_b = NULL;
+		sl811->stat_b++;
+	}
+#endif
+	if (irqstat & SL11H_INTMASK_SOFINTR) {
+		unsigned index;
+
+		index = sl811->frame++ % (PERIODIC_SIZE - 1);
+		sl811->stat_sof++;
+
+		/* be graceful about almost-inevitable periodic schedule
+		 * overruns:  continue the previous frame's transfers iff
+		 * this one has nothing scheduled.
+		 */
+		if (sl811->next_periodic) {
+			// ERR("overrun to slot %d\n", index);
+			sl811->stat_overrun++;
+		}
+		if (sl811->periodic[index])
+			sl811->next_periodic = sl811->periodic[index];
+	}
+
+	/* khubd manages debouncing and wakeup */
+	if (irqstat & SL11H_INTMASK_INSRMV) {
+		sl811->stat_insrmv++;
+
+		/* most stats are reset for each VBUS session */
+		sl811->stat_wake = 0;
+		sl811->stat_sof = 0;
+		sl811->stat_a = 0;
+		sl811->stat_b = 0;
+		sl811->stat_lost = 0;
+
+		sl811->ctrl1 = 0;
+		sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
+
+		sl811->irq_enable = SL11H_INTMASK_INSRMV;
+		sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
+
+		/* usbcore nukes other pending transactions on disconnect */
+		if (sl811->active_a) {
+			sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0);
+			finish_request(sl811, sl811->active_a,
+				container_of(sl811->active_a->hep->urb_list.next,
+					struct urb, urb_list),
+				NULL, -ESHUTDOWN);
+			sl811->active_a = NULL;
+		}
+#ifdef	USE_B
+		if (sl811->active_b) {
+			sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0);
+			finish_request(sl811, sl811->active_b,
+				container_of(sl811->active_b->hep->urb_list.next,
+					struct urb, urb_list),
+				NULL, -ESHUTDOWN);
+			sl811->active_b = NULL;
+		}
+#endif
+
+		/* port status seems wierd until after reset, so
+		 * force the reset and make khubd clean up later.
+		 */
+		sl811->port1 |= (1 << USB_PORT_FEAT_C_CONNECTION)
+				| (1 << USB_PORT_FEAT_CONNECTION);
+
+	} else if (irqstat & SL11H_INTMASK_RD) {
+		if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND)) {
+			DBG("wakeup\n");
+			sl811->port1 |= 1 << USB_PORT_FEAT_C_SUSPEND;
+			sl811->stat_wake++;
+		} else
+			irqstat &= ~SL11H_INTMASK_RD;
+	}
+
+	if (irqstat) {
+		if (sl811->port1 & (1 << USB_PORT_FEAT_ENABLE))
+			start_transfer(sl811);
+		ret = IRQ_HANDLED;
+		if (retries--)
+			goto retry;
+	}
+
+	if (sl811->periodic_count == 0 && list_empty(&sl811->async)) 
+		sofirq_off(sl811);
+	sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
+
+	spin_unlock(&sl811->lock);
+
+	return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* usb 1.1 says max 90% of a frame is available for periodic transfers.
+ * this driver doesn't promise that much since it's got to handle an
+ * IRQ per packet; irq handling latencies also use up that time.
+ */
+#define	MAX_PERIODIC_LOAD	500	/* out of 1000 usec */
+
+static int balance(struct sl811 *sl811, u16 period, u16 load)
+{
+	int	i, branch = -ENOSPC;
+
+	/* search for the least loaded schedule branch of that period
+	 * which has enough bandwidth left unreserved.
+	 */
+	for (i = 0; i < period ; i++) {
+		if (branch < 0 || sl811->load[branch] > sl811->load[i]) {
+			int	j;
+
+			for (j = i; j < PERIODIC_SIZE; j += period) {
+				if ((sl811->load[j] + load)
+						> MAX_PERIODIC_LOAD)
+					break;
+			}
+			if (j < PERIODIC_SIZE)
+				continue;
+			branch = i; 
+		}
+	}
+	return branch;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int sl811h_urb_enqueue(
+	struct usb_hcd		*hcd,
+	struct usb_host_endpoint *hep,
+	struct urb		*urb,
+	int			mem_flags
+) {
+	struct sl811		*sl811 = hcd_to_sl811(hcd);
+	struct usb_device	*udev = urb->dev;
+	unsigned int		pipe = urb->pipe;
+	int			is_out = !usb_pipein(pipe);
+	int			type = usb_pipetype(pipe);
+	int			epnum = usb_pipeendpoint(pipe);
+	struct sl811h_ep	*ep = NULL;
+	unsigned long		flags;
+	int			i;
+	int			retval = 0;
+
+#ifdef	DISABLE_ISO
+	if (type == PIPE_ISOCHRONOUS)
+		return -ENOSPC;
+#endif
+
+	/* avoid all allocations within spinlocks */
+	if (!hep->hcpriv)
+		ep = kcalloc(1, sizeof *ep, mem_flags);
+
+	spin_lock_irqsave(&sl811->lock, flags);
+
+	/* don't submit to a dead or disabled port */
+	if (!(sl811->port1 & (1 << USB_PORT_FEAT_ENABLE))
+			|| !HC_IS_RUNNING(hcd->state)) {
+		retval = -ENODEV;
+		goto fail;
+	}
+
+	if (hep->hcpriv) {
+		kfree(ep);
+		ep = hep->hcpriv;
+	} else if (!ep) {
+		retval = -ENOMEM;
+		goto fail;
+
+	} else {
+		INIT_LIST_HEAD(&ep->schedule);
+		ep->udev = usb_get_dev(udev);
+		ep->epnum = epnum;
+		ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out);
+		ep->defctrl = SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENABLE;
+		usb_settoggle(udev, epnum, is_out, 0);
+
+		if (type == PIPE_CONTROL)
+			ep->nextpid = USB_PID_SETUP;
+		else if (is_out)
+			ep->nextpid = USB_PID_OUT;
+		else
+			ep->nextpid = USB_PID_IN;
+
+		if (ep->maxpacket > H_MAXPACKET) {
+			/* iso packets up to 240 bytes could work... */
+			DBG("dev %d ep%d maxpacket %d\n",
+				udev->devnum, epnum, ep->maxpacket);
+			retval = -EINVAL;
+			goto fail;
+		}
+
+		if (udev->speed == USB_SPEED_LOW) {
+			/* send preamble for external hub? */
+			if (!(sl811->ctrl1 & SL11H_CTL1MASK_LSPD))
+				ep->defctrl |= SL11H_HCTLMASK_PREAMBLE;
+		}
+		switch (type) {
+		case PIPE_ISOCHRONOUS:
+		case PIPE_INTERRUPT:
+			if (urb->interval > PERIODIC_SIZE)
+				urb->interval = PERIODIC_SIZE;
+			ep->period = urb->interval;
+			ep->branch = PERIODIC_SIZE;
+			if (type == PIPE_ISOCHRONOUS)
+				ep->defctrl |= SL11H_HCTLMASK_ISOCH;
+			ep->load = usb_calc_bus_time(udev->speed, !is_out,
+				(type == PIPE_ISOCHRONOUS),
+				usb_maxpacket(udev, pipe, is_out))
+					/ 1000;
+			break;
+		}
+
+		hep->hcpriv = ep;
+	}
+
+	/* maybe put endpoint into schedule */
+	switch (type) {
+	case PIPE_CONTROL:
+	case PIPE_BULK:
+		if (list_empty(&ep->schedule))
+			list_add_tail(&ep->schedule, &sl811->async);
+		break;
+	case PIPE_ISOCHRONOUS:
+	case PIPE_INTERRUPT:
+		urb->interval = ep->period;
+		if (ep->branch < PERIODIC_SIZE)
+			break;
+
+		retval = balance(sl811, ep->period, ep->load);
+		if (retval < 0)
+			goto fail;
+		ep->branch = retval;
+		retval = 0;
+		urb->start_frame = (sl811->frame & (PERIODIC_SIZE - 1))
+					+ ep->branch;
+
+		/* sort each schedule branch by period (slow before fast)
+		 * to share the faster parts of the tree without needing
+		 * dummy/placeholder nodes
+		 */
+		DBG("schedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+		for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
+			struct sl811h_ep	**prev = &sl811->periodic[i];
+			struct sl811h_ep	*here = *prev;
+
+			while (here && ep != here) {
+				if (ep->period > here->period)
+					break;
+				prev = &here->next;
+				here = *prev;
+			}
+			if (ep != here) {
+				ep->next = here;
+				*prev = ep;
+			}
+			sl811->load[i] += ep->load;
+		}
+		sl811->periodic_count++;
+		hcd->self.bandwidth_allocated += ep->load / ep->period;
+		sofirq_on(sl811);
+	}
+
+	/* in case of unlink-during-submit */
+	spin_lock(&urb->lock);
+	if (urb->status != -EINPROGRESS) {
+		spin_unlock(&urb->lock);
+		finish_request(sl811, ep, urb, NULL, 0);
+		retval = 0;
+		goto fail;
+	}
+	urb->hcpriv = hep;
+	spin_unlock(&urb->lock);
+
+	start_transfer(sl811);
+	sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
+fail:
+	spin_unlock_irqrestore(&sl811->lock, flags);
+	return retval;
+}
+
+static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+{
+	struct sl811		*sl811 = hcd_to_sl811(hcd);
+	struct usb_host_endpoint *hep = urb->hcpriv;
+	unsigned long		flags;
+	struct sl811h_ep	*ep;
+	int			retval = 0;
+
+	if (!hep)
+		return -EINVAL;
+
+	spin_lock_irqsave(&sl811->lock, flags);
+	ep = hep->hcpriv;
+	if (ep) {
+		/* finish right away if this urb can't be active ...
+		 * note that some drivers wrongly expect delays
+		 */
+		if (ep->hep->urb_list.next != &urb->urb_list) {
+			/* not front of queue?  never active */
+
+		/* for active transfers, we expect an IRQ */
+		} else if (sl811->active_a == ep) {
+			if (time_before_eq(sl811->jiffies_a, jiffies)) {
+				/* happens a lot with lowspeed?? */
+				DBG("giveup on DONE_A: ctrl %02x sts %02x\n",
+					sl811_read(sl811,
+						SL811_EP_A(SL11H_HOSTCTLREG)),
+					sl811_read(sl811,
+						SL811_EP_A(SL11H_PKTSTATREG)));
+				sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG),
+						0);
+				sl811->active_a = NULL;
+			} else
+				urb = NULL;
+#ifdef	USE_B
+		} else if (sl811->active_b == ep) {
+			if (time_before_eq(sl811->jiffies_a, jiffies)) {
+				/* happens a lot with lowspeed?? */
+				DBG("giveup on DONE_B: ctrl %02x sts %02x\n",
+					sl811_read(sl811,
+						SL811_EP_B(SL11H_HOSTCTLREG)),
+					sl811_read(sl811,
+						SL811_EP_B(SL11H_PKTSTATREG)));
+				sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG),
+						0);
+				sl811->active_b = NULL;
+			} else
+				urb = NULL;
+#endif
+		} else {
+			/* front of queue for inactive endpoint */
+		}
+
+		if (urb)
+			finish_request(sl811, ep, urb, NULL, 0);
+		else
+			VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
+				(sl811->active_a == ep) ? "A" : "B");
+	} else
+		retval = -EINVAL;
+	spin_unlock_irqrestore(&sl811->lock, flags);
+	return retval;
+}
+
+static void
+sl811h_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
+{
+	struct sl811h_ep	*ep = hep->hcpriv;
+
+	if (!ep)
+		return;
+
+	/* assume we'd just wait for the irq */
+	if (!list_empty(&hep->urb_list))
+		msleep(3);
+	if (!list_empty(&hep->urb_list))
+		WARN("ep %p not empty?\n", ep);
+
+	usb_put_dev(ep->udev);
+	kfree(ep);
+	hep->hcpriv = NULL;
+}
+
+static int
+sl811h_get_frame(struct usb_hcd *hcd)
+{
+	struct sl811 *sl811 = hcd_to_sl811(hcd);
+
+	/* wrong except while periodic transfers are scheduled;
+	 * never matches the on-the-wire frame;
+	 * subject to overruns.
+	 */
+	return sl811->frame;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* the virtual root hub timer IRQ checks for hub status */
+static int
+sl811h_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+	struct sl811 *sl811 = hcd_to_sl811(hcd);
+#ifdef	QUIRK3
+	unsigned long flags;
+
+	/* non-SMP HACK: use root hub timer as i/o watchdog
+	 * this seems essential when SOF IRQs aren't in use...
+	 */
+	local_irq_save(flags);
+	if (!timer_pending(&sl811->timer)) {
+		if (sl811h_irq( /* ~0, */ hcd, NULL) != IRQ_NONE)
+			sl811->stat_lost++;
+	}
+	local_irq_restore(flags);
+#endif
+
+	if (!(sl811->port1 & (0xffff << 16)))
+		return 0;
+
+	/* tell khubd port 1 changed */
+	*buf = (1 << 1);
+	return 1;
+}
+
+static void
+sl811h_hub_descriptor (
+	struct sl811			*sl811,
+	struct usb_hub_descriptor	*desc
+) {
+	u16		temp = 0;
+
+	desc->bDescriptorType = 0x29;
+	desc->bHubContrCurrent = 0;
+
+	desc->bNbrPorts = 1;
+	desc->bDescLength = 9;
+
+	/* per-port power switching (gang of one!), or none */
+	desc->bPwrOn2PwrGood = 0;
+	if (sl811->board && sl811->board->port_power) {
+		desc->bPwrOn2PwrGood = sl811->board->potpg;
+		if (!desc->bPwrOn2PwrGood)
+			desc->bPwrOn2PwrGood = 10;
+		temp = 0x0001;
+	} else
+		temp = 0x0002;
+
+	/* no overcurrent errors detection/handling */
+	temp |= 0x0010;
+
+	desc->wHubCharacteristics = (__force __u16)cpu_to_le16(temp);
+
+	/* two bitmaps:  ports removable, and legacy PortPwrCtrlMask */
+	desc->bitmap[0] = 1 << 1;
+	desc->bitmap[1] = ~0;
+}
+
+static void
+sl811h_timer(unsigned long _sl811)
+{
+	struct sl811 	*sl811 = (void *) _sl811;
+	unsigned long	flags;
+	u8		irqstat;
+	u8		signaling = sl811->ctrl1 & SL11H_CTL1MASK_FORCE;
+	const u32	mask = (1 << USB_PORT_FEAT_CONNECTION)
+				| (1 << USB_PORT_FEAT_ENABLE)
+				| (1 << USB_PORT_FEAT_LOWSPEED);
+
+	spin_lock_irqsave(&sl811->lock, flags);
+
+	/* stop special signaling */
+	sl811->ctrl1 &= ~SL11H_CTL1MASK_FORCE;
+	sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
+	udelay(3);
+
+	irqstat = sl811_read(sl811, SL11H_IRQ_STATUS);
+
+	switch (signaling) {
+	case SL11H_CTL1MASK_SE0:
+		DBG("end reset\n");
+		sl811->port1 = (1 << USB_PORT_FEAT_C_RESET)
+				| (1 << USB_PORT_FEAT_POWER);
+		sl811->ctrl1 = 0;
+		/* don't wrongly ack RD */
+		if (irqstat & SL11H_INTMASK_INSRMV)
+			irqstat &= ~SL11H_INTMASK_RD;
+		break;
+	case SL11H_CTL1MASK_K:
+		DBG("end resume\n");
+		sl811->port1 &= ~(1 << USB_PORT_FEAT_SUSPEND);
+		break;
+	default:
+		DBG("odd timer signaling: %02x\n", signaling);
+		break;
+	}
+	sl811_write(sl811, SL11H_IRQ_STATUS, irqstat);
+
+	if (irqstat & SL11H_INTMASK_RD) {
+		/* usbcore nukes all pending transactions on disconnect */
+		if (sl811->port1 & (1 << USB_PORT_FEAT_CONNECTION))
+			sl811->port1 |= (1 << USB_PORT_FEAT_C_CONNECTION)
+					| (1 << USB_PORT_FEAT_C_ENABLE);
+		sl811->port1 &= ~mask;
+		sl811->irq_enable = SL11H_INTMASK_INSRMV;
+	} else {
+		sl811->port1 |= mask;
+		if (irqstat & SL11H_INTMASK_DP)
+			sl811->port1 &= ~(1 << USB_PORT_FEAT_LOWSPEED);
+		sl811->irq_enable = SL11H_INTMASK_INSRMV | SL11H_INTMASK_RD;
+	}
+
+	if (sl811->port1 & (1 << USB_PORT_FEAT_CONNECTION)) {
+		u8	ctrl2 = SL811HS_CTL2_INIT;
+
+		sl811->irq_enable |= SL11H_INTMASK_DONE_A;
+#ifdef USE_B
+		sl811->irq_enable |= SL11H_INTMASK_DONE_B;
+#endif
+		if (sl811->port1 & (1 << USB_PORT_FEAT_LOWSPEED)) {
+			sl811->ctrl1 |= SL11H_CTL1MASK_LSPD;
+			ctrl2 |= SL811HS_CTL2MASK_DSWAP;
+		}
+
+		/* start SOFs flowing, kickstarting with A registers */
+		sl811->ctrl1 |= SL11H_CTL1MASK_SOF_ENA;
+		sl811_write(sl811, SL11H_SOFLOWREG, 0xe0);
+		sl811_write(sl811, SL811HS_CTLREG2, ctrl2);
+
+		/* autoincrementing */
+		sl811_write(sl811, SL811_EP_A(SL11H_BUFLNTHREG), 0);
+		writeb(SL_SOF, sl811->data_reg);
+		writeb(0, sl811->data_reg);
+		sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG),
+				SL11H_HCTLMASK_ARM);
+
+		/* khubd provides debounce delay */
+	} else {
+		sl811->ctrl1 = 0;
+	}
+	sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
+
+	/* reenable irqs */
+	sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
+	spin_unlock_irqrestore(&sl811->lock, flags);
+}
+
+static int
+sl811h_hub_control(
+	struct usb_hcd	*hcd,
+	u16		typeReq,
+	u16		wValue,
+	u16		wIndex,
+	char		*buf,
+	u16		wLength
+) {
+	struct sl811	*sl811 = hcd_to_sl811(hcd);
+	int		retval = 0;
+	unsigned long	flags;
+
+	spin_lock_irqsave(&sl811->lock, flags);
+
+	switch (typeReq) {
+	case ClearHubFeature:
+	case SetHubFeature:
+		switch (wValue) {
+		case C_HUB_OVER_CURRENT:
+		case C_HUB_LOCAL_POWER:
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case ClearPortFeature:
+		if (wIndex != 1 || wLength != 0)
+			goto error;
+
+		switch (wValue) {
+		case USB_PORT_FEAT_ENABLE:
+			sl811->port1 &= (1 << USB_PORT_FEAT_POWER);
+			sl811->ctrl1 = 0;
+			sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
+			sl811->irq_enable = SL11H_INTMASK_INSRMV;
+			sl811_write(sl811, SL11H_IRQ_ENABLE,
+						sl811->irq_enable);
+			break;
+		case USB_PORT_FEAT_SUSPEND:
+			if (!(sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND)))
+				break;
+
+			/* 20 msec of resume/K signaling, other irqs blocked */
+			DBG("start resume...\n");
+			sl811->irq_enable = 0;
+			sl811_write(sl811, SL11H_IRQ_ENABLE,
+						sl811->irq_enable);
+			sl811->ctrl1 |= SL11H_CTL1MASK_K;
+			sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
+
+			mod_timer(&sl811->timer, jiffies
+					+ msecs_to_jiffies(20));
+			break;
+		case USB_PORT_FEAT_POWER:
+			port_power(sl811, 0);
+			break;
+		case USB_PORT_FEAT_C_ENABLE:
+		case USB_PORT_FEAT_C_SUSPEND:
+		case USB_PORT_FEAT_C_CONNECTION:
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+		case USB_PORT_FEAT_C_RESET:
+			break;
+		default:
+			goto error;
+		}
+		sl811->port1 &= ~(1 << wValue);
+		break;
+	case GetHubDescriptor:
+		sl811h_hub_descriptor(sl811, (struct usb_hub_descriptor *) buf);
+		break;
+	case GetHubStatus:
+		*(__le32 *) buf = cpu_to_le32(0);
+		break;
+	case GetPortStatus:
+		if (wIndex != 1)
+			goto error;
+		*(__le32 *) buf = cpu_to_le32(sl811->port1);
+
+#ifndef	VERBOSE
+	if (*(u16*)(buf+2))	/* only if wPortChange is interesting */
+#endif
+		DBG("GetPortStatus %08x\n", sl811->port1);
+		break;
+	case SetPortFeature:
+		if (wIndex != 1 || wLength != 0)
+			goto error;
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			if (sl811->port1 & (1 << USB_PORT_FEAT_RESET))
+				goto error;
+			if (!(sl811->port1 & (1 << USB_PORT_FEAT_ENABLE)))
+				goto error;
+
+			DBG("suspend...\n");
+			sl811->ctrl1 &= ~SL11H_CTL1MASK_SOF_ENA;
+			sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
+			break;
+		case USB_PORT_FEAT_POWER:
+			port_power(sl811, 1);
+			break;
+		case USB_PORT_FEAT_RESET:
+			if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND))
+				goto error;
+			if (!(sl811->port1 & (1 << USB_PORT_FEAT_POWER)))
+				break;
+
+			/* 50 msec of reset/SE0 signaling, irqs blocked */
+			sl811->irq_enable = 0;
+			sl811_write(sl811, SL11H_IRQ_ENABLE,
+						sl811->irq_enable);
+			sl811->ctrl1 = SL11H_CTL1MASK_SE0;
+			sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
+			sl811->port1 |= (1 << USB_PORT_FEAT_RESET);
+			mod_timer(&sl811->timer, jiffies
+					+ msecs_to_jiffies(50));
+			break;
+		default:
+			goto error;
+		}
+		sl811->port1 |= 1 << wValue;
+		break;
+
+	default:
+error:
+		/* "protocol stall" on error */
+		retval = -EPIPE;
+	}
+
+	spin_unlock_irqrestore(&sl811->lock, flags);
+	return retval;
+}
+
+#ifdef	CONFIG_PM
+
+static int
+sl811h_hub_suspend(struct usb_hcd *hcd)
+{
+	// SOFs off
+	DBG("%s\n", __FUNCTION__);
+	return 0;
+}
+
+static int
+sl811h_hub_resume(struct usb_hcd *hcd)
+{
+	// SOFs on
+	DBG("%s\n", __FUNCTION__);
+	return 0;
+}
+
+#else
+
+#define	sl811h_hub_suspend	NULL
+#define	sl811h_hub_resume	NULL
+
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef STUB_DEBUG_FILE
+
+static inline void create_debug_file(struct sl811 *sl811) { }
+static inline void remove_debug_file(struct sl811 *sl811) { }
+
+#else
+
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+static void dump_irq(struct seq_file *s, char *label, u8 mask)
+{
+	seq_printf(s, "%s %02x%s%s%s%s%s%s\n", label, mask,
+		(mask & SL11H_INTMASK_DONE_A) ? " done_a" : "",
+		(mask & SL11H_INTMASK_DONE_B) ? " done_b" : "",
+		(mask & SL11H_INTMASK_SOFINTR) ? " sof" : "",
+		(mask & SL11H_INTMASK_INSRMV) ? " ins/rmv" : "",
+		(mask & SL11H_INTMASK_RD) ? " rd" : "",
+		(mask & SL11H_INTMASK_DP) ? " dp" : "");
+}
+
+static int proc_sl811h_show(struct seq_file *s, void *unused)
+{
+	struct sl811		*sl811 = s->private;
+	struct sl811h_ep	*ep;
+	unsigned		i;
+
+	seq_printf(s, "%s\n%s version %s\nportstatus[1] = %08x\n",
+		sl811_to_hcd(sl811)->product_desc,
+		hcd_name, DRIVER_VERSION,
+		sl811->port1);
+
+	seq_printf(s, "insert/remove: %ld\n", sl811->stat_insrmv);
+	seq_printf(s, "current session:  done_a %ld done_b %ld "
+			"wake %ld sof %ld overrun %ld lost %ld\n\n",
+		sl811->stat_a, sl811->stat_b,
+		sl811->stat_wake, sl811->stat_sof,
+		sl811->stat_overrun, sl811->stat_lost);
+
+	spin_lock_irq(&sl811->lock);
+
+	if (sl811->ctrl1 & SL11H_CTL1MASK_SUSPEND)
+		seq_printf(s, "(suspended)\n\n");
+	else {
+		u8	t = sl811_read(sl811, SL11H_CTLREG1);
+
+		seq_printf(s, "ctrl1 %02x%s%s%s%s\n", t,
+			(t & SL11H_CTL1MASK_SOF_ENA) ? " sofgen" : "",
+			({char *s; switch (t & SL11H_CTL1MASK_FORCE) {
+			case SL11H_CTL1MASK_NORMAL: s = ""; break;
+			case SL11H_CTL1MASK_SE0: s = " se0/reset"; break;
+			case SL11H_CTL1MASK_K: s = " k/resume"; break;
+			default: s = "j"; break;
+			}; s; }),
+			(t & SL11H_CTL1MASK_LSPD) ? " lowspeed" : "",
+			(t & SL11H_CTL1MASK_SUSPEND) ? " suspend" : "");
+
+		dump_irq(s, "irq_enable",
+				sl811_read(sl811, SL11H_IRQ_ENABLE));
+		dump_irq(s, "irq_status",
+				sl811_read(sl811, SL11H_IRQ_STATUS));
+		seq_printf(s, "frame clocks remaining:  %d\n",
+				sl811_read(sl811, SL11H_SOFTMRREG) << 6);
+	}
+
+	seq_printf(s, "A: qh%p ctl %02x sts %02x\n", sl811->active_a,
+		sl811_read(sl811, SL811_EP_A(SL11H_HOSTCTLREG)),
+		sl811_read(sl811, SL811_EP_A(SL11H_PKTSTATREG)));
+	seq_printf(s, "B: qh%p ctl %02x sts %02x\n", sl811->active_b,
+		sl811_read(sl811, SL811_EP_B(SL11H_HOSTCTLREG)),
+		sl811_read(sl811, SL811_EP_B(SL11H_PKTSTATREG)));
+	seq_printf(s, "\n");
+	list_for_each_entry (ep, &sl811->async, schedule) {
+		struct urb		*urb;
+
+		seq_printf(s, "%s%sqh%p, ep%d%s, maxpacket %d"
+					" nak %d err %d\n",
+			(ep == sl811->active_a) ? "(A) " : "",
+			(ep == sl811->active_b) ? "(B) " : "",
+			ep, ep->epnum,
+			({ char *s; switch (ep->nextpid) {
+			case USB_PID_IN: s = "in"; break;
+			case USB_PID_OUT: s = "out"; break;
+			case USB_PID_SETUP: s = "setup"; break;
+			case USB_PID_ACK: s = "status"; break;
+			default: s = "?"; break;
+			}; s;}),
+			ep->maxpacket,
+			ep->nak_count, ep->error_count);
+		list_for_each_entry (urb, &ep->hep->urb_list, urb_list) {
+			seq_printf(s, "  urb%p, %d/%d\n", urb,
+				urb->actual_length,
+				urb->transfer_buffer_length);
+		}
+	}
+	if (!list_empty(&sl811->async))
+		seq_printf(s, "\n");
+
+	seq_printf(s, "periodic size= %d\n", PERIODIC_SIZE);
+
+	for (i = 0; i < PERIODIC_SIZE; i++) {
+		ep = sl811->periodic[i];
+		if (!ep)
+			continue;
+		seq_printf(s, "%2d [%3d]:\n", i, sl811->load[i]);
+
+		/* DUMB: prints shared entries multiple times */
+		do {
+			seq_printf(s,
+				"   %s%sqh%d/%p (%sdev%d ep%d%s max %d) "
+					"err %d\n",
+				(ep == sl811->active_a) ? "(A) " : "",
+				(ep == sl811->active_b) ? "(B) " : "",
+				ep->period, ep,
+				(ep->udev->speed == USB_SPEED_FULL)
+					? "" : "ls ",
+				ep->udev->devnum, ep->epnum,
+				(ep->epnum == 0) ? ""
+					: ((ep->nextpid == USB_PID_IN)
+						? "in"
+						: "out"),
+				ep->maxpacket, ep->error_count);
+			ep = ep->next;
+		} while (ep);
+	}
+
+	spin_unlock_irq(&sl811->lock);
+	seq_printf(s, "\n");
+
+	return 0;
+}
+
+static int proc_sl811h_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, proc_sl811h_show, PDE(inode)->data);
+}
+
+static struct file_operations proc_ops = {
+	.open		= proc_sl811h_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+/* expect just one sl811 per system */
+static const char proc_filename[] = "driver/sl811h";
+
+static void create_debug_file(struct sl811 *sl811)
+{
+	struct proc_dir_entry *pde;
+
+	pde = create_proc_entry(proc_filename, 0, NULL);
+	if (pde == NULL)
+		return;
+
+	pde->proc_fops = &proc_ops;
+	pde->data = sl811;
+	sl811->pde = pde;
+}
+
+static void remove_debug_file(struct sl811 *sl811)
+{
+	if (sl811->pde)
+		remove_proc_entry(proc_filename, NULL);
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static void
+sl811h_stop(struct usb_hcd *hcd)
+{
+	struct sl811	*sl811 = hcd_to_sl811(hcd);
+	unsigned long	flags;
+
+	del_timer_sync(&hcd->rh_timer);
+
+	spin_lock_irqsave(&sl811->lock, flags);
+	port_power(sl811, 0);
+	spin_unlock_irqrestore(&sl811->lock, flags);
+}
+
+static int
+sl811h_start(struct usb_hcd *hcd)
+{
+	struct sl811		*sl811 = hcd_to_sl811(hcd);
+	struct usb_device	*udev;
+
+	/* chip has been reset, VBUS power is off */
+
+	udev = usb_alloc_dev(NULL, &hcd->self, 0);
+	if (!udev)
+		return -ENOMEM;
+
+	udev->speed = USB_SPEED_FULL;
+	hcd->state = HC_STATE_RUNNING;
+
+	if (sl811->board)
+		hcd->can_wakeup = sl811->board->can_wakeup;
+
+	if (usb_hcd_register_root_hub(udev, hcd) != 0) {
+		usb_put_dev(udev);
+		sl811h_stop(hcd);
+		return -ENODEV;
+	}
+
+	if (sl811->board && sl811->board->power)
+		hub_set_power_budget(udev, sl811->board->power * 2);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct hc_driver sl811h_hc_driver = {
+	.description =		hcd_name,
+	.hcd_priv_size =	sizeof(struct sl811),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			sl811h_irq,
+	.flags =		HCD_USB11 | HCD_MEMORY,
+
+	/* Basic lifecycle operations */
+	.start =		sl811h_start,
+	.stop =			sl811h_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		sl811h_urb_enqueue,
+	.urb_dequeue =		sl811h_urb_dequeue,
+	.endpoint_disable =	sl811h_endpoint_disable,
+
+	/*
+	 * periodic schedule support
+	 */
+	.get_frame_number =	sl811h_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	sl811h_hub_status_data,
+	.hub_control =		sl811h_hub_control,
+	.hub_suspend =		sl811h_hub_suspend,
+	.hub_resume =		sl811h_hub_resume,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init_or_module
+sl811h_remove(struct device *dev)
+{
+	struct usb_hcd		*hcd = dev_get_drvdata(dev);
+	struct sl811		*sl811 = hcd_to_sl811(hcd);
+	struct platform_device	*pdev;
+	struct resource		*res;
+
+	pdev = container_of(dev, struct platform_device, dev);
+
+	remove_debug_file(sl811);
+	usb_remove_hcd(hcd);
+
+	iounmap(sl811->data_reg);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	release_mem_region(res->start, 1);
+
+	iounmap(sl811->addr_reg);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(res->start, 1);
+
+	usb_put_hcd(hcd);
+	return 0;
+}
+
+#define resource_len(r) (((r)->end - (r)->start) + 1)
+
+static int __init
+sl811h_probe(struct device *dev)
+{
+	struct usb_hcd		*hcd;
+	struct sl811		*sl811;
+	struct platform_device	*pdev;
+	struct resource		*addr, *data;
+	int			irq;
+	void __iomem		*addr_reg;
+	void __iomem		*data_reg;
+	int			retval;
+	u8			tmp;
+
+	/* basic sanity checks first.  board-specific init logic should
+	 * have initialized these three resources and probably board
+	 * specific platform_data.  we don't probe for IRQs, and do only
+	 * minimal sanity checking.
+	 */
+	pdev = container_of(dev, struct platform_device, dev);
+	if (pdev->num_resources < 3)
+		return -ENODEV;
+
+	addr = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	data = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	irq = platform_get_irq(pdev, 0);
+	if (!addr || !data || irq < 0)
+		return -ENODEV;
+
+	/* refuse to confuse usbcore */
+	if (dev->dma_mask) {
+		DBG("no we won't dma\n");
+		return -EINVAL;
+	}
+
+	if (!request_mem_region(addr->start, 1, hcd_name)) {
+		retval = -EBUSY;
+		goto err1;
+	}
+	addr_reg = ioremap(addr->start, resource_len(addr));
+	if (addr_reg == NULL) {
+		retval = -ENOMEM;
+		goto err2;
+	}
+
+	if (!request_mem_region(data->start, 1, hcd_name)) {
+		retval = -EBUSY;
+		goto err3;
+	}
+	data_reg = ioremap(data->start, resource_len(addr));
+	if (data_reg == NULL) {
+		retval = -ENOMEM;
+		goto err4;
+	}
+
+	/* allocate and initialize hcd */
+	hcd = usb_create_hcd(&sl811h_hc_driver, dev, dev->bus_id);
+	if (!hcd) {
+		retval = -ENOMEM;
+		goto err5;
+	}
+	hcd->rsrc_start = addr->start;
+	sl811 = hcd_to_sl811(hcd);
+
+	spin_lock_init(&sl811->lock);
+	INIT_LIST_HEAD(&sl811->async);
+	sl811->board = dev->platform_data;
+	init_timer(&sl811->timer);
+	sl811->timer.function = sl811h_timer;
+	sl811->timer.data = (unsigned long) sl811;
+	sl811->addr_reg = addr_reg;
+	sl811->data_reg = data_reg;
+
+	spin_lock_irq(&sl811->lock);
+	port_power(sl811, 0);
+	spin_unlock_irq(&sl811->lock);
+	msleep(200);
+
+	tmp = sl811_read(sl811, SL11H_HWREVREG);
+	switch (tmp >> 4) {
+	case 1:
+		hcd->product_desc = "SL811HS v1.2";
+		break;
+	case 2:
+		hcd->product_desc = "SL811HS v1.5";
+		break;
+	default:
+		/* reject case 0, SL11S is less functional */
+		DBG("chiprev %02x\n", tmp);
+		retval = -ENXIO;
+		goto err6;
+	}
+
+	/* sl811s would need a different handler for this irq */
+#ifdef	CONFIG_ARM
+	/* Cypress docs say the IRQ is IRQT_HIGH ... */
+	set_irq_type(irq, IRQT_RISING);
+#endif
+	retval = usb_add_hcd(hcd, irq, SA_INTERRUPT);
+	if (retval != 0)
+		goto err6;
+
+	create_debug_file(sl811);
+	return retval;
+
+ err6:
+	usb_put_hcd(hcd);
+ err5:
+	iounmap(data_reg);
+ err4:
+	release_mem_region(data->start, 1);
+ err3:
+	iounmap(addr_reg);
+ err2:
+	release_mem_region(addr->start, 1);
+ err1:
+	DBG("init error, %d\n", retval);
+	return retval;
+}
+
+#ifdef	CONFIG_PM
+
+/* for this device there's no useful distinction between the controller
+ * and its root hub, except that the root hub only gets direct PM calls 
+ * when CONFIG_USB_SUSPEND is enabled.
+ */
+
+static int
+sl811h_suspend(struct device *dev, pm_message_t state, u32 phase)
+{
+	struct usb_hcd	*hcd = dev_get_drvdata(dev);
+	struct sl811	*sl811 = hcd_to_sl811(hcd);
+	int		retval = 0;
+
+	if (phase != SUSPEND_POWER_DOWN)
+		return retval;
+
+	if (state <= PM_SUSPEND_MEM)
+		retval = sl811h_hub_suspend(hcd);
+	else
+		port_power(sl811, 0);
+	if (retval == 0)
+		dev->power.power_state = state;
+	return retval;
+}
+
+static int
+sl811h_resume(struct device *dev, u32 phase)
+{
+	struct usb_hcd	*hcd = dev_get_drvdata(dev);
+	struct sl811	*sl811 = hcd_to_sl811(hcd);
+
+	if (phase != RESUME_POWER_ON)
+		return 0;
+
+	/* with no "check to see if VBUS is still powered" board hook,
+	 * let's assume it'd only be powered to enable remote wakeup.
+	 */
+	if (dev->power.power_state > PM_SUSPEND_MEM
+			|| !hcd->can_wakeup) {
+		sl811->port1 = 0;
+		port_power(sl811, 1);
+		return 0;
+	}
+
+	dev->power.power_state = PMSG_ON;
+	return sl811h_hub_resume(hcd);
+}
+
+#else
+
+#define	sl811h_suspend	NULL
+#define	sl811h_resume	NULL
+
+#endif
+
+
+static struct device_driver sl811h_driver = {
+	.name =		(char *) hcd_name,
+	.bus =		&platform_bus_type,
+
+	.probe =	sl811h_probe,
+	.remove =	sl811h_remove,
+
+	.suspend =	sl811h_suspend,
+	.resume =	sl811h_resume,
+};
+
+/*-------------------------------------------------------------------------*/
+ 
+static int __init sl811h_init(void) 
+{
+	if (usb_disabled())
+		return -ENODEV;
+
+	INFO("driver %s, %s\n", hcd_name, DRIVER_VERSION);
+	return driver_register(&sl811h_driver);
+}
+module_init(sl811h_init);
+
+static void __exit sl811h_cleanup(void) 
+{	
+	driver_unregister(&sl811h_driver);
+}
+module_exit(sl811h_cleanup);
diff --git a/drivers/usb/host/sl811.h b/drivers/usb/host/sl811.h
new file mode 100644
index 0000000..7690d98
--- /dev/null
+++ b/drivers/usb/host/sl811.h
@@ -0,0 +1,266 @@
+/*
+ * SL811HS register declarations and HCD data structures
+ *
+ * Copyright (C) 2004 Psion Teklogix
+ * Copyright (C) 2004 David Brownell
+ * Copyright (C) 2001 Cypress Semiconductor Inc. 
+ */
+
+/*
+ * SL811HS has transfer registers, and control registers.  In host/master
+ * mode one set of registers is used; in peripheral/slave mode, another.
+ *  - SL11H only has some "A" transfer registers from 0x00-0x04
+ *  - SL811HS also has "B" registers from 0x08-0x0c
+ *  - SL811S (or HS in slave mode) has four A+B sets, at 00, 10, 20, 30
+ */
+
+#define SL811_EP_A(base)	((base) + 0)
+#define SL811_EP_B(base)	((base) + 8)
+
+#define SL811_HOST_BUF		0x00
+#define SL811_PERIPH_EP0	0x00
+#define SL811_PERIPH_EP1	0x10
+#define SL811_PERIPH_EP2	0x20
+#define SL811_PERIPH_EP3	0x30
+
+
+/* TRANSFER REGISTERS:  host and peripheral sides are similar
+ * except for the control models (master vs slave).
+ */
+#define SL11H_HOSTCTLREG	0
+#	define SL11H_HCTLMASK_ARM	0x01
+#	define SL11H_HCTLMASK_ENABLE	0x02
+#	define SL11H_HCTLMASK_IN	0x00
+#	define SL11H_HCTLMASK_OUT	0x04
+#	define SL11H_HCTLMASK_ISOCH	0x10
+#	define SL11H_HCTLMASK_AFTERSOF	0x20
+#	define SL11H_HCTLMASK_TOGGLE	0x40
+#	define SL11H_HCTLMASK_PREAMBLE	0x80
+#define SL11H_BUFADDRREG	1
+#define SL11H_BUFLNTHREG	2
+#define SL11H_PKTSTATREG	3	/* read */
+#	define SL11H_STATMASK_ACK	0x01
+#	define SL11H_STATMASK_ERROR	0x02
+#	define SL11H_STATMASK_TMOUT	0x04
+#	define SL11H_STATMASK_SEQ	0x08
+#	define SL11H_STATMASK_SETUP	0x10
+#	define SL11H_STATMASK_OVF	0x20
+#	define SL11H_STATMASK_NAK	0x40
+#	define SL11H_STATMASK_STALL	0x80
+#define SL11H_PIDEPREG		3	/* write */
+#	define	SL_SETUP	0xd0
+#	define	SL_IN		0x90
+#	define	SL_OUT		0x10
+#	define	SL_SOF		0x50
+#	define	SL_PREAMBLE	0xc0
+#	define	SL_NAK		0xa0
+#	define	SL_STALL	0xe0
+#	define	SL_DATA0	0x30
+#	define	SL_DATA1	0xb0
+#define SL11H_XFERCNTREG	4	/* read */
+#define SL11H_DEVADDRREG	4	/* write */
+
+
+/* CONTROL REGISTERS:  host and peripheral are very different.
+ */
+#define SL11H_CTLREG1		5
+#	define SL11H_CTL1MASK_SOF_ENA	0x01
+#	define SL11H_CTL1MASK_FORCE	0x18
+#		define SL11H_CTL1MASK_NORMAL	0x00
+#		define SL11H_CTL1MASK_SE0	0x08	/* reset */
+#		define SL11H_CTL1MASK_J		0x10
+#		define SL11H_CTL1MASK_K		0x18	/* resume */
+#	define SL11H_CTL1MASK_LSPD	0x20
+#	define SL11H_CTL1MASK_SUSPEND	0x40
+#define SL11H_IRQ_ENABLE	6
+#	define SL11H_INTMASK_DONE_A	0x01
+#	define SL11H_INTMASK_DONE_B	0x02
+#	define SL11H_INTMASK_SOFINTR	0x10
+#	define SL11H_INTMASK_INSRMV	0x20	/* to/from SE0 */
+#	define SL11H_INTMASK_RD		0x40
+#	define SL11H_INTMASK_DP		0x80	/* only in INTSTATREG */
+#define SL11S_ADDRESS		7
+
+/* 0x08-0x0c are for the B buffer (not in SL11) */
+
+#define SL11H_IRQ_STATUS	0x0D	/* write to ack */
+#define SL11H_HWREVREG		0x0E	/* read */
+#	define SL11H_HWRMASK_HWREV	0xF0
+#define SL11H_SOFLOWREG		0x0E	/* write */
+#define SL11H_SOFTMRREG		0x0F	/* read */
+
+/* a write to this register enables SL811HS features.
+ * HOST flag presumably overrides the chip input signal?
+ */
+#define SL811HS_CTLREG2		0x0F
+#	define SL811HS_CTL2MASK_SOF_MASK	0x3F
+#	define SL811HS_CTL2MASK_DSWAP		0x40
+#	define SL811HS_CTL2MASK_HOST		0x80
+
+#define SL811HS_CTL2_INIT	(SL811HS_CTL2MASK_HOST | 0x2e)
+
+
+/* DATA BUFFERS: registers from 0x10..0xff are for data buffers;
+ * that's 240 bytes, which we'll split evenly between A and B sides.
+ * Only ISO can use more than 64 bytes per packet.
+ * (The SL11S has 0x40..0xff for buffers.)
+ */
+#define H_MAXPACKET	120		/* bytes in A or B fifos */
+
+#define SL11H_DATA_START	0x10
+#define	SL811HS_PACKET_BUF(is_a)	((is_a) \
+		? SL11H_DATA_START \
+		: (SL11H_DATA_START + H_MAXPACKET))
+
+/*-------------------------------------------------------------------------*/
+
+#define	LOG2_PERIODIC_SIZE	5	/* arbitrary; this matches OHCI */
+#define	PERIODIC_SIZE		(1 << LOG2_PERIODIC_SIZE)
+
+struct sl811 {
+	spinlock_t		lock;
+	void __iomem		*addr_reg;
+	void __iomem		*data_reg;
+	struct sl811_platform_data	*board;
+	struct proc_dir_entry	*pde;
+
+	unsigned long		stat_insrmv;
+	unsigned long		stat_wake;
+	unsigned long		stat_sof;
+	unsigned long		stat_a;
+	unsigned long		stat_b;
+	unsigned long		stat_lost;
+	unsigned long		stat_overrun;
+
+	/* sw model */
+	struct timer_list	timer;
+	struct sl811h_ep	*next_periodic;
+	struct sl811h_ep	*next_async;
+
+	struct sl811h_ep	*active_a;
+	unsigned long		jiffies_a;
+	struct sl811h_ep	*active_b;
+	unsigned long		jiffies_b;
+
+	u32			port1;
+	u8			ctrl1, ctrl2, irq_enable;
+	u16			frame;
+
+	/* async schedule: control, bulk */
+	struct list_head	async;
+
+	/* periodic schedule: interrupt, iso */
+	u16			load[PERIODIC_SIZE];
+	struct sl811h_ep	*periodic[PERIODIC_SIZE];
+	unsigned		periodic_count;
+};
+
+static inline struct sl811 *hcd_to_sl811(struct usb_hcd *hcd)
+{
+	return (struct sl811 *) (hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *sl811_to_hcd(struct sl811 *sl811)
+{
+	return container_of((void *) sl811, struct usb_hcd, hcd_priv);
+}
+
+struct sl811h_ep {
+	struct usb_host_endpoint *hep;
+	struct usb_device	*udev;
+
+	u8			defctrl;
+	u8			maxpacket;
+	u8			epnum;
+	u8			nextpid;
+
+	u16			error_count;
+	u16			nak_count;
+	u16			length;		/* of current packet */
+
+	/* periodic schedule */
+	u16			period;
+	u16			branch;
+	u16			load;
+	struct sl811h_ep	*next;
+
+	/* async schedule */
+	struct list_head	schedule;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* These register utilities should work for the SL811S register API too
+ * NOTE:  caller must hold sl811->lock.
+ */
+
+static inline u8 sl811_read(struct sl811 *sl811, int reg)
+{
+	writeb(reg, sl811->addr_reg);
+	return readb(sl811->data_reg);
+}
+
+static inline void sl811_write(struct sl811 *sl811, int reg, u8 val)
+{
+	writeb(reg, sl811->addr_reg);
+	writeb(val, sl811->data_reg);
+}
+
+static inline void
+sl811_write_buf(struct sl811 *sl811, int addr, const void *buf, size_t count)
+{
+	const u8	*data;
+	void __iomem	*data_reg;
+
+	if (!count)
+		return;
+	writeb(addr, sl811->addr_reg);
+
+	data = buf;
+	data_reg = sl811->data_reg;
+	do {
+		writeb(*data++, data_reg);
+	} while (--count);
+}
+
+static inline void
+sl811_read_buf(struct sl811 *sl811, int addr, void *buf, size_t count)
+{
+	u8 		*data;
+	void __iomem	*data_reg;
+
+	if (!count)
+		return;
+	writeb(addr, sl811->addr_reg);
+
+	data = buf;
+	data_reg = sl811->data_reg;
+	do {
+		*data++ = readb(data_reg);
+	} while (--count);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#define DBG(stuff...)		printk(KERN_DEBUG "sl811: " stuff)
+#else
+#define DBG(stuff...)		do{}while(0)
+#endif
+
+#ifdef VERBOSE
+#    define VDBG		DBG
+#else
+#    define VDBG(stuff...)	do{}while(0)
+#endif
+
+#ifdef PACKET_TRACE
+#    define PACKET		VDBG
+#else
+#    define PACKET(stuff...)	do{}while(0)
+#endif
+
+#define ERR(stuff...)		printk(KERN_ERR "sl811: " stuff)
+#define WARN(stuff...)		printk(KERN_WARNING "sl811: " stuff)
+#define INFO(stuff...)		printk(KERN_INFO "sl811: " stuff)
+
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
new file mode 100644
index 0000000..24c73c5
--- /dev/null
+++ b/drivers/usb/host/uhci-debug.c
@@ -0,0 +1,587 @@
+/*
+ * UHCI-specific debugging code. Invaluable when something
+ * goes wrong, but don't get in my face.
+ *
+ * Kernel visible pointers are surrounded in []'s and bus
+ * visible pointers are surrounded in ()'s
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2001 Johannes Erdfelt
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/smp_lock.h>
+#include <asm/io.h>
+
+#include "uhci-hcd.h"
+
+static struct dentry *uhci_debugfs_root = NULL;
+
+/* Handle REALLY large printk's so we don't overflow buffers */
+static inline void lprintk(char *buf)
+{
+	char *p;
+
+	/* Just write one line at a time */
+	while (buf) {
+		p = strchr(buf, '\n');
+		if (p)
+			*p = 0;
+		printk(KERN_DEBUG "%s\n", buf);
+		buf = p;
+		if (buf)
+			buf++;
+	}
+}
+
+static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
+{
+	char *out = buf;
+	char *spid;
+	u32 status, token;
+
+	/* Try to make sure there's enough memory */
+	if (len < 160)
+		return 0;
+
+	status = td_status(td);
+	out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td, le32_to_cpu(td->link));
+	out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
+		((status >> 27) & 3),
+		(status & TD_CTRL_SPD) ?      "SPD " : "",
+		(status & TD_CTRL_LS) ?       "LS " : "",
+		(status & TD_CTRL_IOC) ?      "IOC " : "",
+		(status & TD_CTRL_ACTIVE) ?   "Active " : "",
+		(status & TD_CTRL_STALLED) ?  "Stalled " : "",
+		(status & TD_CTRL_DBUFERR) ?  "DataBufErr " : "",
+		(status & TD_CTRL_BABBLE) ?   "Babble " : "",
+		(status & TD_CTRL_NAK) ?      "NAK " : "",
+		(status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
+		(status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
+		status & 0x7ff);
+
+	token = td_token(td);
+	switch (uhci_packetid(token)) {
+		case USB_PID_SETUP:
+			spid = "SETUP";
+			break;
+		case USB_PID_OUT:
+			spid = "OUT";
+			break;
+		case USB_PID_IN:
+			spid = "IN";
+			break;
+		default:
+			spid = "?";
+			break;
+	}
+
+	out += sprintf(out, "MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ",
+		token >> 21,
+		((token >> 19) & 1),
+		(token >> 15) & 15,
+		(token >> 8) & 127,
+		(token & 0xff),
+		spid);
+	out += sprintf(out, "(buf=%08x)\n", le32_to_cpu(td->buffer));
+
+	return out - buf;
+}
+
+static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
+{
+	char *out = buf;
+	struct urb_priv *urbp;
+	struct list_head *head, *tmp;
+	struct uhci_td *td;
+	int i = 0, checked = 0, prevactive = 0;
+	__le32 element = qh_element(qh);
+
+	/* Try to make sure there's enough memory */
+	if (len < 80 * 6)
+		return 0;
+
+	out += sprintf(out, "%*s[%p] link (%08x) element (%08x)\n", space, "",
+			qh, le32_to_cpu(qh->link), le32_to_cpu(element));
+
+	if (element & UHCI_PTR_QH)
+		out += sprintf(out, "%*s  Element points to QH (bug?)\n", space, "");
+
+	if (element & UHCI_PTR_DEPTH)
+		out += sprintf(out, "%*s  Depth traverse\n", space, "");
+
+	if (element & cpu_to_le32(8))
+		out += sprintf(out, "%*s  Bit 3 set (bug?)\n", space, "");
+
+	if (!(element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH)))
+		out += sprintf(out, "%*s  Element is NULL (bug?)\n", space, "");
+
+	if (!qh->urbp) {
+		out += sprintf(out, "%*s  urbp == NULL\n", space, "");
+		goto out;
+	}
+
+	urbp = qh->urbp;
+
+	head = &urbp->td_list;
+	tmp = head->next;
+
+	td = list_entry(tmp, struct uhci_td, list);
+
+	if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS))
+		out += sprintf(out, "%*s Element != First TD\n", space, "");
+
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		out += sprintf(out, "%*s%d: ", space + 2, "", i++);
+		out += uhci_show_td(td, out, len - (out - buf), 0);
+
+		if (i > 10 && !checked && prevactive && tmp != head &&
+		    debug <= 2) {
+			struct list_head *ntmp = tmp;
+			struct uhci_td *ntd = td;
+			int active = 1, ni = i;
+
+			checked = 1;
+
+			while (ntmp != head && ntmp->next != head && active) {
+				ntd = list_entry(ntmp, struct uhci_td, list);
+
+				ntmp = ntmp->next;
+
+				active = td_status(ntd) & TD_CTRL_ACTIVE;
+
+				ni++;
+			}
+
+			if (active && ni > i) {
+				out += sprintf(out, "%*s[skipped %d active TD's]\n", space, "", ni - i);
+				tmp = ntmp;
+				td = ntd;
+				i = ni;
+			}
+		}
+
+		prevactive = td_status(td) & TD_CTRL_ACTIVE;
+	}
+
+	if (list_empty(&urbp->queue_list) || urbp->queued)
+		goto out;
+
+	out += sprintf(out, "%*sQueued QH's:\n", -space, "--");
+
+	head = &urbp->queue_list;
+	tmp = head->next;
+
+	while (tmp != head) {
+		struct urb_priv *nurbp = list_entry(tmp, struct urb_priv,
+						queue_list);
+		tmp = tmp->next;
+
+		out += uhci_show_qh(nurbp->qh, out, len - (out - buf), space);
+	}
+
+out:
+	return out - buf;
+}
+
+#define show_frame_num()	\
+	if (!shown) {		\
+	  shown = 1;		\
+	  out += sprintf(out, "- Frame %d\n", i); \
+	}
+
+#ifdef CONFIG_PROC_FS
+static const char *qh_names[] = {
+  "skel_int128_qh", "skel_int64_qh",
+  "skel_int32_qh", "skel_int16_qh",
+  "skel_int8_qh", "skel_int4_qh",
+  "skel_int2_qh", "skel_int1_qh",
+  "skel_ls_control_qh", "skel_fs_control_qh",
+  "skel_bulk_qh", "skel_term_qh"
+};
+
+#define show_qh_name()		\
+	if (!shown) {		\
+	  shown = 1;		\
+	  out += sprintf(out, "- %s\n", qh_names[i]); \
+	}
+
+static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
+{
+	char *out = buf;
+
+	/* Try to make sure there's enough memory */
+	if (len < 160)
+		return 0;
+
+	out += sprintf(out, "  stat%d     =     %04x  %s%s%s%s%s%s%s%s%s%s\n",
+		port,
+		status,
+		(status & USBPORTSC_SUSP) ?	" Suspend" : "",
+		(status & USBPORTSC_OCC) ?	" OverCurrentChange" : "",
+		(status & USBPORTSC_OC) ?	" OverCurrent" : "",
+		(status & USBPORTSC_PR) ?	" Reset" : "",
+		(status & USBPORTSC_LSDA) ?	" LowSpeed" : "",
+		(status & USBPORTSC_RD) ?	" ResumeDetect" : "",
+		(status & USBPORTSC_PEC) ?	" EnableChange" : "",
+		(status & USBPORTSC_PE) ?	" Enabled" : "",
+		(status & USBPORTSC_CSC) ?	" ConnectChange" : "",
+		(status & USBPORTSC_CCS) ?	" Connected" : "");
+
+	return out - buf;
+}
+
+static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
+{
+	char *out = buf;
+	unsigned long io_addr = uhci->io_addr;
+	unsigned short usbcmd, usbstat, usbint, usbfrnum;
+	unsigned int flbaseadd;
+	unsigned char sof;
+	unsigned short portsc1, portsc2;
+
+	/* Try to make sure there's enough memory */
+	if (len < 80 * 6)
+		return 0;
+
+	usbcmd    = inw(io_addr + 0);
+	usbstat   = inw(io_addr + 2);
+	usbint    = inw(io_addr + 4);
+	usbfrnum  = inw(io_addr + 6);
+	flbaseadd = inl(io_addr + 8);
+	sof       = inb(io_addr + 12);
+	portsc1   = inw(io_addr + 16);
+	portsc2   = inw(io_addr + 18);
+
+	out += sprintf(out, "  usbcmd    =     %04x   %s%s%s%s%s%s%s%s\n",
+		usbcmd,
+		(usbcmd & USBCMD_MAXP) ?    "Maxp64 " : "Maxp32 ",
+		(usbcmd & USBCMD_CF) ?      "CF " : "",
+		(usbcmd & USBCMD_SWDBG) ?   "SWDBG " : "",
+		(usbcmd & USBCMD_FGR) ?     "FGR " : "",
+		(usbcmd & USBCMD_EGSM) ?    "EGSM " : "",
+		(usbcmd & USBCMD_GRESET) ?  "GRESET " : "",
+		(usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
+		(usbcmd & USBCMD_RS) ?      "RS " : "");
+
+	out += sprintf(out, "  usbstat   =     %04x   %s%s%s%s%s%s\n",
+		usbstat,
+		(usbstat & USBSTS_HCH) ?    "HCHalted " : "",
+		(usbstat & USBSTS_HCPE) ?   "HostControllerProcessError " : "",
+		(usbstat & USBSTS_HSE) ?    "HostSystemError " : "",
+		(usbstat & USBSTS_RD) ?     "ResumeDetect " : "",
+		(usbstat & USBSTS_ERROR) ?  "USBError " : "",
+		(usbstat & USBSTS_USBINT) ? "USBINT " : "");
+
+	out += sprintf(out, "  usbint    =     %04x\n", usbint);
+	out += sprintf(out, "  usbfrnum  =   (%d)%03x\n", (usbfrnum >> 10) & 1,
+		0xfff & (4*(unsigned int)usbfrnum));
+	out += sprintf(out, "  flbaseadd = %08x\n", flbaseadd);
+	out += sprintf(out, "  sof       =       %02x\n", sof);
+	out += uhci_show_sc(1, portsc1, out, len - (out - buf));
+	out += uhci_show_sc(2, portsc2, out, len - (out - buf));
+
+	return out - buf;
+}
+
+static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp, char *buf, int len)
+{
+	struct list_head *tmp;
+	char *out = buf;
+	int count = 0;
+
+	if (len < 200)
+		return 0;
+
+	out += sprintf(out, "urb_priv [%p] ", urbp);
+	out += sprintf(out, "urb [%p] ", urbp->urb);
+	out += sprintf(out, "qh [%p] ", urbp->qh);
+	out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe));
+	out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe), (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT"));
+
+	switch (usb_pipetype(urbp->urb->pipe)) {
+	case PIPE_ISOCHRONOUS: out += sprintf(out, "ISO "); break;
+	case PIPE_INTERRUPT: out += sprintf(out, "INT "); break;
+	case PIPE_BULK: out += sprintf(out, "BLK "); break;
+	case PIPE_CONTROL: out += sprintf(out, "CTL "); break;
+	}
+
+	out += sprintf(out, "%s", (urbp->fsbr ? "FSBR " : ""));
+	out += sprintf(out, "%s", (urbp->fsbr_timeout ? "FSBR_TO " : ""));
+
+	if (urbp->urb->status != -EINPROGRESS)
+		out += sprintf(out, "Status=%d ", urbp->urb->status);
+	//out += sprintf(out, "Inserttime=%lx ",urbp->inserttime);
+	//out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime);
+
+	count = 0;
+	list_for_each(tmp, &urbp->td_list)
+		count++;
+	out += sprintf(out, "TDs=%d ",count);
+
+	if (urbp->queued)
+		out += sprintf(out, "queued\n");
+	else {
+		count = 0;
+		list_for_each(tmp, &urbp->queue_list)
+			count++;
+		out += sprintf(out, "queued URBs=%d\n", count);
+	}
+
+	return out - buf;
+}
+
+static int uhci_show_lists(struct uhci_hcd *uhci, char *buf, int len)
+{
+	char *out = buf;
+	struct list_head *head, *tmp;
+	int count;
+
+	out += sprintf(out, "Main list URBs:");
+	if (list_empty(&uhci->urb_list))
+		out += sprintf(out, " Empty\n");
+	else {
+		out += sprintf(out, "\n");
+		count = 0;
+		head = &uhci->urb_list;
+		tmp = head->next;
+		while (tmp != head) {
+			struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
+
+			out += sprintf(out, "  %d: ", ++count);
+			out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
+			tmp = tmp->next;
+		}
+	}
+
+	out += sprintf(out, "Remove list URBs:");
+	if (list_empty(&uhci->urb_remove_list))
+		out += sprintf(out, " Empty\n");
+	else {
+		out += sprintf(out, "\n");
+		count = 0;
+		head = &uhci->urb_remove_list;
+		tmp = head->next;
+		while (tmp != head) {
+			struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
+
+			out += sprintf(out, "  %d: ", ++count);
+			out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
+			tmp = tmp->next;
+		}
+	}
+
+	out += sprintf(out, "Complete list URBs:");
+	if (list_empty(&uhci->complete_list))
+		out += sprintf(out, " Empty\n");
+	else {
+		out += sprintf(out, "\n");
+		count = 0;
+		head = &uhci->complete_list;
+		tmp = head->next;
+		while (tmp != head) {
+			struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
+
+			out += sprintf(out, "  %d: ", ++count);
+			out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
+			tmp = tmp->next;
+		}
+	}
+
+	return out - buf;
+}
+
+static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
+{
+	unsigned long flags;
+	char *out = buf;
+	int i, j;
+	struct uhci_qh *qh;
+	struct uhci_td *td;
+	struct list_head *tmp, *head;
+
+	spin_lock_irqsave(&uhci->lock, flags);
+
+	out += sprintf(out, "HC status\n");
+	out += uhci_show_status(uhci, out, len - (out - buf));
+
+	out += sprintf(out, "Frame List\n");
+	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
+		int shown = 0;
+		td = uhci->fl->frame_cpu[i];
+		if (!td)
+			continue;
+
+		if (td->dma_handle != (dma_addr_t)uhci->fl->frame[i]) {
+			show_frame_num();
+			out += sprintf(out, "    frame list does not match td->dma_handle!\n");
+		}
+		show_frame_num();
+
+		head = &td->fl_list;
+		tmp = head;
+		do {
+			td = list_entry(tmp, struct uhci_td, fl_list);
+			tmp = tmp->next;
+			out += uhci_show_td(td, out, len - (out - buf), 4);
+		} while (tmp != head);
+	}
+
+	out += sprintf(out, "Skeleton QH's\n");
+
+	for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
+		int shown = 0;
+
+		qh = uhci->skelqh[i];
+
+		if (debug > 1) {
+			show_qh_name();
+			out += uhci_show_qh(qh, out, len - (out - buf), 4);
+		}
+
+		/* Last QH is the Terminating QH, it's different */
+		if (i == UHCI_NUM_SKELQH - 1) {
+			if (qh->link != UHCI_PTR_TERM)
+				out += sprintf(out, "    bandwidth reclamation on!\n");
+
+			if (qh_element(qh) != cpu_to_le32(uhci->term_td->dma_handle))
+				out += sprintf(out, "    skel_term_qh element is not set to term_td!\n");
+
+			continue;
+		}
+
+		j = (i < 7) ? 7 : i+1;		/* Next skeleton */
+		if (list_empty(&qh->list)) {
+			if (i < UHCI_NUM_SKELQH - 1) {
+				if (qh->link !=
+				    (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH)) {
+					show_qh_name();
+					out += sprintf(out, "    skeleton QH not linked to next skeleton QH!\n");
+				}
+			}
+
+			continue;
+		}
+
+		show_qh_name();
+
+		head = &qh->list;
+		tmp = head->next;
+
+		while (tmp != head) {
+			qh = list_entry(tmp, struct uhci_qh, list);
+
+			tmp = tmp->next;
+
+			out += uhci_show_qh(qh, out, len - (out - buf), 4);
+		}
+
+		if (i < UHCI_NUM_SKELQH - 1) {
+			if (qh->link !=
+			    (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH))
+				out += sprintf(out, "    last QH not linked to next skeleton!\n");
+		}
+	}
+
+	if (debug > 2)
+		out += uhci_show_lists(uhci, out, len - (out - buf));
+
+	spin_unlock_irqrestore(&uhci->lock, flags);
+
+	return out - buf;
+}
+
+#define MAX_OUTPUT	(64 * 1024)
+
+struct uhci_debug {
+	int size;
+	char *data;
+	struct uhci_hcd *uhci;
+};
+
+static int uhci_debug_open(struct inode *inode, struct file *file)
+{
+	struct uhci_hcd *uhci = inode->u.generic_ip;
+	struct uhci_debug *up;
+	int ret = -ENOMEM;
+
+	lock_kernel();
+	up = kmalloc(sizeof(*up), GFP_KERNEL);
+	if (!up)
+		goto out;
+
+	up->data = kmalloc(MAX_OUTPUT, GFP_KERNEL);
+	if (!up->data) {
+		kfree(up);
+		goto out;
+	}
+
+	up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
+
+	file->private_data = up;
+
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
+}
+
+static loff_t uhci_debug_lseek(struct file *file, loff_t off, int whence)
+{
+	struct uhci_debug *up;
+	loff_t new = -1;
+
+	lock_kernel();
+	up = file->private_data;
+
+	switch (whence) {
+	case 0:
+		new = off;
+		break;
+	case 1:
+		new = file->f_pos + off;
+		break;
+	}
+	if (new < 0 || new > up->size) {
+		unlock_kernel();
+		return -EINVAL;
+	}
+	unlock_kernel();
+	return (file->f_pos = new);
+}
+
+static ssize_t uhci_debug_read(struct file *file, char __user *buf,
+				size_t nbytes, loff_t *ppos)
+{
+	struct uhci_debug *up = file->private_data;
+	return simple_read_from_buffer(buf, nbytes, ppos, up->data, up->size);
+}
+
+static int uhci_debug_release(struct inode *inode, struct file *file)
+{
+	struct uhci_debug *up = file->private_data;
+
+	kfree(up->data);
+	kfree(up);
+
+	return 0;
+}
+
+static struct file_operations uhci_debug_operations = {
+	.open =		uhci_debug_open,
+	.llseek =	uhci_debug_lseek,
+	.read =		uhci_debug_read,
+	.release =	uhci_debug_release,
+};
+
+#else	/* CONFIG_DEBUG_FS */
+
+#define uhci_debug_operations (* (struct file_operations *) NULL)
+
+#endif
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
new file mode 100644
index 0000000..324a1a9
--- /dev/null
+++ b/drivers/usb/host/uhci-hcd.c
@@ -0,0 +1,919 @@
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * Maintainer: Alan Stern <stern@rowland.harvard.edu>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ * (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu
+ *
+ * Intel documents this fairly well, and as far as I know there
+ * are no royalties or anything like that, but even so there are
+ * people who decided that they want to do the same thing in a
+ * completely different way.
+ *
+ * WARNING! The USB documentation is downright evil. Most of it
+ * is just crap, written by a committee. You're better off ignoring
+ * most of it, the important stuff is:
+ *  - the low-level protocol (fairly simple but lots of small details)
+ *  - working around the horridness of the rest
+ */
+
+#include <linux/config.h>
+#ifdef CONFIG_USB_DEBUG
+#define DEBUG
+#else
+#undef DEBUG
+#endif
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/pm.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <linux/usb.h>
+#include <linux/bitops.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "../core/hcd.h"
+#include "uhci-hcd.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v2.2"
+#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \
+Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \
+Alan Stern"
+#define DRIVER_DESC "USB Universal Host Controller Interface driver"
+
+/*
+ * debug = 0, no debugging messages
+ * debug = 1, dump failed URB's except for stalls
+ * debug = 2, dump all failed URB's (including stalls)
+ *            show all queues in /debug/uhci/[pci_addr]
+ * debug = 3, show all TD's in URB's when dumping
+ */
+#ifdef DEBUG
+static int debug = 1;
+#else
+static int debug = 0;
+#endif
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level");
+static char *errbuf;
+#define ERRBUF_LEN    (32 * 1024)
+
+static kmem_cache_t *uhci_up_cachep;	/* urb_priv */
+
+static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
+static void hc_state_transitions(struct uhci_hcd *uhci);
+
+/* If a transfer is still active after this much time, turn off FSBR */
+#define IDLE_TIMEOUT	msecs_to_jiffies(50)
+#define FSBR_DELAY	msecs_to_jiffies(50)
+
+/* When we timeout an idle transfer for FSBR, we'll switch it over to */
+/* depth first traversal. We'll do it in groups of this number of TD's */
+/* to make sure it doesn't hog all of the bandwidth */
+#define DEPTH_INTERVAL 5
+
+#include "uhci-hub.c"
+#include "uhci-debug.c"
+#include "uhci-q.c"
+
+static int init_stall_timer(struct usb_hcd *hcd);
+
+static void stall_callback(unsigned long ptr)
+{
+	struct usb_hcd *hcd = (struct usb_hcd *)ptr;
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	struct urb_priv *up;
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->lock, flags);
+	uhci_scan_schedule(uhci, NULL);
+
+	list_for_each_entry(up, &uhci->urb_list, urb_list) {
+		struct urb *u = up->urb;
+
+		spin_lock(&u->lock);
+
+		/* Check if the FSBR timed out */
+		if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT))
+			uhci_fsbr_timeout(uhci, u);
+
+		spin_unlock(&u->lock);
+	}
+
+	/* Really disable FSBR */
+	if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {
+		uhci->fsbrtimeout = 0;
+		uhci->skel_term_qh->link = UHCI_PTR_TERM;
+	}
+
+	/* Poll for and perform state transitions */
+	hc_state_transitions(uhci);
+	if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED))
+		uhci_check_ports(uhci);
+
+	init_stall_timer(hcd);
+	spin_unlock_irqrestore(&uhci->lock, flags);
+}
+
+static int init_stall_timer(struct usb_hcd *hcd)
+{
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+
+	init_timer(&uhci->stall_timer);
+	uhci->stall_timer.function = stall_callback;
+	uhci->stall_timer.data = (unsigned long)hcd;
+	uhci->stall_timer.expires = jiffies + msecs_to_jiffies(100);
+	add_timer(&uhci->stall_timer);
+
+	return 0;
+}
+
+static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
+{
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	unsigned long io_addr = uhci->io_addr;
+	unsigned short status;
+
+	/*
+	 * Read the interrupt status, and write it back to clear the
+	 * interrupt cause.  Contrary to the UHCI specification, the
+	 * "HC Halted" status bit is persistent: it is RO, not R/WC.
+	 */
+	status = inw(io_addr + USBSTS);
+	if (!(status & ~USBSTS_HCH))	/* shared interrupt, not mine */
+		return IRQ_NONE;
+	outw(status, io_addr + USBSTS);		/* Clear it */
+
+	if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
+		if (status & USBSTS_HSE)
+			dev_err(uhci_dev(uhci), "host system error, "
+					"PCI problems?\n");
+		if (status & USBSTS_HCPE)
+			dev_err(uhci_dev(uhci), "host controller process "
+					"error, something bad happened!\n");
+		if ((status & USBSTS_HCH) && uhci->state > 0) {
+			dev_err(uhci_dev(uhci), "host controller halted, "
+					"very bad!\n");
+			/* FIXME: Reset the controller, fix the offending TD */
+		}
+	}
+
+	if (status & USBSTS_RD)
+		uhci->resume_detect = 1;
+
+	spin_lock(&uhci->lock);
+	uhci_scan_schedule(uhci, regs);
+	spin_unlock(&uhci->lock);
+
+	return IRQ_HANDLED;
+}
+
+static void reset_hc(struct uhci_hcd *uhci)
+{
+	unsigned long io_addr = uhci->io_addr;
+
+	/* Turn off PIRQ, SMI, and all interrupts.  This also turns off
+	 * the BIOS's USB Legacy Support.
+	 */
+	pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
+	outw(0, uhci->io_addr + USBINTR);
+
+	/* Global reset for 50ms */
+	uhci->state = UHCI_RESET;
+	outw(USBCMD_GRESET, io_addr + USBCMD);
+	msleep(50);
+	outw(0, io_addr + USBCMD);
+
+	/* Another 10ms delay */
+	msleep(10);
+	uhci->resume_detect = 0;
+	uhci->is_stopped = UHCI_IS_STOPPED;
+}
+
+static void suspend_hc(struct uhci_hcd *uhci)
+{
+	unsigned long io_addr = uhci->io_addr;
+
+	dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
+	uhci->state = UHCI_SUSPENDED;
+	uhci->resume_detect = 0;
+	outw(USBCMD_EGSM, io_addr + USBCMD);
+
+	/* FIXME: Wait for the controller to actually stop */
+	uhci_get_current_frame_number(uhci);
+	uhci->is_stopped = UHCI_IS_STOPPED;
+
+	uhci_scan_schedule(uhci, NULL);
+}
+
+static void wakeup_hc(struct uhci_hcd *uhci)
+{
+	unsigned long io_addr = uhci->io_addr;
+
+	switch (uhci->state) {
+		case UHCI_SUSPENDED:		/* Start the resume */
+			dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
+
+			/* Global resume for >= 20ms */
+			outw(USBCMD_FGR | USBCMD_EGSM, io_addr + USBCMD);
+			uhci->state = UHCI_RESUMING_1;
+			uhci->state_end = jiffies + msecs_to_jiffies(20);
+			uhci->is_stopped = 0;
+			break;
+
+		case UHCI_RESUMING_1:		/* End global resume */
+			uhci->state = UHCI_RESUMING_2;
+			outw(0, io_addr + USBCMD);
+			/* Falls through */
+
+		case UHCI_RESUMING_2:		/* Wait for EOP to be sent */
+			if (inw(io_addr + USBCMD) & USBCMD_FGR)
+				break;
+
+			/* Run for at least 1 second, and
+			 * mark it configured with a 64-byte max packet */
+			uhci->state = UHCI_RUNNING_GRACE;
+			uhci->state_end = jiffies + HZ;
+			outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP,
+					io_addr + USBCMD);
+			break;
+
+		case UHCI_RUNNING_GRACE:	/* Now allowed to suspend */
+			uhci->state = UHCI_RUNNING;
+			break;
+
+		default:
+			break;
+	}
+}
+
+static int ports_active(struct uhci_hcd *uhci)
+{
+	unsigned long io_addr = uhci->io_addr;
+	int connection = 0;
+	int i;
+
+	for (i = 0; i < uhci->rh_numports; i++)
+		connection |= (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_CCS);
+
+	return connection;
+}
+
+static int suspend_allowed(struct uhci_hcd *uhci)
+{
+	unsigned long io_addr = uhci->io_addr;
+	int i;
+
+	if (to_pci_dev(uhci_dev(uhci))->vendor != PCI_VENDOR_ID_INTEL)
+		return 1;
+
+	/* Some of Intel's USB controllers have a bug that causes false
+	 * resume indications if any port has an over current condition.
+	 * To prevent problems, we will not allow a global suspend if
+	 * any ports are OC.
+	 *
+	 * Some motherboards using Intel's chipsets (but not using all
+	 * the USB ports) appear to hardwire the over current inputs active
+	 * to disable the USB ports.
+	 */
+
+	/* check for over current condition on any port */
+	for (i = 0; i < uhci->rh_numports; i++) {
+		if (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_OC)
+			return 0;
+	}
+
+	return 1;
+}
+
+static void hc_state_transitions(struct uhci_hcd *uhci)
+{
+	switch (uhci->state) {
+		case UHCI_RUNNING:
+
+			/* global suspend if nothing connected for 1 second */
+			if (!ports_active(uhci) && suspend_allowed(uhci)) {
+				uhci->state = UHCI_SUSPENDING_GRACE;
+				uhci->state_end = jiffies + HZ;
+			}
+			break;
+
+		case UHCI_SUSPENDING_GRACE:
+			if (ports_active(uhci))
+				uhci->state = UHCI_RUNNING;
+			else if (time_after_eq(jiffies, uhci->state_end))
+				suspend_hc(uhci);
+			break;
+
+		case UHCI_SUSPENDED:
+
+			/* wakeup if requested by a device */
+			if (uhci->resume_detect)
+				wakeup_hc(uhci);
+			break;
+
+		case UHCI_RESUMING_1:
+		case UHCI_RESUMING_2:
+		case UHCI_RUNNING_GRACE:
+			if (time_after_eq(jiffies, uhci->state_end))
+				wakeup_hc(uhci);
+			break;
+
+		default:
+			break;
+	}
+}
+
+/*
+ * Store the current frame number in uhci->frame_number if the controller
+ * is runnning
+ */
+static void uhci_get_current_frame_number(struct uhci_hcd *uhci)
+{
+	if (!uhci->is_stopped)
+		uhci->frame_number = inw(uhci->io_addr + USBFRNUM);
+}
+
+static int start_hc(struct uhci_hcd *uhci)
+{
+	unsigned long io_addr = uhci->io_addr;
+	int timeout = 10;
+
+	/*
+	 * Reset the HC - this will force us to get a
+	 * new notification of any already connected
+	 * ports due to the virtual disconnect that it
+	 * implies.
+	 */
+	outw(USBCMD_HCRESET, io_addr + USBCMD);
+	while (inw(io_addr + USBCMD) & USBCMD_HCRESET) {
+		if (--timeout < 0) {
+			dev_err(uhci_dev(uhci), "USBCMD_HCRESET timed out!\n");
+			return -ETIMEDOUT;
+		}
+		msleep(1);
+	}
+
+	/* Mark controller as running before we enable interrupts */
+	uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
+
+	/* Turn on PIRQ and all interrupts */
+	pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
+			USBLEGSUP_DEFAULT);
+	outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
+		io_addr + USBINTR);
+
+	/* Start at frame 0 */
+	outw(0, io_addr + USBFRNUM);
+	outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD);
+
+	/* Run and mark it configured with a 64-byte max packet */
+	uhci->state = UHCI_RUNNING_GRACE;
+	uhci->state_end = jiffies + HZ;
+	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
+	uhci->is_stopped = 0;
+
+	return 0;
+}
+
+/*
+ * De-allocate all resources
+ */
+static void release_uhci(struct uhci_hcd *uhci)
+{
+	int i;
+
+	for (i = 0; i < UHCI_NUM_SKELQH; i++)
+		if (uhci->skelqh[i]) {
+			uhci_free_qh(uhci, uhci->skelqh[i]);
+			uhci->skelqh[i] = NULL;
+		}
+
+	if (uhci->term_td) {
+		uhci_free_td(uhci, uhci->term_td);
+		uhci->term_td = NULL;
+	}
+
+	if (uhci->qh_pool) {
+		dma_pool_destroy(uhci->qh_pool);
+		uhci->qh_pool = NULL;
+	}
+
+	if (uhci->td_pool) {
+		dma_pool_destroy(uhci->td_pool);
+		uhci->td_pool = NULL;
+	}
+
+	if (uhci->fl) {
+		dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
+				uhci->fl, uhci->fl->dma_handle);
+		uhci->fl = NULL;
+	}
+
+	if (uhci->dentry) {
+		debugfs_remove(uhci->dentry);
+		uhci->dentry = NULL;
+	}
+}
+
+static int uhci_reset(struct usb_hcd *hcd)
+{
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+
+	uhci->io_addr = (unsigned long) hcd->rsrc_start;
+
+	/* Kick BIOS off this hardware and reset, so we won't get
+	 * interrupts from any previous setup.
+	 */
+	reset_hc(uhci);
+	return 0;
+}
+
+/*
+ * Allocate a frame list, and then setup the skeleton
+ *
+ * The hardware doesn't really know any difference
+ * in the queues, but the order does matter for the
+ * protocols higher up. The order is:
+ *
+ *  - any isochronous events handled before any
+ *    of the queues. We don't do that here, because
+ *    we'll create the actual TD entries on demand.
+ *  - The first queue is the interrupt queue.
+ *  - The second queue is the control queue, split into low- and full-speed
+ *  - The third queue is bulk queue.
+ *  - The fourth queue is the bandwidth reclamation queue, which loops back
+ *    to the full-speed control queue.
+ */
+static int uhci_start(struct usb_hcd *hcd)
+{
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	int retval = -EBUSY;
+	int i, port;
+	unsigned io_size;
+	dma_addr_t dma_handle;
+	struct usb_device *udev;
+	struct dentry *dentry;
+
+	io_size = (unsigned) hcd->rsrc_len;
+
+	dentry = debugfs_create_file(hcd->self.bus_name, S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci, &uhci_debug_operations);
+	if (!dentry) {
+		dev_err(uhci_dev(uhci), "couldn't create uhci debugfs entry\n");
+		retval = -ENOMEM;
+		goto err_create_debug_entry;
+	}
+	uhci->dentry = dentry;
+
+	uhci->fsbr = 0;
+	uhci->fsbrtimeout = 0;
+
+	spin_lock_init(&uhci->lock);
+	INIT_LIST_HEAD(&uhci->qh_remove_list);
+
+	INIT_LIST_HEAD(&uhci->td_remove_list);
+
+	INIT_LIST_HEAD(&uhci->urb_remove_list);
+
+	INIT_LIST_HEAD(&uhci->urb_list);
+
+	INIT_LIST_HEAD(&uhci->complete_list);
+
+	init_waitqueue_head(&uhci->waitqh);
+
+	uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
+			&dma_handle, 0);
+	if (!uhci->fl) {
+		dev_err(uhci_dev(uhci), "unable to allocate "
+				"consistent memory for frame list\n");
+		goto err_alloc_fl;
+	}
+
+	memset((void *)uhci->fl, 0, sizeof(*uhci->fl));
+
+	uhci->fl->dma_handle = dma_handle;
+
+	uhci->td_pool = dma_pool_create("uhci_td", uhci_dev(uhci),
+			sizeof(struct uhci_td), 16, 0);
+	if (!uhci->td_pool) {
+		dev_err(uhci_dev(uhci), "unable to create td dma_pool\n");
+		goto err_create_td_pool;
+	}
+
+	uhci->qh_pool = dma_pool_create("uhci_qh", uhci_dev(uhci),
+			sizeof(struct uhci_qh), 16, 0);
+	if (!uhci->qh_pool) {
+		dev_err(uhci_dev(uhci), "unable to create qh dma_pool\n");
+		goto err_create_qh_pool;
+	}
+
+	/* Initialize the root hub */
+
+	/* UHCI specs says devices must have 2 ports, but goes on to say */
+	/*  they may have more but give no way to determine how many they */
+	/*  have. However, according to the UHCI spec, Bit 7 is always set */
+	/*  to 1. So we try to use this to our advantage */
+	for (port = 0; port < (io_size - 0x10) / 2; port++) {
+		unsigned int portstatus;
+
+		portstatus = inw(uhci->io_addr + 0x10 + (port * 2));
+		if (!(portstatus & 0x0080))
+			break;
+	}
+	if (debug)
+		dev_info(uhci_dev(uhci), "detected %d ports\n", port);
+
+	/* This is experimental so anything less than 2 or greater than 8 is */
+	/*  something weird and we'll ignore it */
+	if (port < 2 || port > UHCI_RH_MAXCHILD) {
+		dev_info(uhci_dev(uhci), "port count misdetected? "
+				"forcing to 2 ports\n");
+		port = 2;
+	}
+
+	uhci->rh_numports = port;
+
+	udev = usb_alloc_dev(NULL, &hcd->self, 0);
+	if (!udev) {
+		dev_err(uhci_dev(uhci), "unable to allocate root hub\n");
+		goto err_alloc_root_hub;
+	}
+
+	uhci->term_td = uhci_alloc_td(uhci, udev);
+	if (!uhci->term_td) {
+		dev_err(uhci_dev(uhci), "unable to allocate terminating TD\n");
+		goto err_alloc_term_td;
+	}
+
+	for (i = 0; i < UHCI_NUM_SKELQH; i++) {
+		uhci->skelqh[i] = uhci_alloc_qh(uhci, udev);
+		if (!uhci->skelqh[i]) {
+			dev_err(uhci_dev(uhci), "unable to allocate QH\n");
+			goto err_alloc_skelqh;
+		}
+	}
+
+	/*
+	 * 8 Interrupt queues; link all higher int queues to int1,
+	 * then link int1 to control and control to bulk
+	 */
+	uhci->skel_int128_qh->link =
+			uhci->skel_int64_qh->link =
+			uhci->skel_int32_qh->link =
+			uhci->skel_int16_qh->link =
+			uhci->skel_int8_qh->link =
+			uhci->skel_int4_qh->link =
+			uhci->skel_int2_qh->link =
+			cpu_to_le32(uhci->skel_int1_qh->dma_handle) | UHCI_PTR_QH;
+	uhci->skel_int1_qh->link = cpu_to_le32(uhci->skel_ls_control_qh->dma_handle) | UHCI_PTR_QH;
+
+	uhci->skel_ls_control_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;
+	uhci->skel_fs_control_qh->link = cpu_to_le32(uhci->skel_bulk_qh->dma_handle) | UHCI_PTR_QH;
+	uhci->skel_bulk_qh->link = cpu_to_le32(uhci->skel_term_qh->dma_handle) | UHCI_PTR_QH;
+
+	/* This dummy TD is to work around a bug in Intel PIIX controllers */
+	uhci_fill_td(uhci->term_td, 0, (UHCI_NULL_DATA_SIZE << 21) |
+		(0x7f << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_IN, 0);
+	uhci->term_td->link = cpu_to_le32(uhci->term_td->dma_handle);
+
+	uhci->skel_term_qh->link = UHCI_PTR_TERM;
+	uhci->skel_term_qh->element = cpu_to_le32(uhci->term_td->dma_handle);
+
+	/*
+	 * Fill the frame list: make all entries point to the proper
+	 * interrupt queue.
+	 *
+	 * The interrupt queues will be interleaved as evenly as possible.
+	 * There's not much to be done about period-1 interrupts; they have
+	 * to occur in every frame.  But we can schedule period-2 interrupts
+	 * in odd-numbered frames, period-4 interrupts in frames congruent
+	 * to 2 (mod 4), and so on.  This way each frame only has two
+	 * interrupt QHs, which will help spread out bandwidth utilization.
+	 */
+	for (i = 0; i < UHCI_NUMFRAMES; i++) {
+		int irq;
+
+		/*
+		 * ffs (Find First bit Set) does exactly what we need:
+		 * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[6],
+		 * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[5], etc.
+		 * ffs > 6 => not on any high-period queue, so use
+		 *	skel_int1_qh = skelqh[7].
+		 * Add UHCI_NUMFRAMES to insure at least one bit is set.
+		 */
+		irq = 6 - (int) __ffs(i + UHCI_NUMFRAMES);
+		if (irq < 0)
+			irq = 7;
+
+		/* Only place we don't use the frame list routines */
+		uhci->fl->frame[i] = UHCI_PTR_QH |
+				cpu_to_le32(uhci->skelqh[irq]->dma_handle);
+	}
+
+	/*
+	 * Some architectures require a full mb() to enforce completion of
+	 * the memory writes above before the I/O transfers in start_hc().
+	 */
+	mb();
+	if ((retval = start_hc(uhci)) != 0)
+		goto err_alloc_skelqh;
+
+	init_stall_timer(hcd);
+
+	udev->speed = USB_SPEED_FULL;
+
+	if (usb_hcd_register_root_hub(udev, hcd) != 0) {
+		dev_err(uhci_dev(uhci), "unable to start root hub\n");
+		retval = -ENOMEM;
+		goto err_start_root_hub;
+	}
+
+	return 0;
+
+/*
+ * error exits:
+ */
+err_start_root_hub:
+	reset_hc(uhci);
+
+	del_timer_sync(&uhci->stall_timer);
+
+err_alloc_skelqh:
+	for (i = 0; i < UHCI_NUM_SKELQH; i++)
+		if (uhci->skelqh[i]) {
+			uhci_free_qh(uhci, uhci->skelqh[i]);
+			uhci->skelqh[i] = NULL;
+		}
+
+	uhci_free_td(uhci, uhci->term_td);
+	uhci->term_td = NULL;
+
+err_alloc_term_td:
+	usb_put_dev(udev);
+
+err_alloc_root_hub:
+	dma_pool_destroy(uhci->qh_pool);
+	uhci->qh_pool = NULL;
+
+err_create_qh_pool:
+	dma_pool_destroy(uhci->td_pool);
+	uhci->td_pool = NULL;
+
+err_create_td_pool:
+	dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
+			uhci->fl, uhci->fl->dma_handle);
+	uhci->fl = NULL;
+
+err_alloc_fl:
+	debugfs_remove(uhci->dentry);
+	uhci->dentry = NULL;
+
+err_create_debug_entry:
+	return retval;
+}
+
+static void uhci_stop(struct usb_hcd *hcd)
+{
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+
+	del_timer_sync(&uhci->stall_timer);
+	reset_hc(uhci);
+
+	spin_lock_irq(&uhci->lock);
+	uhci_scan_schedule(uhci, NULL);
+	spin_unlock_irq(&uhci->lock);
+	
+	release_uhci(uhci);
+}
+
+#ifdef CONFIG_PM
+static int uhci_suspend(struct usb_hcd *hcd, u32 state)
+{
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+
+	spin_lock_irq(&uhci->lock);
+
+	/* Don't try to suspend broken motherboards, reset instead */
+	if (suspend_allowed(uhci))
+		suspend_hc(uhci);
+	else {
+		spin_unlock_irq(&uhci->lock);
+		reset_hc(uhci);
+		spin_lock_irq(&uhci->lock);
+		uhci_scan_schedule(uhci, NULL);
+	}
+
+	spin_unlock_irq(&uhci->lock);
+	return 0;
+}
+
+static int uhci_resume(struct usb_hcd *hcd)
+{
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	int rc;
+
+	pci_set_master(to_pci_dev(uhci_dev(uhci)));
+
+	spin_lock_irq(&uhci->lock);
+
+	if (uhci->state == UHCI_SUSPENDED) {
+
+		/*
+		 * Some systems don't maintain the UHCI register values
+		 * during a PM suspend/resume cycle, so reinitialize
+		 * the Frame Number, Framelist Base Address, Interrupt
+		 * Enable, and Legacy Support registers.
+		 */
+		pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
+				0);
+		outw(uhci->frame_number, uhci->io_addr + USBFRNUM);
+		outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);
+		outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC |
+				USBINTR_SP, uhci->io_addr + USBINTR);
+		uhci->resume_detect = 1;
+		pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
+				USBLEGSUP_DEFAULT);
+	} else {
+		spin_unlock_irq(&uhci->lock);
+		reset_hc(uhci);
+		if ((rc = start_hc(uhci)) != 0)
+			return rc;
+		spin_lock_irq(&uhci->lock);
+	}
+	hcd->state = HC_STATE_RUNNING;
+
+	spin_unlock_irq(&uhci->lock);
+	return 0;
+}
+#endif
+
+/* Wait until all the URBs for a particular device/endpoint are gone */
+static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd,
+		struct usb_host_endpoint *ep)
+{
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+
+	wait_event_interruptible(uhci->waitqh, list_empty(&ep->urb_list));
+}
+
+static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
+{
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	int frame_number;
+	unsigned long flags;
+
+	/* Minimize latency by avoiding the spinlock */
+	local_irq_save(flags);
+	rmb();
+	frame_number = (uhci->is_stopped ? uhci->frame_number :
+			inw(uhci->io_addr + USBFRNUM));
+	local_irq_restore(flags);
+	return frame_number;
+}
+
+static const char hcd_name[] = "uhci_hcd";
+
+static const struct hc_driver uhci_driver = {
+	.description =		hcd_name,
+	.product_desc =		"UHCI Host Controller",
+	.hcd_priv_size =	sizeof(struct uhci_hcd),
+
+	/* Generic hardware linkage */
+	.irq =			uhci_irq,
+	.flags =		HCD_USB11,
+
+	/* Basic lifecycle operations */
+	.reset =		uhci_reset,
+	.start =		uhci_start,
+#ifdef CONFIG_PM
+	.suspend =		uhci_suspend,
+	.resume =		uhci_resume,
+#endif
+	.stop =			uhci_stop,
+
+	.urb_enqueue =		uhci_urb_enqueue,
+	.urb_dequeue =		uhci_urb_dequeue,
+
+	.endpoint_disable =	uhci_hcd_endpoint_disable,
+	.get_frame_number =	uhci_hcd_get_frame_number,
+
+	.hub_status_data =	uhci_hub_status_data,
+	.hub_control =		uhci_hub_control,
+};
+
+static const struct pci_device_id uhci_pci_ids[] = { {
+	/* handle any USB UHCI controller */
+	PCI_DEVICE_CLASS(((PCI_CLASS_SERIAL_USB << 8) | 0x00), ~0),
+	.driver_data =	(unsigned long) &uhci_driver,
+	}, { /* end: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE(pci, uhci_pci_ids);
+
+static struct pci_driver uhci_pci_driver = {
+	.name =		(char *)hcd_name,
+	.id_table =	uhci_pci_ids,
+
+	.probe =	usb_hcd_pci_probe,
+	.remove =	usb_hcd_pci_remove,
+
+#ifdef	CONFIG_PM
+	.suspend =	usb_hcd_pci_suspend,
+	.resume =	usb_hcd_pci_resume,
+#endif	/* PM */
+};
+ 
+static int __init uhci_hcd_init(void)
+{
+	int retval = -ENOMEM;
+
+	printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION "\n");
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	if (debug) {
+		errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
+		if (!errbuf)
+			goto errbuf_failed;
+	}
+
+	uhci_debugfs_root = debugfs_create_dir("uhci", NULL);
+	if (!uhci_debugfs_root)
+		goto debug_failed;
+
+	uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
+		sizeof(struct urb_priv), 0, 0, NULL, NULL);
+	if (!uhci_up_cachep)
+		goto up_failed;
+
+	retval = pci_register_driver(&uhci_pci_driver);
+	if (retval)
+		goto init_failed;
+
+	return 0;
+
+init_failed:
+	if (kmem_cache_destroy(uhci_up_cachep))
+		warn("not all urb_priv's were freed!");
+
+up_failed:
+	debugfs_remove(uhci_debugfs_root);
+
+debug_failed:
+	if (errbuf)
+		kfree(errbuf);
+
+errbuf_failed:
+
+	return retval;
+}
+
+static void __exit uhci_hcd_cleanup(void) 
+{
+	pci_unregister_driver(&uhci_pci_driver);
+	
+	if (kmem_cache_destroy(uhci_up_cachep))
+		warn("not all urb_priv's were freed!");
+
+	debugfs_remove(uhci_debugfs_root);
+
+	if (errbuf)
+		kfree(errbuf);
+}
+
+module_init(uhci_hcd_init);
+module_exit(uhci_hcd_cleanup);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
new file mode 100644
index 0000000..02255d6
--- /dev/null
+++ b/drivers/usb/host/uhci-hcd.h
@@ -0,0 +1,454 @@
+#ifndef __LINUX_UHCI_HCD_H
+#define __LINUX_UHCI_HCD_H
+
+#include <linux/list.h>
+#include <linux/usb.h>
+
+#define usb_packetid(pipe)	(usb_pipein(pipe) ? USB_PID_IN : USB_PID_OUT)
+#define PIPE_DEVEP_MASK		0x0007ff00
+
+/*
+ * Universal Host Controller Interface data structures and defines
+ */
+
+/* Command register */
+#define USBCMD		0
+#define   USBCMD_RS		0x0001	/* Run/Stop */
+#define   USBCMD_HCRESET	0x0002	/* Host reset */
+#define   USBCMD_GRESET		0x0004	/* Global reset */
+#define   USBCMD_EGSM		0x0008	/* Global Suspend Mode */
+#define   USBCMD_FGR		0x0010	/* Force Global Resume */
+#define   USBCMD_SWDBG		0x0020	/* SW Debug mode */
+#define   USBCMD_CF		0x0040	/* Config Flag (sw only) */
+#define   USBCMD_MAXP		0x0080	/* Max Packet (0 = 32, 1 = 64) */
+
+/* Status register */
+#define USBSTS		2
+#define   USBSTS_USBINT		0x0001	/* Interrupt due to IOC */
+#define   USBSTS_ERROR		0x0002	/* Interrupt due to error */
+#define   USBSTS_RD		0x0004	/* Resume Detect */
+#define   USBSTS_HSE		0x0008	/* Host System Error - basically PCI problems */
+#define   USBSTS_HCPE		0x0010	/* Host Controller Process Error - the scripts were buggy */
+#define   USBSTS_HCH		0x0020	/* HC Halted */
+
+/* Interrupt enable register */
+#define USBINTR		4
+#define   USBINTR_TIMEOUT	0x0001	/* Timeout/CRC error enable */
+#define   USBINTR_RESUME	0x0002	/* Resume interrupt enable */
+#define   USBINTR_IOC		0x0004	/* Interrupt On Complete enable */
+#define   USBINTR_SP		0x0008	/* Short packet interrupt enable */
+
+#define USBFRNUM	6
+#define USBFLBASEADD	8
+#define USBSOF		12
+
+/* USB port status and control registers */
+#define USBPORTSC1	16
+#define USBPORTSC2	18
+#define   USBPORTSC_CCS		0x0001	/* Current Connect Status ("device present") */
+#define   USBPORTSC_CSC		0x0002	/* Connect Status Change */
+#define   USBPORTSC_PE		0x0004	/* Port Enable */
+#define   USBPORTSC_PEC		0x0008	/* Port Enable Change */
+#define   USBPORTSC_DPLUS	0x0010	/* D+ high (line status) */
+#define   USBPORTSC_DMINUS	0x0020	/* D- high (line status) */
+#define   USBPORTSC_RD		0x0040	/* Resume Detect */
+#define   USBPORTSC_RES1	0x0080	/* reserved, always 1 */
+#define   USBPORTSC_LSDA	0x0100	/* Low Speed Device Attached */
+#define   USBPORTSC_PR		0x0200	/* Port Reset */
+/* OC and OCC from Intel 430TX and later (not UHCI 1.1d spec) */
+#define   USBPORTSC_OC		0x0400	/* Over Current condition */
+#define   USBPORTSC_OCC		0x0800	/* Over Current Change R/WC */
+#define   USBPORTSC_SUSP	0x1000	/* Suspend */
+#define   USBPORTSC_RES2	0x2000	/* reserved, write zeroes */
+#define   USBPORTSC_RES3	0x4000	/* reserved, write zeroes */
+#define   USBPORTSC_RES4	0x8000	/* reserved, write zeroes */
+
+/* Legacy support register */
+#define USBLEGSUP		0xc0
+#define   USBLEGSUP_DEFAULT	0x2000	/* only PIRQ enable set */
+
+#define UHCI_NULL_DATA_SIZE	0x7FF	/* for UHCI controller TD */
+
+#define UHCI_PTR_BITS		cpu_to_le32(0x000F)
+#define UHCI_PTR_TERM		cpu_to_le32(0x0001)
+#define UHCI_PTR_QH		cpu_to_le32(0x0002)
+#define UHCI_PTR_DEPTH		cpu_to_le32(0x0004)
+#define UHCI_PTR_BREADTH	cpu_to_le32(0x0000)
+
+#define UHCI_NUMFRAMES		1024	/* in the frame list [array] */
+#define UHCI_MAX_SOF_NUMBER	2047	/* in an SOF packet */
+#define CAN_SCHEDULE_FRAMES	1000	/* how far future frames can be scheduled */
+
+struct uhci_frame_list {
+	__le32 frame[UHCI_NUMFRAMES];
+
+	void *frame_cpu[UHCI_NUMFRAMES];
+
+	dma_addr_t dma_handle;
+};
+
+struct urb_priv;
+
+/*
+ * One role of a QH is to hold a queue of TDs for some endpoint.  Each QH is
+ * used with one URB, and qh->element (updated by the HC) is either:
+ *   - the next unprocessed TD for the URB, or
+ *   - UHCI_PTR_TERM (when there's no more traffic for this endpoint), or
+ *   - the QH for the next URB queued to the same endpoint.
+ *
+ * The other role of a QH is to serve as a "skeleton" framelist entry, so we
+ * can easily splice a QH for some endpoint into the schedule at the right
+ * place.  Then qh->element is UHCI_PTR_TERM.
+ *
+ * In the frame list, qh->link maintains a list of QHs seen by the HC:
+ *     skel1 --> ep1-qh --> ep2-qh --> ... --> skel2 --> ...
+ */
+struct uhci_qh {
+	/* Hardware fields */
+	__le32 link;			/* Next queue */
+	__le32 element;			/* Queue element pointer */
+
+	/* Software fields */
+	dma_addr_t dma_handle;
+
+	struct usb_device *dev;
+	struct urb_priv *urbp;
+
+	struct list_head list;		/* P: uhci->frame_list_lock */
+	struct list_head remove_list;	/* P: uhci->remove_list_lock */
+} __attribute__((aligned(16)));
+
+/*
+ * We need a special accessor for the element pointer because it is
+ * subject to asynchronous updates by the controller
+ */
+static __le32 inline qh_element(struct uhci_qh *qh) {
+	__le32 element = qh->element;
+
+	barrier();
+	return element;
+}
+
+/*
+ * for TD <status>:
+ */
+#define TD_CTRL_SPD		(1 << 29)	/* Short Packet Detect */
+#define TD_CTRL_C_ERR_MASK	(3 << 27)	/* Error Counter bits */
+#define TD_CTRL_C_ERR_SHIFT	27
+#define TD_CTRL_LS		(1 << 26)	/* Low Speed Device */
+#define TD_CTRL_IOS		(1 << 25)	/* Isochronous Select */
+#define TD_CTRL_IOC		(1 << 24)	/* Interrupt on Complete */
+#define TD_CTRL_ACTIVE		(1 << 23)	/* TD Active */
+#define TD_CTRL_STALLED		(1 << 22)	/* TD Stalled */
+#define TD_CTRL_DBUFERR		(1 << 21)	/* Data Buffer Error */
+#define TD_CTRL_BABBLE		(1 << 20)	/* Babble Detected */
+#define TD_CTRL_NAK		(1 << 19)	/* NAK Received */
+#define TD_CTRL_CRCTIMEO	(1 << 18)	/* CRC/Time Out Error */
+#define TD_CTRL_BITSTUFF	(1 << 17)	/* Bit Stuff Error */
+#define TD_CTRL_ACTLEN_MASK	0x7FF	/* actual length, encoded as n - 1 */
+
+#define TD_CTRL_ANY_ERROR	(TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
+				 TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
+
+#define uhci_maxerr(err)		((err) << TD_CTRL_C_ERR_SHIFT)
+#define uhci_status_bits(ctrl_sts)	((ctrl_sts) & 0xF60000)
+#define uhci_actual_length(ctrl_sts)	(((ctrl_sts) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
+
+/*
+ * for TD <info>: (a.k.a. Token)
+ */
+#define td_token(td)		le32_to_cpu((td)->token)
+#define TD_TOKEN_DEVADDR_SHIFT	8
+#define TD_TOKEN_TOGGLE_SHIFT	19
+#define TD_TOKEN_TOGGLE		(1 << 19)
+#define TD_TOKEN_EXPLEN_SHIFT	21
+#define TD_TOKEN_EXPLEN_MASK	0x7FF		/* expected length, encoded as n - 1 */
+#define TD_TOKEN_PID_MASK	0xFF
+
+#define uhci_explen(len)	((len) << TD_TOKEN_EXPLEN_SHIFT)
+
+#define uhci_expected_length(token) ((((token) >> 21) + 1) & TD_TOKEN_EXPLEN_MASK)
+#define uhci_toggle(token)	(((token) >> TD_TOKEN_TOGGLE_SHIFT) & 1)
+#define uhci_endpoint(token)	(((token) >> 15) & 0xf)
+#define uhci_devaddr(token)	(((token) >> TD_TOKEN_DEVADDR_SHIFT) & 0x7f)
+#define uhci_devep(token)	(((token) >> TD_TOKEN_DEVADDR_SHIFT) & 0x7ff)
+#define uhci_packetid(token)	((token) & TD_TOKEN_PID_MASK)
+#define uhci_packetout(token)	(uhci_packetid(token) != USB_PID_IN)
+#define uhci_packetin(token)	(uhci_packetid(token) == USB_PID_IN)
+
+/*
+ * The documentation says "4 words for hardware, 4 words for software".
+ *
+ * That's silly, the hardware doesn't care. The hardware only cares that
+ * the hardware words are 16-byte aligned, and we can have any amount of
+ * sw space after the TD entry as far as I can tell.
+ *
+ * But let's just go with the documentation, at least for 32-bit machines.
+ * On 64-bit machines we probably want to take advantage of the fact that
+ * hw doesn't really care about the size of the sw-only area.
+ *
+ * Alas, not anymore, we have more than 4 words for software, woops.
+ * Everything still works tho, surprise! -jerdfelt
+ *
+ * td->link points to either another TD (not necessarily for the same urb or
+ * even the same endpoint), or nothing (PTR_TERM), or a QH (for queued urbs)
+ */
+struct uhci_td {
+	/* Hardware fields */
+	__le32 link;
+	__le32 status;
+	__le32 token;
+	__le32 buffer;
+
+	/* Software fields */
+	dma_addr_t dma_handle;
+
+	struct usb_device *dev;
+	struct urb *urb;
+
+	struct list_head list;		/* P: urb->lock */
+	struct list_head remove_list;	/* P: uhci->td_remove_list_lock */
+
+	int frame;			/* for iso: what frame? */
+	struct list_head fl_list;	/* P: uhci->frame_list_lock */
+} __attribute__((aligned(16)));
+
+/*
+ * We need a special accessor for the control/status word because it is
+ * subject to asynchronous updates by the controller
+ */
+static u32 inline td_status(struct uhci_td *td) {
+	__le32 status = td->status;
+
+	barrier();
+	return le32_to_cpu(status);
+}
+
+
+/*
+ * The UHCI driver places Interrupt, Control and Bulk into QH's both
+ * to group together TD's for one transfer, and also to faciliate queuing
+ * of URB's. To make it easy to insert entries into the schedule, we have
+ * a skeleton of QH's for each predefined Interrupt latency, low-speed
+ * control, full-speed control and terminating QH (see explanation for
+ * the terminating QH below).
+ *
+ * When we want to add a new QH, we add it to the end of the list for the
+ * skeleton QH.
+ *
+ * For instance, the queue can look like this:
+ *
+ * skel int128 QH
+ * dev 1 interrupt QH
+ * dev 5 interrupt QH
+ * skel int64 QH
+ * skel int32 QH
+ * ...
+ * skel int1 QH
+ * skel low-speed control QH
+ * dev 5 control QH
+ * skel full-speed control QH
+ * skel bulk QH
+ * dev 1 bulk QH
+ * dev 2 bulk QH
+ * skel terminating QH
+ *
+ * The terminating QH is used for 2 reasons:
+ * - To place a terminating TD which is used to workaround a PIIX bug
+ *   (see Intel errata for explanation)
+ * - To loop back to the full-speed control queue for full-speed bandwidth
+ *   reclamation
+ *
+ * Isochronous transfers are stored before the start of the skeleton
+ * schedule and don't use QH's. While the UHCI spec doesn't forbid the
+ * use of QH's for Isochronous, it doesn't use them either. Since we don't
+ * need to use them either, we follow the spec diagrams in hope that it'll
+ * be more compatible with future UHCI implementations.
+ */
+
+#define UHCI_NUM_SKELQH		12
+#define skel_int128_qh		skelqh[0]
+#define skel_int64_qh		skelqh[1]
+#define skel_int32_qh		skelqh[2]
+#define skel_int16_qh		skelqh[3]
+#define skel_int8_qh		skelqh[4]
+#define skel_int4_qh		skelqh[5]
+#define skel_int2_qh		skelqh[6]
+#define skel_int1_qh		skelqh[7]
+#define skel_ls_control_qh	skelqh[8]
+#define skel_fs_control_qh	skelqh[9]
+#define skel_bulk_qh		skelqh[10]
+#define skel_term_qh		skelqh[11]
+
+/*
+ * Search tree for determining where <interval> fits in the skelqh[]
+ * skeleton.
+ *
+ * An interrupt request should be placed into the slowest skelqh[]
+ * which meets the interval/period/frequency requirement.
+ * An interrupt request is allowed to be faster than <interval> but not slower.
+ *
+ * For a given <interval>, this function returns the appropriate/matching
+ * skelqh[] index value.
+ */
+static inline int __interval_to_skel(int interval)
+{
+	if (interval < 16) {
+		if (interval < 4) {
+			if (interval < 2)
+				return 7;	/* int1 for 0-1 ms */
+			return 6;		/* int2 for 2-3 ms */
+		}
+		if (interval < 8)
+			return 5;		/* int4 for 4-7 ms */
+		return 4;			/* int8 for 8-15 ms */
+	}
+	if (interval < 64) {
+		if (interval < 32)
+			return 3;		/* int16 for 16-31 ms */
+		return 2;			/* int32 for 32-63 ms */
+	}
+	if (interval < 128)
+		return 1;			/* int64 for 64-127 ms */
+	return 0;				/* int128 for 128-255 ms (Max.) */
+}
+
+/*
+ * Device states for the host controller.
+ *
+ * To prevent "bouncing" in the presence of electrical noise,
+ * we insist on a 1-second "grace" period, before switching to
+ * the RUNNING or SUSPENDED states, during which the state is
+ * not allowed to change.
+ *
+ * The resume process is divided into substates in order to avoid
+ * potentially length delays during the timer handler.
+ *
+ * States in which the host controller is halted must have values <= 0.
+ */
+enum uhci_state {
+	UHCI_RESET,
+	UHCI_RUNNING_GRACE,		/* Before RUNNING */
+	UHCI_RUNNING,			/* The normal state */
+	UHCI_SUSPENDING_GRACE,		/* Before SUSPENDED */
+	UHCI_SUSPENDED = -10,		/* When no devices are attached */
+	UHCI_RESUMING_1,
+	UHCI_RESUMING_2
+};
+
+/*
+ * This describes the full uhci information.
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs.
+ */
+struct uhci_hcd {
+
+	/* debugfs */
+	struct dentry *dentry;
+
+	/* Grabbed from PCI */
+	unsigned long io_addr;
+
+	struct dma_pool *qh_pool;
+	struct dma_pool *td_pool;
+
+	struct usb_bus *bus;
+
+	struct uhci_td *term_td;	/* Terminating TD, see UHCI bug */
+	struct uhci_qh *skelqh[UHCI_NUM_SKELQH];	/* Skeleton QH's */
+
+	spinlock_t lock;
+	struct uhci_frame_list *fl;		/* P: uhci->lock */
+	int fsbr;				/* Full-speed bandwidth reclamation */
+	unsigned long fsbrtimeout;		/* FSBR delay */
+
+	enum uhci_state state;			/* FIXME: needs a spinlock */
+	unsigned long state_end;		/* Time of next transition */
+	unsigned int frame_number;		/* As of last check */
+	unsigned int is_stopped;
+#define UHCI_IS_STOPPED		9999		/* Larger than a frame # */
+
+	unsigned int scan_in_progress:1;	/* Schedule scan is running */
+	unsigned int need_rescan:1;		/* Redo the schedule scan */
+	unsigned int resume_detect:1;		/* Need a Global Resume */
+
+	/* Support for port suspend/resume/reset */
+	unsigned long port_c_suspend;		/* Bit-arrays of ports */
+	unsigned long suspended_ports;
+	unsigned long resuming_ports;
+	unsigned long ports_timeout;		/* Time to stop signalling */
+
+	/* Main list of URB's currently controlled by this HC */
+	struct list_head urb_list;		/* P: uhci->lock */
+
+	/* List of QH's that are done, but waiting to be unlinked (race) */
+	struct list_head qh_remove_list;	/* P: uhci->lock */
+	unsigned int qh_remove_age;		/* Age in frames */
+
+	/* List of TD's that are done, but waiting to be freed (race) */
+	struct list_head td_remove_list;	/* P: uhci->lock */
+	unsigned int td_remove_age;		/* Age in frames */
+
+	/* List of asynchronously unlinked URB's */
+	struct list_head urb_remove_list;	/* P: uhci->lock */
+	unsigned int urb_remove_age;		/* Age in frames */
+
+	/* List of URB's awaiting completion callback */
+	struct list_head complete_list;		/* P: uhci->lock */
+
+	int rh_numports;
+
+	struct timer_list stall_timer;
+
+	wait_queue_head_t waitqh;		/* endpoint_disable waiters */
+};
+
+/* Convert between a usb_hcd pointer and the corresponding uhci_hcd */
+static inline struct uhci_hcd *hcd_to_uhci(struct usb_hcd *hcd)
+{
+	return (struct uhci_hcd *) (hcd->hcd_priv);
+}
+static inline struct usb_hcd *uhci_to_hcd(struct uhci_hcd *uhci)
+{
+	return container_of((void *) uhci, struct usb_hcd, hcd_priv);
+}
+
+#define uhci_dev(u)	(uhci_to_hcd(u)->self.controller)
+
+struct urb_priv {
+	struct list_head urb_list;
+
+	struct urb *urb;
+
+	struct uhci_qh *qh;		/* QH for this URB */
+	struct list_head td_list;	/* P: urb->lock */
+
+	unsigned fsbr : 1;		/* URB turned on FSBR */
+	unsigned fsbr_timeout : 1;	/* URB timed out on FSBR */
+	unsigned queued : 1;		/* QH was queued (not linked in) */
+	unsigned short_control_packet : 1;	/* If we get a short packet during */
+						/*  a control transfer, retrigger */
+						/*  the status phase */
+
+	unsigned long inserttime;	/* In jiffies */
+	unsigned long fsbrtime;		/* In jiffies */
+
+	struct list_head queue_list;	/* P: uhci->frame_list_lock */
+};
+
+/*
+ * Locking in uhci.c
+ *
+ * Almost everything relating to the hardware schedule and processing
+ * of URBs is protected by uhci->lock.  urb->status is protected by
+ * urb->lock; that's the one exception.
+ *
+ * To prevent deadlocks, never lock uhci->lock while holding urb->lock.
+ * The safe order of locking is:
+ *
+ * #1 uhci->lock
+ * #2 urb->lock
+ */
+
+#endif
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
new file mode 100644
index 0000000..4c45ba8
--- /dev/null
+++ b/drivers/usb/host/uhci-hub.c
@@ -0,0 +1,299 @@
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * Maintainer: Alan Stern <stern@rowland.harvard.edu>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu
+ */
+
+static __u8 root_hub_hub_des[] =
+{
+	0x09,			/*  __u8  bLength; */
+	0x29,			/*  __u8  bDescriptorType; Hub-descriptor */
+	0x02,			/*  __u8  bNbrPorts; */
+	0x0a,			/* __u16  wHubCharacteristics; */
+	0x00,			/*   (per-port OC, no power switching) */
+	0x01,			/*  __u8  bPwrOn2pwrGood; 2ms */
+	0x00,			/*  __u8  bHubContrCurrent; 0 mA */
+	0x00,			/*  __u8  DeviceRemovable; *** 7 Ports max *** */
+	0xff			/*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+#define	UHCI_RH_MAXCHILD	7
+
+/* must write as zeroes */
+#define WZ_BITS		(USBPORTSC_RES2 | USBPORTSC_RES3 | USBPORTSC_RES4)
+
+/* status change bits:  nonzero writes will clear */
+#define RWC_BITS	(USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC)
+
+static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	int port;
+
+	*buf = 0;
+	for (port = 0; port < uhci->rh_numports; ++port) {
+		if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & RWC_BITS) ||
+				test_bit(port, &uhci->port_c_suspend))
+			*buf |= (1 << (port + 1));
+	}
+	if (*buf && uhci->state == UHCI_SUSPENDED)
+		uhci->resume_detect = 1;
+	return !!*buf;
+}
+
+#define OK(x)			len = (x); break
+
+#define CLR_RH_PORTSTAT(x) \
+	status = inw(port_addr); \
+	status &= ~(RWC_BITS|WZ_BITS); \
+	status &= ~(x); \
+	status |= RWC_BITS & (x); \
+	outw(status, port_addr)
+
+#define SET_RH_PORTSTAT(x) \
+	status = inw(port_addr); \
+	status |= (x); \
+	status &= ~(RWC_BITS|WZ_BITS); \
+	outw(status, port_addr)
+
+/* UHCI controllers don't automatically stop resume signalling after 20 msec,
+ * so we have to poll and check timeouts in order to take care of it.
+ */
+static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
+		unsigned long port_addr)
+{
+	int status;
+
+	if (test_bit(port, &uhci->suspended_ports)) {
+		CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD);
+		clear_bit(port, &uhci->suspended_ports);
+		clear_bit(port, &uhci->resuming_ports);
+		set_bit(port, &uhci->port_c_suspend);
+
+		/* The controller won't actually turn off the RD bit until
+		 * it has had a chance to send a low-speed EOP sequence,
+		 * which takes 3 bit times (= 2 microseconds).  We'll delay
+		 * slightly longer for good luck. */
+		udelay(4);
+	}
+}
+
+static void uhci_check_ports(struct uhci_hcd *uhci)
+{
+	unsigned int port;
+	unsigned long port_addr;
+	int status;
+
+	for (port = 0; port < uhci->rh_numports; ++port) {
+		port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
+		status = inw(port_addr);
+		if (unlikely(status & USBPORTSC_PR)) {
+			if (time_after_eq(jiffies, uhci->ports_timeout)) {
+				CLR_RH_PORTSTAT(USBPORTSC_PR);
+				udelay(10);
+
+				/* If the port was enabled before, turning
+				 * reset on caused a port enable change.
+				 * Turning reset off causes a port connect
+				 * status change.  Clear these changes. */
+				CLR_RH_PORTSTAT(USBPORTSC_CSC | USBPORTSC_PEC);
+				SET_RH_PORTSTAT(USBPORTSC_PE);
+			}
+		}
+		if (unlikely(status & USBPORTSC_RD)) {
+			if (!test_bit(port, &uhci->resuming_ports)) {
+
+				/* Port received a wakeup request */
+				set_bit(port, &uhci->resuming_ports);
+				uhci->ports_timeout = jiffies +
+						msecs_to_jiffies(20);
+			} else if (time_after_eq(jiffies,
+						uhci->ports_timeout)) {
+				uhci_finish_suspend(uhci, port, port_addr);
+			}
+		}
+	}
+}
+
+/* size of returned buffer is part of USB spec */
+static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+			u16 wIndex, char *buf, u16 wLength)
+{
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	int status, lstatus, retval = 0, len = 0;
+	unsigned int port = wIndex - 1;
+	unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
+	u16 wPortChange, wPortStatus;
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->lock, flags);
+	switch (typeReq) {
+
+	case GetHubStatus:
+		*(__le32 *)buf = cpu_to_le32(0);
+		OK(4);		/* hub power */
+	case GetPortStatus:
+		if (port >= uhci->rh_numports)
+			goto err;
+
+		uhci_check_ports(uhci);
+		status = inw(port_addr);
+
+		/* Intel controllers report the OverCurrent bit active on.
+		 * VIA controllers report it active off, so we'll adjust the
+		 * bit value.  (It's not standardized in the UHCI spec.)
+		 */
+		if (to_pci_dev(hcd->self.controller)->vendor ==
+				PCI_VENDOR_ID_VIA)
+			status ^= USBPORTSC_OC;
+
+		/* UHCI doesn't support C_RESET (always false) */
+		wPortChange = lstatus = 0;
+		if (status & USBPORTSC_CSC)
+			wPortChange |= USB_PORT_STAT_C_CONNECTION;
+		if (status & USBPORTSC_PEC)
+			wPortChange |= USB_PORT_STAT_C_ENABLE;
+		if (status & USBPORTSC_OCC)
+			wPortChange |= USB_PORT_STAT_C_OVERCURRENT;
+
+		if (test_bit(port, &uhci->port_c_suspend)) {
+			wPortChange |= USB_PORT_STAT_C_SUSPEND;
+			lstatus |= 1;
+		}
+		if (test_bit(port, &uhci->suspended_ports))
+			lstatus |= 2;
+		if (test_bit(port, &uhci->resuming_ports))
+			lstatus |= 4;
+
+		/* UHCI has no power switching (always on) */
+		wPortStatus = USB_PORT_STAT_POWER;
+		if (status & USBPORTSC_CCS)
+			wPortStatus |= USB_PORT_STAT_CONNECTION;
+		if (status & USBPORTSC_PE) {
+			wPortStatus |= USB_PORT_STAT_ENABLE;
+			if (status & (USBPORTSC_SUSP | USBPORTSC_RD))
+				wPortStatus |= USB_PORT_STAT_SUSPEND;
+		}
+		if (status & USBPORTSC_OC)
+			wPortStatus |= USB_PORT_STAT_OVERCURRENT;
+		if (status & USBPORTSC_PR)
+			wPortStatus |= USB_PORT_STAT_RESET;
+		if (status & USBPORTSC_LSDA)
+			wPortStatus |= USB_PORT_STAT_LOW_SPEED;
+
+		if (wPortChange)
+			dev_dbg(uhci_dev(uhci), "port %d portsc %04x,%02x\n",
+					wIndex, status, lstatus);
+
+		*(__le16 *)buf = cpu_to_le16(wPortStatus);
+		*(__le16 *)(buf + 2) = cpu_to_le16(wPortChange);
+		OK(4);
+	case SetHubFeature:		/* We don't implement these */
+	case ClearHubFeature:
+		switch (wValue) {
+		case C_HUB_OVER_CURRENT:
+		case C_HUB_LOCAL_POWER:
+			OK(0);
+		default:
+			goto err;
+		}
+		break;
+	case SetPortFeature:
+		if (port >= uhci->rh_numports)
+			goto err;
+
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			set_bit(port, &uhci->suspended_ports);
+			SET_RH_PORTSTAT(USBPORTSC_SUSP);
+			OK(0);
+		case USB_PORT_FEAT_RESET:
+			SET_RH_PORTSTAT(USBPORTSC_PR);
+
+			/* Reset terminates Resume signalling */
+			uhci_finish_suspend(uhci, port, port_addr);
+
+			/* USB v2.0 7.1.7.5 */
+			uhci->ports_timeout = jiffies + msecs_to_jiffies(50);
+			OK(0);
+		case USB_PORT_FEAT_POWER:
+			/* UHCI has no power switching */
+			OK(0);
+		default:
+			goto err;
+		}
+		break;
+	case ClearPortFeature:
+		if (port >= uhci->rh_numports)
+			goto err;
+
+		switch (wValue) {
+		case USB_PORT_FEAT_ENABLE:
+			CLR_RH_PORTSTAT(USBPORTSC_PE);
+
+			/* Disable terminates Resume signalling */
+			uhci_finish_suspend(uhci, port, port_addr);
+			OK(0);
+		case USB_PORT_FEAT_C_ENABLE:
+			CLR_RH_PORTSTAT(USBPORTSC_PEC);
+			OK(0);
+		case USB_PORT_FEAT_SUSPEND:
+			if (test_bit(port, &uhci->suspended_ports) &&
+					!test_and_set_bit(port,
+						&uhci->resuming_ports)) {
+				SET_RH_PORTSTAT(USBPORTSC_RD);
+
+				/* The controller won't allow RD to be set
+				 * if the port is disabled.  When this happens
+				 * just skip the Resume signalling.
+				 */
+				if (!(inw(port_addr) & USBPORTSC_RD))
+					uhci_finish_suspend(uhci, port,
+							port_addr);
+				else
+					/* USB v2.0 7.1.7.7 */
+					uhci->ports_timeout = jiffies +
+						msecs_to_jiffies(20);
+			}
+			OK(0);
+		case USB_PORT_FEAT_C_SUSPEND:
+			clear_bit(port, &uhci->port_c_suspend);
+			OK(0);
+		case USB_PORT_FEAT_POWER:
+			/* UHCI has no power switching */
+			goto err;
+		case USB_PORT_FEAT_C_CONNECTION:
+			CLR_RH_PORTSTAT(USBPORTSC_CSC);
+			OK(0);
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+			CLR_RH_PORTSTAT(USBPORTSC_OCC);
+			OK(0);
+		case USB_PORT_FEAT_C_RESET:
+			/* this driver won't report these */
+			OK(0);
+		default:
+			goto err;
+		}
+		break;
+	case GetHubDescriptor:
+		len = min_t(unsigned int, sizeof(root_hub_hub_des), wLength);
+		memcpy(buf, root_hub_hub_des, len);
+		if (len > 2)
+			buf[2] = uhci->rh_numports;
+		OK(len);
+	default:
+err:
+		retval = -EPIPE;
+	}
+	spin_unlock_irqrestore(&uhci->lock, flags);
+
+	return retval;
+}
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
new file mode 100644
index 0000000..2a7c195
--- /dev/null
+++ b/drivers/usb/host/uhci-q.c
@@ -0,0 +1,1539 @@
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * Maintainer: Alan Stern <stern@rowland.harvard.edu>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ * (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu
+ */
+
+static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
+static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb);
+static void uhci_remove_pending_urbps(struct uhci_hcd *uhci);
+static void uhci_free_pending_qhs(struct uhci_hcd *uhci);
+static void uhci_free_pending_tds(struct uhci_hcd *uhci);
+
+/*
+ * Technically, updating td->status here is a race, but it's not really a
+ * problem. The worst that can happen is that we set the IOC bit again
+ * generating a spurious interrupt. We could fix this by creating another
+ * QH and leaving the IOC bit always set, but then we would have to play
+ * games with the FSBR code to make sure we get the correct order in all
+ * the cases. I don't think it's worth the effort
+ */
+static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci)
+{
+	uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC); 
+}
+
+static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
+{
+	uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC);
+}
+
+static inline void uhci_moveto_complete(struct uhci_hcd *uhci, 
+					struct urb_priv *urbp)
+{
+	list_move_tail(&urbp->urb_list, &uhci->complete_list);
+}
+
+static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *dev)
+{
+	dma_addr_t dma_handle;
+	struct uhci_td *td;
+
+	td = dma_pool_alloc(uhci->td_pool, GFP_ATOMIC, &dma_handle);
+	if (!td)
+		return NULL;
+
+	td->dma_handle = dma_handle;
+
+	td->link = UHCI_PTR_TERM;
+	td->buffer = 0;
+
+	td->frame = -1;
+	td->dev = dev;
+
+	INIT_LIST_HEAD(&td->list);
+	INIT_LIST_HEAD(&td->remove_list);
+	INIT_LIST_HEAD(&td->fl_list);
+
+	usb_get_dev(dev);
+
+	return td;
+}
+
+static inline void uhci_fill_td(struct uhci_td *td, u32 status,
+		u32 token, u32 buffer)
+{
+	td->status = cpu_to_le32(status);
+	td->token = cpu_to_le32(token);
+	td->buffer = cpu_to_le32(buffer);
+}
+
+/*
+ * We insert Isochronous URB's directly into the frame list at the beginning
+ */
+static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, unsigned framenum)
+{
+	framenum &= (UHCI_NUMFRAMES - 1);
+
+	td->frame = framenum;
+
+	/* Is there a TD already mapped there? */
+	if (uhci->fl->frame_cpu[framenum]) {
+		struct uhci_td *ftd, *ltd;
+
+		ftd = uhci->fl->frame_cpu[framenum];
+		ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list);
+
+		list_add_tail(&td->fl_list, &ftd->fl_list);
+
+		td->link = ltd->link;
+		wmb();
+		ltd->link = cpu_to_le32(td->dma_handle);
+	} else {
+		td->link = uhci->fl->frame[framenum];
+		wmb();
+		uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle);
+		uhci->fl->frame_cpu[framenum] = td;
+	}
+}
+
+static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td)
+{
+	/* If it's not inserted, don't remove it */
+	if (td->frame == -1 && list_empty(&td->fl_list))
+		return;
+
+	if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) {
+		if (list_empty(&td->fl_list)) {
+			uhci->fl->frame[td->frame] = td->link;
+			uhci->fl->frame_cpu[td->frame] = NULL;
+		} else {
+			struct uhci_td *ntd;
+
+			ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
+			uhci->fl->frame[td->frame] = cpu_to_le32(ntd->dma_handle);
+			uhci->fl->frame_cpu[td->frame] = ntd;
+		}
+	} else {
+		struct uhci_td *ptd;
+
+		ptd = list_entry(td->fl_list.prev, struct uhci_td, fl_list);
+		ptd->link = td->link;
+	}
+
+	wmb();
+	td->link = UHCI_PTR_TERM;
+
+	list_del_init(&td->fl_list);
+	td->frame = -1;
+}
+
+/*
+ * Inserts a td list into qh.
+ */
+static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, __le32 breadth)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci_td *td;
+	__le32 *plink;
+
+	/* Ordering isn't important here yet since the QH hasn't been */
+	/* inserted into the schedule yet */
+	plink = &qh->element;
+	list_for_each_entry(td, &urbp->td_list, list) {
+		*plink = cpu_to_le32(td->dma_handle) | breadth;
+		plink = &td->link;
+	}
+	*plink = UHCI_PTR_TERM;
+}
+
+static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
+{
+	if (!list_empty(&td->list))
+		dev_warn(uhci_dev(uhci), "td %p still in list!\n", td);
+	if (!list_empty(&td->remove_list))
+		dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td);
+	if (!list_empty(&td->fl_list))
+		dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
+
+	if (td->dev)
+		usb_put_dev(td->dev);
+
+	dma_pool_free(uhci->td_pool, td, td->dma_handle);
+}
+
+static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *dev)
+{
+	dma_addr_t dma_handle;
+	struct uhci_qh *qh;
+
+	qh = dma_pool_alloc(uhci->qh_pool, GFP_ATOMIC, &dma_handle);
+	if (!qh)
+		return NULL;
+
+	qh->dma_handle = dma_handle;
+
+	qh->element = UHCI_PTR_TERM;
+	qh->link = UHCI_PTR_TERM;
+
+	qh->dev = dev;
+	qh->urbp = NULL;
+
+	INIT_LIST_HEAD(&qh->list);
+	INIT_LIST_HEAD(&qh->remove_list);
+
+	usb_get_dev(dev);
+
+	return qh;
+}
+
+static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+	if (!list_empty(&qh->list))
+		dev_warn(uhci_dev(uhci), "qh %p list not empty!\n", qh);
+	if (!list_empty(&qh->remove_list))
+		dev_warn(uhci_dev(uhci), "qh %p still in remove_list!\n", qh);
+
+	if (qh->dev)
+		usb_put_dev(qh->dev);
+
+	dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
+}
+
+/*
+ * Append this urb's qh after the last qh in skelqh->list
+ *
+ * Note that urb_priv.queue_list doesn't have a separate queue head;
+ * it's a ring with every element "live".
+ */
+static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct urb_priv *turbp;
+	struct uhci_qh *lqh;
+
+	/* Grab the last QH */
+	lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
+
+	/* Point to the next skelqh */
+	urbp->qh->link = lqh->link;
+	wmb();				/* Ordering is important */
+
+	/*
+	 * Patch QHs for previous endpoint's queued URBs?  HC goes
+	 * here next, not to the next skelqh it now points to.
+	 *
+	 *    lqh --> td ... --> qh ... --> td --> qh ... --> td
+	 *     |                 |                 |
+	 *     v                 v                 v
+	 *     +<----------------+-----------------+
+	 *     v
+	 *    newqh --> td ... --> td
+	 *     |
+	 *     v
+	 *    ...
+	 *
+	 * The HC could see (and use!) any of these as we write them.
+	 */
+	lqh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
+	if (lqh->urbp) {
+		list_for_each_entry(turbp, &lqh->urbp->queue_list, queue_list)
+			turbp->qh->link = lqh->link;
+	}
+
+	list_add_tail(&urbp->qh->list, &skelqh->list);
+}
+
+/*
+ * Start removal of QH from schedule; it finishes next frame.
+ * TDs should be unlinked before this is called.
+ */
+static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+	struct uhci_qh *pqh;
+	__le32 newlink;
+
+	if (!qh)
+		return;
+
+	/*
+	 * Only go through the hoops if it's actually linked in
+	 */
+	if (!list_empty(&qh->list)) {
+
+		/* If our queue is nonempty, make the next URB the head */
+		if (!list_empty(&qh->urbp->queue_list)) {
+			struct urb_priv *nurbp;
+
+			nurbp = list_entry(qh->urbp->queue_list.next,
+					struct urb_priv, queue_list);
+			nurbp->queued = 0;
+			list_add(&nurbp->qh->list, &qh->list);
+			newlink = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
+		} else
+			newlink = qh->link;
+
+		/* Fix up the previous QH's queue to link to either
+		 * the new head of this queue or the start of the
+		 * next endpoint's queue. */
+		pqh = list_entry(qh->list.prev, struct uhci_qh, list);
+		pqh->link = newlink;
+		if (pqh->urbp) {
+			struct urb_priv *turbp;
+
+			list_for_each_entry(turbp, &pqh->urbp->queue_list,
+					queue_list)
+				turbp->qh->link = newlink;
+		}
+		wmb();
+
+		/* Leave qh->link in case the HC is on the QH now, it will */
+		/* continue the rest of the schedule */
+		qh->element = UHCI_PTR_TERM;
+
+		list_del_init(&qh->list);
+	}
+
+	list_del_init(&qh->urbp->queue_list);
+	qh->urbp = NULL;
+
+	uhci_get_current_frame_number(uhci);
+	if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age) {
+		uhci_free_pending_qhs(uhci);
+		uhci->qh_remove_age = uhci->frame_number;
+	}
+
+	/* Check to see if the remove list is empty. Set the IOC bit */
+	/* to force an interrupt so we can remove the QH */
+	if (list_empty(&uhci->qh_remove_list))
+		uhci_set_next_interrupt(uhci);
+
+	list_add(&qh->remove_list, &uhci->qh_remove_list);
+}
+
+static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci_td *td;
+
+	list_for_each_entry(td, &urbp->td_list, list) {
+		if (toggle)
+			td->token |= cpu_to_le32(TD_TOKEN_TOGGLE);
+		else
+			td->token &= ~cpu_to_le32(TD_TOKEN_TOGGLE);
+
+		toggle ^= 1;
+	}
+
+	return toggle;
+}
+
+/* This function will append one URB's QH to another URB's QH. This is for */
+/* queuing interrupt, control or bulk transfers */
+static void uhci_append_queued_urb(struct uhci_hcd *uhci, struct urb *eurb, struct urb *urb)
+{
+	struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
+	struct uhci_td *lltd;
+
+	eurbp = eurb->hcpriv;
+	urbp = urb->hcpriv;
+
+	/* Find the first URB in the queue */
+	furbp = eurbp;
+	if (eurbp->queued) {
+		list_for_each_entry(furbp, &eurbp->queue_list, queue_list)
+			if (!furbp->queued)
+				break;
+	}
+
+	lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list);
+
+	lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
+
+	/* Control transfers always start with toggle 0 */
+	if (!usb_pipecontrol(urb->pipe))
+		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+				usb_pipeout(urb->pipe),
+				uhci_fixup_toggle(urb,
+					uhci_toggle(td_token(lltd)) ^ 1));
+
+	/* All qh's in the queue need to link to the next queue */
+	urbp->qh->link = eurbp->qh->link;
+
+	wmb();			/* Make sure we flush everything */
+
+	lltd->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
+
+	list_add_tail(&urbp->queue_list, &furbp->queue_list);
+
+	urbp->queued = 1;
+}
+
+static void uhci_delete_queued_urb(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp, *nurbp, *purbp, *turbp;
+	struct uhci_td *pltd;
+	unsigned int toggle;
+
+	urbp = urb->hcpriv;
+
+	if (list_empty(&urbp->queue_list))
+		return;
+
+	nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list);
+
+	/*
+	 * Fix up the toggle for the following URBs in the queue.
+	 * Only needed for bulk and interrupt: control and isochronous
+	 * endpoints don't propagate toggles between messages.
+	 */
+	if (usb_pipebulk(urb->pipe) || usb_pipeint(urb->pipe)) {
+		if (!urbp->queued)
+			/* We just set the toggle in uhci_unlink_generic */
+			toggle = usb_gettoggle(urb->dev,
+					usb_pipeendpoint(urb->pipe),
+					usb_pipeout(urb->pipe));
+		else {
+			/* If we're in the middle of the queue, grab the */
+			/* toggle from the TD previous to us */
+			purbp = list_entry(urbp->queue_list.prev,
+					struct urb_priv, queue_list);
+			pltd = list_entry(purbp->td_list.prev,
+					struct uhci_td, list);
+			toggle = uhci_toggle(td_token(pltd)) ^ 1;
+		}
+
+		list_for_each_entry(turbp, &urbp->queue_list, queue_list) {
+			if (!turbp->queued)
+				break;
+			toggle = uhci_fixup_toggle(turbp->urb, toggle);
+		}
+
+		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+				usb_pipeout(urb->pipe), toggle);
+	}
+
+	if (urbp->queued) {
+		/* We're somewhere in the middle (or end).  The case where
+		 * we're at the head is handled in uhci_remove_qh(). */
+		purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
+				queue_list);
+
+		pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
+		if (nurbp->queued)
+			pltd->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
+		else
+			/* The next URB happens to be the beginning, so */
+			/*  we're the last, end the chain */
+			pltd->link = UHCI_PTR_TERM;
+	}
+
+	/* urbp->queue_list is handled in uhci_remove_qh() */
+}
+
+static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp;
+
+	urbp = kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC);
+	if (!urbp)
+		return NULL;
+
+	memset((void *)urbp, 0, sizeof(*urbp));
+
+	urbp->inserttime = jiffies;
+	urbp->fsbrtime = jiffies;
+	urbp->urb = urb;
+	
+	INIT_LIST_HEAD(&urbp->td_list);
+	INIT_LIST_HEAD(&urbp->queue_list);
+	INIT_LIST_HEAD(&urbp->urb_list);
+
+	list_add_tail(&urbp->urb_list, &uhci->urb_list);
+
+	urb->hcpriv = urbp;
+
+	return urbp;
+}
+
+static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+	td->urb = urb;
+
+	list_add_tail(&td->list, &urbp->td_list);
+}
+
+static void uhci_remove_td_from_urb(struct uhci_td *td)
+{
+	if (list_empty(&td->list))
+		return;
+
+	list_del_init(&td->list);
+
+	td->urb = NULL;
+}
+
+static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct uhci_td *td, *tmp;
+	struct urb_priv *urbp;
+
+	urbp = (struct urb_priv *)urb->hcpriv;
+	if (!urbp)
+		return;
+
+	if (!list_empty(&urbp->urb_list))
+		dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list "
+				"or uhci->remove_list!\n", urb);
+
+	uhci_get_current_frame_number(uhci);
+	if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age) {
+		uhci_free_pending_tds(uhci);
+		uhci->td_remove_age = uhci->frame_number;
+	}
+
+	/* Check to see if the remove list is empty. Set the IOC bit */
+	/* to force an interrupt so we can remove the TD's*/
+	if (list_empty(&uhci->td_remove_list))
+		uhci_set_next_interrupt(uhci);
+
+	list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
+		uhci_remove_td_from_urb(td);
+		uhci_remove_td(uhci, td);
+		list_add(&td->remove_list, &uhci->td_remove_list);
+	}
+
+	urb->hcpriv = NULL;
+	kmem_cache_free(uhci_up_cachep, urbp);
+}
+
+static void uhci_inc_fsbr(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+	if ((!(urb->transfer_flags & URB_NO_FSBR)) && !urbp->fsbr) {
+		urbp->fsbr = 1;
+		if (!uhci->fsbr++ && !uhci->fsbrtimeout)
+			uhci->skel_term_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;
+	}
+}
+
+static void uhci_dec_fsbr(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+	if ((!(urb->transfer_flags & URB_NO_FSBR)) && urbp->fsbr) {
+		urbp->fsbr = 0;
+		if (!--uhci->fsbr)
+			uhci->fsbrtimeout = jiffies + FSBR_DELAY;
+	}
+}
+
+/*
+ * Map status to standard result codes
+ *
+ * <status> is (td_status(td) & 0xF60000), a.k.a.
+ * uhci_status_bits(td_status(td)).
+ * Note: <status> does not include the TD_CTRL_NAK bit.
+ * <dir_out> is True for output TDs and False for input TDs.
+ */
+static int uhci_map_status(int status, int dir_out)
+{
+	if (!status)
+		return 0;
+	if (status & TD_CTRL_BITSTUFF)			/* Bitstuff error */
+		return -EPROTO;
+	if (status & TD_CTRL_CRCTIMEO) {		/* CRC/Timeout */
+		if (dir_out)
+			return -EPROTO;
+		else
+			return -EILSEQ;
+	}
+	if (status & TD_CTRL_BABBLE)			/* Babble */
+		return -EOVERFLOW;
+	if (status & TD_CTRL_DBUFERR)			/* Buffer error */
+		return -ENOSR;
+	if (status & TD_CTRL_STALLED)			/* Stalled */
+		return -EPIPE;
+	WARN_ON(status & TD_CTRL_ACTIVE);		/* Active */
+	return 0;
+}
+
+/*
+ * Control transfers
+ */
+static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci_td *td;
+	struct uhci_qh *qh, *skelqh;
+	unsigned long destination, status;
+	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	int len = urb->transfer_buffer_length;
+	dma_addr_t data = urb->transfer_dma;
+
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
+
+	/* 3 errors */
+	status = TD_CTRL_ACTIVE | uhci_maxerr(3);
+	if (urb->dev->speed == USB_SPEED_LOW)
+		status |= TD_CTRL_LS;
+
+	/*
+	 * Build the TD for the control request setup packet
+	 */
+	td = uhci_alloc_td(uhci, urb->dev);
+	if (!td)
+		return -ENOMEM;
+
+	uhci_add_td_to_urb(urb, td);
+	uhci_fill_td(td, status, destination | uhci_explen(7),
+		urb->setup_dma);
+
+	/*
+	 * If direction is "send", change the packet ID from SETUP (0x2D)
+	 * to OUT (0xE1).  Else change it from SETUP to IN (0x69) and
+	 * set Short Packet Detect (SPD) for all data packets.
+	 */
+	if (usb_pipeout(urb->pipe))
+		destination ^= (USB_PID_SETUP ^ USB_PID_OUT);
+	else {
+		destination ^= (USB_PID_SETUP ^ USB_PID_IN);
+		status |= TD_CTRL_SPD;
+	}
+
+	/*
+	 * Build the DATA TD's
+	 */
+	while (len > 0) {
+		int pktsze = len;
+
+		if (pktsze > maxsze)
+			pktsze = maxsze;
+
+		td = uhci_alloc_td(uhci, urb->dev);
+		if (!td)
+			return -ENOMEM;
+
+		/* Alternate Data0/1 (start with Data1) */
+		destination ^= TD_TOKEN_TOGGLE;
+	
+		uhci_add_td_to_urb(urb, td);
+		uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1),
+			data);
+
+		data += pktsze;
+		len -= pktsze;
+	}
+
+	/*
+	 * Build the final TD for control status 
+	 */
+	td = uhci_alloc_td(uhci, urb->dev);
+	if (!td)
+		return -ENOMEM;
+
+	/*
+	 * It's IN if the pipe is an output pipe or we're not expecting
+	 * data back.
+	 */
+	destination &= ~TD_TOKEN_PID_MASK;
+	if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
+		destination |= USB_PID_IN;
+	else
+		destination |= USB_PID_OUT;
+
+	destination |= TD_TOKEN_TOGGLE;		/* End in Data1 */
+
+	status &= ~TD_CTRL_SPD;
+
+	uhci_add_td_to_urb(urb, td);
+	uhci_fill_td(td, status | TD_CTRL_IOC,
+		destination | uhci_explen(UHCI_NULL_DATA_SIZE), 0);
+
+	qh = uhci_alloc_qh(uhci, urb->dev);
+	if (!qh)
+		return -ENOMEM;
+
+	urbp->qh = qh;
+	qh->urbp = urbp;
+
+	uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
+
+	/* Low-speed transfers get a different queue, and won't hog the bus.
+	 * Also, some devices enumerate better without FSBR; the easiest way
+	 * to do that is to put URBs on the low-speed queue while the device
+	 * is in the DEFAULT state. */
+	if (urb->dev->speed == USB_SPEED_LOW ||
+			urb->dev->state == USB_STATE_DEFAULT)
+		skelqh = uhci->skel_ls_control_qh;
+	else {
+		skelqh = uhci->skel_fs_control_qh;
+		uhci_inc_fsbr(uhci, urb);
+	}
+
+	if (eurb)
+		uhci_append_queued_urb(uhci, eurb, urb);
+	else
+		uhci_insert_qh(uhci, skelqh, urb);
+
+	return -EINPROGRESS;
+}
+
+/*
+ * If control-IN transfer was short, the status packet wasn't sent.
+ * This routine changes the element pointer in the QH to point at the
+ * status TD.  It's safe to do this even while the QH is live, because
+ * the hardware only updates the element pointer following a successful
+ * transfer.  The inactive TD for the short packet won't cause an update,
+ * so the pointer won't get overwritten.  The next time the controller
+ * sees this QH, it will send the status packet.
+ */
+static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci_td *td;
+
+	urbp->short_control_packet = 1;
+
+	td = list_entry(urbp->td_list.prev, struct uhci_td, list);
+	urbp->qh->element = cpu_to_le32(td->dma_handle);
+
+	return -EINPROGRESS;
+}
+
+
+static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct list_head *tmp, *head;
+	struct urb_priv *urbp = urb->hcpriv;
+	struct uhci_td *td;
+	unsigned int status;
+	int ret = 0;
+
+	if (list_empty(&urbp->td_list))
+		return -EINVAL;
+
+	head = &urbp->td_list;
+
+	if (urbp->short_control_packet) {
+		tmp = head->prev;
+		goto status_stage;
+	}
+
+	tmp = head->next;
+	td = list_entry(tmp, struct uhci_td, list);
+
+	/* The first TD is the SETUP stage, check the status, but skip */
+	/*  the count */
+	status = uhci_status_bits(td_status(td));
+	if (status & TD_CTRL_ACTIVE)
+		return -EINPROGRESS;
+
+	if (status)
+		goto td_error;
+
+	urb->actual_length = 0;
+
+	/* The rest of the TD's (but the last) are data */
+	tmp = tmp->next;
+	while (tmp != head && tmp->next != head) {
+		unsigned int ctrlstat;
+
+		td = list_entry(tmp, struct uhci_td, list);
+		tmp = tmp->next;
+
+		ctrlstat = td_status(td);
+		status = uhci_status_bits(ctrlstat);
+		if (status & TD_CTRL_ACTIVE)
+			return -EINPROGRESS;
+
+		urb->actual_length += uhci_actual_length(ctrlstat);
+
+		if (status)
+			goto td_error;
+
+		/* Check to see if we received a short packet */
+		if (uhci_actual_length(ctrlstat) <
+				uhci_expected_length(td_token(td))) {
+			if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+				ret = -EREMOTEIO;
+				goto err;
+			}
+
+			if (uhci_packetid(td_token(td)) == USB_PID_IN)
+				return usb_control_retrigger_status(uhci, urb);
+			else
+				return 0;
+		}
+	}
+
+status_stage:
+	td = list_entry(tmp, struct uhci_td, list);
+
+	/* Control status stage */
+	status = td_status(td);
+
+#ifdef I_HAVE_BUGGY_APC_BACKUPS
+	/* APC BackUPS Pro kludge */
+	/* It tries to send all of the descriptor instead of the amount */
+	/*  we requested */
+	if (status & TD_CTRL_IOC &&	/* IOC is masked out by uhci_status_bits */
+	    status & TD_CTRL_ACTIVE &&
+	    status & TD_CTRL_NAK)
+		return 0;
+#endif
+
+	status = uhci_status_bits(status);
+	if (status & TD_CTRL_ACTIVE)
+		return -EINPROGRESS;
+
+	if (status)
+		goto td_error;
+
+	return 0;
+
+td_error:
+	ret = uhci_map_status(status, uhci_packetout(td_token(td)));
+
+err:
+	if ((debug == 1 && ret != -EPIPE) || debug > 1) {
+		/* Some debugging code */
+		dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
+				__FUNCTION__, status);
+
+		if (errbuf) {
+			/* Print the chain for debugging purposes */
+			uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
+
+			lprintk(errbuf);
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * Common submit for bulk and interrupt
+ */
+static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb, struct uhci_qh *skelqh)
+{
+	struct uhci_td *td;
+	struct uhci_qh *qh;
+	unsigned long destination, status;
+	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	int len = urb->transfer_buffer_length;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	dma_addr_t data = urb->transfer_dma;
+
+	if (len < 0)
+		return -EINVAL;
+
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+	status = uhci_maxerr(3) | TD_CTRL_ACTIVE;
+	if (urb->dev->speed == USB_SPEED_LOW)
+		status |= TD_CTRL_LS;
+	if (usb_pipein(urb->pipe))
+		status |= TD_CTRL_SPD;
+
+	/*
+	 * Build the DATA TD's
+	 */
+	do {	/* Allow zero length packets */
+		int pktsze = maxsze;
+
+		if (pktsze >= len) {
+			pktsze = len;
+			if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
+				status &= ~TD_CTRL_SPD;
+		}
+
+		td = uhci_alloc_td(uhci, urb->dev);
+		if (!td)
+			return -ENOMEM;
+
+		uhci_add_td_to_urb(urb, td);
+		uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1) |
+			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
+			data);
+
+		data += pktsze;
+		len -= maxsze;
+
+		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			usb_pipeout(urb->pipe));
+	} while (len > 0);
+
+	/*
+	 * URB_ZERO_PACKET means adding a 0-length packet, if direction
+	 * is OUT and the transfer_length was an exact multiple of maxsze,
+	 * hence (len = transfer_length - N * maxsze) == 0
+	 * however, if transfer_length == 0, the zero packet was already
+	 * prepared above.
+	 */
+	if (usb_pipeout(urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) &&
+	    !len && urb->transfer_buffer_length) {
+		td = uhci_alloc_td(uhci, urb->dev);
+		if (!td)
+			return -ENOMEM;
+
+		uhci_add_td_to_urb(urb, td);
+		uhci_fill_td(td, status, destination | uhci_explen(UHCI_NULL_DATA_SIZE) |
+			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
+			data);
+
+		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			usb_pipeout(urb->pipe));
+	}
+
+	/* Set the interrupt-on-completion flag on the last packet.
+	 * A more-or-less typical 4 KB URB (= size of one memory page)
+	 * will require about 3 ms to transfer; that's a little on the
+	 * fast side but not enough to justify delaying an interrupt
+	 * more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT
+	 * flag setting. */
+	td->status |= cpu_to_le32(TD_CTRL_IOC);
+
+	qh = uhci_alloc_qh(uhci, urb->dev);
+	if (!qh)
+		return -ENOMEM;
+
+	urbp->qh = qh;
+	qh->urbp = urbp;
+
+	/* Always breadth first */
+	uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
+
+	if (eurb)
+		uhci_append_queued_urb(uhci, eurb, urb);
+	else
+		uhci_insert_qh(uhci, skelqh, urb);
+
+	return -EINPROGRESS;
+}
+
+/*
+ * Common result for bulk and interrupt
+ */
+static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp = urb->hcpriv;
+	struct uhci_td *td;
+	unsigned int status = 0;
+	int ret = 0;
+
+	urb->actual_length = 0;
+
+	list_for_each_entry(td, &urbp->td_list, list) {
+		unsigned int ctrlstat = td_status(td);
+
+		status = uhci_status_bits(ctrlstat);
+		if (status & TD_CTRL_ACTIVE)
+			return -EINPROGRESS;
+
+		urb->actual_length += uhci_actual_length(ctrlstat);
+
+		if (status)
+			goto td_error;
+
+		if (uhci_actual_length(ctrlstat) <
+				uhci_expected_length(td_token(td))) {
+			if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+				ret = -EREMOTEIO;
+				goto err;
+			} else
+				return 0;
+		}
+	}
+
+	return 0;
+
+td_error:
+	ret = uhci_map_status(status, uhci_packetout(td_token(td)));
+
+err:
+	/* 
+	 * Enable this chunk of code if you want to see some more debugging.
+	 * But be careful, it has the tendancy to starve out khubd and prevent
+	 * disconnects from happening successfully if you have a slow debug
+	 * log interface (like a serial console.
+	 */
+#if 0
+	if ((debug == 1 && ret != -EPIPE) || debug > 1) {
+		/* Some debugging code */
+		dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
+				__FUNCTION__, status);
+
+		if (errbuf) {
+			/* Print the chain for debugging purposes */
+			uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
+
+			lprintk(errbuf);
+		}
+	}
+#endif
+	return ret;
+}
+
+static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
+{
+	int ret;
+
+	/* Can't have low-speed bulk transfers */
+	if (urb->dev->speed == USB_SPEED_LOW)
+		return -EINVAL;
+
+	ret = uhci_submit_common(uhci, urb, eurb, uhci->skel_bulk_qh);
+	if (ret == -EINPROGRESS)
+		uhci_inc_fsbr(uhci, urb);
+
+	return ret;
+}
+
+static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
+{
+	/* USB 1.1 interrupt transfers only involve one packet per interval;
+	 * that's the uhci_submit_common() "breadth first" policy.  Drivers
+	 * can submit urbs of any length, but longer ones might need many
+	 * intervals to complete.
+	 */
+	return uhci_submit_common(uhci, urb, eurb, uhci->skelqh[__interval_to_skel(urb->interval)]);
+}
+
+/*
+ * Isochronous transfers
+ */
+static int isochronous_find_limits(struct uhci_hcd *uhci, struct urb *urb, unsigned int *start, unsigned int *end)
+{
+	struct urb *last_urb = NULL;
+	struct urb_priv *up;
+	int ret = 0;
+
+	list_for_each_entry(up, &uhci->urb_list, urb_list) {
+		struct urb *u = up->urb;
+
+		/* look for pending URB's with identical pipe handle */
+		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
+		    (u->status == -EINPROGRESS) && (u != urb)) {
+			if (!last_urb)
+				*start = u->start_frame;
+			last_urb = u;
+		}
+	}
+
+	if (last_urb) {
+		*end = (last_urb->start_frame + last_urb->number_of_packets *
+				last_urb->interval) & (UHCI_NUMFRAMES-1);
+		ret = 0;
+	} else
+		ret = -1;	/* no previous urb found */
+
+	return ret;
+}
+
+static int isochronous_find_start(struct uhci_hcd *uhci, struct urb *urb)
+{
+	int limits;
+	unsigned int start = 0, end = 0;
+
+	if (urb->number_of_packets > 900)	/* 900? Why? */
+		return -EFBIG;
+
+	limits = isochronous_find_limits(uhci, urb, &start, &end);
+
+	if (urb->transfer_flags & URB_ISO_ASAP) {
+		if (limits) {
+			uhci_get_current_frame_number(uhci);
+			urb->start_frame = (uhci->frame_number + 10)
+					& (UHCI_NUMFRAMES - 1);
+		} else
+			urb->start_frame = end;
+	} else {
+		urb->start_frame &= (UHCI_NUMFRAMES - 1);
+		/* FIXME: Sanity check */
+	}
+
+	return 0;
+}
+
+/*
+ * Isochronous transfers
+ */
+static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct uhci_td *td;
+	int i, ret, frame;
+	int status, destination;
+
+	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+	ret = isochronous_find_start(uhci, urb);
+	if (ret)
+		return ret;
+
+	frame = urb->start_frame;
+	for (i = 0; i < urb->number_of_packets; i++, frame += urb->interval) {
+		if (!urb->iso_frame_desc[i].length)
+			continue;
+
+		td = uhci_alloc_td(uhci, urb->dev);
+		if (!td)
+			return -ENOMEM;
+
+		uhci_add_td_to_urb(urb, td);
+		uhci_fill_td(td, status, destination | uhci_explen(urb->iso_frame_desc[i].length - 1),
+			urb->transfer_dma + urb->iso_frame_desc[i].offset);
+
+		if (i + 1 >= urb->number_of_packets)
+			td->status |= cpu_to_le32(TD_CTRL_IOC);
+
+		uhci_insert_td_frame_list(uhci, td, frame);
+	}
+
+	return -EINPROGRESS;
+}
+
+static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct uhci_td *td;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	int status;
+	int i, ret = 0;
+
+	urb->actual_length = 0;
+
+	i = 0;
+	list_for_each_entry(td, &urbp->td_list, list) {
+		int actlength;
+		unsigned int ctrlstat = td_status(td);
+
+		if (ctrlstat & TD_CTRL_ACTIVE)
+			return -EINPROGRESS;
+
+		actlength = uhci_actual_length(ctrlstat);
+		urb->iso_frame_desc[i].actual_length = actlength;
+		urb->actual_length += actlength;
+
+		status = uhci_map_status(uhci_status_bits(ctrlstat),
+				usb_pipeout(urb->pipe));
+		urb->iso_frame_desc[i].status = status;
+		if (status) {
+			urb->error_count++;
+			ret = status;
+		}
+
+		i++;
+	}
+
+	return ret;
+}
+
+static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct urb_priv *up;
+
+	/* We don't match Isoc transfers since they are special */
+	if (usb_pipeisoc(urb->pipe))
+		return NULL;
+
+	list_for_each_entry(up, &uhci->urb_list, urb_list) {
+		struct urb *u = up->urb;
+
+		if (u->dev == urb->dev && u->status == -EINPROGRESS) {
+			/* For control, ignore the direction */
+			if (usb_pipecontrol(urb->pipe) &&
+			    (u->pipe & ~USB_DIR_IN) == (urb->pipe & ~USB_DIR_IN))
+				return u;
+			else if (u->pipe == urb->pipe)
+				return u;
+		}
+	}
+
+	return NULL;
+}
+
+static int uhci_urb_enqueue(struct usb_hcd *hcd,
+		struct usb_host_endpoint *ep,
+		struct urb *urb, int mem_flags)
+{
+	int ret;
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	unsigned long flags;
+	struct urb *eurb;
+	int bustime;
+
+	spin_lock_irqsave(&uhci->lock, flags);
+
+	ret = urb->status;
+	if (ret != -EINPROGRESS)		/* URB already unlinked! */
+		goto out;
+
+	eurb = uhci_find_urb_ep(uhci, urb);
+
+	if (!uhci_alloc_urb_priv(uhci, urb)) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		ret = uhci_submit_control(uhci, urb, eurb);
+		break;
+	case PIPE_INTERRUPT:
+		if (!eurb) {
+			bustime = usb_check_bandwidth(urb->dev, urb);
+			if (bustime < 0)
+				ret = bustime;
+			else {
+				ret = uhci_submit_interrupt(uhci, urb, eurb);
+				if (ret == -EINPROGRESS)
+					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
+			}
+		} else {	/* inherit from parent */
+			urb->bandwidth = eurb->bandwidth;
+			ret = uhci_submit_interrupt(uhci, urb, eurb);
+		}
+		break;
+	case PIPE_BULK:
+		ret = uhci_submit_bulk(uhci, urb, eurb);
+		break;
+	case PIPE_ISOCHRONOUS:
+		bustime = usb_check_bandwidth(urb->dev, urb);
+		if (bustime < 0) {
+			ret = bustime;
+			break;
+		}
+
+		ret = uhci_submit_isochronous(uhci, urb);
+		if (ret == -EINPROGRESS)
+			usb_claim_bandwidth(urb->dev, urb, bustime, 1);
+		break;
+	}
+
+	if (ret != -EINPROGRESS) {
+		/* Submit failed, so delete it from the urb_list */
+		struct urb_priv *urbp = urb->hcpriv;
+
+		list_del_init(&urbp->urb_list);
+		uhci_destroy_urb_priv(uhci, urb);
+	} else
+		ret = 0;
+
+out:
+	spin_unlock_irqrestore(&uhci->lock, flags);
+	return ret;
+}
+
+/*
+ * Return the result of a transfer
+ */
+static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb)
+{
+	int ret = -EINPROGRESS;
+	struct urb_priv *urbp;
+
+	spin_lock(&urb->lock);
+
+	urbp = (struct urb_priv *)urb->hcpriv;
+
+	if (urb->status != -EINPROGRESS)	/* URB already dequeued */
+		goto out;
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		ret = uhci_result_control(uhci, urb);
+		break;
+	case PIPE_BULK:
+	case PIPE_INTERRUPT:
+		ret = uhci_result_common(uhci, urb);
+		break;
+	case PIPE_ISOCHRONOUS:
+		ret = uhci_result_isochronous(uhci, urb);
+		break;
+	}
+
+	if (ret == -EINPROGRESS)
+		goto out;
+	urb->status = ret;
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+	case PIPE_BULK:
+	case PIPE_ISOCHRONOUS:
+		/* Release bandwidth for Interrupt or Isoc. transfers */
+		if (urb->bandwidth)
+			usb_release_bandwidth(urb->dev, urb, 1);
+		uhci_unlink_generic(uhci, urb);
+		break;
+	case PIPE_INTERRUPT:
+		/* Release bandwidth for Interrupt or Isoc. transfers */
+		/* Make sure we don't release if we have a queued URB */
+		if (list_empty(&urbp->queue_list) && urb->bandwidth)
+			usb_release_bandwidth(urb->dev, urb, 0);
+		else
+			/* bandwidth was passed on to queued URB, */
+			/* so don't let usb_unlink_urb() release it */
+			urb->bandwidth = 0;
+		uhci_unlink_generic(uhci, urb);
+		break;
+	default:
+		dev_info(uhci_dev(uhci), "%s: unknown pipe type %d "
+				"for urb %p\n",
+				__FUNCTION__, usb_pipetype(urb->pipe), urb);
+	}
+
+	/* Move it from uhci->urb_list to uhci->complete_list */
+	uhci_moveto_complete(uhci, urbp);
+
+out:
+	spin_unlock(&urb->lock);
+}
+
+static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct list_head *head;
+	struct uhci_td *td;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	int prevactive = 0;
+
+	uhci_dec_fsbr(uhci, urb);	/* Safe since it checks */
+
+	/*
+	 * Now we need to find out what the last successful toggle was
+	 * so we can update the local data toggle for the next transfer
+	 *
+	 * There are 2 ways the last successful completed TD is found:
+	 *
+	 * 1) The TD is NOT active and the actual length < expected length
+	 * 2) The TD is NOT active and it's the last TD in the chain
+	 *
+	 * and a third way the first uncompleted TD is found:
+	 *
+	 * 3) The TD is active and the previous TD is NOT active
+	 *
+	 * Control and Isochronous ignore the toggle, so this is safe
+	 * for all types
+	 *
+	 * FIXME: The toggle fixups won't be 100% reliable until we
+	 * change over to using a single queue for each endpoint and
+	 * stop the queue before unlinking.
+	 */
+	head = &urbp->td_list;
+	list_for_each_entry(td, head, list) {
+		unsigned int ctrlstat = td_status(td);
+
+		if (!(ctrlstat & TD_CTRL_ACTIVE) &&
+				(uhci_actual_length(ctrlstat) <
+				 uhci_expected_length(td_token(td)) ||
+				td->list.next == head))
+			usb_settoggle(urb->dev, uhci_endpoint(td_token(td)),
+				uhci_packetout(td_token(td)),
+				uhci_toggle(td_token(td)) ^ 1);
+		else if ((ctrlstat & TD_CTRL_ACTIVE) && !prevactive)
+			usb_settoggle(urb->dev, uhci_endpoint(td_token(td)),
+				uhci_packetout(td_token(td)),
+				uhci_toggle(td_token(td)));
+
+		prevactive = ctrlstat & TD_CTRL_ACTIVE;
+	}
+
+	uhci_delete_queued_urb(uhci, urb);
+
+	/* The interrupt loop will reclaim the QH's */
+	uhci_remove_qh(uhci, urbp->qh);
+	urbp->qh = NULL;
+}
+
+static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+{
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	unsigned long flags;
+	struct urb_priv *urbp;
+
+	spin_lock_irqsave(&uhci->lock, flags);
+	urbp = urb->hcpriv;
+	if (!urbp)			/* URB was never linked! */
+		goto done;
+	list_del_init(&urbp->urb_list);
+
+	uhci_unlink_generic(uhci, urb);
+
+	uhci_get_current_frame_number(uhci);
+	if (uhci->frame_number + uhci->is_stopped != uhci->urb_remove_age) {
+		uhci_remove_pending_urbps(uhci);
+		uhci->urb_remove_age = uhci->frame_number;
+	}
+
+	/* If we're the first, set the next interrupt bit */
+	if (list_empty(&uhci->urb_remove_list))
+		uhci_set_next_interrupt(uhci);
+	list_add_tail(&urbp->urb_list, &uhci->urb_remove_list);
+
+done:
+	spin_unlock_irqrestore(&uhci->lock, flags);
+	return 0;
+}
+
+static int uhci_fsbr_timeout(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct list_head *head;
+	struct uhci_td *td;
+	int count = 0;
+
+	uhci_dec_fsbr(uhci, urb);
+
+	urbp->fsbr_timeout = 1;
+
+	/*
+	 * Ideally we would want to fix qh->element as well, but it's
+	 * read/write by the HC, so that can introduce a race. It's not
+	 * really worth the hassle
+	 */
+
+	head = &urbp->td_list;
+	list_for_each_entry(td, head, list) {
+		/*
+		 * Make sure we don't do the last one (since it'll have the
+		 * TERM bit set) as well as we skip every so many TD's to
+		 * make sure it doesn't hog the bandwidth
+		 */
+		if (td->list.next != head && (count % DEPTH_INTERVAL) ==
+				(DEPTH_INTERVAL - 1))
+			td->link |= UHCI_PTR_DEPTH;
+
+		count++;
+	}
+
+	return 0;
+}
+
+static void uhci_free_pending_qhs(struct uhci_hcd *uhci)
+{
+	struct uhci_qh *qh, *tmp;
+
+	list_for_each_entry_safe(qh, tmp, &uhci->qh_remove_list, remove_list) {
+		list_del_init(&qh->remove_list);
+
+		uhci_free_qh(uhci, qh);
+	}
+}
+
+static void uhci_free_pending_tds(struct uhci_hcd *uhci)
+{
+	struct uhci_td *td, *tmp;
+
+	list_for_each_entry_safe(td, tmp, &uhci->td_remove_list, remove_list) {
+		list_del_init(&td->remove_list);
+
+		uhci_free_td(uhci, td);
+	}
+}
+
+static void
+uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
+__releases(uhci->lock)
+__acquires(uhci->lock)
+{
+	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+
+	uhci_destroy_urb_priv(uhci, urb);
+
+	spin_unlock(&uhci->lock);
+	usb_hcd_giveback_urb(hcd, urb, regs);
+	spin_lock(&uhci->lock);
+}
+
+static void uhci_finish_completion(struct uhci_hcd *uhci, struct pt_regs *regs)
+{
+	struct urb_priv *urbp, *tmp;
+
+	list_for_each_entry_safe(urbp, tmp, &uhci->complete_list, urb_list) {
+		struct urb *urb = urbp->urb;
+
+		list_del_init(&urbp->urb_list);
+		uhci_finish_urb(uhci_to_hcd(uhci), urb, regs);
+	}
+}
+
+static void uhci_remove_pending_urbps(struct uhci_hcd *uhci)
+{
+
+	/* Splice the urb_remove_list onto the end of the complete_list */
+	list_splice_init(&uhci->urb_remove_list, uhci->complete_list.prev);
+}
+
+/* Process events in the schedule, but only in one thread at a time */
+static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
+{
+	struct urb_priv *urbp, *tmp;
+
+	/* Don't allow re-entrant calls */
+	if (uhci->scan_in_progress) {
+		uhci->need_rescan = 1;
+		return;
+	}
+	uhci->scan_in_progress = 1;
+ rescan:
+	uhci->need_rescan = 0;
+
+	uhci_get_current_frame_number(uhci);
+
+	if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age)
+		uhci_free_pending_qhs(uhci);
+	if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age)
+		uhci_free_pending_tds(uhci);
+	if (uhci->frame_number + uhci->is_stopped != uhci->urb_remove_age)
+		uhci_remove_pending_urbps(uhci);
+
+	/* Walk the list of pending URBs to see which ones completed
+	 * (must be _safe because uhci_transfer_result() dequeues URBs) */
+	list_for_each_entry_safe(urbp, tmp, &uhci->urb_list, urb_list) {
+		struct urb *urb = urbp->urb;
+
+		/* Checks the status and does all of the magic necessary */
+		uhci_transfer_result(uhci, urb);
+	}
+	uhci_finish_completion(uhci, regs);
+
+	/* If the controller is stopped, we can finish these off right now */
+	if (uhci->is_stopped) {
+		uhci_free_pending_qhs(uhci);
+		uhci_free_pending_tds(uhci);
+		uhci_remove_pending_urbps(uhci);
+	}
+
+	if (uhci->need_rescan)
+		goto rescan;
+	uhci->scan_in_progress = 0;
+
+	if (list_empty(&uhci->urb_remove_list) &&
+	    list_empty(&uhci->td_remove_list) &&
+	    list_empty(&uhci->qh_remove_list))
+		uhci_clear_next_interrupt(uhci);
+	else
+		uhci_set_next_interrupt(uhci);
+
+	/* Wake up anyone waiting for an URB to complete */
+	wake_up_all(&uhci->waitqh);
+}