ChangeSet 1.1026, 2003/03/05 14:49:41-08:00, greg@kroah.com

[PATCH] USB: move the UHCI drivers into drivers/usb/host


 drivers/usb/uhci-debug.h          |  573 ------
 drivers/usb/uhci.c                | 3172 --------------------------------------
 drivers/usb/uhci.h                |  441 -----
 drivers/usb/usb-uhci-debug.h      |  195 --
 drivers/usb/usb-uhci.c            | 3143 -------------------------------------
 drivers/usb/usb-uhci.h            |  308 ---
 drivers/usb/Config.in             |    8 
 drivers/usb/Makefile              |    4 
 drivers/usb/host/Config.in        |    8 
 drivers/usb/host/Makefile         |    2 
 drivers/usb/host/uhci-debug.h     |  573 ++++++
 drivers/usb/host/uhci.c           | 3172 ++++++++++++++++++++++++++++++++++++++
 drivers/usb/host/uhci.h           |  441 +++++
 drivers/usb/host/usb-uhci-debug.h |  195 ++
 drivers/usb/host/usb-uhci.c       | 3143 +++++++++++++++++++++++++++++++++++++
 drivers/usb/host/usb-uhci.h       |  308 +++
 16 files changed, 7844 insertions(+), 7842 deletions(-)


diff -Nru a/drivers/usb/Config.in b/drivers/usb/Config.in
--- a/drivers/usb/Config.in	Thu Mar  6 14:22:16 2003
+++ b/drivers/usb/Config.in	Thu Mar  6 14:22:16 2003
@@ -18,14 +18,6 @@
 
    comment 'USB Host Controller Drivers'
    source drivers/usb/host/Config.in
-   if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
-      dep_tristate '  UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
-   fi
-   if [ "$CONFIG_USB_UHCI" != "y" ]; then
-      dep_tristate '  UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
-   else
-      define_bool CONFIG_USB_UHCI_ALT n
-   fi
    dep_tristate '  OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
 
    comment 'USB Device Class drivers'
diff -Nru a/drivers/usb/Makefile b/drivers/usb/Makefile
--- a/drivers/usb/Makefile	Thu Mar  6 14:22:16 2003
+++ b/drivers/usb/Makefile	Thu Mar  6 14:22:16 2003
@@ -56,14 +56,14 @@
 	obj-y += host/ehci-hcd.o
 endif
 
-obj-$(CONFIG_USB_UHCI)		+= usb-uhci.o
-obj-$(CONFIG_USB_UHCI_ALT)	+= uhci.o
 obj-$(CONFIG_USB_OHCI)		+= usb-ohci.o
 
 ifneq ($(CONFIG_USB_EHCI_HCD),n)
 	usbcore-objs		+= hcd.o
 endif
 subdir-$(CONFIG_USB_EHCI_HCD)	+= host
+subdir-$(CONFIG_USB_UHCI_ALT)	+= host
+subdir-$(CONFIG_USB_UHCI)	+= host
 
 obj-$(CONFIG_USB_MOUSE)		+= usbmouse.o
 obj-$(CONFIG_USB_HID)		+= hid.o
diff -Nru a/drivers/usb/host/Config.in b/drivers/usb/host/Config.in
--- a/drivers/usb/host/Config.in	Thu Mar  6 14:22:16 2003
+++ b/drivers/usb/host/Config.in	Thu Mar  6 14:22:16 2003
@@ -4,4 +4,12 @@
 dep_tristate '  EHCI HCD (USB 2.0) support (EXPERIMENTAL)' CONFIG_USB_EHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
 # dep_tristate '  OHCI HCD support (EXPERIMENTAL)' CONFIG_USB_OHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
 # dep_tristate '  UHCI HCD (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_USB_UHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
+if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
+   dep_tristate '  UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
+fi
+if [ "$CONFIG_USB_UHCI" != "y" ]; then
+   dep_tristate '  UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
+else
+   define_bool CONFIG_USB_UHCI_ALT n
+fi
 
diff -Nru a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
--- a/drivers/usb/host/Makefile	Thu Mar  6 14:22:16 2003
+++ b/drivers/usb/host/Makefile	Thu Mar  6 14:22:16 2003
@@ -6,6 +6,8 @@
 O_TARGET	:=
 
 obj-$(CONFIG_USB_EHCI_HCD)			+= ehci-hcd.o
+obj-$(CONFIG_USB_UHCI_ALT)			+= uhci.o
+obj-$(CONFIG_USB_UHCI)				+= usb-uhci.o
 # obj-$(CONFIG_USB_OHCI_HCD)			+= ohci-hcd.o
 # obj-$(CONFIG_USB_UHCI_HCD)			+= uhci-hcd.o
 
diff -Nru a/drivers/usb/host/uhci-debug.h b/drivers/usb/host/uhci-debug.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/host/uhci-debug.h	Thu Mar  6 14:22:16 2003
@@ -0,0 +1,573 @@
+/*
+ * 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/proc_fs.h>
+#include <asm/io.h>
+
+#include "uhci.h"
+
+/* Handle REALLY large printk's so we don't overflow buffers */
+static void inline lprintk(char *buf)
+{
+	char *p;
+
+	/* Just write one line at a time */
+	while (buf) {
+		p = strchr(buf, '\n');
+		if (p)
+			*p = 0;
+		printk("%s\n", buf);
+		buf = p;
+		if (buf)
+			buf++;
+	}
+}
+
+static int inline uhci_is_skeleton_td(struct uhci *uhci, struct uhci_td *td)
+{
+	int i;
+
+	for (i = 0; i < UHCI_NUM_SKELTD; i++)
+		if (td == uhci->skeltd[i])
+			return 1;
+
+	return 0;
+}
+
+static int inline uhci_is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh)
+{
+	int i;
+
+	for (i = 0; i < UHCI_NUM_SKELQH; i++)
+		if (qh == uhci->skelqh[i])
+			return 1;
+
+	return 0;
+}
+
+static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
+{
+	char *out = buf;
+	char *spid;
+
+	/* Try to make sure there's enough memory */
+	if (len < 160)
+		return 0;
+
+	out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td, td->link);
+	out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
+		((td->status >> 27) & 3),
+		(td->status & TD_CTRL_SPD) ?      "SPD " : "",
+		(td->status & TD_CTRL_LS) ?       "LS " : "",
+		(td->status & TD_CTRL_IOC) ?      "IOC " : "",
+		(td->status & TD_CTRL_ACTIVE) ?   "Active " : "",
+		(td->status & TD_CTRL_STALLED) ?  "Stalled " : "",
+		(td->status & TD_CTRL_DBUFERR) ?  "DataBufErr " : "",
+		(td->status & TD_CTRL_BABBLE) ?   "Babble " : "",
+		(td->status & TD_CTRL_NAK) ?      "NAK " : "",
+		(td->status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
+		(td->status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
+		td->status & 0x7ff);
+
+	switch (td->info & 0xff) {
+		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) ",
+		td->info >> 21,
+		((td->info >> 19) & 1),
+		(td->info >> 15) & 15,
+		(td->info >> 8) & 127,
+		(td->info & 0xff),
+		spid);
+	out += sprintf(out, "(buf=%08x)\n", td->buffer);
+
+	return out - buf;
+}
+
+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 < 80)
+		return 0;
+
+	out += sprintf(out, "  stat%d     =     %04x   %s%s%s%s%s%s%s%s\n",
+		port,
+		status,
+		(status & USBPORTSC_SUSP) ? "PortSuspend " : "",
+		(status & USBPORTSC_PR) ?   "PortReset " : "",
+		(status & USBPORTSC_LSDA) ? "LowSpeed " : "",
+		(status & USBPORTSC_RD) ?   "ResumeDetect " : "",
+		(status & USBPORTSC_PEC) ?  "EnableChange " : "",
+		(status & USBPORTSC_PE) ?   "PortEnabled " : "",
+		(status & USBPORTSC_CSC) ?  "ConnectChange " : "",
+		(status & USBPORTSC_CCS) ?  "PortConnected " : "");
+
+	return out - buf;
+}
+
+static int uhci_show_status(struct uhci *uhci, char *buf, int len)
+{
+	char *out = buf;
+	unsigned int 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_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;
+
+	/* 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, qh->link, qh->element);
+
+	if (qh->element & UHCI_PTR_QH)
+		out += sprintf(out, "%*s  Element points to QH (bug?)\n", space, "");
+
+	if (qh->element & UHCI_PTR_DEPTH)
+		out += sprintf(out, "%*s  Depth traverse\n", space, "");
+
+	if (qh->element & 8)
+		out += sprintf(out, "%*s  Bit 3 set (bug?)\n", space, "");
+
+	if (!(qh->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 (td->dma_handle != (qh->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 = ntd->status & 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_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;
+}
+
+static const char *td_names[] = {"skel_int1_td", "skel_int2_td",
+				 "skel_int4_td", "skel_int8_td",
+				 "skel_int16_td", "skel_int32_td",
+				 "skel_int64_td", "skel_int128_td",
+				 "skel_int256_td", "skel_term_td" };
+static const char *qh_names[] = { "skel_ls_control_qh", "skel_hs_control_qh",
+				  "skel_bulk_qh", "skel_term_qh" };
+
+#define show_frame_num()	\
+	if (!shown) {		\
+	  shown = 1;		\
+	  out += sprintf(out, "- Frame %d\n", i); \
+	}
+
+#define show_td_name()		\
+	if (!shown) {		\
+	  shown = 1;		\
+	  out += sprintf(out, "- %s\n", td_names[i]); \
+	}
+
+#define show_qh_name()		\
+	if (!shown) {		\
+	  shown = 1;		\
+	  out += sprintf(out, "- %s\n", qh_names[i]); \
+	}
+
+static int uhci_sprint_schedule(struct uhci *uhci, char *buf, int len)
+{
+	char *out = buf;
+	int i;
+	struct uhci_qh *qh;
+	struct uhci_td *td;
+	struct list_head *tmp, *head;
+
+	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");
+		}
+		if (uhci_is_skeleton_td(uhci, td))
+			continue;
+		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 TD's\n");
+	for (i = UHCI_NUM_SKELTD - 1; i >= 0; i--) {
+		int shown = 0;
+
+		td = uhci->skeltd[i];
+
+		if (debug > 1) {
+			show_td_name();
+			out += uhci_show_td(td, out, len - (out - buf), 4);
+		}
+
+		if (list_empty(&td->fl_list)) {
+			/* TD 0 is the int1 TD and links to control_ls_qh */
+			if (!i) {
+				if (td->link !=
+				    (uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH)) {
+					show_td_name();
+					out += sprintf(out, "    skeleton TD not linked to ls_control QH!\n");
+				}
+			} else if (i < 9) {
+				if (td->link != uhci->skeltd[i - 1]->dma_handle) {
+					show_td_name();
+					out += sprintf(out, "    skeleton TD not linked to next skeleton TD!\n");
+				}
+			} else {
+				show_td_name();
+
+				if (td->link != td->dma_handle)
+					out += sprintf(out, "    skel_term_td does not link to self\n");
+
+				/* Don't show it twice */
+				if (debug <= 1)
+					out += uhci_show_td(td, out, len - (out - buf), 4);
+			}
+
+			continue;
+		}
+
+		show_td_name();
+
+		head = &td->fl_list;
+		tmp = head->next;
+
+		while (tmp != head) {
+			td = list_entry(tmp, struct uhci_td, fl_list);
+
+			tmp = tmp->next;
+
+			out += uhci_show_td(td, out, len - (out - buf), 4);
+		}
+
+		if (!i) {
+			if (td->link !=
+			    (uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH))
+				out += sprintf(out, "    last TD not linked to ls_control QH!\n");
+		} else if (i < 9) {
+			if (td->link != uhci->skeltd[i - 1]->dma_handle)
+				out += sprintf(out, "    last TD not linked to next skeleton!\n");
+		}
+	}
+
+	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);
+		}
+
+		/* QH 3 is the Terminating QH, it's different */
+		if (i == 3) {
+			if (qh->link != UHCI_PTR_TERM) {
+				show_qh_name();
+				out += sprintf(out, "    bandwidth reclamation on!\n");
+			}
+
+			if (qh->element != uhci->skel_term_td->dma_handle) {
+				show_qh_name();
+				out += sprintf(out, "    skel_term_qh element is not set to skel_term_td\n");
+			}
+		}
+
+		if (list_empty(&qh->list)) {
+			if (i < 3) {
+				if (qh->link !=
+				    (uhci->skelqh[i + 1]->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 < 3) {
+			if (qh->link !=
+			    (uhci->skelqh[i + 1]->dma_handle | UHCI_PTR_QH))
+				out += sprintf(out, "    last QH not linked to next skeleton!\n");
+		}
+	}
+
+	return out - buf;
+}
+
+#ifdef CONFIG_PROC_FS
+#define MAX_OUTPUT	(PAGE_SIZE * 8)
+
+static struct proc_dir_entry *uhci_proc_root = NULL;
+
+struct uhci_proc {
+	int size;
+	char *data;
+	struct uhci *uhci;
+};
+
+static int uhci_proc_open(struct inode *inode, struct file *file)
+{
+	const struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct uhci *uhci = dp->data;
+	struct uhci_proc *up;
+	unsigned long flags;
+	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;
+	}
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+
+	file->private_data = up;
+
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
+}
+
+static loff_t uhci_proc_lseek(struct file *file, loff_t off, int whence)
+{
+	struct uhci_proc *up = file->private_data;
+	loff_t new;
+
+	switch (whence) {
+	case 0:
+		new = off;
+		break;
+	case 1:
+		new = file->f_pos + off;
+		break;
+	case 2:
+	default:
+		return -EINVAL;
+	}
+	if (new < 0 || new > up->size)
+		return -EINVAL;
+	return (file->f_pos = new);
+}
+
+static ssize_t uhci_proc_read(struct file *file, char *buf, size_t nbytes,
+			loff_t *ppos)
+{
+	struct uhci_proc *up = file->private_data;
+	unsigned int pos;
+	unsigned int size;
+
+	pos = *ppos;
+	size = up->size;
+	if (pos >= size)
+		return 0;
+	if (nbytes >= size)
+		nbytes = size;
+	if (pos + nbytes > size)
+		nbytes = size - pos;
+
+	if (!access_ok(VERIFY_WRITE, buf, nbytes))
+		return -EINVAL;
+
+	copy_to_user(buf, up->data + pos, nbytes);
+
+	*ppos += nbytes;
+
+	return nbytes;
+}
+
+static int uhci_proc_release(struct inode *inode, struct file *file)
+{
+	struct uhci_proc *up = file->private_data;
+
+	kfree(up->data);
+	kfree(up);
+
+	return 0;
+}
+
+static struct file_operations uhci_proc_operations = {
+	open:		uhci_proc_open,
+	llseek:		uhci_proc_lseek,
+	read:		uhci_proc_read,
+//	write:		uhci_proc_write,
+	release:	uhci_proc_release,
+};
+#endif
+
diff -Nru a/drivers/usb/host/uhci.c b/drivers/usb/host/uhci.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/host/uhci.c	Thu Mar  6 14:22:16 2003
@@ -0,0 +1,3172 @@
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * Maintainer: Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * (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)
+ *
+ * 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>
+#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/proc_fs.h>
+#ifdef CONFIG_USB_DEBUG
+#define DEBUG
+#else
+#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "uhci.h"
+
+#include <linux/pm.h>
+
+#include "../hcd.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.1"
+#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
+#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 /proc/uhci/hc*
+ * debug = 3, show all TD's in URB's when dumping
+ */
+#ifdef DEBUG
+static int debug = 1;
+#else
+static int debug = 0;
+#endif
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level");
+static char *errbuf;
+#define ERRBUF_LEN    (PAGE_SIZE * 8)
+
+#include "uhci-debug.h"
+
+static kmem_cache_t *uhci_up_cachep;	/* urb_priv */
+
+static int rh_submit_urb(struct urb *urb);
+static int rh_unlink_urb(struct urb *urb);
+static int uhci_get_current_frame_number(struct usb_device *dev);
+static int uhci_unlink_urb(struct urb *urb);
+static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb);
+static void uhci_call_completion(struct urb *urb);
+
+static int  ports_active(struct uhci *uhci);
+static void suspend_hc(struct uhci *uhci);
+static void wakeup_hc(struct uhci *uhci);
+
+/* If a transfer is still active after this much time, turn off FSBR */
+#define IDLE_TIMEOUT	(HZ / 20)	/* 50 ms */
+#define FSBR_DELAY	(HZ / 20)	/* 50 ms */
+
+/* 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
+
+#define MAX_URB_LOOP	2048		/* Maximum number of linked URB's */
+
+/*
+ * Only the USB core should call uhci_alloc_dev and uhci_free_dev
+ */
+static int uhci_alloc_dev(struct usb_device *dev)
+{
+	return 0;
+}
+
+static int uhci_free_dev(struct usb_device *dev)
+{
+	return 0;
+}
+
+/*
+ * 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 spurios 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 *uhci)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	uhci->skel_term_td->status |= TD_CTRL_IOC;
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+static inline void uhci_clear_next_interrupt(struct uhci *uhci)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	uhci->skel_term_td->status &= ~TD_CTRL_IOC;
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+static inline void uhci_add_complete(struct urb *urb)
+{
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->complete_list_lock, flags);
+	list_add(&urbp->complete_list, &uhci->complete_list);
+	spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
+}
+
+static struct uhci_td *uhci_alloc_td(struct uhci *uhci, struct usb_device *dev)
+{
+	dma_addr_t dma_handle;
+	struct uhci_td *td;
+
+	td = pci_pool_alloc(uhci->td_pool, GFP_DMA | 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->fl_list);
+
+	usb_inc_dev_use(dev);
+
+	return td;
+}
+
+static void inline uhci_fill_td(struct uhci_td *td, __u32 status,
+		__u32 info, __u32 buffer)
+{
+	td->status = status;
+	td->info = info;
+	td->buffer = buffer;
+}
+
+static void uhci_insert_td(struct uhci *uhci, struct uhci_td *skeltd, struct uhci_td *td)
+{
+	unsigned long flags;
+	struct uhci_td *ltd;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+
+	ltd = list_entry(skeltd->fl_list.prev, struct uhci_td, fl_list);
+
+	td->link = ltd->link;
+	mb();
+	ltd->link = td->dma_handle;
+
+	list_add_tail(&td->fl_list, &skeltd->fl_list);
+
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+/*
+ * We insert Isochronous transfers directly into the frame list at the
+ * beginning
+ * The layout looks as follows:
+ * frame list pointer -> iso td's (if any) ->
+ * periodic interrupt td (if frame 0) -> irq td's -> control qh -> bulk qh
+ */
+static void uhci_insert_td_frame_list(struct uhci *uhci, struct uhci_td *td, unsigned framenum)
+{
+	unsigned long flags;
+
+	framenum %= UHCI_NUMFRAMES;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+
+	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;
+		mb();
+		ltd->link = td->dma_handle;
+	} else {
+		td->link = uhci->fl->frame[framenum];
+		mb();
+		uhci->fl->frame[framenum] = td->dma_handle;
+		uhci->fl->frame_cpu[framenum] = td;
+	}
+
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+static void uhci_remove_td(struct uhci *uhci, struct uhci_td *td)
+{
+	unsigned long flags;
+
+	/* If it's not inserted, don't remove it */
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	if (td->frame == -1 && list_empty(&td->fl_list))
+		goto out;
+
+	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] = 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;
+	}
+
+	mb();
+	td->link = UHCI_PTR_TERM;
+
+	list_del_init(&td->fl_list);
+	td->frame = -1;
+
+out:
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+/*
+ * Inserts a td into qh list at the top.
+ */
+static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, int breadth)
+{
+	struct list_head *tmp, *head;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci_td *td, *ptd;
+
+	if (list_empty(&urbp->td_list))
+		return;
+
+	head = &urbp->td_list;
+	tmp = head->next;
+
+	/* Ordering isn't important here yet since the QH hasn't been */
+	/*  inserted into the schedule yet */
+	td = list_entry(tmp, struct uhci_td, list);
+
+	/* Add the first TD to the QH element pointer */
+	qh->element = td->dma_handle | (breadth ? 0 : UHCI_PTR_DEPTH);
+
+	ptd = td;
+
+	/* Then link the rest of the TD's */
+	tmp = tmp->next;
+	while (tmp != head) {
+		td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		ptd->link = td->dma_handle | (breadth ? 0 : UHCI_PTR_DEPTH);
+
+		ptd = td;
+	}
+
+	ptd->link = UHCI_PTR_TERM;
+}
+
+static void uhci_free_td(struct uhci *uhci, struct uhci_td *td)
+{
+	if (!list_empty(&td->list) || !list_empty(&td->fl_list))
+		dbg("td is still in URB list!");
+
+	if (td->dev)
+		usb_dec_dev_use(td->dev);
+
+	pci_pool_free(uhci->td_pool, td, td->dma_handle);
+}
+
+static struct uhci_qh *uhci_alloc_qh(struct uhci *uhci, struct usb_device *dev)
+{
+	dma_addr_t dma_handle;
+	struct uhci_qh *qh;
+
+	qh = pci_pool_alloc(uhci->qh_pool, GFP_DMA | 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_inc_dev_use(dev);
+
+	return qh;
+}
+
+static void uhci_free_qh(struct uhci *uhci, struct uhci_qh *qh)
+{
+	if (!list_empty(&qh->list))
+		dbg("qh list not empty!");
+	if (!list_empty(&qh->remove_list))
+		dbg("qh still in remove_list!");
+
+	if (qh->dev)
+		usb_dec_dev_use(qh->dev);
+
+	pci_pool_free(uhci->qh_pool, qh, qh->dma_handle);
+}
+
+/*
+ * MUST be called with uhci->frame_list_lock acquired
+ */
+static void _uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct list_head *head, *tmp;
+	struct uhci_qh *lqh;
+
+	/* Grab the last QH */
+	lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
+
+	if (lqh->urbp) {
+		head = &lqh->urbp->queue_list;
+		tmp = head->next;
+		while (head != tmp) {
+			struct urb_priv *turbp =
+				list_entry(tmp, struct urb_priv, queue_list);
+
+			tmp = tmp->next;
+
+			turbp->qh->link = urbp->qh->dma_handle | UHCI_PTR_QH;
+		}
+	}
+
+	head = &urbp->queue_list;
+	tmp = head->next;
+	while (head != tmp) {
+		struct urb_priv *turbp =
+			list_entry(tmp, struct urb_priv, queue_list);
+
+		tmp = tmp->next;
+
+		turbp->qh->link = lqh->link;
+	}
+
+	urbp->qh->link = lqh->link;
+	mb();				/* Ordering is important */
+	lqh->link = urbp->qh->dma_handle | UHCI_PTR_QH;
+
+	list_add_tail(&urbp->qh->list, &skelqh->list);
+}
+
+static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb *urb)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	_uhci_insert_qh(uhci, skelqh, urb);
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
+{
+	unsigned long flags;
+	struct uhci_qh *pqh;
+
+	if (!qh)
+		return;
+
+	qh->urbp = NULL;
+
+	/* Only go through the hoops if it's actually linked in */
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	if (!list_empty(&qh->list)) {
+		pqh = list_entry(qh->list.prev, struct uhci_qh, list);
+
+		if (pqh->urbp) {
+			struct list_head *head, *tmp;
+
+			head = &pqh->urbp->queue_list;
+			tmp = head->next;
+			while (head != tmp) {
+				struct urb_priv *turbp =
+					list_entry(tmp, struct urb_priv, queue_list);
+
+				tmp = tmp->next;
+
+				turbp->qh->link = qh->link;
+			}
+		}
+
+		pqh->link = qh->link;
+		mb();
+		qh->element = qh->link = UHCI_PTR_TERM;
+
+		list_del_init(&qh->list);
+	}
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+
+	spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);
+
+	/* 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);
+
+	spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags);
+}
+
+static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct list_head *head, *tmp;
+
+	head = &urbp->td_list;
+	tmp = head->next;
+	while (head != tmp) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		if (toggle)
+			td->info |= TD_TOKEN_TOGGLE;
+		else
+			td->info &= ~TD_TOKEN_TOGGLE;
+
+		toggle ^= 1;
+	}
+
+	return toggle;
+}
+
+/* This function will append one URB's QH to another URB's QH. This is for */
+/*  USB_QUEUE_BULK support for bulk transfers and soon implicitily for */
+/*  control transfers */
+static void uhci_append_queued_urb(struct uhci *uhci, struct urb *eurb, struct urb *urb)
+{
+	struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
+	struct list_head *tmp;
+	struct uhci_td *lltd;
+	unsigned long flags;
+
+	eurbp = eurb->hcpriv;
+	urbp = urb->hcpriv;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+
+	/* Find the first URB in the queue */
+	if (eurbp->queued) {
+		struct list_head *head = &eurbp->queue_list;
+
+		tmp = head->next;
+		while (tmp != head) {
+			struct urb_priv *turbp =
+				list_entry(tmp, struct urb_priv, queue_list);
+
+			if (!turbp->queued)
+				break;
+
+			tmp = tmp->next;
+		}
+	} else
+		tmp = &eurbp->queue_list;
+
+	furbp = list_entry(tmp, struct urb_priv, queue_list);
+	lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list);
+
+	lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
+
+	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe),
+		uhci_fixup_toggle(urb, uhci_toggle(lltd->info) ^ 1));
+
+	/* All qh's in the queue need to link to the next queue */
+	urbp->qh->link = eurbp->qh->link;
+
+	mb();			/* Make sure we flush everything */
+	/* Only support bulk right now, so no depth */
+	lltd->link = urbp->qh->dma_handle | UHCI_PTR_QH;
+
+	list_add_tail(&urbp->queue_list, &furbp->queue_list);
+
+	urbp->queued = 1;
+
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+static void uhci_delete_queued_urb(struct uhci *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp, *nurbp;
+	struct list_head *head, *tmp;
+	struct urb_priv *purbp;
+	struct uhci_td *pltd;
+	unsigned int toggle;
+	unsigned long flags;
+
+	urbp = urb->hcpriv;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+
+	if (list_empty(&urbp->queue_list))
+		goto out;
+
+	nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list);
+
+	/* Fix up the toggle for the next URB's */
+	if (!urbp->queued)
+		/* We set the toggle when we unlink */
+		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(pltd->info) ^ 1;
+	}
+
+	head = &urbp->queue_list;
+	tmp = head->next;
+	while (head != tmp) {
+		struct urb_priv *turbp;
+
+		turbp = list_entry(tmp, struct urb_priv, queue_list);
+
+		tmp = tmp->next;
+
+		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) {
+		nurbp->queued = 0;
+
+		_uhci_insert_qh(uhci, uhci->skel_bulk_qh, nurbp->urb);
+	} else {
+		/* We're somewhere in the middle (or end). A bit trickier */
+		/*  than the head scenario */
+		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 = 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;
+	}
+
+	list_del_init(&urbp->queue_list);
+
+out:
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+static struct urb_priv *uhci_alloc_urb_priv(struct uhci *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp;
+
+	urbp = kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC);
+	if (!urbp) {
+		err("uhci_alloc_urb_priv: couldn't allocate memory for urb_priv\n");
+		return NULL;
+	}
+
+	memset((void *)urbp, 0, sizeof(*urbp));
+
+	urbp->inserttime = jiffies;
+	urbp->fsbrtime = jiffies;
+	urbp->urb = urb;
+	urbp->dev = urb->dev;
+	
+	INIT_LIST_HEAD(&urbp->td_list);
+	INIT_LIST_HEAD(&urbp->queue_list);
+	INIT_LIST_HEAD(&urbp->complete_list);
+
+	urb->hcpriv = urbp;
+
+	if (urb->dev != uhci->rh.dev) {
+		if (urb->transfer_buffer_length) {
+			urbp->transfer_buffer_dma_handle = pci_map_single(uhci->dev,
+				urb->transfer_buffer, urb->transfer_buffer_length,
+				usb_pipein(urb->pipe) ? PCI_DMA_FROMDEVICE :
+				PCI_DMA_TODEVICE);
+			if (!urbp->transfer_buffer_dma_handle)
+				return NULL;
+		}
+
+		if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet) {
+			urbp->setup_packet_dma_handle = pci_map_single(uhci->dev,
+				urb->setup_packet, sizeof(struct usb_ctrlrequest),
+				PCI_DMA_TODEVICE);
+			if (!urbp->setup_packet_dma_handle)
+				return NULL;
+		}
+	}
+
+	return urbp;
+}
+
+/*
+ * MUST be called with urb->lock acquired
+ */
+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);
+}
+
+/*
+ * MUST be called with urb->lock acquired
+ */
+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;
+}
+
+/*
+ * MUST be called with urb->lock acquired
+ */
+static void uhci_destroy_urb_priv(struct urb *urb)
+{
+	struct list_head *head, *tmp;
+	struct urb_priv *urbp;
+	struct uhci *uhci;
+
+	urbp = (struct urb_priv *)urb->hcpriv;
+	if (!urbp)
+		return;
+
+	if (!urbp->dev || !urbp->dev->bus || !urbp->dev->bus->hcpriv) {
+		warn("uhci_destroy_urb_priv: urb %p belongs to disconnected device or bus?", urb);
+		return;
+	}
+
+	if (!list_empty(&urb->urb_list))
+		warn("uhci_destroy_urb_priv: urb %p still on uhci->urb_list or uhci->remove_list", urb);
+
+	if (!list_empty(&urbp->complete_list))
+		warn("uhci_destroy_urb_priv: urb %p still on uhci->complete_list", urb);
+
+	uhci = urbp->dev->bus->hcpriv;
+
+	head = &urbp->td_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		uhci_remove_td_from_urb(td);
+		uhci_remove_td(uhci, td);
+		uhci_free_td(uhci, td);
+	}
+
+	if (urbp->setup_packet_dma_handle) {
+		pci_unmap_single(uhci->dev, urbp->setup_packet_dma_handle,
+			sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
+		urbp->setup_packet_dma_handle = 0;
+	}
+
+	if (urbp->transfer_buffer_dma_handle) {
+		pci_unmap_single(uhci->dev, urbp->transfer_buffer_dma_handle,
+			urb->transfer_buffer_length, usb_pipein(urb->pipe) ?
+			PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+		urbp->transfer_buffer_dma_handle = 0;
+	}
+
+	urb->hcpriv = NULL;
+	kmem_cache_free(uhci_up_cachep, urbp);
+}
+
+static void uhci_inc_fsbr(struct uhci *uhci, struct urb *urb)
+{
+	unsigned long flags;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+
+	if ((!(urb->transfer_flags & USB_NO_FSBR)) && !urbp->fsbr) {
+		urbp->fsbr = 1;
+		if (!uhci->fsbr++ && !uhci->fsbrtimeout)
+			uhci->skel_term_qh->link = uhci->skel_hs_control_qh->dma_handle | UHCI_PTR_QH;
+	}
+
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+static void uhci_dec_fsbr(struct uhci *uhci, struct urb *urb)
+{
+	unsigned long flags;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+
+	if ((!(urb->transfer_flags & USB_NO_FSBR)) && urbp->fsbr) {
+		urbp->fsbr = 0;
+		if (!--uhci->fsbr)
+			uhci->fsbrtimeout = jiffies + FSBR_DELAY;
+	}
+
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+/*
+ * Map status to standard result codes
+ *
+ * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)]
+ * <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 -ETIMEDOUT;
+		else
+			return -EILSEQ;
+	}
+	if (status & TD_CTRL_NAK)			/* NAK */
+		return -ETIMEDOUT;
+	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;
+	if (status & TD_CTRL_ACTIVE)			/* Active */
+		return 0;
+
+	return -EINVAL;
+}
+
+/*
+ * Control transfers
+ */
+static int uhci_submit_control(struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	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;
+	dma_addr_t data = urbp->transfer_buffer_dma_handle;
+
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
+
+	/* 3 errors */
+	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
+
+	/*
+	 * Build the TD for the control request
+	 */
+	td = uhci_alloc_td(uhci, urb->dev);
+	if (!td)
+		return -ENOMEM;
+
+	uhci_add_td_to_urb(urb, td);
+	uhci_fill_td(td, status, destination | (7 << 21),
+		urbp->setup_packet_dma_handle);
+
+	/*
+	 * If direction is "send", change the frame from SETUP (0x2D)
+	 * to OUT (0xE1). Else change it from SETUP to IN (0x69).
+	 */
+	destination ^= (USB_PID_SETUP ^ usb_packetid(urb->pipe));
+
+	if (!(urb->transfer_flags & USB_DISABLE_SPD))
+		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 | ((pktsze - 1) << 21),
+			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_NULL_DATA_SIZE << 21), 0);
+
+	qh = uhci_alloc_qh(uhci, urb->dev);
+	if (!qh)
+		return -ENOMEM;
+
+	urbp->qh = qh;
+	qh->urbp = urbp;
+
+	/* Low speed or small transfers gets a different queue and treatment */
+	if (urb->pipe & TD_CTRL_LS) {
+		uhci_insert_tds_in_qh(qh, urb, 0);
+		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
+	} else {
+		uhci_insert_tds_in_qh(qh, urb, 1);
+		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
+		uhci_inc_fsbr(uhci, urb);
+	}
+
+	return -EINPROGRESS;
+}
+
+static int usb_control_retrigger_status(struct urb *urb);
+
+static int uhci_result_control(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_phase;
+	}
+
+	tmp = head->next;
+	td = list_entry(tmp, struct uhci_td, list);
+
+	/* The first TD is the SETUP phase, check the status, but skip */
+	/*  the count */
+	status = uhci_status_bits(td->status);
+	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) {
+		td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		status = uhci_status_bits(td->status);
+		if (status & TD_CTRL_ACTIVE)
+			return -EINPROGRESS;
+
+		urb->actual_length += uhci_actual_length(td->status);
+
+		if (status)
+			goto td_error;
+
+		/* Check to see if we received a short packet */
+		if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) {
+			if (urb->transfer_flags & USB_DISABLE_SPD) {
+				ret = -EREMOTEIO;
+				goto err;
+			}
+
+			if (uhci_packetid(td->info) == USB_PID_IN)
+				return usb_control_retrigger_status(urb);
+			else
+				return 0;
+		}
+	}
+
+status_phase:
+	td = list_entry(tmp, struct uhci_td, list);
+
+	/* Control status phase */
+	status = uhci_status_bits(td->status);
+
+#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 (td->status & TD_CTRL_IOC &&	/* IOC is masked out by uhci_status_bits */
+	    status & TD_CTRL_ACTIVE &&
+	    status & TD_CTRL_NAK)
+		return 0;
+#endif
+
+	if (status & TD_CTRL_ACTIVE)
+		return -EINPROGRESS;
+
+	if (status)
+		goto td_error;
+
+	return 0;
+
+td_error:
+	ret = uhci_map_status(status, uhci_packetout(td->info));
+	if (ret == -EPIPE)
+		/* endpoint has stalled - mark it halted */
+		usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
+	    			uhci_packetout(td->info));
+
+err:
+	if ((debug == 1 && ret != -EPIPE) || debug > 1) {
+		/* Some debugging code */
+		dbg("uhci_result_control() failed with status %x", status);
+
+		if (errbuf) {
+			/* Print the chain for debugging purposes */
+			uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
+
+			lprintk(errbuf);
+		}
+	}
+
+	return ret;
+}
+
+static int usb_control_retrigger_status(struct urb *urb)
+{
+	struct list_head *tmp, *head;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci *uhci = urb->dev->bus->hcpriv;
+
+	urbp->short_control_packet = 1;
+
+	/* Create a new QH to avoid pointer overwriting problems */
+	uhci_remove_qh(uhci, urbp->qh);
+
+	/* Delete all of the TD's except for the status TD at the end */
+	head = &urbp->td_list;
+	tmp = head->next;
+	while (tmp != head && tmp->next != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		uhci_remove_td_from_urb(td);
+		uhci_remove_td(uhci, td);
+		uhci_free_td(uhci, td);
+	}
+
+	urbp->qh = uhci_alloc_qh(uhci, urb->dev);
+	if (!urbp->qh) {
+		err("unable to allocate new QH for control retrigger");
+		return -ENOMEM;
+	}
+
+	urbp->qh->urbp = urbp;
+
+	/* One TD, who cares about Breadth first? */
+	uhci_insert_tds_in_qh(urbp->qh, urb, 0);
+
+	/* Low speed or small transfers gets a different queue and treatment */
+	if (urb->pipe & TD_CTRL_LS)
+		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
+	else
+		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
+
+	return -EINPROGRESS;
+}
+
+/*
+ * Interrupt transfers
+ */
+static int uhci_submit_interrupt(struct urb *urb)
+{
+	struct uhci_td *td;
+	unsigned long destination, status;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+	if (urb->transfer_buffer_length > usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))
+		return -EINVAL;
+
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
+
+	td = uhci_alloc_td(uhci, urb->dev);
+	if (!td)
+		return -ENOMEM;
+
+	destination |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT);
+	destination |= ((urb->transfer_buffer_length - 1) << 21);
+
+	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+
+	uhci_add_td_to_urb(urb, td);
+	uhci_fill_td(td, status, destination, urbp->transfer_buffer_dma_handle);
+
+	uhci_insert_td(uhci, uhci->skeltd[__interval_to_skel(urb->interval)], td);
+
+	return -EINPROGRESS;
+}
+
+static int uhci_result_interrupt(struct urb *urb)
+{
+	struct list_head *tmp, *head;
+	struct urb_priv *urbp = urb->hcpriv;
+	struct uhci_td *td;
+	unsigned int status;
+	int ret = 0;
+
+	urb->actual_length = 0;
+
+	head = &urbp->td_list;
+	tmp = head->next;
+	while (tmp != head) {
+		td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		status = uhci_status_bits(td->status);
+		if (status & TD_CTRL_ACTIVE)
+			return -EINPROGRESS;
+
+		urb->actual_length += uhci_actual_length(td->status);
+
+		if (status)
+			goto td_error;
+
+		if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) {
+			if (urb->transfer_flags & USB_DISABLE_SPD) {
+				ret = -EREMOTEIO;
+				goto err;
+			} else
+				return 0;
+		}
+	}
+
+	return 0;
+
+td_error:
+	ret = uhci_map_status(status, uhci_packetout(td->info));
+	if (ret == -EPIPE)
+		/* endpoint has stalled - mark it halted */
+		usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
+	    			uhci_packetout(td->info));
+
+err:
+	if ((debug == 1 && ret != -EPIPE) || debug > 1) {
+		/* Some debugging code */
+		dbg("uhci_result_interrupt/bulk() failed with status %x",
+			status);
+
+		if (errbuf) {
+			/* Print the chain for debugging purposes */
+			if (urbp->qh)
+				uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
+			else
+				uhci_show_td(td, errbuf, ERRBUF_LEN, 0);
+
+			lprintk(errbuf);
+		}
+	}
+
+	return ret;
+}
+
+static void uhci_reset_interrupt(struct urb *urb)
+{
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci_td *td;
+	unsigned long flags;
+
+	spin_lock_irqsave(&urb->lock, flags);
+
+	/* Root hub is special */
+	if (urb->dev == uhci->rh.dev)
+		goto out;
+
+	td = list_entry(urbp->td_list.next, struct uhci_td, list);
+
+	td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
+	td->info &= ~TD_TOKEN_TOGGLE;
+	td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT);
+	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+
+out:
+	urb->status = -EINPROGRESS;
+
+	spin_unlock_irqrestore(&urb->lock, flags);
+}
+
+/*
+ * Bulk transfers
+ */
+static int uhci_submit_bulk(struct urb *urb, struct urb *eurb)
+{
+	struct uhci_td *td;
+	struct uhci_qh *qh;
+	unsigned long destination, status;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	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 = urbp->transfer_buffer_dma_handle;
+
+	if (len < 0)
+		return -EINVAL;
+
+	/* Can't have low speed bulk transfers */
+	if (urb->pipe & TD_CTRL_LS)
+		return -EINVAL;
+
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+	/* 3 errors */
+	status = TD_CTRL_ACTIVE | (3 << TD_CTRL_C_ERR_SHIFT);
+
+	if (!(urb->transfer_flags & USB_DISABLE_SPD))
+		status |= TD_CTRL_SPD;
+
+	/*
+	 * Build the DATA TD's
+	 */
+	do {	/* Allow zero length packets */
+		int pktsze = len;
+
+		if (pktsze > maxsze)
+			pktsze = maxsze;
+
+		td = uhci_alloc_td(uhci, urb->dev);
+		if (!td)
+			return -ENOMEM;
+
+		uhci_add_td_to_urb(urb, td);
+		uhci_fill_td(td, status, destination |
+			(((pktsze - 1) & UHCI_NULL_DATA_SIZE) << 21) |
+			(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);
+
+	/*
+	 * USB_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 & USB_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_NULL_DATA_SIZE << 21) |
+			(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 flag on the last packet */
+	td->status |= TD_CTRL_IOC;
+
+	qh = uhci_alloc_qh(uhci, urb->dev);
+	if (!qh)
+		return -ENOMEM;
+
+	urbp->qh = qh;
+	qh->urbp = urbp;
+
+	/* Always assume breadth first */
+	uhci_insert_tds_in_qh(qh, urb, 1);
+
+	if (urb->transfer_flags & USB_QUEUE_BULK && eurb)
+		uhci_append_queued_urb(uhci, eurb, urb);
+	else
+		uhci_insert_qh(uhci, uhci->skel_bulk_qh, urb);
+
+	uhci_inc_fsbr(uhci, urb);
+
+	return -EINPROGRESS;
+}
+
+/* We can use the result interrupt since they're identical */
+#define uhci_result_bulk uhci_result_interrupt
+
+/*
+ * Isochronous transfers
+ */
+static int isochronous_find_limits(struct urb *urb, unsigned int *start, unsigned int *end)
+{
+	struct urb *last_urb = NULL;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	struct list_head *tmp, *head;
+	int ret = 0;
+
+	head = &uhci->urb_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *u = list_entry(tmp, struct urb, urb_list);
+
+		tmp = tmp->next;
+
+		/* 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) & 1023;
+		ret = 0;
+	} else
+		ret = -1;	/* no previous urb found */
+
+	return ret;
+}
+
+static int isochronous_find_start(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(urb, &start, &end);
+
+	if (urb->transfer_flags & USB_ISO_ASAP) {
+		if (limits) {
+			int curframe;
+
+			curframe = uhci_get_current_frame_number(urb->dev) % UHCI_NUMFRAMES;
+			urb->start_frame = (curframe + 10) % UHCI_NUMFRAMES;
+		} else
+			urb->start_frame = end;
+	} else {
+		urb->start_frame %= UHCI_NUMFRAMES;
+		/* FIXME: Sanity check */
+	}
+
+	return 0;
+}
+
+/*
+ * Isochronous transfers
+ */
+static int uhci_submit_isochronous(struct urb *urb)
+{
+	struct uhci_td *td;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	int i, ret, framenum;
+	int status, destination;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+	ret = isochronous_find_start(urb);
+	if (ret)
+		return ret;
+
+	framenum = urb->start_frame;
+	for (i = 0; i < urb->number_of_packets; i++, framenum++) {
+		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 | ((urb->iso_frame_desc[i].length - 1) << 21),
+			urbp->transfer_buffer_dma_handle + urb->iso_frame_desc[i].offset);
+
+		if (i + 1 >= urb->number_of_packets)
+			td->status |= TD_CTRL_IOC;
+
+		uhci_insert_td_frame_list(uhci, td, framenum);
+	}
+
+	return -EINPROGRESS;
+}
+
+static int uhci_result_isochronous(struct urb *urb)
+{
+	struct list_head *tmp, *head;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	int status;
+	int i, ret = 0;
+
+	urb->actual_length = 0;
+
+	i = 0;
+	head = &urbp->td_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+		int actlength;
+
+		tmp = tmp->next;
+
+		if (td->status & TD_CTRL_ACTIVE)
+			return -EINPROGRESS;
+
+		actlength = uhci_actual_length(td->status);
+		urb->iso_frame_desc[i].actual_length = actlength;
+		urb->actual_length += actlength;
+
+		status = uhci_map_status(uhci_status_bits(td->status), usb_pipeout(urb->pipe));
+		urb->iso_frame_desc[i].status = status;
+		if (status) {
+			urb->error_count++;
+			ret = status;
+		}
+
+		i++;
+	}
+
+	return ret;
+}
+
+/*
+ * MUST be called with uhci->urb_list_lock acquired
+ */
+static struct urb *uhci_find_urb_ep(struct uhci *uhci, struct urb *urb)
+{
+	struct list_head *tmp, *head;
+
+	/* We don't match Isoc transfers since they are special */
+	if (usb_pipeisoc(urb->pipe))
+		return NULL;
+
+	head = &uhci->urb_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *u = list_entry(tmp, struct urb, urb_list);
+
+		tmp = tmp->next;
+
+		if (u->dev == urb->dev && u->pipe == urb->pipe &&
+		    u->status == -EINPROGRESS)
+			return u;
+	}
+
+	return NULL;
+}
+
+static int uhci_submit_urb(struct urb *urb)
+{
+	int ret = -EINVAL;
+	struct uhci *uhci;
+	unsigned long flags;
+	struct urb *eurb;
+	int bustime;
+
+	if (!urb)
+		return -EINVAL;
+
+	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) {
+		warn("uhci_submit_urb: urb %p belongs to disconnected device or bus?", urb);
+		return -ENODEV;
+	}
+
+	uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+	usb_inc_dev_use(urb->dev);
+
+	spin_lock_irqsave(&uhci->urb_list_lock, flags);
+	spin_lock(&urb->lock);
+
+	if (urb->status == -EINPROGRESS || urb->status == -ECONNRESET ||
+	    urb->status == -ECONNABORTED) {
+		dbg("uhci_submit_urb: urb not available to submit (status = %d)", urb->status);
+		/* Since we can have problems on the out path */
+		spin_unlock(&urb->lock);
+		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+		usb_dec_dev_use(urb->dev);
+
+		return ret;
+	}
+
+	INIT_LIST_HEAD(&urb->urb_list);
+	if (!uhci_alloc_urb_priv(uhci, urb)) {
+		ret = -ENOMEM;
+
+		goto out;
+	}
+
+	eurb = uhci_find_urb_ep(uhci, urb);
+	if (eurb && !(urb->transfer_flags & USB_QUEUE_BULK)) {
+		ret = -ENXIO;
+
+		goto out;
+	}
+
+	/* Short circuit the virtual root hub */
+	if (urb->dev == uhci->rh.dev) {
+		ret = rh_submit_urb(urb);
+
+		goto out;
+	}
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		ret = uhci_submit_control(urb);
+		break;
+	case PIPE_INTERRUPT:
+		if (urb->bandwidth == 0) {	/* not yet checked/allocated */
+			bustime = usb_check_bandwidth(urb->dev, urb);
+			if (bustime < 0)
+				ret = bustime;
+			else {
+				ret = uhci_submit_interrupt(urb);
+				if (ret == -EINPROGRESS)
+					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
+			}
+		} else		/* bandwidth is already set */
+			ret = uhci_submit_interrupt(urb);
+		break;
+	case PIPE_BULK:
+		ret = uhci_submit_bulk(urb, eurb);
+		break;
+	case PIPE_ISOCHRONOUS:
+		if (urb->bandwidth == 0) {	/* not yet checked/allocated */
+			if (urb->number_of_packets <= 0) {
+				ret = -EINVAL;
+				break;
+			}
+			bustime = usb_check_bandwidth(urb->dev, urb);
+			if (bustime < 0) {
+				ret = bustime;
+				break;
+			}
+
+			ret = uhci_submit_isochronous(urb);
+			if (ret == -EINPROGRESS)
+				usb_claim_bandwidth(urb->dev, urb, bustime, 1);
+		} else		/* bandwidth is already set */
+			ret = uhci_submit_isochronous(urb);
+		break;
+	}
+
+out:
+	urb->status = ret;
+
+	if (ret == -EINPROGRESS) {
+		/* We use _tail to make find_urb_ep more efficient */
+		list_add_tail(&urb->urb_list, &uhci->urb_list);
+
+		spin_unlock(&urb->lock);
+		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+
+		return 0;
+	}
+
+	uhci_unlink_generic(uhci, urb);
+
+	spin_unlock(&urb->lock);
+	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+
+	/* Only call completion if it was successful */
+	if (!ret)
+		uhci_call_completion(urb);
+
+	return ret;
+}
+
+/*
+ * Return the result of a transfer
+ *
+ * MUST be called with urb_list_lock acquired
+ */
+static void uhci_transfer_result(struct uhci *uhci, struct urb *urb)
+{
+	int ret = -EINVAL;
+	unsigned long flags;
+	struct urb_priv *urbp;
+
+	/* The root hub is special */
+	if (urb->dev == uhci->rh.dev)
+		return;
+
+	spin_lock_irqsave(&urb->lock, flags);
+
+	urbp = (struct urb_priv *)urb->hcpriv;
+
+	if (urb->status != -EINPROGRESS) {
+		info("uhci_transfer_result: called for URB %p not in flight?", urb);
+		goto out;
+	}
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		ret = uhci_result_control(urb);
+		break;
+	case PIPE_INTERRUPT:
+		ret = uhci_result_interrupt(urb);
+		break;
+	case PIPE_BULK:
+		ret = uhci_result_bulk(urb);
+		break;
+	case PIPE_ISOCHRONOUS:
+		ret = uhci_result_isochronous(urb);
+		break;
+	}
+
+	urbp->status = ret;
+
+	if (ret == -EINPROGRESS)
+		goto out;
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+	case PIPE_BULK:
+	case PIPE_ISOCHRONOUS:
+		/* Release bandwidth for Interrupt or Isoc. transfers */
+		/* Spinlock needed ? */
+		if (urb->bandwidth)
+			usb_release_bandwidth(urb->dev, urb, 1);
+		uhci_unlink_generic(uhci, urb);
+		break;
+	case PIPE_INTERRUPT:
+		/* Interrupts are an exception */
+		if (urb->interval)
+			goto out_complete;
+
+		/* Release bandwidth for Interrupt or Isoc. transfers */
+		/* Spinlock needed ? */
+		if (urb->bandwidth)
+			usb_release_bandwidth(urb->dev, urb, 0);
+		uhci_unlink_generic(uhci, urb);
+		break;
+	default:
+		info("uhci_transfer_result: unknown pipe type %d for urb %p\n",
+			usb_pipetype(urb->pipe), urb);
+	}
+
+	/* Remove it from uhci->urb_list */
+	list_del_init(&urb->urb_list);
+
+out_complete:
+	uhci_add_complete(urb);
+
+out:
+	spin_unlock_irqrestore(&urb->lock, flags);
+}
+
+/*
+ * MUST be called with urb->lock acquired
+ */
+static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb)
+{
+	struct list_head *head, *tmp;
+	struct urb_priv *urbp = urb->hcpriv;
+	int prevactive = 1;
+
+	/* We can get called when urbp allocation fails, so check */
+	if (!urbp)
+		return;
+
+	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's 3 way's 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
+	 * 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
+	 */
+	head = &urbp->td_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		if (!(td->status & TD_CTRL_ACTIVE) &&
+		    (uhci_actual_length(td->status) < uhci_expected_length(td->info) ||
+		    tmp == head))
+			usb_settoggle(urb->dev, uhci_endpoint(td->info),
+				uhci_packetout(td->info),
+				uhci_toggle(td->info) ^ 1);
+		else if ((td->status & TD_CTRL_ACTIVE) && !prevactive)
+			usb_settoggle(urb->dev, uhci_endpoint(td->info),
+				uhci_packetout(td->info),
+				uhci_toggle(td->info));
+
+		prevactive = td->status & 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_unlink_urb(struct urb *urb)
+{
+	struct uhci *uhci;
+	unsigned long flags;
+	struct urb_priv *urbp = urb->hcpriv;
+
+	if (!urb)
+		return -EINVAL;
+
+	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
+		return -ENODEV;
+
+	uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+	spin_lock_irqsave(&uhci->urb_list_lock, flags);
+	spin_lock(&urb->lock);
+
+	/* Release bandwidth for Interrupt or Isoc. transfers */
+	/* Spinlock needed ? */
+	if (urb->bandwidth) {
+		switch (usb_pipetype(urb->pipe)) {
+		case PIPE_INTERRUPT:
+			usb_release_bandwidth(urb->dev, urb, 0);
+			break;
+		case PIPE_ISOCHRONOUS:
+			usb_release_bandwidth(urb->dev, urb, 1);
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (urb->status != -EINPROGRESS) {
+		spin_unlock(&urb->lock);
+		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+		return 0;
+	}
+
+	list_del_init(&urb->urb_list);
+
+	uhci_unlink_generic(uhci, urb);
+
+	/* Short circuit the virtual root hub */
+	if (urb->dev == uhci->rh.dev) {
+		rh_unlink_urb(urb);
+
+		spin_unlock(&urb->lock);
+		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+
+		uhci_call_completion(urb);
+	} else {
+		if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+			urbp->status = urb->status = -ECONNABORTED;
+
+			spin_lock(&uhci->urb_remove_list_lock);
+
+			/* If we're the first, set the next interrupt bit */
+			if (list_empty(&uhci->urb_remove_list))
+				uhci_set_next_interrupt(uhci);
+			
+			list_add(&urb->urb_list, &uhci->urb_remove_list);
+
+			spin_unlock(&uhci->urb_remove_list_lock);
+
+			spin_unlock(&urb->lock);
+			spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+
+		} else {
+			urb->status = -ENOENT;
+
+			spin_unlock(&urb->lock);
+			spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+
+			if (in_interrupt()) {	/* wait at least 1 frame */
+				static int errorcount = 10;
+
+				if (errorcount--)
+					dbg("uhci_unlink_urb called from interrupt for urb %p", urb);
+				udelay(1000);
+			} else
+				schedule_timeout(1+1*HZ/1000); 
+
+			uhci_call_completion(urb);
+		}
+	}
+
+	return 0;
+}
+
+static int uhci_fsbr_timeout(struct uhci *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct list_head *head, *tmp;
+	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;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		/*
+		 * 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 (tmp != head && (count % DEPTH_INTERVAL) == (DEPTH_INTERVAL - 1))
+			td->link |= UHCI_PTR_DEPTH;
+
+		count++;
+	}
+
+	return 0;
+}
+
+/*
+ * uhci_get_current_frame_number()
+ *
+ * returns the current frame number for a USB bus/controller.
+ */
+static int uhci_get_current_frame_number(struct usb_device *dev)
+{
+	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
+
+	return inw(uhci->io_addr + USBFRNUM);
+}
+
+struct usb_operations uhci_device_operations = {
+	uhci_alloc_dev,
+	uhci_free_dev,
+	uhci_get_current_frame_number,
+	uhci_submit_urb,
+	uhci_unlink_urb
+};
+
+/* Virtual Root Hub */
+
+static __u8 root_hub_dev_des[] =
+{
+ 	0x12,			/*  __u8  bLength; */
+	0x01,			/*  __u8  bDescriptorType; Device */
+	0x00,			/*  __u16 bcdUSB; v1.0 */
+	0x01,
+	0x09,			/*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  bDeviceSubClass; */
+	0x00,			/*  __u8  bDeviceProtocol; */
+	0x08,			/*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x00,			/*  __u16 idVendor; */
+	0x00,
+	0x00,			/*  __u16 idProduct; */
+	0x00,
+	0x00,			/*  __u16 bcdDevice; */
+	0x00,
+	0x00,			/*  __u8  iManufacturer; */
+	0x02,			/*  __u8  iProduct; */
+	0x01,			/*  __u8  iSerialNumber; */
+	0x01			/*  __u8  bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+	0x09,			/*  __u8  bLength; */
+	0x02,			/*  __u8  bDescriptorType; Configuration */
+	0x19,			/*  __u16 wTotalLength; */
+	0x00,
+	0x01,			/*  __u8  bNumInterfaces; */
+	0x01,			/*  __u8  bConfigurationValue; */
+	0x00,			/*  __u8  iConfiguration; */
+	0x40,			/*  __u8  bmAttributes;
+					Bit 7: Bus-powered, 6: Self-powered,
+					Bit 5 Remote-wakeup, 4..0: resvd */
+	0x00,			/*  __u8  MaxPower; */
+
+	/* interface */
+	0x09,			/*  __u8  if_bLength; */
+	0x04,			/*  __u8  if_bDescriptorType; Interface */
+	0x00,			/*  __u8  if_bInterfaceNumber; */
+	0x00,			/*  __u8  if_bAlternateSetting; */
+	0x01,			/*  __u8  if_bNumEndpoints; */
+	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  if_bInterfaceSubClass; */
+	0x00,			/*  __u8  if_bInterfaceProtocol; */
+	0x00,			/*  __u8  if_iInterface; */
+
+	/* endpoint */
+	0x07,			/*  __u8  ep_bLength; */
+	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+	0x03,			/*  __u8  ep_bmAttributes; Interrupt */
+	0x08,			/*  __u16 ep_wMaxPacketSize; 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 *** */
+};
+
+/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
+static int rh_send_irq(struct urb *urb)
+{
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	unsigned int io_addr = uhci->io_addr;
+	unsigned long flags;
+	int i, len = 1;
+	__u16 data = 0;
+
+	spin_lock_irqsave(&urb->lock, flags);
+	for (i = 0; i < uhci->rh.numports; i++) {
+		data |= ((inw(io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);
+		len = (i + 1) / 8 + 1;
+	}
+
+	*(__u16 *) urb->transfer_buffer = cpu_to_le16(data);
+	urb->actual_length = len;
+	urbp->status = 0;
+
+	spin_unlock_irqrestore(&urb->lock, flags);
+
+	if ((data > 0) && (uhci->rh.send != 0)) {
+		dbg("root-hub INT complete: port1: %x port2: %x data: %x",
+			inw(io_addr + USBPORTSC1), inw(io_addr + USBPORTSC2), data);
+		uhci_call_completion(urb);
+	}
+
+	return 0;
+}
+
+/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
+static int rh_init_int_timer(struct urb *urb);
+
+static void rh_int_timer_do(unsigned long ptr)
+{
+	struct urb *urb = (struct urb *)ptr;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	struct list_head list, *tmp, *head;
+	unsigned long flags;
+
+	if (uhci->rh.send)
+		rh_send_irq(urb);
+
+	INIT_LIST_HEAD(&list);
+
+	spin_lock_irqsave(&uhci->urb_list_lock, flags);
+	head = &uhci->urb_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *u = list_entry(tmp, struct urb, urb_list);
+		struct urb_priv *up = (struct urb_priv *)u->hcpriv;
+
+		tmp = tmp->next;
+
+		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);
+
+		/* Check if the URB timed out */
+		if (u->timeout && time_after_eq(jiffies, up->inserttime + u->timeout)) {
+			list_del(&u->urb_list);
+			list_add_tail(&u->urb_list, &list);
+		}
+
+		spin_unlock(&u->lock);
+	}
+	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+
+	head = &list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *u = list_entry(tmp, struct urb, urb_list);
+
+		tmp = tmp->next;
+
+		u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
+		uhci_unlink_urb(u);
+	}
+
+	/* 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;
+	}
+
+	/* enter global suspend if nothing connected */
+	if (!uhci->is_suspended && !ports_active(uhci))
+		suspend_hc(uhci);
+
+	rh_init_int_timer(urb);
+}
+
+/* Root Hub INTs are polled by this timer */
+static int rh_init_int_timer(struct urb *urb)
+{
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+	uhci->rh.interval = urb->interval;
+	init_timer(&uhci->rh.rh_int_timer);
+	uhci->rh.rh_int_timer.function = rh_int_timer_do;
+	uhci->rh.rh_int_timer.data = (unsigned long)urb;
+	uhci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000;
+	add_timer(&uhci->rh.rh_int_timer);
+
+	return 0;
+}
+
+#define OK(x)			len = (x); break
+
+#define CLR_RH_PORTSTAT(x) \
+	status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
+	status = (status & 0xfff5) & ~(x); \
+	outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
+
+#define SET_RH_PORTSTAT(x) \
+	status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
+	status = (status & 0xfff5) | (x); \
+	outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
+
+
+/* Root Hub Control Pipe */
+static int rh_submit_urb(struct urb *urb)
+{
+	struct uhci *uhci = (struct uhci *)urb->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 status = 0;
+	int stat = 0;
+	int i;
+	unsigned int io_addr = uhci->io_addr;
+	__u16 cstatus;
+	__u16 bmRType_bReq;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+
+	if (usb_pipetype(pipe) == PIPE_INTERRUPT) {
+		uhci->rh.urb = urb;
+		uhci->rh.send = 1;
+		uhci->rh.interval = urb->interval;
+		rh_init_int_timer(urb);
+
+		return -EINPROGRESS;
+	}
+
+	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);
+
+	for (i = 0; i < 8; i++)
+		uhci->rh.c_p_r[i] = 0;
+
+	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:
+		status = inw(io_addr + USBPORTSC1 + 2 * (wIndex - 1));
+		cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
+			((status & USBPORTSC_PEC) >> (3 - 1)) |
+			(uhci->rh.c_p_r[wIndex - 1] << (0 + 4));
+			status = (status & USBPORTSC_CCS) |
+			((status & USBPORTSC_PE) >> (2 - 1)) |
+			((status & USBPORTSC_SUSP) >> (12 - 2)) |
+			((status & USBPORTSC_PR) >> (9 - 4)) |
+			(1 << 8) |      /* power on */
+			((status & USBPORTSC_LSDA) << (-8 + 9));
+
+		*(__u16 *)data = cpu_to_le16(status);
+		*(__u16 *)(data + 2) = cpu_to_le16(cstatus);
+		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:
+			CLR_RH_PORTSTAT(USBPORTSC_PE);
+			OK(0);
+		case RH_PORT_SUSPEND:
+			CLR_RH_PORTSTAT(USBPORTSC_SUSP);
+			OK(0);
+		case RH_PORT_POWER:
+			OK(0);	/* port power */
+		case RH_C_PORT_CONNECTION:
+			SET_RH_PORTSTAT(USBPORTSC_CSC);
+			OK(0);
+		case RH_C_PORT_ENABLE:
+			SET_RH_PORTSTAT(USBPORTSC_PEC);
+			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:
+			uhci->rh.c_p_r[wIndex - 1] = 0;
+			OK(0);
+		}
+		break;
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case RH_PORT_SUSPEND:
+			SET_RH_PORTSTAT(USBPORTSC_SUSP);
+			OK(0);
+		case RH_PORT_RESET:
+			SET_RH_PORTSTAT(USBPORTSC_PR);
+			mdelay(50);	/* USB v1.1 7.1.7.3 */
+			uhci->rh.c_p_r[wIndex - 1] = 1;
+			CLR_RH_PORTSTAT(USBPORTSC_PR);
+			udelay(10);
+			SET_RH_PORTSTAT(USBPORTSC_PE);
+			mdelay(10);
+			SET_RH_PORTSTAT(0xa);
+			OK(0);
+		case RH_PORT_POWER:
+			OK(0); /* port power ** */
+		case RH_PORT_ENABLE:
+			SET_RH_PORTSTAT(USBPORTSC_PE);
+			OK(0);
+		}
+		break;
+	case RH_SET_ADDRESS:
+		uhci->rh.devnum = wValue;
+		OK(0);
+	case RH_GET_DESCRIPTOR:
+		switch ((wValue & 0xff00) >> 8) {
+		case 0x01:	/* device descriptor */
+			len = min_t(unsigned int, leni,
+				  min_t(unsigned int,
+				      sizeof(root_hub_dev_des), wLength));
+			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,
+				uhci->io_addr, "UHCI-alt",
+				data, wLength);
+			if (len > 0) {
+				OK(min_t(int, leni, len));
+			} else 
+				stat = -EPIPE;
+		}
+		break;
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+		root_hub_hub_des[2] = uhci->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);
+	case RH_GET_INTERFACE | RH_INTERFACE:
+		*(__u8 *)data = 0x00;
+		OK(1);
+	case RH_SET_INTERFACE | RH_INTERFACE:
+		OK(0);
+	default:
+		stat = -EPIPE;
+	}
+
+	urb->actual_length = len;
+
+	return stat;
+}
+
+/*
+ * MUST be called with urb->lock acquired
+ */
+static int rh_unlink_urb(struct urb *urb)
+{
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+	if (uhci->rh.urb == urb) {
+		urb->status = -ENOENT;
+		uhci->rh.send = 0;
+		uhci->rh.urb = NULL;
+		del_timer(&uhci->rh.rh_int_timer);
+	}
+	return 0;
+}
+
+static void uhci_free_pending_qhs(struct uhci *uhci)
+{
+	struct list_head *tmp, *head;
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);
+	head = &uhci->qh_remove_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_qh *qh = list_entry(tmp, struct uhci_qh, remove_list);
+
+		tmp = tmp->next;
+
+		list_del_init(&qh->remove_list);
+
+		uhci_free_qh(uhci, qh);
+	}
+	spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags);
+}
+
+static void uhci_call_completion(struct urb *urb)
+{
+	struct urb_priv *urbp;
+	struct usb_device *dev = urb->dev;
+	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
+	int is_ring = 0, killed, resubmit_interrupt, status;
+	struct urb *nurb;
+	unsigned long flags;
+
+	spin_lock_irqsave(&urb->lock, flags);
+
+	urbp = (struct urb_priv *)urb->hcpriv;
+	if (!urbp || !urb->dev) {
+		spin_unlock_irqrestore(&urb->lock, flags);
+		return;
+	}
+
+	killed = (urb->status == -ENOENT || urb->status == -ECONNABORTED ||
+			urb->status == -ECONNRESET);
+	resubmit_interrupt = (usb_pipetype(urb->pipe) == PIPE_INTERRUPT &&
+			urb->interval);
+
+	nurb = urb->next;
+	if (nurb && !killed) {
+		int count = 0;
+
+		while (nurb && nurb != urb && count < MAX_URB_LOOP) {
+			if (nurb->status == -ENOENT ||
+			    nurb->status == -ECONNABORTED ||
+			    nurb->status == -ECONNRESET) {
+				killed = 1;
+				break;
+			}
+
+			nurb = nurb->next;
+			count++;
+		}
+
+		if (count == MAX_URB_LOOP)
+			err("uhci_call_completion: too many linked URB's, loop? (first loop)");
+
+		/* Check to see if chain is a ring */
+		is_ring = (nurb == urb);
+	}
+
+	if (urbp->transfer_buffer_dma_handle)
+		pci_dma_sync_single(uhci->dev, urbp->transfer_buffer_dma_handle,
+			urb->transfer_buffer_length, usb_pipein(urb->pipe) ?
+			PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+
+	if (urbp->setup_packet_dma_handle)
+		pci_dma_sync_single(uhci->dev, urbp->setup_packet_dma_handle,
+			sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
+
+	status = urbp->status;
+	if (!resubmit_interrupt || killed)
+		/* We don't need urb_priv anymore */
+		uhci_destroy_urb_priv(urb);
+
+	if (!killed)
+		urb->status = status;
+
+	urb->dev = NULL;
+	spin_unlock_irqrestore(&urb->lock, flags);
+
+	if (urb->complete)
+		urb->complete(urb);
+
+	if (resubmit_interrupt)
+		/* Recheck the status. The completion handler may have */
+		/*  unlinked the resubmitting interrupt URB */
+		killed = (urb->status == -ENOENT ||
+			  urb->status == -ECONNABORTED ||
+			  urb->status == -ECONNRESET);
+
+	if (resubmit_interrupt && !killed) {
+		urb->dev = dev;
+		uhci_reset_interrupt(urb);
+	} else {
+		if (is_ring && !killed) {
+			urb->dev = dev;
+			uhci_submit_urb(urb);
+		} else {
+			/* We decrement the usage count after we're done */
+			/*  with everything */
+			usb_dec_dev_use(dev);
+		}
+	}
+}
+
+static void uhci_finish_completion(struct uhci *uhci)
+{
+	struct list_head *tmp, *head;
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->complete_list_lock, flags);
+	head = &uhci->complete_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list);
+		struct urb *urb = urbp->urb;
+
+		list_del_init(&urbp->complete_list);
+		spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
+
+		uhci_call_completion(urb);
+
+		spin_lock_irqsave(&uhci->complete_list_lock, flags);
+		head = &uhci->complete_list;
+		tmp = head->next;
+	}
+	spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
+}
+
+static void uhci_remove_pending_qhs(struct uhci *uhci)
+{
+	struct list_head *tmp, *head;
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->urb_remove_list_lock, flags);
+	head = &uhci->urb_remove_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *urb = list_entry(tmp, struct urb, urb_list);
+		struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+		tmp = tmp->next;
+
+		list_del_init(&urb->urb_list);
+
+		urbp->status = urb->status = -ECONNRESET;
+
+		uhci_add_complete(urb);
+	}
+	spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags);
+}
+
+static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
+{
+	struct uhci *uhci = __uhci;
+	unsigned int io_addr = uhci->io_addr;
+	unsigned short status;
+	struct list_head *tmp, *head;
+
+	/*
+	 * Read the interrupt status, and write it back to clear the
+	 * interrupt cause
+	 */
+	status = inw(io_addr + USBSTS);
+	if (!status)	/* shared interrupt, not mine */
+		return;
+	outw(status, io_addr + USBSTS);		/* Clear it */
+
+	if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
+		if (status & USBSTS_HSE)
+			err("%x: host system error, PCI problems?", io_addr);
+		if (status & USBSTS_HCPE)
+			err("%x: host controller process error. something bad happened", io_addr);
+		if ((status & USBSTS_HCH) && !uhci->is_suspended) {
+			err("%x: host controller halted. very bad", io_addr);
+			/* FIXME: Reset the controller, fix the offending TD */
+		}
+	}
+
+	if (status & USBSTS_RD)
+		wakeup_hc(uhci);
+
+	uhci_free_pending_qhs(uhci);
+
+	uhci_remove_pending_qhs(uhci);
+
+	uhci_clear_next_interrupt(uhci);
+
+	/* Walk the list of pending URB's to see which ones completed */
+	spin_lock(&uhci->urb_list_lock);
+	head = &uhci->urb_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *urb = list_entry(tmp, struct urb, urb_list);
+
+		tmp = tmp->next;
+
+		/* Checks the status and does all of the magic necessary */
+		uhci_transfer_result(uhci, urb);
+	}
+	spin_unlock(&uhci->urb_list_lock);
+
+	uhci_finish_completion(uhci);
+}
+
+static void reset_hc(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr;
+
+	/* Global reset for 50ms */
+	outw(USBCMD_GRESET, io_addr + USBCMD);
+	wait_ms(50);
+	outw(0, io_addr + USBCMD);
+	wait_ms(10);
+}
+
+static void suspend_hc(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr;
+
+	dbg("%x: suspend_hc", io_addr);
+
+	outw(USBCMD_EGSM, io_addr + USBCMD);
+
+	uhci->is_suspended = 1;
+}
+
+static void wakeup_hc(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr;
+	unsigned int status;
+
+	dbg("%x: wakeup_hc", io_addr);
+
+	outw(0, io_addr + USBCMD);
+	
+	/* wait for EOP to be sent */
+	status = inw(io_addr + USBCMD);
+	while (status & USBCMD_FGR)
+		status = inw(io_addr + USBCMD);
+
+	uhci->is_suspended = 0;
+
+	/* Run and mark it configured with a 64-byte max packet */
+	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
+}
+
+static int ports_active(struct uhci *uhci)
+{
+	unsigned int 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) & 0x1);
+
+	return connection;
+}
+
+static void start_hc(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr;
+	int timeout = 1000;
+
+	/*
+	 * 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) {
+			printk(KERN_ERR "uhci: USBCMD_HCRESET timed out!\n");
+			break;
+		}
+	}
+
+	/* Turn on all interrupts */
+	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 */
+	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
+}
+
+#ifdef CONFIG_PROC_FS
+static int uhci_num = 0;
+#endif
+
+static void free_uhci(struct uhci *uhci)
+{
+	kfree(uhci);
+}
+
+/*
+ * De-allocate all resources..
+ */
+static void release_uhci(struct uhci *uhci)
+{
+	int i;
+#ifdef CONFIG_PROC_FS
+	char buf[8];
+#endif
+
+	if (uhci->irq >= 0) {
+		free_irq(uhci->irq, uhci);
+		uhci->irq = -1;
+	}
+
+	for (i = 0; i < UHCI_NUM_SKELQH; i++)
+		if (uhci->skelqh[i]) {
+			uhci_free_qh(uhci, uhci->skelqh[i]);
+			uhci->skelqh[i] = NULL;
+		}
+
+	for (i = 0; i < UHCI_NUM_SKELTD; i++)
+		if (uhci->skeltd[i]) {
+			uhci_free_td(uhci, uhci->skeltd[i]);
+			uhci->skeltd[i] = NULL;
+		}
+
+	if (uhci->qh_pool) {
+		pci_pool_destroy(uhci->qh_pool);
+		uhci->qh_pool = NULL;
+	}
+
+	if (uhci->td_pool) {
+		pci_pool_destroy(uhci->td_pool);
+		uhci->td_pool = NULL;
+	}
+
+	if (uhci->fl) {
+		pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
+		uhci->fl = NULL;
+	}
+
+	if (uhci->bus) {
+		usb_free_bus(uhci->bus);
+		uhci->bus = NULL;
+	}
+
+#ifdef CONFIG_PROC_FS
+	if (uhci->proc_entry) {
+		sprintf(buf, "hc%d", uhci->num);
+
+		remove_proc_entry(buf, uhci_proc_root);
+		uhci->proc_entry = NULL;
+	}
+#endif
+
+	free_uhci(uhci);
+}
+
+/*
+ * 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 high speed
+ *  - The third queue is bulk queue.
+ *  - The fourth queue is the bandwidth reclamation queue, which loops back
+ *    to the high speed control queue.
+ */
+static int alloc_uhci(struct pci_dev *dev, unsigned int io_addr, unsigned int io_size)
+{
+	struct uhci *uhci;
+	int retval;
+	char buf[8], *bufp = buf;
+	int i, port;
+	struct usb_bus *bus;
+	dma_addr_t dma_handle;
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *ent;
+#endif
+
+	retval = -ENODEV;
+	if (pci_enable_device(dev) < 0) {
+		err("couldn't enable PCI device");
+		goto err_enable_device;
+	}
+
+	if (!dev->irq) {
+		err("found UHCI device with no IRQ assigned. check BIOS settings!");
+		goto err_invalid_irq;
+	}
+
+	if (!pci_dma_supported(dev, 0xFFFFFFFF)) {
+		err("PCI subsystem doesn't support 32 bit addressing?");
+		goto err_pci_dma_supported;
+	}
+
+	retval = -EBUSY;
+	if (!request_region(io_addr, io_size, "usb-uhci")) {
+		err("couldn't allocate I/O range %x - %x", io_addr,
+			io_addr + io_size - 1);
+		goto err_request_region;
+	}
+
+	pci_set_master(dev);
+
+#ifndef __sparc__
+	sprintf(buf, "%d", dev->irq);
+#else
+	bufp = __irq_itoa(dev->irq);
+#endif
+	printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n",
+		io_addr, bufp);
+
+	if (pci_set_dma_mask(dev, 0xFFFFFFFF)) {
+		err("couldn't set PCI dma mask");
+		retval = -ENODEV;
+		goto err_pci_set_dma_mask;
+	}
+
+	uhci = kmalloc(sizeof(*uhci), GFP_KERNEL);
+	if (!uhci) {
+		err("couldn't allocate uhci structure");
+		retval = -ENOMEM;
+		goto err_alloc_uhci;
+	}
+
+	uhci->dev = dev;
+	uhci->irq = dev->irq;
+	uhci->io_addr = io_addr;
+	uhci->io_size = io_size;
+	pci_set_drvdata(dev, uhci);
+
+#ifdef CONFIG_PROC_FS
+	uhci->num = uhci_num++;
+
+	sprintf(buf, "hc%d", uhci->num);
+
+	ent = create_proc_entry(buf, S_IFREG|S_IRUGO|S_IWUSR, uhci_proc_root);
+	if (!ent) {
+		err("couldn't create uhci proc entry");
+		retval = -ENOMEM;
+		goto err_create_proc_entry;
+	}
+
+	ent->data = uhci;
+	ent->proc_fops = &uhci_proc_operations;
+	ent->size = 0;
+	uhci->proc_entry = ent;
+#endif
+
+	/* Reset here so we don't get any interrupts from an old setup */
+	/*  or broken setup */
+	reset_hc(uhci);
+
+	uhci->fsbr = 0;
+	uhci->fsbrtimeout = 0;
+
+	uhci->is_suspended = 0;
+
+	spin_lock_init(&uhci->qh_remove_list_lock);
+	INIT_LIST_HEAD(&uhci->qh_remove_list);
+
+	spin_lock_init(&uhci->urb_remove_list_lock);
+	INIT_LIST_HEAD(&uhci->urb_remove_list);
+
+	spin_lock_init(&uhci->urb_list_lock);
+	INIT_LIST_HEAD(&uhci->urb_list);
+
+	spin_lock_init(&uhci->complete_list_lock);
+	INIT_LIST_HEAD(&uhci->complete_list);
+
+	spin_lock_init(&uhci->frame_list_lock);
+
+	/* We need exactly one page (per UHCI specs), how convenient */
+	/* We assume that one page is atleast 4k (1024 frames * 4 bytes) */
+#if PAGE_SIZE < (4 * 1024)
+#error PAGE_SIZE is not atleast 4k
+#endif
+	uhci->fl = pci_alloc_consistent(uhci->dev, sizeof(*uhci->fl), &dma_handle);
+	if (!uhci->fl) {
+		err("unable to allocate consistent memory for frame list");
+		goto err_alloc_fl;
+	}
+
+	memset((void *)uhci->fl, 0, sizeof(*uhci->fl));
+
+	uhci->fl->dma_handle = dma_handle;
+
+	uhci->td_pool = pci_pool_create("uhci_td", uhci->dev,
+		sizeof(struct uhci_td), 16, 0, GFP_DMA | GFP_ATOMIC);
+	if (!uhci->td_pool) {
+		err("unable to create td pci_pool");
+		goto err_create_td_pool;
+	}
+
+	uhci->qh_pool = pci_pool_create("uhci_qh", uhci->dev,
+		sizeof(struct uhci_qh), 16, 0, GFP_DMA | GFP_ATOMIC);
+	if (!uhci->qh_pool) {
+		err("unable to create qh pci_pool");
+		goto err_create_qh_pool;
+	}
+
+	bus = usb_alloc_bus(&uhci_device_operations);
+	if (!bus) {
+		err("unable to allocate bus");
+		goto err_alloc_bus;
+	}
+
+	uhci->bus = bus;
+	bus->bus_name = dev->slot_name;
+	bus->hcpriv = uhci;
+
+	usb_register_bus(uhci->bus);
+
+	/* 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 < (uhci->io_size - 0x10) / 2; port++) {
+		unsigned int portstatus;
+
+		portstatus = inw(uhci->io_addr + 0x10 + (port * 2));
+		if (!(portstatus & 0x0080))
+			break;
+	}
+	if (debug)
+		info("detected %d ports", 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 > 8) {
+		info("port count misdetected? forcing to 2 ports");
+		port = 2;
+	}
+
+	uhci->rh.numports = port;
+
+	uhci->bus->root_hub = uhci->rh.dev = usb_alloc_dev(NULL, uhci->bus);
+	if (!uhci->rh.dev) {
+		err("unable to allocate root hub");
+		goto err_alloc_root_hub;
+	}
+
+	uhci->skeltd[0] = uhci_alloc_td(uhci, uhci->rh.dev);
+	if (!uhci->skeltd[0]) {
+		err("unable to allocate TD 0");
+		goto err_alloc_skeltd;
+	}
+
+	/*
+	 * 9 Interrupt queues; link int2 to int1, int4 to int2, etc
+	 * then link int1 to control and control to bulk
+	 */
+	for (i = 1; i < 9; i++) {
+		struct uhci_td *td;
+
+		td = uhci->skeltd[i] = uhci_alloc_td(uhci, uhci->rh.dev);
+		if (!td) {
+			err("unable to allocate TD %d", i);
+			goto err_alloc_skeltd;
+		}
+
+		uhci_fill_td(td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
+		td->link = uhci->skeltd[i - 1]->dma_handle;
+	}
+
+	uhci->skel_term_td = uhci_alloc_td(uhci, uhci->rh.dev);
+	if (!uhci->skel_term_td) {
+		err("unable to allocate skel TD term");
+		goto err_alloc_skeltd;
+	}
+
+	for (i = 0; i < UHCI_NUM_SKELQH; i++) {
+		uhci->skelqh[i] = uhci_alloc_qh(uhci, uhci->rh.dev);
+		if (!uhci->skelqh[i]) {
+			err("unable to allocate QH %d", i);
+			goto err_alloc_skelqh;
+		}
+	}
+
+	uhci_fill_td(uhci->skel_int1_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
+	uhci->skel_int1_td->link = uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH;
+
+	uhci->skel_ls_control_qh->link = uhci->skel_hs_control_qh->dma_handle | UHCI_PTR_QH;
+	uhci->skel_ls_control_qh->element = UHCI_PTR_TERM;
+
+	uhci->skel_hs_control_qh->link = uhci->skel_bulk_qh->dma_handle | UHCI_PTR_QH;
+	uhci->skel_hs_control_qh->element = UHCI_PTR_TERM;
+
+	uhci->skel_bulk_qh->link = uhci->skel_term_qh->dma_handle | UHCI_PTR_QH;
+	uhci->skel_bulk_qh->element = UHCI_PTR_TERM;
+
+	/* This dummy TD is to work around a bug in Intel PIIX controllers */
+	uhci_fill_td(uhci->skel_term_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
+	uhci->skel_term_td->link = uhci->skel_term_td->dma_handle;
+
+	uhci->skel_term_qh->link = UHCI_PTR_TERM;
+	uhci->skel_term_qh->element = uhci->skel_term_td->dma_handle;
+
+	/*
+	 * Fill the frame list: make all entries point to
+	 * the proper interrupt queue.
+	 *
+	 * This is probably silly, but it's a simple way to
+	 * scatter the interrupt queues in a way that gives
+	 * us a reasonable dynamic range for irq latencies.
+	 */
+	for (i = 0; i < UHCI_NUMFRAMES; i++) {
+		int irq = 0;
+
+		if (i & 1) {
+			irq++;
+			if (i & 2) {
+				irq++;
+				if (i & 4) { 
+					irq++;
+					if (i & 8) { 
+						irq++;
+						if (i & 16) {
+							irq++;
+							if (i & 32) {
+								irq++;
+								if (i & 64)
+									irq++;
+							}
+						}
+					}
+				}
+			}
+		}
+
+		/* Only place we don't use the frame list routines */
+		uhci->fl->frame[i] =  uhci->skeltd[irq]->dma_handle;
+	}
+
+	start_hc(uhci);
+
+	if (request_irq(dev->irq, uhci_interrupt, SA_SHIRQ, "usb-uhci", uhci))
+		goto err_request_irq;
+
+	/* disable legacy emulation */
+	pci_write_config_word(uhci->dev, USBLEGSUP, USBLEGSUP_DEFAULT);
+
+	usb_connect(uhci->rh.dev);
+
+	if (usb_new_device(uhci->rh.dev) != 0) {
+		err("unable to start root hub");
+		retval = -ENOMEM;
+		goto err_start_root_hub;
+	}
+
+	return 0;
+
+/*
+ * error exits:
+ */
+err_start_root_hub:
+	free_irq(uhci->irq, uhci);
+	uhci->irq = -1;
+
+err_request_irq:
+	for (i = 0; i < UHCI_NUM_SKELQH; i++)
+		if (uhci->skelqh[i]) {
+			uhci_free_qh(uhci, uhci->skelqh[i]);
+			uhci->skelqh[i] = NULL;
+		}
+
+err_alloc_skelqh:
+	for (i = 0; i < UHCI_NUM_SKELTD; i++)
+		if (uhci->skeltd[i]) {
+			uhci_free_td(uhci, uhci->skeltd[i]);
+			uhci->skeltd[i] = NULL;
+		}
+
+err_alloc_skeltd:
+	usb_free_dev(uhci->rh.dev);
+	uhci->rh.dev = NULL;
+
+err_alloc_root_hub:
+	usb_free_bus(uhci->bus);
+	uhci->bus = NULL;
+
+err_alloc_bus:
+	pci_pool_destroy(uhci->qh_pool);
+	uhci->qh_pool = NULL;
+
+err_create_qh_pool:
+	pci_pool_destroy(uhci->td_pool);
+	uhci->td_pool = NULL;
+
+err_create_td_pool:
+	pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
+	uhci->fl = NULL;
+
+err_alloc_fl:
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry(buf, uhci_proc_root);
+	uhci->proc_entry = NULL;
+
+err_create_proc_entry:
+	free_uhci(uhci);
+#endif
+
+err_alloc_uhci:
+
+err_pci_set_dma_mask:
+	release_region(io_addr, io_size);
+
+err_request_region:
+
+err_pci_dma_supported:
+
+err_invalid_irq:
+
+err_enable_device:
+
+	return retval;
+}
+
+static int __devinit uhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	int i;
+
+	/* Search for the IO base address.. */
+	for (i = 0; i < 6; i++) {
+		unsigned int io_addr = pci_resource_start(dev, i);
+		unsigned int io_size = pci_resource_len(dev, i);
+
+		/* IO address? */
+		if (!(pci_resource_flags(dev, i) & IORESOURCE_IO))
+			continue;
+
+		return alloc_uhci(dev, io_addr, io_size);
+	}
+
+	return -ENODEV;
+}
+
+static void __devexit uhci_pci_remove(struct pci_dev *dev)
+{
+	struct uhci *uhci = pci_get_drvdata(dev);
+
+	if (uhci->bus->root_hub)
+		usb_disconnect(&uhci->bus->root_hub);
+
+	usb_deregister_bus(uhci->bus);
+
+	/*
+	 * At this point, we're guaranteed that no new connects can be made
+	 * to this bus since there are no more parents
+	 */
+	uhci_free_pending_qhs(uhci);
+	uhci_remove_pending_qhs(uhci);
+
+	reset_hc(uhci);
+	release_region(uhci->io_addr, uhci->io_size);
+
+	uhci_free_pending_qhs(uhci);
+
+	release_uhci(uhci);
+}
+
+#ifdef CONFIG_PM
+static int uhci_pci_suspend(struct pci_dev *dev, u32 state)
+{
+	suspend_hc((struct uhci *) pci_get_drvdata(dev));
+	return 0;
+}
+
+static int uhci_pci_resume(struct pci_dev *dev)
+{
+	reset_hc((struct uhci *) pci_get_drvdata(dev));
+	start_hc((struct uhci *) pci_get_drvdata(dev));
+	return 0;
+}
+#endif
+
+static const struct pci_device_id __devinitdata uhci_pci_ids[] = { {
+
+	/* handle any USB UHCI controller */
+	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x00),
+	class_mask: 	~0,
+
+	/* no matter who makes it */
+	vendor:		PCI_ANY_ID,
+	device:		PCI_ANY_ID,
+	subvendor:	PCI_ANY_ID,
+	subdevice:	PCI_ANY_ID,
+
+	}, { /* end: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE(pci, uhci_pci_ids);
+
+static struct pci_driver uhci_pci_driver = {
+	name:		"usb-uhci",
+	id_table:	uhci_pci_ids,
+
+	probe:		uhci_pci_probe,
+	remove:		__devexit_p(uhci_pci_remove),
+
+#ifdef	CONFIG_PM
+	suspend:	uhci_pci_suspend,
+	resume:		uhci_pci_resume,
+#endif	/* PM */
+};
+
+ 
+static int __init uhci_hcd_init(void)
+{
+	int retval = -ENOMEM;
+
+	info(DRIVER_DESC " " DRIVER_VERSION);
+
+	if (debug) {
+		errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
+		if (!errbuf)
+			goto errbuf_failed;
+	}
+
+#ifdef CONFIG_PROC_FS
+	uhci_proc_root = create_proc_entry("driver/uhci", S_IFDIR, 0);
+	if (!uhci_proc_root)
+		goto proc_failed;
+#endif
+
+	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_module_init(&uhci_pci_driver);
+	if (retval)
+		goto init_failed;
+
+	return 0;
+
+init_failed:
+	if (kmem_cache_destroy(uhci_up_cachep))
+		printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
+
+up_failed:
+
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("driver/uhci", 0);
+
+proc_failed:
+#endif
+	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))
+		printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
+
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("driver/uhci", 0);
+#endif
+
+	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 -Nru a/drivers/usb/host/uhci.h b/drivers/usb/host/uhci.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/host/uhci.h	Thu Mar  6 14:22:16 2003
@@ -0,0 +1,441 @@
+#ifndef __LINUX_UHCI_H
+#define __LINUX_UHCI_H
+
+#include <linux/list.h>
+#include <linux/usb.h>
+
+/*
+ * 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_LS		0x0030	/* Line Status */
+#define   USBPORTSC_RD		0x0040	/* Resume Detect */
+#define   USBPORTSC_LSDA	0x0100	/* Low Speed Device Attached */
+#define   USBPORTSC_PR		0x0200	/* Port Reset */
+#define   USBPORTSC_SUSP	0x1000	/* Suspend */
+
+/* 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		0x000F
+#define UHCI_PTR_TERM		0x0001
+#define UHCI_PTR_QH		0x0002
+#define UHCI_PTR_DEPTH		0x0004
+
+#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 {
+	__u32 frame[UHCI_NUMFRAMES];
+
+	void *frame_cpu[UHCI_NUMFRAMES];
+
+	dma_addr_t dma_handle;
+};
+
+struct urb_priv;
+
+struct uhci_qh {
+	/* Hardware fields */
+	__u32 link;			/* Next queue */
+	__u32 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)));
+
+/*
+ * 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_status_bits(ctrl_sts)	(ctrl_sts & 0xFE0000)
+#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_TOGGLE_SHIFT	19
+#define TD_TOKEN_TOGGLE		(1 << 19)
+#define TD_TOKEN_PID_MASK	0xFF
+#define TD_TOKEN_EXPLEN_MASK	0x7FF		/* expected length, encoded as n - 1 */
+
+#define uhci_maxlen(token)	((token) >> 21)
+#define uhci_expected_length(info) (((info >> 21) + 1) & TD_TOKEN_EXPLEN_MASK) /* 1-based */
+#define uhci_toggle(token)	(((token) >> TD_TOKEN_TOGGLE_SHIFT) & 1)
+#define uhci_endpoint(token)	(((token) >> 15) & 0xf)
+#define uhci_devaddr(token)	(((token) >> 8) & 0x7f)
+#define uhci_devep(token)	(((token) >> 8) & 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
+ */
+struct uhci_td {
+	/* Hardware fields */
+	__u32 link;
+	__u32 status;
+	__u32 info;
+	__u32 buffer;
+
+	/* Software fields */
+	dma_addr_t dma_handle;
+
+	struct usb_device *dev;
+	struct urb *urb;
+
+	struct list_head list;		/* P: urb->lock */
+
+	int frame;
+	struct list_head fl_list;	/* P: uhci->frame_list_lock */
+} __attribute__((aligned(16)));
+
+/*
+ * There are various standard queues. We set up several different
+ * queues for each of the three basic queue types: interrupt,
+ * control, and bulk.
+ *
+ *  - There are various different interrupt latencies: ranging from
+ *    every other USB frame (2 ms apart) to every 256 USB frames (ie
+ *    256 ms apart). Make your choice according to how obnoxious you
+ *    want to be on the wire, vs how critical latency is for you.
+ *  - The control list is done every frame.
+ *  - There are 4 bulk lists, so that up to four devices can have a
+ *    bulk list of their own and when run concurrently all four lists
+ *    will be be serviced.
+ *
+ * This is a bit misleading, there are various interrupt latencies, but they
+ * vary a bit, interrupt2 isn't exactly 2ms, it can vary up to 4ms since the
+ * other queues can "override" it. interrupt4 can vary up to 8ms, etc. Minor
+ * problem
+ *
+ * In the case of the root hub, these QH's are just head's of qh's. Don't
+ * be scared, it kinda makes sense. Look at this wonderful picture care of
+ * Linus:
+ *
+ *  generic-  ->  dev1-  ->  generic-  ->  dev1-  ->  control-  ->  bulk- -> ...
+ *   iso-QH      iso-QH       irq-QH      irq-QH        QH           QH
+ *      |           |            |           |           |            |
+ *     End     dev1-iso-TD1     End     dev1-irq-TD1    ...          ... 
+ *                  |
+ *             dev1-iso-TD2
+ *                  |
+ *                ....
+ *
+ * This may vary a bit (the UHCI docs don't explicitly say you can put iso
+ * transfers in QH's and all of their pictures don't have that either) but
+ * other than that, that is what we're doing now
+ *
+ * And now we don't put Iso transfers in QH's, so we don't waste one on it
+ * --jerdfelt
+ *
+ * To keep with Linus' nomenclature, this is called the QH skeleton. These
+ * labels (below) are only signficant to the root hub's QH's
+ */
+
+#define UHCI_NUM_SKELTD		10
+#define skel_int1_td		skeltd[0]
+#define skel_int2_td		skeltd[1]
+#define skel_int4_td		skeltd[2]
+#define skel_int8_td		skeltd[3]
+#define skel_int16_td		skeltd[4]
+#define skel_int32_td		skeltd[5]
+#define skel_int64_td		skeltd[6]
+#define skel_int128_td		skeltd[7]
+#define skel_int256_td		skeltd[8]
+#define skel_term_td		skeltd[9]	/* To work around PIIX UHCI bug */
+
+#define UHCI_NUM_SKELQH		4
+#define skel_ls_control_qh	skelqh[0]
+#define skel_hs_control_qh	skelqh[1]
+#define skel_bulk_qh		skelqh[2]
+#define skel_term_qh		skelqh[3]
+
+/*
+ * 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.
+ *
+ * NOTE: For UHCI, we don't really need int256_qh since the maximum interval
+ * is 255 ms.  However, we do need an int1_qh since 1 is a valid interval
+ * and we should meet that frequency when requested to do so.
+ * This will require some change(s) to the UHCI skeleton.
+ */
+static inline int __interval_to_skel(int interval)
+{
+	if (interval < 16) {
+		if (interval < 4) {
+			if (interval < 2)
+				return 0;	/* int1 for 0-1 ms */
+			return 1;		/* int2 for 2-3 ms */
+		}
+		if (interval < 8)
+			return 2;		/* int4 for 4-7 ms */
+		return 3;			/* int8 for 8-15 ms */
+	}
+	if (interval < 64) {
+		if (interval < 32)
+			return 4;		/* int16 for 16-31 ms */
+		return 5;			/* int32 for 32-63 ms */
+	}
+	if (interval < 128)
+		return 6;			/* int64 for 64-127 ms */
+	return 7;				/* int128 for 128-255 ms (Max.) */
+}
+
+struct virt_root_hub {
+	struct usb_device *dev;
+	int devnum;		/* Address of Root Hub endpoint */
+	struct urb *urb;
+	void *int_addr;
+	int send;
+	int interval;
+	int numports;
+	int c_p_r[8];
+	struct timer_list rh_int_timer;
+};
+
+/*
+ * This describes the full uhci information.
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs.
+ */
+struct uhci {
+	struct pci_dev *dev;
+
+#ifdef CONFIG_PROC_FS
+	/* procfs */
+	int num;
+	struct proc_dir_entry *proc_entry;
+#endif
+
+	/* Grabbed from PCI */
+	int irq;
+	unsigned int io_addr;
+	unsigned int io_size;
+
+	struct pci_pool *qh_pool;
+	struct pci_pool *td_pool;
+
+	struct usb_bus *bus;
+
+	struct uhci_td *skeltd[UHCI_NUM_SKELTD];	/* Skeleton TD's */
+	struct uhci_qh *skelqh[UHCI_NUM_SKELQH];	/* Skeleton QH's */
+
+	spinlock_t frame_list_lock;
+	struct uhci_frame_list *fl;		/* P: uhci->frame_list_lock */
+	int fsbr;				/* Full speed bandwidth reclamation */
+	unsigned long fsbrtimeout;		/* FSBR delay */
+	int is_suspended;
+
+	/* Main list of URB's currently controlled by this HC */
+	spinlock_t urb_list_lock;
+	struct list_head urb_list;		/* P: uhci->urb_list_lock */
+
+	/* List of QH's that are done, but waiting to be unlinked (race) */
+	spinlock_t qh_remove_list_lock;
+	struct list_head qh_remove_list;	/* P: uhci->qh_remove_list_lock */
+
+	/* List of asynchronously unlinked URB's */
+	spinlock_t urb_remove_list_lock;
+	struct list_head urb_remove_list;	/* P: uhci->urb_remove_list_lock */
+
+	/* List of URB's awaiting completion callback */
+	spinlock_t complete_list_lock;
+	struct list_head complete_list;		/* P: uhci->complete_list_lock */
+
+	struct virt_root_hub rh;	/* private data of the virtual root hub */
+};
+
+struct urb_priv {
+	struct urb *urb;
+	struct usb_device *dev;
+
+	dma_addr_t setup_packet_dma_handle;
+	dma_addr_t transfer_buffer_dma_handle;
+
+	struct uhci_qh *qh;		/* QH for this URB */
+	struct list_head td_list;	/* P: urb->lock */
+
+	int fsbr : 1;			/* URB turned on FSBR */
+	int fsbr_timeout : 1;		/* URB timed out on FSBR */
+	int queued : 1;			/* QH was queued (not linked in) */
+	int short_control_packet : 1;	/* If we get a short packet during */
+					/*  a control transfer, retrigger */
+					/*  the status phase */
+
+	int status;			/* Final status */
+
+	unsigned long inserttime;	/* In jiffies */
+	unsigned long fsbrtime;		/* In jiffies */
+
+	struct list_head queue_list;	/* P: uhci->frame_list_lock */
+	struct list_head complete_list;	/* P: uhci->complete_list_lock */
+};
+
+/*
+ * Locking in uhci.c
+ *
+ * spinlocks are used extensively to protect the many lists and data
+ * structures we have. It's not that pretty, but it's necessary. We
+ * need to be done with all of the locks (except complete_list_lock) when
+ * we call urb->complete. I've tried to make it simple enough so I don't
+ * have to spend hours racking my brain trying to figure out if the
+ * locking is safe.
+ *
+ * Here's the safe locking order to prevent deadlocks:
+ *
+ * #1 uhci->urb_list_lock
+ * #2 urb->lock
+ * #3 uhci->urb_remove_list_lock, uhci->frame_list_lock, 
+ *   uhci->qh_remove_list_lock
+ * #4 uhci->complete_list_lock
+ *
+ * If you're going to grab 2 or more locks at once, ALWAYS grab the lock
+ * at the lowest level FIRST and NEVER grab locks at the same level at the
+ * same time.
+ * 
+ * So, if you need uhci->urb_list_lock, grab it before you grab urb->lock
+ */
+
+/* -------------------------------------------------------------------------
+   Virtual Root HUB
+   ------------------------------------------------------------------------- */
+/* destination of request */
+#define RH_DEVICE		0x00
+#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
+
+#endif
+
diff -Nru a/drivers/usb/host/usb-uhci-debug.h b/drivers/usb/host/usb-uhci-debug.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/host/usb-uhci-debug.h	Thu Mar  6 14:22:16 2003
@@ -0,0 +1,195 @@
+#ifdef DEBUG
+static void __attribute__((__unused__)) uhci_show_qh (puhci_desc_t qh)
+{
+	if (qh->type != QH_TYPE) {
+		dbg("qh has not QH_TYPE");
+		return;
+	}
+	dbg("QH @ %p/%08llX:", qh, (unsigned long long)qh->dma_addr);
+
+	if (qh->hw.qh.head & UHCI_PTR_TERM)
+		dbg("    Head Terminate");
+	else 
+		dbg("    Head: %s @ %08X",
+		    (qh->hw.qh.head & UHCI_PTR_QH?"QH":"TD"),
+		    qh->hw.qh.head & ~UHCI_PTR_BITS);
+
+	if (qh->hw.qh.element & UHCI_PTR_TERM)
+		dbg("    Element Terminate");
+	else 
+		dbg("    Element: %s @ %08X",
+		    (qh->hw.qh.element & UHCI_PTR_QH?"QH":"TD"),
+		    qh->hw.qh.element & ~UHCI_PTR_BITS);
+}
+#endif
+
+#if 0
+static void uhci_show_td (puhci_desc_t td)
+{
+	char *spid;
+	
+	switch (td->hw.td.info & 0xff) {
+	case USB_PID_SETUP:
+		spid = "SETUP";
+		break;
+	case USB_PID_OUT:
+		spid = " OUT ";
+		break;
+	case USB_PID_IN:
+		spid = " IN  ";
+		break;
+	default:
+		spid = "  ?  ";
+		break;
+	}
+
+	warn("  TD @ %p/%08X, MaxLen=%02x DT%d EP=%x Dev=%x PID=(%s) buf=%08x",
+	     td, td->dma_addr,
+	     td->hw.td.info >> 21,
+	     ((td->hw.td.info >> 19) & 1),
+	     (td->hw.td.info >> 15) & 15,
+	     (td->hw.td.info >> 8) & 127,
+	     spid,
+	     td->hw.td.buffer);
+
+	warn("    Len=%02x e%d %s%s%s%s%s%s%s%s%s%s",
+	     td->hw.td.status & 0x7ff,
+	     ((td->hw.td.status >> 27) & 3),
+	     (td->hw.td.status & TD_CTRL_SPD) ? "SPD " : "",
+	     (td->hw.td.status & TD_CTRL_LS) ? "LS " : "",
+	     (td->hw.td.status & TD_CTRL_IOC) ? "IOC " : "",
+	     (td->hw.td.status & TD_CTRL_ACTIVE) ? "Active " : "",
+	     (td->hw.td.status & TD_CTRL_STALLED) ? "Stalled " : "",
+	     (td->hw.td.status & TD_CTRL_DBUFERR) ? "DataBufErr " : "",
+	     (td->hw.td.status & TD_CTRL_BABBLE) ? "Babble " : "",
+	     (td->hw.td.status & TD_CTRL_NAK) ? "NAK " : "",
+	     (td->hw.td.status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
+	     (td->hw.td.status & TD_CTRL_BITSTUFF) ? "BitStuff " : ""
+		);
+
+	if (td->hw.td.link & UHCI_PTR_TERM)
+		warn("   TD Link Terminate");
+	else 
+		warn("    Link points to %s @ %08x, %s",
+		     (td->hw.td.link & UHCI_PTR_QH?"QH":"TD"),
+		     td->hw.td.link & ~UHCI_PTR_BITS,
+		     (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : "Breadth first"));
+}
+#endif
+
+#ifdef DEBUG
+static void __attribute__((__unused__)) uhci_show_td_queue (puhci_desc_t td)
+{
+	//dbg("uhci_show_td_queue %p (%08lX):", td, td->dma_addr);
+#if 1
+	return;
+#else
+	while (1) {
+		uhci_show_td (td);
+		if (td->hw.td.link & UHCI_PTR_TERM)
+			break;
+		if (td != bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS))
+			td = bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS);
+		else {
+			dbg("td points to itself!");
+			break;
+		}
+	}
+#endif
+}
+
+static void __attribute__((__unused__)) uhci_show_queue (puhci_desc_t qh)
+{
+#if 0
+	uhci_desc_t *start_qh=qh;
+#endif
+
+	dbg("uhci_show_queue %p:", qh);
+#if 1
+	return;
+#else
+	while (1) {
+		uhci_show_qh (qh);
+
+		if (!(qh->hw.qh.element & UHCI_PTR_TERM))
+			uhci_show_td_queue (bus_to_virt (qh->hw.qh.element & ~UHCI_PTR_BITS));
+
+		if (qh->hw.qh.head & UHCI_PTR_TERM)
+			break;
+
+		if (qh != bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS))
+			qh = bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS);
+		else {
+			dbg("qh points to itself!");
+			break;
+		}
+		
+		if (qh==start_qh) { // avoid loop
+			dbg("Loop detect");
+			break;
+		}
+	}		
+#endif
+}
+
+static void __attribute__((__unused__)) uhci_show_sc (int port, unsigned short status)
+{
+	dbg("  stat%d     =     %04x   %s%s%s%s%s%s%s%s",
+	     port,
+	     status,
+	     (status & USBPORTSC_SUSP) ? "PortSuspend " : "",
+	     (status & USBPORTSC_PR) ? "PortReset " : "",
+	     (status & USBPORTSC_LSDA) ? "LowSpeed " : "",
+	     (status & USBPORTSC_RD) ? "ResumeDetect " : "",
+	     (status & USBPORTSC_PEC) ? "EnableChange " : "",
+	     (status & USBPORTSC_PE) ? "PortEnabled " : "",
+	     (status & USBPORTSC_CSC) ? "ConnectChange " : "",
+	     (status & USBPORTSC_CCS) ? "PortConnected " : "");
+}
+
+void uhci_show_status (puhci_t s)
+{
+	unsigned int io_addr = s->io_addr;
+	unsigned short usbcmd, usbstat, usbint, usbfrnum;
+	unsigned int flbaseadd;
+	unsigned char sof;
+	unsigned short portsc1, portsc2;
+
+	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);
+
+	dbg("  usbcmd    =     %04x   %s%s%s%s%s%s%s%s",
+	     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 " : "");
+
+	dbg("  usbstat   =     %04x   %s%s%s%s%s%s",
+	     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 " : "");
+
+	dbg("  usbint    =     %04x", usbint);
+	dbg("  usbfrnum  =   (%d)%03x", (usbfrnum >> 10) & 1,
+	     0xfff & (4 * (unsigned int) usbfrnum));
+	dbg("  flbaseadd = %08x", flbaseadd);
+	dbg("  sof       =       %02x", sof);
+	uhci_show_sc (1, portsc1);
+	uhci_show_sc (2, portsc2);
+}
+#endif
diff -Nru a/drivers/usb/host/usb-uhci.c b/drivers/usb/host/usb-uhci.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/host/usb-uhci.c	Thu Mar  6 14:22:16 2003
@@ -0,0 +1,3143 @@
+/* 
+ * Universal Host Controller Interface driver for USB (take II).
+ *
+ * (c) 1999-2001 Georg Acher, acher@in.tum.de (executive slave) (base guitar)
+ *               Deti Fliegl, deti@fliegl.de (executive slave) (lead voice)
+ *               Thomas Sailer, sailer@ife.ee.ethz.ch (chief consultant) (cheer leader)
+ *               Roman Weissgaerber, weissg@vienna.at (virt root hub) (studio porter)
+ * (c) 2000      Yggdrasil Computing, Inc. (port of new PCI interface support
+ *               from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (C) 2000      David Brownell, david-b@pacbell.net (usb-ohci.c)
+ *          
+ * HW-initalization based on material of
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999 Johannes Erdfelt
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Gregory P. Smith
+ *
+ * $Id: usb-uhci.c,v 1.275 2002/01/19 20:57:33 acher Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.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/unistd.h>
+#include <linux/interrupt.h>	/* for in_interrupt() */
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/pm.h>
+#include <linux/timer.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+/* This enables more detailed sanity checks in submit_iso */
+//#define ISO_SANITY_CHECK
+
+/* This enables debug printks */
+#define DEBUG
+
+/* This enables all symbols to be exported, to ease debugging oopses */
+//#define DEBUG_SYMBOLS
+
+/* This enables an extra UHCI slab for memory debugging */
+#define DEBUG_SLAB
+
+#define VERSTR "$Revision: 1.275 $ time " __TIME__ " " __DATE__
+
+#include <linux/usb.h>
+#include "usb-uhci.h"
+#include "usb-uhci-debug.h"
+
+#include "../hcd.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.275"
+#define DRIVER_AUTHOR "Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
+#define DRIVER_DESC "USB Universal Host Controller Interface driver"
+
+#undef DEBUG
+#undef dbg
+#define dbg(format, arg...) do {} while (0)
+#define DEBUG_SYMBOLS
+#ifdef DEBUG_SYMBOLS
+	#define _static
+	#ifndef EXPORT_SYMTAB
+		#define EXPORT_SYMTAB
+	#endif
+#else
+	#define _static static
+#endif
+
+#define queue_dbg dbg //err
+#define async_dbg dbg //err
+
+#ifdef DEBUG_SLAB
+	static kmem_cache_t *urb_priv_kmem;
+#endif
+
+#define SLAB_FLAG     (in_interrupt () || current->state != TASK_RUNNING ? SLAB_ATOMIC : SLAB_KERNEL)
+#define KMALLOC_FLAG  (in_interrupt () || current->state != TASK_RUNNING ? GFP_ATOMIC : GFP_KERNEL)
+
+/* CONFIG_USB_UHCI_HIGH_BANDWITH turns on Full Speed Bandwidth
+ * Reclamation: feature that puts loop on descriptor loop when
+ * there's some transfer going on. With FSBR, USB performance
+ * is optimal, but PCI can be slowed down up-to 5 times, slowing down
+ * system performance (eg. framebuffer devices).
+ */
+#define CONFIG_USB_UHCI_HIGH_BANDWIDTH
+
+/* *_DEPTH_FIRST puts descriptor in depth-first mode. This has
+ * somehow similar effect to FSBR (higher speed), but does not
+ * slow PCI down. OTOH USB performace is slightly slower than
+ * in FSBR case and single device could hog whole USB, starving
+ * other devices.
+ */
+#define USE_CTRL_DEPTH_FIRST 0  // 0: Breadth first, 1: Depth first
+#define USE_BULK_DEPTH_FIRST 0  // 0: Breadth first, 1: Depth first
+
+/* Turning off both CONFIG_USB_UHCI_HIGH_BANDWITH and *_DEPTH_FIRST
+ * will lead to <64KB/sec performance over USB for bulk transfers targeting
+ * one device's endpoint. You probably do not want to do that.
+ */
+
+// stop bandwidth reclamation after (roughly) 50ms
+#define IDLE_TIMEOUT  (HZ/20)
+
+// Suppress HC interrupt error messages for 5s
+#define ERROR_SUPPRESSION_TIME (HZ*5)
+
+_static int rh_submit_urb (struct urb *urb);
+_static int rh_unlink_urb (struct urb *urb);
+_static int delete_qh (uhci_t *s, uhci_desc_t *qh);
+_static int process_transfer (uhci_t *s, struct urb *urb, int mode);
+_static int process_interrupt (uhci_t *s, struct urb *urb);
+_static int process_iso (uhci_t *s, struct urb *urb, int force);
+
+// How much URBs with ->next are walked
+#define MAX_NEXT_COUNT 2048
+
+static uhci_t *devs = NULL;
+
+/* used by userspace UHCI data structure dumper */
+uhci_t **uhci_devices = &devs;
+
+/*-------------------------------------------------------------------*/
+// Cleans up collected QHs, but not more than 100 in one go
+void clean_descs(uhci_t *s, int force)
+{
+	struct list_head *q;
+	uhci_desc_t *qh;
+	int now=UHCI_GET_CURRENT_FRAME(s), n=0;
+
+	q=s->free_desc.prev;
+
+	while (q != &s->free_desc && (force || n<100)) {
+		qh = list_entry (q, uhci_desc_t, horizontal);
+		q=qh->horizontal.prev;
+
+		if ((qh->last_used!=now) || force)
+			delete_qh(s,qh);
+		n++;
+	}
+}
+/*-------------------------------------------------------------------*/
+_static void uhci_switch_timer_int(uhci_t *s)
+{
+
+	if (!list_empty(&s->urb_unlinked))
+		set_td_ioc(s->td1ms);
+	else
+		clr_td_ioc(s->td1ms);
+
+	if (s->timeout_urbs)
+		set_td_ioc(s->td32ms);
+	else
+		clr_td_ioc(s->td32ms);
+	wmb();
+}
+/*-------------------------------------------------------------------*/
+#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
+_static void enable_desc_loop(uhci_t *s, struct urb *urb)
+{
+	unsigned long flags;
+
+	if (urb->transfer_flags & USB_NO_FSBR)
+		return;
+
+	spin_lock_irqsave (&s->qh_lock, flags);
+	s->chain_end->hw.qh.head&=cpu_to_le32(~UHCI_PTR_TERM);
+	mb();
+	s->loop_usage++;
+	((urb_priv_t*)urb->hcpriv)->use_loop=1;
+	spin_unlock_irqrestore (&s->qh_lock, flags);
+}
+/*-------------------------------------------------------------------*/
+_static void disable_desc_loop(uhci_t *s, struct urb *urb)
+{
+	unsigned long flags;
+
+	if (urb->transfer_flags & USB_NO_FSBR)
+		return;
+
+	spin_lock_irqsave (&s->qh_lock, flags);
+	if (((urb_priv_t*)urb->hcpriv)->use_loop) {
+		s->loop_usage--;
+
+		if (!s->loop_usage) {
+			s->chain_end->hw.qh.head|=cpu_to_le32(UHCI_PTR_TERM);
+			mb();
+		}
+		((urb_priv_t*)urb->hcpriv)->use_loop=0;
+	}
+	spin_unlock_irqrestore (&s->qh_lock, flags);
+}
+#endif
+/*-------------------------------------------------------------------*/
+_static void queue_urb_unlocked (uhci_t *s, struct urb *urb)
+{
+	struct list_head *p=&urb->urb_list;
+#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
+	{
+		int type;
+		type=usb_pipetype (urb->pipe);
+
+		if ((type == PIPE_BULK) || (type == PIPE_CONTROL))
+			enable_desc_loop(s, urb);
+	}
+#endif
+	urb->status = -EINPROGRESS;
+	((urb_priv_t*)urb->hcpriv)->started=jiffies;
+	list_add (p, &s->urb_list);
+	if (urb->timeout)
+		s->timeout_urbs++;
+	uhci_switch_timer_int(s);
+}
+/*-------------------------------------------------------------------*/
+_static void queue_urb (uhci_t *s, struct urb *urb)
+{
+	unsigned long flags=0;
+
+	spin_lock_irqsave (&s->urb_list_lock, flags);
+	queue_urb_unlocked(s,urb);
+	spin_unlock_irqrestore (&s->urb_list_lock, flags);
+}
+/*-------------------------------------------------------------------*/
+_static void dequeue_urb (uhci_t *s, struct urb *urb)
+{
+#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
+	int type;
+
+	type=usb_pipetype (urb->pipe);
+
+	if ((type == PIPE_BULK) || (type == PIPE_CONTROL))
+		disable_desc_loop(s, urb);
+#endif
+
+	list_del (&urb->urb_list);
+	if (urb->timeout && s->timeout_urbs)
+		s->timeout_urbs--;
+
+}
+/*-------------------------------------------------------------------*/
+_static int alloc_td (uhci_t *s, uhci_desc_t ** new, int flags)
+{
+	dma_addr_t dma_handle;
+
+	*new = pci_pool_alloc(s->desc_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
+	if (!*new)
+		return -ENOMEM;
+	memset (*new, 0, sizeof (uhci_desc_t));
+	(*new)->dma_addr = dma_handle;
+	set_td_link((*new), UHCI_PTR_TERM | (flags & UHCI_PTR_BITS));	// last by default
+	(*new)->type = TD_TYPE;
+	mb();
+	INIT_LIST_HEAD (&(*new)->vertical);
+	INIT_LIST_HEAD (&(*new)->horizontal);
+	
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+// append a qh to td.link physically, the SW linkage is not affected
+_static void append_qh(uhci_t *s, uhci_desc_t *td, uhci_desc_t* qh, int  flags)
+{
+	unsigned long xxx;
+	
+	spin_lock_irqsave (&s->td_lock, xxx);
+
+	set_td_link(td, qh->dma_addr | (flags & UHCI_PTR_DEPTH) | UHCI_PTR_QH);
+       
+	mb();
+	spin_unlock_irqrestore (&s->td_lock, xxx);
+}
+/*-------------------------------------------------------------------*/
+/* insert td at last position in td-list of qh (vertical) */
+_static int insert_td (uhci_t *s, uhci_desc_t *qh, uhci_desc_t* new, int flags)
+{
+	uhci_desc_t *prev;
+	unsigned long xxx;
+	
+	spin_lock_irqsave (&s->td_lock, xxx);
+
+	list_add_tail (&new->vertical, &qh->vertical);
+
+	prev = list_entry (new->vertical.prev, uhci_desc_t, vertical);
+
+	if (qh == prev ) {
+		// virgin qh without any tds
+		set_qh_element(qh, new->dma_addr | UHCI_PTR_TERM);
+	}
+	else {
+		// already tds inserted, implicitely remove TERM bit of prev
+		set_td_link(prev, new->dma_addr | (flags & UHCI_PTR_DEPTH));
+	}
+	mb();
+	spin_unlock_irqrestore (&s->td_lock, xxx);
+	
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+/* insert new_td after td (horizontal) */
+_static int insert_td_horizontal (uhci_t *s, uhci_desc_t *td, uhci_desc_t* new)
+{
+	uhci_desc_t *next;
+	unsigned long flags;
+	
+	spin_lock_irqsave (&s->td_lock, flags);
+
+	next = list_entry (td->horizontal.next, uhci_desc_t, horizontal);
+	list_add (&new->horizontal, &td->horizontal);
+	new->hw.td.link = td->hw.td.link;
+	set_td_link(td, new->dma_addr);
+	mb();
+	spin_unlock_irqrestore (&s->td_lock, flags);	
+	
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+_static int unlink_td (uhci_t *s, uhci_desc_t *element, int phys_unlink)
+{
+	uhci_desc_t *next, *prev;
+	int dir = 0;
+	unsigned long flags;
+	
+	spin_lock_irqsave (&s->td_lock, flags);
+	
+	next = list_entry (element->vertical.next, uhci_desc_t, vertical);
+	
+	if (next == element) {
+		dir = 1;
+		prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal);
+	}
+	else 
+		prev = list_entry (element->vertical.prev, uhci_desc_t, vertical);
+	
+	if (phys_unlink) {
+		// really remove HW linking
+		if (prev->type == TD_TYPE)
+			prev->hw.td.link = element->hw.td.link;
+		else
+			prev->hw.qh.element = element->hw.td.link;
+	}
+
+	mb ();
+
+	if (dir == 0)
+		list_del (&element->vertical);
+	else
+		list_del (&element->horizontal);
+	
+	spin_unlock_irqrestore (&s->td_lock, flags);	
+	
+	return 0;
+}
+
+/*-------------------------------------------------------------------*/
+_static int delete_desc (uhci_t *s, uhci_desc_t *element)
+{
+	pci_pool_free(s->desc_pool, element, element->dma_addr);
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+// Allocates qh element
+_static int alloc_qh (uhci_t *s, uhci_desc_t ** new)
+{
+	dma_addr_t dma_handle;
+
+	*new = pci_pool_alloc(s->desc_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
+	if (!*new)
+		return -ENOMEM;
+	memset (*new, 0, sizeof (uhci_desc_t));
+	(*new)->dma_addr = dma_handle;
+	set_qh_head(*new, UHCI_PTR_TERM);
+	set_qh_element(*new, UHCI_PTR_TERM);
+	(*new)->type = QH_TYPE;
+	
+	mb();
+	INIT_LIST_HEAD (&(*new)->horizontal);
+	INIT_LIST_HEAD (&(*new)->vertical);
+	
+	dbg("Allocated qh @ %p", *new);
+	
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+// inserts new qh before/after the qh at pos
+// flags: 0: insert before pos, 1: insert after pos (for low speed transfers)
+_static int insert_qh (uhci_t *s, uhci_desc_t *pos, uhci_desc_t *new, int order)
+{
+	uhci_desc_t *old;
+	unsigned long flags;
+
+	spin_lock_irqsave (&s->qh_lock, flags);
+
+	if (!order) {
+		// (OLD) (POS) -> (OLD) (NEW) (POS)
+		old = list_entry (pos->horizontal.prev, uhci_desc_t, horizontal);
+		list_add_tail (&new->horizontal, &pos->horizontal);
+		set_qh_head(new, MAKE_QH_ADDR (pos)) ;
+		if (!(old->hw.qh.head & cpu_to_le32(UHCI_PTR_TERM)))
+			set_qh_head(old, MAKE_QH_ADDR (new)) ;
+	}
+	else {
+		// (POS) (OLD) -> (POS) (NEW) (OLD)
+		old = list_entry (pos->horizontal.next, uhci_desc_t, horizontal);
+		list_add (&new->horizontal, &pos->horizontal);
+		set_qh_head(new, MAKE_QH_ADDR (old));
+		set_qh_head(pos, MAKE_QH_ADDR (new)) ;
+	}
+
+	mb ();
+	
+	spin_unlock_irqrestore (&s->qh_lock, flags);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------*/
+_static int unlink_qh (uhci_t *s, uhci_desc_t *element)
+{
+	uhci_desc_t  *prev;
+	unsigned long flags;
+
+	spin_lock_irqsave (&s->qh_lock, flags);
+	
+	prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal);
+	prev->hw.qh.head = element->hw.qh.head;
+
+	dbg("unlink qh %p, pqh %p, nxqh %p, to %08x", element, prev, 
+	    list_entry (element->horizontal.next, uhci_desc_t, horizontal),le32_to_cpu(element->hw.qh.head) &~15);
+	
+	list_del(&element->horizontal);
+
+	mb ();
+	spin_unlock_irqrestore (&s->qh_lock, flags);
+	
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+_static int delete_qh (uhci_t *s, uhci_desc_t *qh)
+{
+	uhci_desc_t *td;
+	struct list_head *p;
+	
+	list_del (&qh->horizontal);
+
+	while ((p = qh->vertical.next) != &qh->vertical) {
+		td = list_entry (p, uhci_desc_t, vertical);
+		dbg("unlink td @ %p",td);
+		unlink_td (s, td, 0); // no physical unlink
+		delete_desc (s, td);
+	}
+
+	delete_desc (s, qh);
+	
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+_static void clean_td_chain (uhci_t *s, uhci_desc_t *td)
+{
+	struct list_head *p;
+	uhci_desc_t *td1;
+
+	if (!td)
+		return;
+	
+	while ((p = td->horizontal.next) != &td->horizontal) {
+		td1 = list_entry (p, uhci_desc_t, horizontal);
+		delete_desc (s, td1);
+	}
+	
+	delete_desc (s, td);
+}
+
+/*-------------------------------------------------------------------*/
+_static void fill_td (uhci_desc_t *td, int status, int info, __u32 buffer)
+{
+	td->hw.td.status = cpu_to_le32(status);
+	td->hw.td.info = cpu_to_le32(info);
+	td->hw.td.buffer = cpu_to_le32(buffer);
+}
+/*-------------------------------------------------------------------*/
+// Removes ALL qhs in chain (paranoia!)
+_static void cleanup_skel (uhci_t *s)
+{
+	unsigned int n;
+	uhci_desc_t *td;
+
+	dbg("cleanup_skel");
+
+	clean_descs(s,1);
+
+	
+	if (s->td32ms) {
+	
+		unlink_td(s,s->td32ms,1);
+		delete_desc(s, s->td32ms);
+	}
+
+	for (n = 0; n < 8; n++) {
+		td = s->int_chain[n];
+		clean_td_chain (s, td);
+	}
+
+	if (s->iso_td) {
+		for (n = 0; n < 1024; n++) {
+			td = s->iso_td[n];
+			clean_td_chain (s, td);
+		}
+		kfree (s->iso_td);
+	}
+
+	if (s->framelist)
+		pci_free_consistent(s->uhci_pci, PAGE_SIZE,
+				    s->framelist, s->framelist_dma);
+
+	if (s->control_chain) {
+		// completed init_skel?
+		struct list_head *p;
+		uhci_desc_t *qh, *qh1;
+
+		qh = s->control_chain;
+		while ((p = qh->horizontal.next) != &qh->horizontal) {
+			qh1 = list_entry (p, uhci_desc_t, horizontal);
+			delete_qh (s, qh1);
+		}
+
+		delete_qh (s, qh);
+	}
+	else {
+		if (s->ls_control_chain)
+			delete_desc (s, s->ls_control_chain);
+		if (s->control_chain)
+			delete_desc (s, s->control_chain);
+		if (s->bulk_chain)
+			delete_desc (s, s->bulk_chain);
+		if (s->chain_end)
+			delete_desc (s, s->chain_end);
+	}
+
+	if (s->desc_pool) {
+		pci_pool_destroy(s->desc_pool);
+		s->desc_pool = NULL;
+	}
+
+	dbg("cleanup_skel finished");	
+}
+/*-------------------------------------------------------------------*/
+// allocates framelist and qh-skeletons
+// only HW-links provide continous linking, SW-links stay in their domain (ISO/INT)
+_static int init_skel (uhci_t *s)
+{
+	int n, ret;
+	uhci_desc_t *qh, *td;
+	
+	dbg("init_skel");
+	
+	s->framelist = pci_alloc_consistent(s->uhci_pci, PAGE_SIZE,
+					    &s->framelist_dma);
+
+	if (!s->framelist)
+		return -ENOMEM;
+
+	memset (s->framelist, 0, 4096);
+
+	dbg("creating descriptor pci_pool");
+
+	s->desc_pool = pci_pool_create("uhci_desc", s->uhci_pci,
+				       sizeof(uhci_desc_t), 16, 0,
+				       GFP_DMA | GFP_ATOMIC);	
+	if (!s->desc_pool)
+		goto init_skel_cleanup;
+
+	dbg("allocating iso desc pointer list");
+	s->iso_td = (uhci_desc_t **) kmalloc (1024 * sizeof (uhci_desc_t*), GFP_KERNEL);
+	
+	if (!s->iso_td)
+		goto init_skel_cleanup;
+
+	s->ls_control_chain = NULL;
+	s->control_chain = NULL;
+	s->bulk_chain = NULL;
+	s->chain_end = NULL;
+
+	dbg("allocating iso descs");
+	for (n = 0; n < 1024; n++) {
+	 	// allocate skeleton iso/irq-tds
+		if (alloc_td (s, &td, 0))
+			goto init_skel_cleanup;
+
+		s->iso_td[n] = td;
+		s->framelist[n] = cpu_to_le32((__u32) td->dma_addr);
+	}
+
+	dbg("allocating qh: chain_end");
+	if (alloc_qh (s, &qh))	
+		goto init_skel_cleanup;
+				
+	s->chain_end = qh;
+
+	if (alloc_td (s, &td, 0))
+		goto init_skel_cleanup;
+	
+	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 1ms interrupt (enabled on demand)
+	insert_td (s, qh, td, 0);
+	qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM); // remove TERM bit
+	s->td1ms=td;
+
+	dbg("allocating qh: bulk_chain");
+	if (alloc_qh (s, &qh))
+		goto init_skel_cleanup;
+	
+	insert_qh (s, s->chain_end, qh, 0);
+	s->bulk_chain = qh;
+
+	dbg("allocating qh: control_chain");
+	ret = alloc_qh (s, &qh);
+	if (ret)
+		goto init_skel_cleanup;
+	
+	insert_qh (s, s->bulk_chain, qh, 0);
+	s->control_chain = qh;
+
+#ifdef	CONFIG_USB_UHCI_HIGH_BANDWIDTH
+	// disabled reclamation loop
+	set_qh_head(s->chain_end, s->control_chain->dma_addr | UHCI_PTR_QH | UHCI_PTR_TERM);
+#endif
+
+	dbg("allocating qh: ls_control_chain");
+	if (alloc_qh (s, &qh))
+		goto init_skel_cleanup;
+	
+	insert_qh (s, s->control_chain, qh, 0);
+	s->ls_control_chain = qh;
+
+	for (n = 0; n < 8; n++)
+		s->int_chain[n] = 0;
+
+	dbg("allocating skeleton INT-TDs");
+	
+	for (n = 0; n < 8; n++) {
+		uhci_desc_t *td;
+
+		if (alloc_td (s, &td, 0))
+			goto init_skel_cleanup;
+
+		s->int_chain[n] = td;
+		if (n == 0) {
+			set_td_link(s->int_chain[0], s->ls_control_chain->dma_addr | UHCI_PTR_QH);
+		}
+		else {
+			set_td_link(s->int_chain[n], s->int_chain[0]->dma_addr);
+		}
+	}
+
+	dbg("Linking skeleton INT-TDs");
+	
+	for (n = 0; n < 1024; n++) {
+		// link all iso-tds to the interrupt chains
+		int m, o;
+		dbg("framelist[%i]=%x",n,le32_to_cpu(s->framelist[n]));
+		if ((n&127)==127) 
+			((uhci_desc_t*) s->iso_td[n])->hw.td.link = cpu_to_le32(s->int_chain[0]->dma_addr);
+		else 
+			for (o = 1, m = 2; m <= 128; o++, m += m)
+				if ((n & (m - 1)) == ((m - 1) / 2))
+					set_td_link(((uhci_desc_t*) s->iso_td[n]), s->int_chain[o]->dma_addr);
+	}
+
+	if (alloc_td (s, &td, 0))
+		goto init_skel_cleanup;
+	
+	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 32ms interrupt (activated later)
+	s->td32ms=td;
+
+	insert_td_horizontal (s, s->int_chain[5], td);
+
+	mb();
+	//uhci_show_queue(s->control_chain);   
+	dbg("init_skel exit");
+	return 0;
+
+      init_skel_cleanup:
+	cleanup_skel (s);
+	return -ENOMEM;
+}
+
+/*-------------------------------------------------------------------*/
+//                         LOW LEVEL STUFF
+//          assembles QHs und TDs for control, bulk and iso
+/*-------------------------------------------------------------------*/
+_static int uhci_submit_control_urb (struct urb *urb)
+{
+	uhci_desc_t *qh, *td;
+	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
+	urb_priv_t *urb_priv = urb->hcpriv;
+	unsigned long destination, status;
+	int maxsze = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
+	unsigned long len;
+	char *data;
+	int depth_first=USE_CTRL_DEPTH_FIRST;  // UHCI descriptor chasing method
+
+	dbg("uhci_submit_control start");
+	if (alloc_qh (s, &qh))		// alloc qh for this request
+		return -ENOMEM;
+
+	if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))		// get td for setup stage
+	{
+		delete_qh (s, qh);
+		return -ENOMEM;
+	}
+
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
+
+	/* 3 errors */
+	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |
+		(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
+
+	/*  Build the TD for the control request, try forever, 8 bytes of data */
+	fill_td (td, status, destination | (7 << 21), urb_priv->setup_packet_dma);
+
+	insert_td (s, qh, td, 0);	// queue 'setup stage'-td in qh
+#if 0
+	{
+		char *sp=urb->setup_packet;
+		dbg("SETUP to pipe %x: %x %x %x %x %x %x %x %x", urb->pipe,
+		    sp[0],sp[1],sp[2],sp[3],sp[4],sp[5],sp[6],sp[7]);
+	}
+	//uhci_show_td(td);
+#endif
+
+	len = urb->transfer_buffer_length;
+	data = urb->transfer_buffer;
+
+	/* If direction is "send", change the frame from SETUP (0x2D)
+	   to OUT (0xE1). Else change it from SETUP to IN (0x69). */
+
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | (usb_pipeout (urb->pipe)?USB_PID_OUT:USB_PID_IN);
+
+	while (len > 0) {
+		int pktsze = len;
+
+		if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))
+			goto fail_unmap_enomem;
+
+		if (pktsze > maxsze)
+			pktsze = maxsze;
+
+		destination ^= 1 << TD_TOKEN_TOGGLE;	// toggle DATA0/1
+
+		// Status, pktsze bytes of data
+		fill_td (td, status, destination | ((pktsze - 1) << 21),
+			 urb_priv->transfer_buffer_dma + (data - (char *)urb->transfer_buffer));
+
+		insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);	// queue 'data stage'-td in qh
+
+		data += pktsze;
+		len -= pktsze;
+	}
+
+	/* Build the final TD for control status */
+	/* It's only IN if the pipe is out AND we aren't expecting data */
+
+	destination &= ~UHCI_PID;
+
+	if (usb_pipeout (urb->pipe) || (urb->transfer_buffer_length == 0))
+		destination |= USB_PID_IN;
+	else
+		destination |= USB_PID_OUT;
+
+	destination |= 1 << TD_TOKEN_TOGGLE;	/* End in Data1 */
+
+	if (alloc_td (s, &td, UHCI_PTR_DEPTH))
+		goto fail_unmap_enomem;
+
+	status &=~TD_CTRL_SPD;
+
+	/* no limit on errors on final packet , 0 bytes of data */
+	fill_td (td, status | TD_CTRL_IOC, destination | (UHCI_NULL_DATA_SIZE << 21),
+		 0);
+
+	insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);	// queue status td
+
+	list_add (&qh->desc_list, &urb_priv->desc_list);
+
+	queue_urb (s, urb);	// queue before inserting in desc chain
+
+	qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM);
+
+	//uhci_show_queue(qh);
+	/* Start it up... put low speed first */
+	if (urb->pipe & TD_CTRL_LS)
+		insert_qh (s, s->control_chain, qh, 0);
+	else
+		insert_qh (s, s->bulk_chain, qh, 0);
+
+	dbg("uhci_submit_control end");
+	return 0;
+
+fail_unmap_enomem:
+	delete_qh(s, qh);
+	return -ENOMEM;
+}
+/*-------------------------------------------------------------------*/
+// For queued bulk transfers, two additional QH helpers are allocated (nqh, bqh)
+// Due to the linking with other bulk urbs, it has to be locked with urb_list_lock!
+
+_static int uhci_submit_bulk_urb (struct urb *urb, struct urb *bulk_urb)
+{
+	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
+	urb_priv_t *urb_priv = urb->hcpriv, *upriv, *bpriv=NULL;
+	uhci_desc_t *qh, *td, *nqh=NULL, *bqh=NULL, *first_td=NULL;
+	unsigned long destination, status;
+	char *data;
+	unsigned int pipe = urb->pipe;
+	int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
+	int info, len, last;
+	int depth_first=USE_BULK_DEPTH_FIRST;  // UHCI descriptor chasing method
+
+	if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)))
+		return -EPIPE;
+
+	queue_dbg("uhci_submit_bulk_urb: urb %p, old %p, pipe %08x, len %i",
+		  urb,bulk_urb,urb->pipe,urb->transfer_buffer_length);
+
+	upriv = (urb_priv_t*)urb->hcpriv;
+
+	if (!bulk_urb) {
+		if (alloc_qh (s, &qh))		// get qh for this request
+			return -ENOMEM;
+
+		if (urb->transfer_flags & USB_QUEUE_BULK) {
+			if (alloc_qh(s, &nqh)) // placeholder for clean unlink
+			{
+				delete_desc (s, qh);
+				return -ENOMEM;
+			}
+			upriv->next_qh = nqh;
+			queue_dbg("new next qh %p",nqh);
+		}
+	}
+	else { 
+		bpriv = (urb_priv_t*)bulk_urb->hcpriv;
+		qh = bpriv->bottom_qh;  // re-use bottom qh and next qh
+		nqh = bpriv->next_qh;
+		upriv->next_qh=nqh;	
+		upriv->prev_queued_urb=bulk_urb;
+	}
+
+	if (urb->transfer_flags & USB_QUEUE_BULK) {
+		if (alloc_qh (s, &bqh))  // "bottom" QH
+		{
+			if (!bulk_urb) { 
+				delete_desc(s, qh);
+				delete_desc(s, nqh);
+			}
+			return -ENOMEM;
+		}
+		set_qh_element(bqh, UHCI_PTR_TERM);
+		set_qh_head(bqh, nqh->dma_addr | UHCI_PTR_QH); // element
+		upriv->bottom_qh = bqh;
+	}
+	queue_dbg("uhci_submit_bulk: qh %p bqh %p nqh %p",qh, bqh, nqh);
+
+	/* The "pipe" thing contains the destination in bits 8--18. */
+	destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
+
+	/* 3 errors */
+	status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |
+		((urb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD) | (3 << 27);
+
+	/* Build the TDs for the bulk request */
+	len = urb->transfer_buffer_length;
+	data = urb->transfer_buffer;
+	
+	do {					// TBD: Really allow zero-length packets?
+		int pktsze = len;
+
+		if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))
+		{
+			delete_qh (s, qh);
+			return -ENOMEM;
+		}
+
+		if (pktsze > maxsze)
+			pktsze = maxsze;
+
+		// pktsze bytes of data 
+		info = destination | (((pktsze - 1)&UHCI_NULL_DATA_SIZE) << 21) |
+			(usb_gettoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);
+
+		fill_td (td, status, info,
+			 urb_priv->transfer_buffer_dma + (data - (char *)urb->transfer_buffer));
+
+		data += pktsze;
+		len -= pktsze;
+		// Use USB_ZERO_PACKET to finish bulk OUTs always with a zero length packet
+		last = (len == 0 && (usb_pipein(pipe) || pktsze < maxsze || !(urb->transfer_flags & USB_ZERO_PACKET)));
+
+		if (last)
+			set_td_ioc(td);	// last one generates INT
+
+		insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);
+		if (!first_td)
+			first_td=td;
+		usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
+
+	} while (!last);
+
+	if (bulk_urb && bpriv)   // everything went OK, link with old bulk URB
+		bpriv->next_queued_urb=urb;
+
+	list_add (&qh->desc_list, &urb_priv->desc_list);
+
+	if (urb->transfer_flags & USB_QUEUE_BULK)
+		append_qh(s, td, bqh, UHCI_PTR_DEPTH * depth_first);
+
+	queue_urb_unlocked (s, urb);
+	
+	if (urb->transfer_flags & USB_QUEUE_BULK)
+		set_qh_element(qh, first_td->dma_addr);
+	else
+		qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM);    // arm QH
+
+	if (!bulk_urb) { 					// new bulk queue	
+		if (urb->transfer_flags & USB_QUEUE_BULK) {
+			spin_lock (&s->td_lock);		// both QHs in one go
+			insert_qh (s, s->chain_end, qh, 0);	// Main QH
+			insert_qh (s, s->chain_end, nqh, 0);	// Helper QH
+			spin_unlock (&s->td_lock);
+		}
+		else
+			insert_qh (s, s->chain_end, qh, 0);
+	}
+	
+	//uhci_show_queue(s->bulk_chain);
+	//dbg("uhci_submit_bulk_urb: exit\n");
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+_static void uhci_clean_iso_step1(uhci_t *s, urb_priv_t *urb_priv)
+{
+	struct list_head *p;
+	uhci_desc_t *td;
+
+	for (p = urb_priv->desc_list.next; p != &urb_priv->desc_list; p = p->next) {
+				td = list_entry (p, uhci_desc_t, desc_list);
+				unlink_td (s, td, 1);
+	}
+}
+/*-------------------------------------------------------------------*/
+_static void uhci_clean_iso_step2(uhci_t *s, urb_priv_t *urb_priv)
+{
+	struct list_head *p;
+	uhci_desc_t *td;
+
+	while ((p = urb_priv->desc_list.next) != &urb_priv->desc_list) {
+				td = list_entry (p, uhci_desc_t, desc_list);
+				list_del (p);
+				delete_desc (s, td);
+	}
+}
+/*-------------------------------------------------------------------*/
+/* mode: CLEAN_TRANSFER_NO_DELETION: unlink but no deletion mark (step 1 of async_unlink)
+         CLEAN_TRANSFER_REGULAR: regular (unlink/delete-mark)
+         CLEAN_TRANSFER_DELETION_MARK: deletion mark for QH (step 2 of async_unlink)
+ looks a bit complicated because of all the bulk queueing goodies
+*/
+
+_static void uhci_clean_transfer (uhci_t *s, struct urb *urb, uhci_desc_t *qh, int mode)
+{
+	uhci_desc_t *bqh, *nqh, *prevqh, *prevtd;
+	int now;
+	urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
+
+	now=UHCI_GET_CURRENT_FRAME(s);
+
+	bqh=priv->bottom_qh;	
+	
+	if (!priv->next_queued_urb)  { // no more appended bulk queues
+
+		queue_dbg("uhci_clean_transfer: No more bulks for urb %p, qh %p, bqh %p, nqh %p", urb, qh, bqh, priv->next_qh);	
+	
+		if (priv->prev_queued_urb && mode != CLEAN_TRANSFER_DELETION_MARK) {  // qh not top of the queue
+				unsigned long flags; 
+				urb_priv_t* ppriv=(urb_priv_t*)priv->prev_queued_urb->hcpriv;
+
+				spin_lock_irqsave (&s->qh_lock, flags);
+				prevqh = list_entry (ppriv->desc_list.next, uhci_desc_t, desc_list);
+				prevtd = list_entry (prevqh->vertical.prev, uhci_desc_t, vertical);
+				set_td_link(prevtd, priv->bottom_qh->dma_addr | UHCI_PTR_QH); // skip current qh
+				mb();
+				queue_dbg("uhci_clean_transfer: relink pqh %p, ptd %p",prevqh, prevtd);
+				spin_unlock_irqrestore (&s->qh_lock, flags);
+
+				ppriv->bottom_qh = priv->bottom_qh;
+				ppriv->next_queued_urb = NULL;
+			}
+		else {   // queue is dead, qh is top of the queue
+			
+			if (mode != CLEAN_TRANSFER_DELETION_MARK) 				
+				unlink_qh(s, qh); // remove qh from horizontal chain
+
+			if (bqh) {  // remove remainings of bulk queue
+				nqh=priv->next_qh;
+
+				if (mode != CLEAN_TRANSFER_DELETION_MARK) 
+					unlink_qh(s, nqh);  // remove nqh from horizontal chain
+				
+				if (mode != CLEAN_TRANSFER_NO_DELETION) {  // add helper QHs to free desc list
+					nqh->last_used = bqh->last_used = now;
+					list_add_tail (&nqh->horizontal, &s->free_desc);
+					list_add_tail (&bqh->horizontal, &s->free_desc);
+				}			
+			}
+		}
+	}
+	else { // there are queued urbs following
+	
+	  queue_dbg("uhci_clean_transfer: urb %p, prevurb %p, nexturb %p, qh %p, bqh %p, nqh %p",
+		       urb, priv->prev_queued_urb,  priv->next_queued_urb, qh, bqh, priv->next_qh);	
+       	
+		if (mode != CLEAN_TRANSFER_DELETION_MARK) {	// no work for cleanup at unlink-completion
+			struct urb *nurb;
+			unsigned long flags;
+
+			nurb = priv->next_queued_urb;
+			spin_lock_irqsave (&s->qh_lock, flags);		
+
+			if (!priv->prev_queued_urb) { // top QH
+				
+				prevqh = list_entry (qh->horizontal.prev, uhci_desc_t, horizontal);
+				set_qh_head(prevqh, bqh->dma_addr | UHCI_PTR_QH);
+				list_del (&qh->horizontal);  // remove this qh form horizontal chain
+				list_add (&bqh->horizontal, &prevqh->horizontal); // insert next bqh in horizontal chain
+			}
+			else {		// intermediate QH
+				urb_priv_t* ppriv=(urb_priv_t*)priv->prev_queued_urb->hcpriv;
+				urb_priv_t* npriv=(urb_priv_t*)nurb->hcpriv;
+				uhci_desc_t * bnqh;
+				
+				bnqh = list_entry (npriv->desc_list.next, uhci_desc_t, desc_list);
+				ppriv->bottom_qh = bnqh;
+				ppriv->next_queued_urb = nurb;				
+				prevqh = list_entry (ppriv->desc_list.next, uhci_desc_t, desc_list);
+				set_qh_head(prevqh, bqh->dma_addr | UHCI_PTR_QH);
+			}
+
+			mb();
+			((urb_priv_t*)nurb->hcpriv)->prev_queued_urb=priv->prev_queued_urb;
+			spin_unlock_irqrestore (&s->qh_lock, flags);
+		}		
+	}
+
+	if (mode != CLEAN_TRANSFER_NO_DELETION) {
+		qh->last_used = now;	
+		list_add_tail (&qh->horizontal, &s->free_desc); // mark qh for later deletion/kfree
+	}
+}
+/*-------------------------------------------------------------------*/
+// Release bandwidth for Interrupt or Isoc. transfers 
+_static void uhci_release_bandwidth(struct urb *urb)
+{       
+	if (urb->bandwidth) {
+		switch (usb_pipetype(urb->pipe)) {
+		case PIPE_INTERRUPT:
+			usb_release_bandwidth (urb->dev, urb, 0);
+			break;
+		case PIPE_ISOCHRONOUS:
+			usb_release_bandwidth (urb->dev, urb, 1);
+			break;
+		default:
+			break;
+		}
+	}	
+}
+
+_static void uhci_urb_dma_sync(uhci_t *s, struct urb *urb, urb_priv_t *urb_priv)
+{
+	if (urb_priv->setup_packet_dma)
+		pci_dma_sync_single(s->uhci_pci, urb_priv->setup_packet_dma,
+				    sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
+
+	if (urb_priv->transfer_buffer_dma)
+		pci_dma_sync_single(s->uhci_pci, urb_priv->transfer_buffer_dma,
+				    urb->transfer_buffer_length,
+				    usb_pipein(urb->pipe) ?
+				    PCI_DMA_FROMDEVICE :
+				    PCI_DMA_TODEVICE);
+}
+
+_static void uhci_urb_dma_unmap(uhci_t *s, struct urb *urb, urb_priv_t *urb_priv)
+{
+	if (urb_priv->setup_packet_dma) {
+		pci_unmap_single(s->uhci_pci, urb_priv->setup_packet_dma,
+				 sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
+		urb_priv->setup_packet_dma = 0;
+	}
+	if (urb_priv->transfer_buffer_dma) {
+		pci_unmap_single(s->uhci_pci, urb_priv->transfer_buffer_dma,
+				 urb->transfer_buffer_length,
+				 usb_pipein(urb->pipe) ?
+				 PCI_DMA_FROMDEVICE :
+				 PCI_DMA_TODEVICE);
+		urb_priv->transfer_buffer_dma = 0;
+	}
+}
+/*-------------------------------------------------------------------*/
+/* needs urb_list_lock!
+   mode: UNLINK_ASYNC_STORE_URB: unlink and move URB into unlinked list
+         UNLINK_ASYNC_DONT_STORE: unlink, don't move URB into unlinked list
+*/
+_static int uhci_unlink_urb_async (uhci_t *s,struct urb *urb, int mode)
+{
+	uhci_desc_t *qh;
+	urb_priv_t *urb_priv;
+	
+	async_dbg("unlink_urb_async called %p",urb);
+
+	if ((urb->status == -EINPROGRESS) ||
+	    ((usb_pipetype (urb->pipe) ==  PIPE_INTERRUPT) && ((urb_priv_t*)urb->hcpriv)->flags))
+	{
+		((urb_priv_t*)urb->hcpriv)->started = ~0;  // mark
+		dequeue_urb (s, urb);
+
+		if (mode==UNLINK_ASYNC_STORE_URB)
+			list_add_tail (&urb->urb_list, &s->urb_unlinked); // store urb
+
+		uhci_switch_timer_int(s);
+       		s->unlink_urb_done = 1;
+		uhci_release_bandwidth(urb);
+
+		urb->status = -ECONNABORTED;	// mark urb as "waiting to be killed"	
+		urb_priv = (urb_priv_t*)urb->hcpriv;
+
+		switch (usb_pipetype (urb->pipe)) {
+		case PIPE_INTERRUPT:
+			usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+
+		case PIPE_ISOCHRONOUS:
+			uhci_clean_iso_step1 (s, urb_priv);
+			break;
+
+		case PIPE_BULK:
+		case PIPE_CONTROL:
+			qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list);
+			uhci_clean_transfer (s, urb, qh, CLEAN_TRANSFER_NO_DELETION);
+			break;
+		}
+		((urb_priv_t*)urb->hcpriv)->started = UHCI_GET_CURRENT_FRAME(s);
+		return -EINPROGRESS;  // completion will follow
+	}		
+
+	return 0;    // URB already dead
+}
+/*-------------------------------------------------------------------*/
+// kills an urb by unlinking descriptors and waiting for at least one frame
+_static int uhci_unlink_urb_sync (uhci_t *s, struct urb *urb)
+{
+	uhci_desc_t *qh;
+	urb_priv_t *urb_priv;
+	unsigned long flags=0;
+	struct usb_device *usb_dev;
+
+	spin_lock_irqsave (&s->urb_list_lock, flags);
+
+	if (urb->status == -EINPROGRESS) {
+
+		// move descriptors out of the running chains, dequeue urb
+		uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_DONT_STORE);
+
+		urb_priv = urb->hcpriv;
+		urb->status = -ENOENT;	// prevent from double deletion after unlock		
+		spin_unlock_irqrestore (&s->urb_list_lock, flags);
+		
+		// cleanup the rest
+		switch (usb_pipetype (urb->pipe)) {
+
+		case PIPE_INTERRUPT:
+		case PIPE_ISOCHRONOUS:
+			uhci_wait_ms(1);
+			uhci_clean_iso_step2(s, urb_priv);
+			break;
+
+		case PIPE_BULK:
+		case PIPE_CONTROL:
+			qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list);
+			uhci_clean_transfer(s, urb, qh, CLEAN_TRANSFER_DELETION_MARK);
+			uhci_wait_ms(1);
+		}
+		urb->status = -ENOENT;	// mark urb as killed		
+					
+		uhci_urb_dma_unmap(s, urb, urb->hcpriv);
+
+#ifdef DEBUG_SLAB
+		kmem_cache_free (urb_priv_kmem, urb->hcpriv);
+#else
+		kfree (urb->hcpriv);
+#endif
+		usb_dev = urb->dev;
+		if (urb->complete) {
+			dbg("unlink_urb: calling completion");
+			urb->dev = NULL;
+			urb->complete ((struct urb *) urb);
+		}
+		usb_dec_dev_use (usb_dev);
+	}
+	else
+		spin_unlock_irqrestore (&s->urb_list_lock, flags);
+
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+// async unlink_urb completion/cleanup work
+// has to be protected by urb_list_lock!
+// features: if set in transfer_flags, the resulting status of the killed
+// transaction is not overwritten
+
+_static void uhci_cleanup_unlink(uhci_t *s, int force)
+{
+	struct list_head *q;
+	struct urb *urb;
+	struct usb_device *dev;
+	int now, type;
+	urb_priv_t *urb_priv;
+
+	q=s->urb_unlinked.next;
+	now=UHCI_GET_CURRENT_FRAME(s);
+
+	while (q != &s->urb_unlinked) {
+
+		urb = list_entry (q, struct urb, urb_list);
+
+		urb_priv = (urb_priv_t*)urb->hcpriv;
+		q = urb->urb_list.next;
+		
+		if (!urb_priv) // avoid crash when URB is corrupted
+			break;
+			
+		if (force || ((urb_priv->started != ~0) && (urb_priv->started != now))) {
+			async_dbg("async cleanup %p",urb);
+			type=usb_pipetype (urb->pipe);
+
+			switch (type) { // process descriptors
+			case PIPE_CONTROL:
+				process_transfer (s, urb, CLEAN_TRANSFER_DELETION_MARK);  // don't unlink (already done)
+				break;
+			case PIPE_BULK:
+				if (!s->avoid_bulk.counter)
+					process_transfer (s, urb, CLEAN_TRANSFER_DELETION_MARK); // don't unlink (already done)
+				else
+					continue;
+				break;
+			case PIPE_ISOCHRONOUS:
+				process_iso (s, urb, PROCESS_ISO_FORCE); // force, don't unlink
+				break;
+			case PIPE_INTERRUPT:
+				process_interrupt (s, urb);
+				break;
+			}
+
+			if (!(urb->transfer_flags & USB_TIMEOUT_KILLED))
+		  		urb->status = -ECONNRESET; // mark as asynchronously killed
+
+			dev = urb->dev;	// completion may destroy all...
+			urb_priv = urb->hcpriv;
+			list_del (&urb->urb_list);
+			
+			uhci_urb_dma_sync(s, urb, urb_priv);
+			if (urb->complete) {
+				spin_unlock(&s->urb_list_lock);
+				urb->dev = NULL;
+				urb->complete ((struct urb *) urb);
+				spin_lock(&s->urb_list_lock);
+			}
+
+			if (!(urb->transfer_flags & USB_TIMEOUT_KILLED))
+				urb->status = -ENOENT;  // now the urb is really dead
+
+			switch (type) {
+			case PIPE_ISOCHRONOUS:
+			case PIPE_INTERRUPT:
+				uhci_clean_iso_step2(s, urb_priv);
+				break;
+			}
+	
+			uhci_urb_dma_unmap(s, urb, urb_priv);
+
+			usb_dec_dev_use (dev);
+#ifdef DEBUG_SLAB
+			kmem_cache_free (urb_priv_kmem, urb_priv);
+#else
+			kfree (urb_priv);
+#endif
+
+		}
+	}
+}
+ 
+/*-------------------------------------------------------------------*/
+_static int uhci_unlink_urb (struct urb *urb)
+{
+	uhci_t *s;
+	unsigned long flags=0;
+	dbg("uhci_unlink_urb called for %p",urb);
+	if (!urb || !urb->dev)		// you never know...
+		return -EINVAL;
+	
+	s = (uhci_t*) urb->dev->bus->hcpriv;
+
+	if (usb_pipedevice (urb->pipe) == s->rh.devnum)
+		return rh_unlink_urb (urb);
+
+	if (!urb->hcpriv)
+		return -EINVAL;
+
+	if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+		int ret;
+       		spin_lock_irqsave (&s->urb_list_lock, flags);
+       		
+		uhci_release_bandwidth(urb);
+		ret = uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
+
+		spin_unlock_irqrestore (&s->urb_list_lock, flags);	
+		return ret;
+	}
+	else
+		return uhci_unlink_urb_sync(s, urb);
+}
+/*-------------------------------------------------------------------*/
+// In case of ASAP iso transfer, search the URB-list for already queued URBs
+// for this EP and calculate the earliest start frame for the new
+// URB (easy seamless URB continuation!)
+_static int find_iso_limits (struct urb *urb, unsigned int *start, unsigned int *end)
+{
+	struct urb *u, *last_urb = NULL;
+	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
+	struct list_head *p;
+	int ret=-1;
+	unsigned long flags;
+	
+	spin_lock_irqsave (&s->urb_list_lock, flags);
+	p=s->urb_list.prev;
+
+	for (; p != &s->urb_list; p = p->prev) {
+		u = list_entry (p, struct urb, urb_list);
+		// look for pending URBs with identical pipe handle
+		// works only because iso doesn't toggle the data bit!
+		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) && (u->status == -EINPROGRESS)) {
+			if (!last_urb)
+				*start = u->start_frame;
+			last_urb = u;
+		}
+	}
+	
+	if (last_urb) {
+		*end = (last_urb->start_frame + last_urb->number_of_packets) & 1023;
+		ret=0;
+	}
+	
+	spin_unlock_irqrestore(&s->urb_list_lock, flags);
+	
+	return ret;
+}
+/*-------------------------------------------------------------------*/
+// adjust start_frame according to scheduling constraints (ASAP etc)
+
+_static int iso_find_start (struct urb *urb)
+{
+	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
+	unsigned int now;
+	unsigned int start_limit = 0, stop_limit = 0, queued_size;
+	int limits;
+
+	now = UHCI_GET_CURRENT_FRAME (s) & 1023;
+
+	if ((unsigned) urb->number_of_packets > 900)
+		return -EFBIG;
+	
+	limits = find_iso_limits (urb, &start_limit, &stop_limit);
+	queued_size = (stop_limit - start_limit) & 1023;
+
+	if (urb->transfer_flags & USB_ISO_ASAP) {
+		// first iso
+		if (limits) {
+			// 10ms setup should be enough //FIXME!
+			urb->start_frame = (now + 10) & 1023;
+		}
+		else {
+			urb->start_frame = stop_limit;		//seamless linkage
+
+			if (((now - urb->start_frame) & 1023) <= (unsigned) urb->number_of_packets) {
+				info("iso_find_start: gap in seamless isochronous scheduling");
+				dbg("iso_find_start: now %u start_frame %u number_of_packets %u pipe 0x%08x",
+					now, urb->start_frame, urb->number_of_packets, urb->pipe);
+				urb->start_frame = (now + 5) & 1023;	// 5ms setup should be enough //FIXME!
+			}
+		}
+	}
+	else {
+		urb->start_frame &= 1023;
+		if (((now - urb->start_frame) & 1023) < (unsigned) urb->number_of_packets) {
+			dbg("iso_find_start: now between start_frame and end");
+			return -EAGAIN;
+		}
+	}
+
+	/* check if either start_frame or start_frame+number_of_packets-1 lies between start_limit and stop_limit */
+	if (limits)
+		return 0;
+
+	if (((urb->start_frame - start_limit) & 1023) < queued_size ||
+	    ((urb->start_frame + urb->number_of_packets - 1 - start_limit) & 1023) < queued_size) {
+		dbg("iso_find_start: start_frame %u number_of_packets %u start_limit %u stop_limit %u",
+			urb->start_frame, urb->number_of_packets, start_limit, stop_limit);
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+// submits USB interrupt (ie. polling ;-) 
+// ASAP-flag set implicitely
+// if period==0, the transfer is only done once
+
+_static int uhci_submit_int_urb (struct urb *urb)
+{
+	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
+	urb_priv_t *urb_priv = urb->hcpriv;
+	int nint, n;
+	uhci_desc_t *td;
+	int status, destination;
+	int info;
+	unsigned int pipe = urb->pipe;
+
+	if (urb->interval < 0 || urb->interval >= 256)
+		return -EINVAL;
+
+	if (urb->interval == 0)
+		nint = 0;
+	else {
+		for (nint = 0, n = 1; nint <= 8; nint++, n += n)	// round interval down to 2^n
+		 {
+			if (urb->interval < n) {
+				urb->interval = n / 2;
+				break;
+			}
+		}
+		nint--;
+	}
+
+	dbg("Rounded interval to %i, chain  %i", urb->interval, nint);
+
+	urb->start_frame = UHCI_GET_CURRENT_FRAME (s) & 1023;	// remember start frame, just in case...
+
+	urb->number_of_packets = 1;
+
+	// INT allows only one packet
+	if (urb->transfer_buffer_length > usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe)))
+		return -EINVAL;
+
+	if (alloc_td (s, &td, UHCI_PTR_DEPTH))
+		return -ENOMEM;
+
+	status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
+		(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
+
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe) |
+		(((urb->transfer_buffer_length - 1) & 0x7ff) << 21);
+
+
+	info = destination | (usb_gettoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);
+
+	fill_td (td, status, info, urb_priv->transfer_buffer_dma);
+	list_add_tail (&td->desc_list, &urb_priv->desc_list);
+
+	queue_urb (s, urb);
+
+	insert_td_horizontal (s, s->int_chain[nint], td);	// store in INT-TDs
+
+	usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
+
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+_static int uhci_submit_iso_urb (struct urb *urb)
+{
+	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
+	urb_priv_t *urb_priv = urb->hcpriv;
+#ifdef ISO_SANITY_CHECK
+	int pipe=urb->pipe;
+	int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
+#endif
+	int n, ret, last=0;
+	uhci_desc_t *td, **tdm;
+	int status, destination;
+	unsigned long flags;
+
+	__save_flags(flags);
+	__cli();		      // Disable IRQs to schedule all ISO-TDs in time
+	ret = iso_find_start (urb);	// adjusts urb->start_frame for later use
+	
+	if (ret)
+		goto err;
+
+	tdm = (uhci_desc_t **) kmalloc (urb->number_of_packets * sizeof (uhci_desc_t*), KMALLOC_FLAG);
+
+	if (!tdm) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	memset(tdm, 0, urb->number_of_packets * sizeof (uhci_desc_t*));
+
+	// First try to get all TDs. Cause: Removing already inserted TDs can only be done 
+	// racefree in three steps: unlink TDs, wait one frame, delete TDs. 
+	// So, this solutions seems simpler...
+
+	for (n = 0; n < urb->number_of_packets; n++) {
+		dbg("n:%d urb->iso_frame_desc[n].length:%d", n, urb->iso_frame_desc[n].length);
+		if (!urb->iso_frame_desc[n].length)
+			continue;  // allows ISO striping by setting length to zero in iso_descriptor
+
+
+#ifdef ISO_SANITY_CHECK
+		if(urb->iso_frame_desc[n].length > maxsze) {
+
+			err("submit_iso: urb->iso_frame_desc[%d].length(%d)>%d",n , urb->iso_frame_desc[n].length, maxsze);
+			ret=-EINVAL;		
+		}
+		else
+#endif
+		if (alloc_td (s, &td, UHCI_PTR_DEPTH)) {
+			int i;	// Cleanup allocated TDs
+
+			for (i = 0; i < n; n++)
+				if (tdm[i])
+					 delete_desc(s, tdm[i]);
+			kfree (tdm);
+			goto err;
+		}
+		last=n;
+		tdm[n] = td;
+	}
+
+	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
+
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe);
+
+	// Queue all allocated TDs
+	for (n = 0; n < urb->number_of_packets; n++) {
+		td = tdm[n];
+		if (!td)
+			continue;
+			
+		if (n  == last) {
+			status |= TD_CTRL_IOC;
+			queue_urb (s, urb);
+		}
+
+		fill_td (td, status, destination | (((urb->iso_frame_desc[n].length - 1) & 0x7ff) << 21),
+			 urb_priv->transfer_buffer_dma + urb->iso_frame_desc[n].offset);
+		list_add_tail (&td->desc_list, &urb_priv->desc_list);
+	
+		insert_td_horizontal (s, s->iso_td[(urb->start_frame + n) & 1023], td);	// store in iso-tds
+	}
+
+	kfree (tdm);
+	dbg("ISO-INT# %i, start %i, now %i", urb->number_of_packets, urb->start_frame, UHCI_GET_CURRENT_FRAME (s) & 1023);
+	ret = 0;
+
+      err:
+	__restore_flags(flags);
+	return ret;
+}
+/*-------------------------------------------------------------------*/
+// returns: 0 (no transfer queued), urb* (this urb already queued)
+ 
+_static struct urb* search_dev_ep (uhci_t *s, struct urb *urb)
+{
+	struct list_head *p;
+	struct urb *tmp;
+	unsigned int mask = usb_pipecontrol(urb->pipe) ? (~USB_DIR_IN) : (~0);
+
+	dbg("search_dev_ep:");
+
+	p=s->urb_list.next;
+
+	for (; p != &s->urb_list; p = p->next) {
+		tmp = list_entry (p, struct urb, urb_list);
+		dbg("urb: %p", tmp);
+		// we can accept this urb if it is not queued at this time 
+		// or if non-iso transfer requests should be scheduled for the same device and pipe
+		if ((!usb_pipeisoc(urb->pipe) && (tmp->dev == urb->dev) && !((tmp->pipe ^ urb->pipe) & mask)) ||
+		    (urb == tmp)) {
+			return tmp;	// found another urb already queued for processing
+		}
+	}
+
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+_static int uhci_submit_urb (struct urb *urb)
+{
+	uhci_t *s;
+	urb_priv_t *urb_priv;
+	int ret = 0, type;
+	unsigned long flags;
+	struct urb *queued_urb=NULL;
+	int bustime;
+		
+	if (!urb->dev || !urb->dev->bus)
+		return -ENODEV;
+
+	s = (uhci_t*) urb->dev->bus->hcpriv;
+	//dbg("submit_urb: %p type %d",urb,usb_pipetype(urb->pipe));
+	
+	if (!s->running)
+		return -ENODEV;
+	
+	type = usb_pipetype (urb->pipe);
+
+	if (usb_pipedevice (urb->pipe) == s->rh.devnum)
+		return rh_submit_urb (urb);	/* virtual root hub */
+
+	// Sanity checks
+	if (usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe)) <= 0) {		
+		err("uhci_submit_urb: pipesize for pipe %x is zero", urb->pipe);
+		return -EMSGSIZE;
+	}
+
+	if (urb->transfer_buffer_length < 0 && type != PIPE_ISOCHRONOUS) {
+		err("uhci_submit_urb: Negative transfer length for urb %p", urb);
+		return -EINVAL;
+	}
+
+	usb_inc_dev_use (urb->dev);
+
+	spin_lock_irqsave (&s->urb_list_lock, flags);
+
+	queued_urb = search_dev_ep (s, urb); // returns already queued urb for that pipe
+
+	if (queued_urb) {
+
+		queue_dbg("found bulk urb %p\n", queued_urb);
+
+		if (( type != PIPE_BULK) ||
+		    ((type == PIPE_BULK) &&
+		     (!(urb->transfer_flags & USB_QUEUE_BULK) || !(queued_urb->transfer_flags & USB_QUEUE_BULK)))) {
+			spin_unlock_irqrestore (&s->urb_list_lock, flags);
+			usb_dec_dev_use (urb->dev);
+			err("ENXIO %08x, flags %x, urb %p, burb %p",urb->pipe,urb->transfer_flags,urb,queued_urb);
+			return -ENXIO;	// urb already queued
+		}
+	}
+
+#ifdef DEBUG_SLAB
+	urb_priv = kmem_cache_alloc(urb_priv_kmem, SLAB_FLAG);
+#else
+	urb_priv = kmalloc (sizeof (urb_priv_t), KMALLOC_FLAG);
+#endif
+	if (!urb_priv) {
+		usb_dec_dev_use (urb->dev);
+		spin_unlock_irqrestore (&s->urb_list_lock, flags);
+		return -ENOMEM;
+	}
+
+	memset(urb_priv, 0, sizeof(urb_priv_t));
+	urb->hcpriv = urb_priv;
+	INIT_LIST_HEAD (&urb_priv->desc_list);
+
+	dbg("submit_urb: scheduling %p", urb);
+	
+	if (type == PIPE_CONTROL)
+		urb_priv->setup_packet_dma = pci_map_single(s->uhci_pci, urb->setup_packet,
+							    sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
+
+	if (urb->transfer_buffer_length)
+		urb_priv->transfer_buffer_dma = pci_map_single(s->uhci_pci,
+							       urb->transfer_buffer,
+							       urb->transfer_buffer_length,
+							       usb_pipein(urb->pipe) ?
+							       PCI_DMA_FROMDEVICE :
+							       PCI_DMA_TODEVICE);
+
+	if (type == PIPE_BULK) {
+	
+		if (queued_urb) {
+			while (((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb)  // find last queued bulk
+				queued_urb=((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb;
+			
+			((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb=urb;
+		}
+		atomic_inc (&s->avoid_bulk);
+		ret = uhci_submit_bulk_urb (urb, queued_urb);
+		atomic_dec (&s->avoid_bulk);
+		spin_unlock_irqrestore (&s->urb_list_lock, flags);
+	}
+	else {
+		spin_unlock_irqrestore (&s->urb_list_lock, flags);
+		switch (type) {
+		case PIPE_ISOCHRONOUS:			
+			if (urb->bandwidth == 0) {      /* not yet checked/allocated */
+				if (urb->number_of_packets <= 0) {
+					ret = -EINVAL;
+					break;
+				}
+
+				bustime = usb_check_bandwidth (urb->dev, urb);
+				if (bustime < 0) 
+					ret = bustime;
+				else {
+					ret = uhci_submit_iso_urb(urb);
+					if (ret == 0)
+						usb_claim_bandwidth (urb->dev, urb, bustime, 1);
+				}
+			} else {        /* bandwidth is already set */
+				ret = uhci_submit_iso_urb(urb);
+			}
+			break;
+		case PIPE_INTERRUPT:
+			if (urb->bandwidth == 0) {      /* not yet checked/allocated */
+				bustime = usb_check_bandwidth (urb->dev, urb);
+				if (bustime < 0)
+					ret = bustime;
+				else {
+					ret = uhci_submit_int_urb(urb);
+					if (ret == 0)
+						usb_claim_bandwidth (urb->dev, urb, bustime, 0);
+				}
+			} else {        /* bandwidth is already set */
+				ret = uhci_submit_int_urb(urb);
+			}
+			break;
+		case PIPE_CONTROL:
+			ret = uhci_submit_control_urb (urb);
+			break;
+		default:
+			ret = -EINVAL;
+		}
+	}
+
+	dbg("submit_urb: scheduled with ret: %d", ret);
+	
+	if (ret != 0) {
+		uhci_urb_dma_unmap(s, urb, urb_priv);
+		usb_dec_dev_use (urb->dev);
+#ifdef DEBUG_SLAB
+		kmem_cache_free(urb_priv_kmem, urb_priv);
+#else
+		kfree (urb_priv);
+#endif
+		return ret;
+	}
+
+	return 0;
+}
+
+// Checks for URB timeout and removes bandwidth reclamation if URB idles too long
+_static void uhci_check_timeouts(uhci_t *s)
+{
+	struct list_head *p,*p2;
+	struct urb *urb;
+	int type;	
+
+	p = s->urb_list.prev;	
+
+	while (p != &s->urb_list) {
+		urb_priv_t *hcpriv;
+
+		p2 = p;
+		p = p->prev;
+		urb = list_entry (p2, struct urb, urb_list);
+		type = usb_pipetype (urb->pipe);
+
+		hcpriv = (urb_priv_t*)urb->hcpriv;
+		
+		if ( urb->timeout && time_after(jiffies, hcpriv->started + urb->timeout)) {
+			urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
+			async_dbg("uhci_check_timeout: timeout for %p",urb);
+			uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
+		}
+#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
+		else if (((type == PIPE_BULK) || (type == PIPE_CONTROL)) &&  
+			 (hcpriv->use_loop) && time_after(jiffies, hcpriv->started + IDLE_TIMEOUT))
+			disable_desc_loop(s, urb);
+#endif
+
+	}
+	s->timeout_check=jiffies;
+}
+
+/*-------------------------------------------------------------------
+ Virtual Root Hub
+ -------------------------------------------------------------------*/
+
+_static __u8 root_hub_dev_des[] =
+{
+	0x12,			/*  __u8  bLength; */
+	0x01,			/*  __u8  bDescriptorType; Device */
+	0x00,			/*  __u16 bcdUSB; v1.0 */
+	0x01,
+	0x09,			/*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  bDeviceSubClass; */
+	0x00,			/*  __u8  bDeviceProtocol; */
+	0x08,			/*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x00,			/*  __u16 idVendor; */
+	0x00,
+	0x00,			/*  __u16 idProduct; */
+	0x00,
+	0x00,			/*  __u16 bcdDevice; */
+	0x00,
+	0x00,			/*  __u8  iManufacturer; */
+	0x02,			/*  __u8  iProduct; */
+	0x01,			/*  __u8  iSerialNumber; */
+	0x01			/*  __u8  bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+_static __u8 root_hub_config_des[] =
+{
+	0x09,			/*  __u8  bLength; */
+	0x02,			/*  __u8  bDescriptorType; Configuration */
+	0x19,			/*  __u16 wTotalLength; */
+	0x00,
+	0x01,			/*  __u8  bNumInterfaces; */
+	0x01,			/*  __u8  bConfigurationValue; */
+	0x00,			/*  __u8  iConfiguration; */
+	0x40,			/*  __u8  bmAttributes; 
+				   Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+	0x00,			/*  __u8  MaxPower; */
+
+     /* interface */
+	0x09,			/*  __u8  if_bLength; */
+	0x04,			/*  __u8  if_bDescriptorType; Interface */
+	0x00,			/*  __u8  if_bInterfaceNumber; */
+	0x00,			/*  __u8  if_bAlternateSetting; */
+	0x01,			/*  __u8  if_bNumEndpoints; */
+	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  if_bInterfaceSubClass; */
+	0x00,			/*  __u8  if_bInterfaceProtocol; */
+	0x00,			/*  __u8  if_iInterface; */
+
+     /* endpoint */
+	0x07,			/*  __u8  ep_bLength; */
+	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+	0x03,			/*  __u8  ep_bmAttributes; Interrupt */
+	0x08,			/*  __u16 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 *** */
+};
+
+/*-------------------------------------------------------------------------*/
+/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
+_static int rh_send_irq (struct urb *urb)
+{
+	int len = 1;
+	int i;
+	uhci_t *uhci = urb->dev->bus->hcpriv;
+	unsigned int io_addr = uhci->io_addr;
+	__u16 data = 0;
+
+	for (i = 0; i < uhci->rh.numports; i++) {
+		data |= ((inw (io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);
+		len = (i + 1) / 8 + 1;
+	}
+
+	*(__u16 *) urb->transfer_buffer = cpu_to_le16 (data);
+	urb->actual_length = len;
+	urb->status = 0;
+	
+	if ((data > 0) && (uhci->rh.send != 0)) {
+		dbg("Root-Hub INT complete: port1: %x port2: %x data: %x",
+		     inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2), data);
+		urb->complete (urb);
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
+_static int rh_init_int_timer (struct urb *urb);
+
+_static void rh_int_timer_do (unsigned long ptr)
+{
+	int len;
+	struct urb *urb = (struct urb*) ptr;
+	uhci_t *uhci = urb->dev->bus->hcpriv;
+
+	if (uhci->rh.send) {
+		len = rh_send_irq (urb);
+		if (len > 0) {
+			urb->actual_length = len;
+			if (urb->complete)
+				urb->complete (urb);
+		}
+	}
+	rh_init_int_timer (urb);
+}
+
+/*-------------------------------------------------------------------------*/
+/* Root Hub INTs are polled by this timer, polling interval 20ms */
+
+_static int rh_init_int_timer (struct urb *urb)
+{
+	uhci_t *uhci = urb->dev->bus->hcpriv;
+
+	uhci->rh.interval = urb->interval;
+	init_timer (&uhci->rh.rh_int_timer);
+	uhci->rh.rh_int_timer.function = rh_int_timer_do;
+	uhci->rh.rh_int_timer.data = (unsigned long) urb;
+	uhci->rh.rh_int_timer.expires = jiffies + (HZ * 20) / 1000;
+	add_timer (&uhci->rh.rh_int_timer);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+#define OK(x) 			len = (x); break
+
+#define CLR_RH_PORTSTAT(x) \
+		status = inw(io_addr+USBPORTSC1+2*(wIndex-1)); \
+		status = (status & 0xfff5) & ~(x); \
+		outw(status, io_addr+USBPORTSC1+2*(wIndex-1))
+
+#define SET_RH_PORTSTAT(x) \
+		status = inw(io_addr+USBPORTSC1+2*(wIndex-1)); \
+		status = (status & 0xfff5) | (x); \
+		outw(status, io_addr+USBPORTSC1+2*(wIndex-1))
+
+
+/*-------------------------------------------------------------------------*/
+/****
+ ** Root Hub Control Pipe
+ *************************/
+
+
+_static int rh_submit_urb (struct urb *urb)
+{
+	struct usb_device *usb_dev = urb->dev;
+	uhci_t *uhci = 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 status = 0;
+	int stat = 0;
+	int i;
+	unsigned int io_addr = uhci->io_addr;
+	__u16 cstatus;
+
+	__u16 bmRType_bReq;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+
+	if (usb_pipetype (pipe) == PIPE_INTERRUPT) {
+		dbg("Root-Hub submit IRQ: every %d ms", urb->interval);
+		uhci->rh.urb = urb;
+		uhci->rh.send = 1;
+		uhci->rh.interval = urb->interval;
+		rh_init_int_timer (urb);
+
+		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);
+
+	for (i = 0; i < 8; i++)
+		uhci->rh.c_p_r[i] = 0;
+
+	dbg("Root-Hub: adr: %2x cmd(%1x): %04x %04x %04x %04x",
+	     uhci->rh.devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
+
+	switch (bmRType_bReq) {
+		/* Request Destination:
+		   without flags: Device, 
+		   RH_INTERFACE: interface, 
+		   RH_ENDPOINT: endpoint,
+		   RH_CLASS means HUB here, 
+		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
+		 */
+
+	case RH_GET_STATUS:
+		*(__u16 *) data = 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:
+		status = inw (io_addr + USBPORTSC1 + 2 * (wIndex - 1));
+		cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
+			((status & USBPORTSC_PEC) >> (3 - 1)) |
+			(uhci->rh.c_p_r[wIndex - 1] << (0 + 4));
+		status = (status & USBPORTSC_CCS) |
+			((status & USBPORTSC_PE) >> (2 - 1)) |
+			((status & USBPORTSC_SUSP) >> (12 - 2)) |
+			((status & USBPORTSC_PR) >> (9 - 4)) |
+			(1 << 8) |	/* power on ** */
+			((status & USBPORTSC_LSDA) << (-8 + 9));
+
+		*(__u16 *) data = cpu_to_le16 (status);
+		*(__u16 *) (data + 2) = cpu_to_le16 (cstatus);
+		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):
+			CLR_RH_PORTSTAT (USBPORTSC_PE);
+			OK (0);
+		case (RH_PORT_SUSPEND):
+			CLR_RH_PORTSTAT (USBPORTSC_SUSP);
+			OK (0);
+		case (RH_PORT_POWER):
+			OK (0);	/* port power ** */
+		case (RH_C_PORT_CONNECTION):
+			SET_RH_PORTSTAT (USBPORTSC_CSC);
+			OK (0);
+		case (RH_C_PORT_ENABLE):
+			SET_RH_PORTSTAT (USBPORTSC_PEC);
+			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):
+			uhci->rh.c_p_r[wIndex - 1] = 0;
+			OK (0);
+		}
+		break;
+
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_SUSPEND):
+			SET_RH_PORTSTAT (USBPORTSC_SUSP);
+			OK (0);
+		case (RH_PORT_RESET):
+			SET_RH_PORTSTAT (USBPORTSC_PR);
+			uhci_wait_ms (10);
+			uhci->rh.c_p_r[wIndex - 1] = 1;
+			CLR_RH_PORTSTAT (USBPORTSC_PR);
+			udelay (10);
+			SET_RH_PORTSTAT (USBPORTSC_PE);
+			uhci_wait_ms (10);
+			SET_RH_PORTSTAT (0xa);
+			OK (0);
+		case (RH_PORT_POWER):
+			OK (0);	/* port power ** */
+		case (RH_PORT_ENABLE):
+			SET_RH_PORTSTAT (USBPORTSC_PE);
+			OK (0);
+		}
+		break;
+
+	case RH_SET_ADDRESS:
+		uhci->rh.devnum = wValue;
+		OK (0);
+
+	case RH_GET_DESCRIPTOR:
+		switch ((wValue & 0xff00) >> 8) {
+		case (0x01):	/* device descriptor */
+			len = min_t(unsigned int, leni,
+				  min_t(unsigned int,
+				      sizeof (root_hub_dev_des), wLength));
+			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,
+			        uhci->io_addr, "UHCI",
+				data, wLength);
+			if (len > 0) {
+				OK(min_t(int, leni, len));
+			} else 
+				stat = -EPIPE;
+		}
+		break;
+
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+		root_hub_hub_des[2] = uhci->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;
+	}
+
+	dbg("Root-Hub stat port1: %x port2: %x",
+	     inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2));
+
+	urb->actual_length = len;
+	urb->status = stat;
+	urb->dev=NULL;
+	if (urb->complete)
+		urb->complete (urb);
+	return 0;
+}
+/*-------------------------------------------------------------------------*/
+
+_static int rh_unlink_urb (struct urb *urb)
+{
+	uhci_t *uhci = urb->dev->bus->hcpriv;
+
+	if (uhci->rh.urb==urb) {
+		dbg("Root-Hub unlink IRQ");
+		uhci->rh.send = 0;
+		del_timer (&uhci->rh.rh_int_timer);
+	}
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+
+/*
+ * Map status to standard result codes
+ *
+ * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)
+ * <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 -ETIMEDOUT;
+		else
+			return -EILSEQ;
+	}
+	if (status & TD_CTRL_NAK)	/* NAK */
+		return -ETIMEDOUT;
+	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;
+	if (status & TD_CTRL_ACTIVE)	/* Active */
+		return 0;
+
+	return -EPROTO;
+}
+
+/*
+ * Only the USB core should call uhci_alloc_dev and uhci_free_dev
+ */
+_static int uhci_alloc_dev (struct usb_device *usb_dev)
+{
+	return 0;
+}
+
+_static void uhci_unlink_urbs(uhci_t *s, struct usb_device *usb_dev, int remove_all)
+{
+	unsigned long flags;
+	struct list_head *p;
+	struct list_head *p2;
+	struct urb *urb;
+
+	spin_lock_irqsave (&s->urb_list_lock, flags);
+	p = s->urb_list.prev;	
+	while (p != &s->urb_list) {
+		p2 = p;
+		p = p->prev ;
+		urb = list_entry (p2, struct urb, urb_list);
+		dbg("urb: %p, dev %p, %p", urb, usb_dev,urb->dev);
+		
+		//urb->transfer_flags |=USB_ASYNC_UNLINK; 
+			
+		if (remove_all || (usb_dev == urb->dev)) {
+			spin_unlock_irqrestore (&s->urb_list_lock, flags);
+			warn("forced removing of queued URB %p due to disconnect",urb);
+			uhci_unlink_urb(urb);
+			urb->dev = NULL; // avoid further processing of this URB
+			spin_lock_irqsave (&s->urb_list_lock, flags);
+			p = s->urb_list.prev;	
+		}
+	}
+	spin_unlock_irqrestore (&s->urb_list_lock, flags);
+}
+
+_static int uhci_free_dev (struct usb_device *usb_dev)
+{
+	uhci_t *s;
+	
+
+	if(!usb_dev || !usb_dev->bus || !usb_dev->bus->hcpriv)
+		return -EINVAL;
+	
+	s=(uhci_t*) usb_dev->bus->hcpriv;	
+	uhci_unlink_urbs(s, usb_dev, 0);
+
+	return 0;
+}
+
+/*
+ * uhci_get_current_frame_number()
+ *
+ * returns the current frame number for a USB bus/controller.
+ */
+_static int uhci_get_current_frame_number (struct usb_device *usb_dev)
+{
+	return UHCI_GET_CURRENT_FRAME ((uhci_t*) usb_dev->bus->hcpriv);
+}
+
+struct usb_operations uhci_device_operations =
+{
+	uhci_alloc_dev,
+	uhci_free_dev,
+	uhci_get_current_frame_number,
+	uhci_submit_urb,
+	uhci_unlink_urb
+};
+
+_static void correct_data_toggles(struct urb *urb)
+{
+	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), 
+		       !usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)));
+
+	while(urb) {
+		urb_priv_t *priv=urb->hcpriv;		
+		uhci_desc_t *qh = list_entry (priv->desc_list.next, uhci_desc_t, desc_list);
+		struct list_head *p = qh->vertical.next;
+		uhci_desc_t *td;
+		dbg("URB to correct %p\n", urb);
+	
+		for (; p != &qh->vertical; p = p->next) {
+			td = list_entry (p, uhci_desc_t, vertical);
+			td->hw.td.info^=cpu_to_le32(1<<TD_TOKEN_TOGGLE);
+		}
+		urb=priv->next_queued_urb;
+	}
+}
+
+/* 
+ * For IN-control transfers, process_transfer gets a bit more complicated,
+ * since there are devices that return less data (eg. strings) than they
+ * have announced. This leads to a queue abort due to the short packet,
+ * the status stage is not executed. If this happens, the status stage
+ * is manually re-executed.
+ * mode: PROCESS_TRANSFER_REGULAR: regular (unlink QH)
+ *       PROCESS_TRANSFER_DONT_UNLINK: QHs already unlinked (for async unlink_urb)
+ */
+
+_static int process_transfer (uhci_t *s, struct urb *urb, int mode)
+{
+	int ret = 0;
+	urb_priv_t *urb_priv = urb->hcpriv;
+	struct list_head *qhl = urb_priv->desc_list.next;
+	uhci_desc_t *qh = list_entry (qhl, uhci_desc_t, desc_list);
+	struct list_head *p = qh->vertical.next;
+	uhci_desc_t *desc= list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
+	uhci_desc_t *last_desc = list_entry (desc->vertical.prev, uhci_desc_t, vertical);
+	int data_toggle = usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));	// save initial data_toggle
+	int maxlength; 	// extracted and remapped info from TD
+	int actual_length;
+	int status = 0;
+
+	//dbg("process_transfer: urb %p, urb_priv %p, qh %p last_desc %p\n",urb,urb_priv, qh, last_desc);
+
+	/* if the status phase has been retriggered and the
+	   queue is empty or the last status-TD is inactive, the retriggered
+	   status stage is completed
+	 */
+
+	if (urb_priv->flags && 
+	    ((qh->hw.qh.element == cpu_to_le32(UHCI_PTR_TERM)) || !is_td_active(desc)))
+		goto transfer_finished;
+
+	urb->actual_length=0;
+
+	for (; p != &qh->vertical; p = p->next) {
+		desc = list_entry (p, uhci_desc_t, vertical);
+
+		if (is_td_active(desc)) {	// do not process active TDs
+			if (mode == CLEAN_TRANSFER_DELETION_MARK) // if called from async_unlink
+				uhci_clean_transfer(s, urb, qh, CLEAN_TRANSFER_DELETION_MARK);
+			return ret;
+		}
+	
+		actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status));		// extract transfer parameters from TD
+		maxlength = (((le32_to_cpu(desc->hw.td.info) >> 21) & 0x7ff) + 1) & 0x7ff;
+		status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
+
+		if (status == -EPIPE) { 		// see if EP is stalled
+			// set up stalled condition
+			usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+		}
+
+		if (status && (status != -EPIPE)) {	// if any error occurred stop processing of further TDs
+			// only set ret if status returned an error
+  is_error:
+			ret = status;
+			urb->error_count++;
+			break;
+		}
+		else if ((le32_to_cpu(desc->hw.td.info) & 0xff) != USB_PID_SETUP)
+			urb->actual_length += actual_length;
+
+		// got less data than requested
+		if ( (actual_length < maxlength)) {
+			if (urb->transfer_flags & USB_DISABLE_SPD) {
+				status = -EREMOTEIO;	// treat as real error
+				dbg("process_transfer: SPD!!");
+				break;	// exit after this TD because SP was detected
+			}
+
+			// short read during control-IN: re-start status stage
+			if ((usb_pipetype (urb->pipe) == PIPE_CONTROL)) {
+				if (uhci_packetid(le32_to_cpu(last_desc->hw.td.info)) == USB_PID_OUT) {
+			
+					set_qh_element(qh, last_desc->dma_addr);  // re-trigger status stage
+					dbg("short packet during control transfer, retrigger status stage @ %p",last_desc);
+					urb_priv->flags = 1; // mark as short control packet
+					return 0;
+				}
+			}
+			// all other cases: short read is OK
+			data_toggle = uhci_toggle (le32_to_cpu(desc->hw.td.info));
+			break;
+		}
+		else if (status)
+			goto is_error;
+
+		data_toggle = uhci_toggle (le32_to_cpu(desc->hw.td.info));
+		queue_dbg("process_transfer: len:%d status:%x mapped:%x toggle:%d", actual_length, le32_to_cpu(desc->hw.td.status),status, data_toggle);      
+
+	}
+
+	if (usb_pipetype (urb->pipe) == PIPE_BULK ) {  /* toggle correction for short bulk transfers (nonqueued/queued) */
+
+		urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
+		struct urb *next_queued_urb=priv->next_queued_urb;
+
+		if (next_queued_urb) {
+			urb_priv_t *next_priv=(urb_priv_t*)next_queued_urb->hcpriv;
+			uhci_desc_t *qh = list_entry (next_priv->desc_list.next, uhci_desc_t, desc_list);
+			uhci_desc_t *first_td=list_entry (qh->vertical.next, uhci_desc_t, vertical);
+
+			if (data_toggle == uhci_toggle (le32_to_cpu(first_td->hw.td.info))) {
+				err("process_transfer: fixed toggle");
+				correct_data_toggles(next_queued_urb);
+			}						
+		}
+		else
+			usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), !data_toggle);		
+	}
+
+ transfer_finished:
+	
+	uhci_clean_transfer(s, urb, qh, mode);
+
+	urb->status = status;
+
+#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH	
+	disable_desc_loop(s,urb);
+#endif	
+
+	queue_dbg("process_transfer: (end) urb %p, wanted len %d, len %d status %x err %d",
+		urb,urb->transfer_buffer_length,urb->actual_length, urb->status, urb->error_count);
+	return ret;
+}
+
+_static int process_interrupt (uhci_t *s, struct urb *urb)
+{
+	int i, ret = -EINPROGRESS;
+	urb_priv_t *urb_priv = urb->hcpriv;
+	struct list_head *p = urb_priv->desc_list.next;
+	uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
+
+	int actual_length;
+	int status = 0;
+
+	//dbg("urb contains interrupt request");
+
+	for (i = 0; p != &urb_priv->desc_list; p = p->next, i++)	// Maybe we allow more than one TD later ;-)
+	{
+		desc = list_entry (p, uhci_desc_t, desc_list);
+
+		if (is_td_active(desc)) {
+			// do not process active TDs
+			//dbg("TD ACT Status @%p %08x",desc,le32_to_cpu(desc->hw.td.status));
+			break;
+		}
+
+		if (!(desc->hw.td.status & cpu_to_le32(TD_CTRL_IOC))) {
+			// do not process one-shot TDs, no recycling
+			break;
+		}
+		// extract transfer parameters from TD
+
+		actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status));
+		status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
+
+		// see if EP is stalled
+		if (status == -EPIPE) {
+			// set up stalled condition
+			usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+		}
+
+		// if any error occurred: ignore this td, and continue
+		if (status != 0) {
+			//uhci_show_td (desc);
+			urb->error_count++;
+			goto recycle;
+		}
+		else
+			urb->actual_length = actual_length;
+
+	recycle:
+		uhci_urb_dma_sync(s, urb, urb->hcpriv);
+		if (urb->complete) {
+			//dbg("process_interrupt: calling completion, status %i",status);
+			urb->status = status;
+			((urb_priv_t*)urb->hcpriv)->flags=1; // if unlink_urb is called during completion
+
+			spin_unlock(&s->urb_list_lock);
+			
+			urb->complete ((struct urb *) urb);
+			
+			spin_lock(&s->urb_list_lock);
+
+			((urb_priv_t*)urb->hcpriv)->flags=0;		       			
+		}
+		
+		if ((urb->status != -ECONNABORTED) && (urb->status != ECONNRESET) &&
+			    (urb->status != -ENOENT)) {
+
+			urb->status = -EINPROGRESS;
+
+			// Recycle INT-TD if interval!=0, else mark TD as one-shot
+			if (urb->interval) {
+				
+				desc->hw.td.info &= cpu_to_le32(~(1 << TD_TOKEN_TOGGLE));
+				if (status==0) {
+					((urb_priv_t*)urb->hcpriv)->started=jiffies;
+					desc->hw.td.info |= cpu_to_le32((usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+									    usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE));
+					usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+				} else {
+					desc->hw.td.info |= cpu_to_le32((!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+									     usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE));
+				}
+				desc->hw.td.status= cpu_to_le32((urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
+					(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27));
+				mb();
+			}
+			else {
+				uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
+				uhci_clean_iso_step2(s, urb_priv);
+				// correct toggle after unlink
+				usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+				clr_td_ioc(desc); // inactivate TD
+			}
+		}
+	}
+
+	return ret;
+}
+
+// mode: PROCESS_ISO_REGULAR: processing only for done TDs, unlink TDs
+// mode: PROCESS_ISO_FORCE: force processing, don't unlink TDs (already unlinked)
+
+_static int process_iso (uhci_t *s, struct urb *urb, int mode)
+{
+	int i;
+	int ret = 0;
+	urb_priv_t *urb_priv = urb->hcpriv;
+	struct list_head *p = urb_priv->desc_list.next, *p_tmp;
+	uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
+
+	dbg("urb contains iso request");
+	if (is_td_active(desc) && mode==PROCESS_ISO_REGULAR)
+		return -EXDEV;	// last TD not finished
+
+	urb->error_count = 0;
+	urb->actual_length = 0;
+	urb->status = 0;
+	dbg("process iso urb %p, %li, %i, %i, %i %08x",urb,jiffies,UHCI_GET_CURRENT_FRAME(s),
+	    urb->number_of_packets,mode,le32_to_cpu(desc->hw.td.status));
+
+	for (i = 0; p != &urb_priv->desc_list;  i++) {
+		desc = list_entry (p, uhci_desc_t, desc_list);
+		
+		//uhci_show_td(desc);
+		if (is_td_active(desc)) {
+			// means we have completed the last TD, but not the TDs before
+			desc->hw.td.status &= cpu_to_le32(~TD_CTRL_ACTIVE);
+			dbg("TD still active (%x)- grrr. paranoia!", le32_to_cpu(desc->hw.td.status));
+			ret = -EXDEV;
+			urb->iso_frame_desc[i].status = ret;
+			unlink_td (s, desc, 1);
+			// FIXME: immediate deletion may be dangerous
+			goto err;
+		}
+
+		if (mode == PROCESS_ISO_REGULAR)
+			unlink_td (s, desc, 1);
+
+		if (urb->number_of_packets <= i) {
+			dbg("urb->number_of_packets (%d)<=(%d)", urb->number_of_packets, i);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		urb->iso_frame_desc[i].actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status));
+		urb->iso_frame_desc[i].status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
+		urb->actual_length += urb->iso_frame_desc[i].actual_length;
+
+	      err:
+
+		if (urb->iso_frame_desc[i].status != 0) {
+			urb->error_count++;
+			urb->status = urb->iso_frame_desc[i].status;
+		}
+		dbg("process_iso: %i: len:%d %08x status:%x",
+		     i, urb->iso_frame_desc[i].actual_length, le32_to_cpu(desc->hw.td.status),urb->iso_frame_desc[i].status);
+
+		p_tmp = p;
+		p = p->next;
+		list_del (p_tmp);
+		delete_desc (s, desc);
+	}
+	
+	dbg("process_iso: exit %i (%d), actual_len %i", i, ret,urb->actual_length);
+	return ret;
+}
+
+
+_static int process_urb (uhci_t *s, struct list_head *p)
+{
+	int ret = 0;
+	struct urb *urb;
+
+	urb=list_entry (p, struct urb, urb_list);
+	//dbg("process_urb: found queued urb: %p", urb);
+
+	switch (usb_pipetype (urb->pipe)) {
+	case PIPE_CONTROL:
+		ret = process_transfer (s, urb, CLEAN_TRANSFER_REGULAR);
+		break;
+	case PIPE_BULK:
+		if (!s->avoid_bulk.counter)
+			ret = process_transfer (s, urb, CLEAN_TRANSFER_REGULAR);
+		else
+			return 0;
+		break;
+	case PIPE_ISOCHRONOUS:
+		ret = process_iso (s, urb, PROCESS_ISO_REGULAR);
+		break;
+	case PIPE_INTERRUPT:
+		ret = process_interrupt (s, urb);
+		break;
+	}
+
+	if (urb->status != -EINPROGRESS) {
+		urb_priv_t *urb_priv;
+		struct usb_device *usb_dev;
+		
+		usb_dev=urb->dev;
+
+		/* Release bandwidth for Interrupt or Iso transfers */
+		if (urb->bandwidth) {
+			if (usb_pipetype(urb->pipe)==PIPE_ISOCHRONOUS)
+				usb_release_bandwidth (urb->dev, urb, 1);
+			else if (usb_pipetype(urb->pipe)==PIPE_INTERRUPT && urb->interval)
+				usb_release_bandwidth (urb->dev, urb, 0);
+		}
+
+		dbg("dequeued urb: %p", urb);
+		dequeue_urb (s, urb);
+
+		urb_priv = urb->hcpriv;
+
+		uhci_urb_dma_unmap(s, urb, urb_priv);
+
+#ifdef DEBUG_SLAB
+		kmem_cache_free(urb_priv_kmem, urb_priv);
+#else
+		kfree (urb_priv);
+#endif
+
+		if ((usb_pipetype (urb->pipe) != PIPE_INTERRUPT)) {  // process_interrupt does completion on its own		
+			struct urb *next_urb = urb->next;
+			int is_ring = 0;
+			int contains_killed = 0;
+			int loop_count=0;
+			
+			if (next_urb) {
+				// Find out if the URBs are linked to a ring
+				while  (next_urb != NULL && next_urb != urb && loop_count < MAX_NEXT_COUNT) {
+					if (next_urb->status == -ENOENT) {// killed URBs break ring structure & resubmission
+						contains_killed = 1;
+						break;
+					}	
+					next_urb = next_urb->next;
+					loop_count++;
+				}
+				
+				if (loop_count == MAX_NEXT_COUNT)
+					err("process_urb: Too much linked URBs in ring detection!");
+
+				if (next_urb == urb)
+					is_ring=1;
+			}			
+
+			// Submit idle/non-killed URBs linked with urb->next
+			// Stop before the current URB				
+			
+			next_urb = urb->next;	
+			if (next_urb && !contains_killed) {
+				int ret_submit;
+				next_urb = urb->next;	
+				
+				loop_count=0;
+				while (next_urb != NULL && next_urb != urb && loop_count < MAX_NEXT_COUNT) {
+					if (next_urb->status != -EINPROGRESS) {
+					
+						if (next_urb->status == -ENOENT) 
+							break;
+
+						spin_unlock(&s->urb_list_lock);
+
+						ret_submit=uhci_submit_urb(next_urb);
+						spin_lock(&s->urb_list_lock);
+						
+						if (ret_submit)
+							break;						
+					}
+					loop_count++;
+					next_urb = next_urb->next;
+				}
+				if (loop_count == MAX_NEXT_COUNT)
+					err("process_urb: Too much linked URBs in resubmission!");
+			}
+
+			// Completion
+			if (urb->complete) {
+				int was_unlinked = (urb->status == -ENOENT);
+				urb->dev = NULL;
+				spin_unlock(&s->urb_list_lock);
+
+				urb->complete ((struct urb *) urb);
+
+				// Re-submit the URB if ring-linked
+				if (is_ring && !was_unlinked && !contains_killed) {
+					urb->dev=usb_dev;
+					uhci_submit_urb (urb);
+				}
+				spin_lock(&s->urb_list_lock);
+			}
+			
+			usb_dec_dev_use (usb_dev);
+		}
+	}
+
+	return ret;
+}
+
+_static void uhci_interrupt (int irq, void *__uhci, struct pt_regs *regs)
+{
+	uhci_t *s = __uhci;
+	unsigned int io_addr = s->io_addr;
+	unsigned short status;
+	struct list_head *p, *p2;
+	int restarts, work_done;
+	
+	/*
+	 * Read the interrupt status, and write it back to clear the
+	 * interrupt cause
+	 */
+
+	status = inw (io_addr + USBSTS);
+
+	if (!status)		/* shared interrupt, not mine */
+		return;
+
+	dbg("interrupt");
+
+	if (status != 1) {
+		// Avoid too much error messages at a time
+		if (time_after(jiffies, s->last_error_time + ERROR_SUPPRESSION_TIME)) {
+			warn("interrupt, status %x, frame# %i", status, 
+			     UHCI_GET_CURRENT_FRAME(s));
+			s->last_error_time = jiffies;
+		}
+		
+		// remove host controller halted state
+		if ((status&0x20) && (s->running)) {
+			err("Host controller halted, trying to restart.");
+			outw (USBCMD_RS | inw(io_addr + USBCMD), io_addr + USBCMD);
+		}
+		//uhci_show_status (s);
+	}
+	/*
+	 * traverse the list in *reverse* direction, because new entries
+	 * may be added at the end.
+	 * also, because process_urb may unlink the current urb,
+	 * we need to advance the list before
+	 * New: check for max. workload and restart count
+	 */
+
+	spin_lock (&s->urb_list_lock);
+
+	restarts=0;
+	work_done=0;
+
+restart:
+	s->unlink_urb_done=0;
+	p = s->urb_list.prev;	
+
+	while (p != &s->urb_list && (work_done < 1024)) {
+		p2 = p;
+		p = p->prev;
+
+		process_urb (s, p2);
+		
+		work_done++;
+
+		if (s->unlink_urb_done) {
+			s->unlink_urb_done=0;
+			restarts++;
+			
+			if (restarts<16)	// avoid endless restarts
+				goto restart;
+			else 
+				break;
+		}
+	}
+	if (time_after(jiffies, s->timeout_check + (HZ/30)))
+		uhci_check_timeouts(s);
+
+	clean_descs(s, CLEAN_NOT_FORCED);
+	uhci_cleanup_unlink(s, CLEAN_NOT_FORCED);
+	uhci_switch_timer_int(s);
+							
+	spin_unlock (&s->urb_list_lock);
+	
+	outw (status, io_addr + USBSTS);
+
+	//dbg("uhci_interrupt: done");
+}
+
+_static void reset_hc (uhci_t *s)
+{
+	unsigned int io_addr = s->io_addr;
+
+	s->apm_state = 0;
+	/* Global reset for 50ms */
+	outw (USBCMD_GRESET, io_addr + USBCMD);
+	uhci_wait_ms (50);
+	outw (0, io_addr + USBCMD);
+	uhci_wait_ms (10);
+}
+
+_static void start_hc (uhci_t *s)
+{
+	unsigned int io_addr = s->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) {
+			err("USBCMD_HCRESET timed out!");
+			break;
+		}
+		udelay(1);
+	}
+
+	/* Turn on all interrupts */
+	outw (USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR);
+
+	/* Start at frame 0 */
+	outw (0, io_addr + USBFRNUM);
+	outl (s->framelist_dma, io_addr + USBFLBASEADD);
+
+	/* Run and mark it configured with a 64-byte max packet */
+	outw (USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
+	s->apm_state = 1;
+	s->running = 1;
+}
+
+/* No  __devexit, since it maybe called from alloc_uhci() */
+_static void
+uhci_pci_remove (struct pci_dev *dev)
+{
+	uhci_t *s = pci_get_drvdata(dev);
+	struct usb_device *root_hub = s->bus->root_hub;
+
+	s->running = 0;		    // Don't allow submit_urb
+
+	if (root_hub)
+		usb_disconnect (&root_hub);
+
+	reset_hc (s);
+	wait_ms (1);
+
+	uhci_unlink_urbs (s, 0, CLEAN_FORCED);  // Forced unlink of remaining URBs
+	uhci_cleanup_unlink (s, CLEAN_FORCED);  // force cleanup of async killed URBs
+	
+	usb_deregister_bus (s->bus);
+
+	release_region (s->io_addr, s->io_size);
+	free_irq (s->irq, s);
+	usb_free_bus (s->bus);
+	cleanup_skel (s);
+	kfree (s);
+}
+
+_static int __init uhci_start_usb (uhci_t *s)
+{				/* start it up */
+	/* connect the virtual root hub */
+	struct usb_device *usb_dev;
+
+	usb_dev = usb_alloc_dev (NULL, s->bus);
+	if (!usb_dev)
+		return -1;
+
+	s->bus->root_hub = usb_dev;
+	usb_connect (usb_dev);
+
+	if (usb_new_device (usb_dev) != 0) {
+		usb_free_dev (usb_dev);
+		return -1;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+_static int
+uhci_pci_suspend (struct pci_dev *dev, u32 state)
+{
+	reset_hc((uhci_t *) pci_get_drvdata(dev));
+	return 0;
+}
+
+_static int
+uhci_pci_resume (struct pci_dev *dev)
+{
+	start_hc((uhci_t *) pci_get_drvdata(dev));
+	return 0;
+}
+#endif
+
+_static int __devinit alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size)
+{
+	uhci_t *s;
+	struct usb_bus *bus;
+	char buf[8], *bufp = buf;
+
+#ifndef __sparc__
+	sprintf(buf, "%d", irq);
+#else
+	bufp = __irq_itoa(irq);
+#endif
+	printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n",
+		io_addr, bufp);
+
+	s = kmalloc (sizeof (uhci_t), GFP_KERNEL);
+	if (!s)
+		return -1;
+
+	memset (s, 0, sizeof (uhci_t));
+	INIT_LIST_HEAD (&s->free_desc);
+	INIT_LIST_HEAD (&s->urb_list);
+	INIT_LIST_HEAD (&s->urb_unlinked);
+	spin_lock_init (&s->urb_list_lock);
+	spin_lock_init (&s->qh_lock);
+	spin_lock_init (&s->td_lock);
+	atomic_set(&s->avoid_bulk, 0);
+	s->irq = -1;
+	s->io_addr = io_addr;
+	s->io_size = io_size;
+	s->uhci_pci=dev;
+
+	bus = usb_alloc_bus (&uhci_device_operations);
+	if (!bus) {
+		kfree (s);
+		return -1;
+	}
+
+	s->bus = bus;
+	bus->bus_name = dev->slot_name;
+	bus->hcpriv = s;
+
+	/* 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, so default to 2 */
+	/* According to the UHCI spec, Bit 7 is always set to 1. So we try */
+	/* to use this to our advantage */
+
+	for (s->maxports = 0; s->maxports < (io_size - 0x10) / 2; s->maxports++) {
+		unsigned int portstatus;
+
+		portstatus = inw (io_addr + 0x10 + (s->maxports * 2));
+		dbg("port %i, adr %x status %x", s->maxports,
+			io_addr + 0x10 + (s->maxports * 2), portstatus);
+		if (!(portstatus & 0x0080))
+			break;
+	}
+	warn("Detected %d ports", s->maxports);
+
+	/* This is experimental so anything less than 2 or greater than 8 is */
+	/*  something weird and we'll ignore it */
+	if (s->maxports < 2 || s->maxports > 8) {
+		dbg("Port count misdetected, forcing to 2 ports");
+		s->maxports = 2;
+	}
+
+	s->rh.numports = s->maxports;
+	s->loop_usage=0;
+	if (init_skel (s)) {
+		usb_free_bus (bus);
+		kfree(s);
+		return -1;
+	}
+
+	request_region (s->io_addr, io_size, MODNAME);
+	reset_hc (s);
+	usb_register_bus (s->bus);
+
+	start_hc (s);
+
+	if (request_irq (irq, uhci_interrupt, SA_SHIRQ, MODNAME, s)) {
+		err("request_irq %d failed!",irq);
+		usb_free_bus (bus);
+		reset_hc (s);
+		release_region (s->io_addr, s->io_size);
+		cleanup_skel(s);
+		kfree(s);
+		return -1;
+	}
+
+	/* Enable PIRQ */
+	pci_write_config_word (dev, USBLEGSUP, USBLEGSUP_DEFAULT);
+
+	s->irq = irq;
+
+	if(uhci_start_usb (s) < 0) {
+		uhci_pci_remove(dev);
+		return -1;
+	}
+
+	//chain new uhci device into global list
+	pci_set_drvdata(dev, s);
+	devs=s;
+
+	return 0;
+}
+
+_static int __devinit
+uhci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
+{
+	int i;
+
+	if (pci_enable_device(dev) < 0)
+		return -ENODEV;
+		
+	if (!dev->irq) {
+		err("found UHCI device with no IRQ assigned. check BIOS settings!");
+		return -ENODEV;
+	}
+	
+	pci_set_master(dev);
+
+	/* Search for the IO base address.. */
+	for (i = 0; i < 6; i++) {
+
+		unsigned int io_addr = pci_resource_start(dev, i);
+		unsigned int io_size = pci_resource_len(dev, i);
+		if (!(pci_resource_flags(dev,i) & IORESOURCE_IO))
+			continue;
+
+		/* Is it already in use? */
+		if (check_region (io_addr, io_size))
+			break;
+		/* disable legacy emulation */
+		pci_write_config_word (dev, USBLEGSUP, 0);
+	
+		return alloc_uhci(dev, dev->irq, io_addr, io_size);
+	}
+	return -ENODEV;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct pci_device_id __devinitdata uhci_pci_ids [] = { {
+
+	/* handle any USB UHCI controller */
+	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x00),
+	class_mask: 	~0,
+
+	/* no matter who makes it */
+	vendor:		PCI_ANY_ID,
+	device:		PCI_ANY_ID,
+	subvendor:	PCI_ANY_ID,
+	subdevice:	PCI_ANY_ID,
+
+	}, { /* end: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE (pci, uhci_pci_ids);
+
+static struct pci_driver uhci_pci_driver = {
+	name:		"usb-uhci",
+	id_table:	&uhci_pci_ids [0],
+
+	probe:		uhci_pci_probe,
+	remove:		uhci_pci_remove,
+
+#ifdef	CONFIG_PM
+	suspend:	uhci_pci_suspend,
+	resume:		uhci_pci_resume,
+#endif	/* PM */
+
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init uhci_hcd_init (void) 
+{
+	int retval;
+
+#ifdef DEBUG_SLAB
+	urb_priv_kmem = kmem_cache_create("urb_priv", sizeof(urb_priv_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	
+	if(!urb_priv_kmem) {
+		err("kmem_cache_create for urb_priv_t failed (out of memory)");
+		return -ENOMEM;
+	}
+#endif	
+	info(VERSTR);
+
+#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
+	info("High bandwidth mode enabled");	
+#endif
+
+	retval = pci_module_init (&uhci_pci_driver);
+
+#ifdef DEBUG_SLAB
+	if (retval < 0 ) {
+		if (kmem_cache_destroy(urb_priv_kmem))
+			err("urb_priv_kmem remained");
+	}
+#endif
+	
+	info(DRIVER_VERSION ":" DRIVER_DESC);
+
+	return retval;
+}
+
+static void __exit uhci_hcd_cleanup (void) 
+{      
+	pci_unregister_driver (&uhci_pci_driver);
+	
+#ifdef DEBUG_SLAB
+	if(kmem_cache_destroy(urb_priv_kmem))
+		err("urb_priv_kmem remained");
+#endif
+}
+
+module_init (uhci_hcd_init);
+module_exit (uhci_hcd_cleanup);
+
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/usb/host/usb-uhci.h b/drivers/usb/host/usb-uhci.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/host/usb-uhci.h	Thu Mar  6 14:22:16 2003
@@ -0,0 +1,308 @@
+#ifndef __LINUX_UHCI_H
+#define __LINUX_UHCI_H
+
+/*
+   $Id: usb-uhci.h,v 1.58 2001/08/28 16:45:00 acher Exp $
+ */
+#define MODNAME "usb-uhci"
+#define UHCI_LATENCY_TIMER 0
+
+static __inline__ void uhci_wait_ms(unsigned int ms)
+{
+	if(!in_interrupt())
+	{
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1 + ms * HZ / 1000);
+	}
+	else
+		mdelay(ms);
+}
+
+/* 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_LS		0x0030	/* Line Status */
+#define   USBPORTSC_RD		0x0040	/* Resume Detect */
+#define   USBPORTSC_LSDA	0x0100	/* Low Speed Device Attached */
+#define   USBPORTSC_PR		0x0200	/* Port Reset */
+#define   USBPORTSC_SUSP	0x1000	/* Suspend */
+
+/* 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_PID 		0xff	/* PID MASK */
+
+#define UHCI_PTR_BITS		0x000F
+#define UHCI_PTR_TERM		0x0001
+#define UHCI_PTR_QH		0x0002
+#define UHCI_PTR_DEPTH		0x0004
+
+#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 */
+
+/*
+ * 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_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_status_bits(ctrl_sts)	(ctrl_sts & 0xFE0000)
+#define uhci_actual_length(ctrl_sts)	((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK)	/* 1-based */
+#define uhci_ptr_to_virt(x)	bus_to_virt(x & ~UHCI_PTR_BITS)
+
+/*
+ * for TD <flags>:
+ */
+#define UHCI_TD_REMOVE		0x0001	/* Remove when done */
+
+/*
+ * for TD <info>: (a.k.a. Token)
+ */
+#define TD_TOKEN_TOGGLE		19
+
+#define uhci_maxlen(token)	((token) >> 21)
+#define uhci_toggle(token)	(((token) >> TD_TOKEN_TOGGLE) & 1)
+#define uhci_endpoint(token)	(((token) >> 15) & 0xf)
+#define uhci_devaddr(token)	(((token) >> 8) & 0x7f)
+#define uhci_devep(token)	(((token) >> 8) & 0x7ff)
+#define uhci_packetid(token)	((token) & 0xff)
+#define uhci_packetout(token)	(uhci_packetid(token) != USB_PID_IN)
+#define uhci_packetin(token)	(uhci_packetid(token) == USB_PID_IN)
+
+/* ------------------------------------------------------------------------------------
+   New TD/QH-structures
+   ------------------------------------------------------------------------------------ */
+typedef enum {
+	TD_TYPE, QH_TYPE
+} uhci_desc_type_t;
+
+typedef struct {
+	__u32 link;
+	__u32 status;
+	__u32 info;
+	__u32 buffer;
+} uhci_td_t, *puhci_td_t;
+
+typedef struct {
+	__u32 head;
+	__u32 element;		/* Queue element pointer */
+} uhci_qh_t, *puhci_qh_t;
+
+typedef struct {
+	union {
+		uhci_td_t td;
+		uhci_qh_t qh;
+	} hw;
+	uhci_desc_type_t type;
+	dma_addr_t dma_addr;
+	struct list_head horizontal;
+	struct list_head vertical;
+	struct list_head desc_list;
+	int last_used;
+} uhci_desc_t, *puhci_desc_t;
+
+typedef struct {
+	struct list_head desc_list;	// list pointer to all corresponding TDs/QHs associated with this request
+	dma_addr_t setup_packet_dma;
+	dma_addr_t transfer_buffer_dma;
+	unsigned long started;
+	struct urb *next_queued_urb;	// next queued urb for this EP
+	struct urb *prev_queued_urb;
+	uhci_desc_t *bottom_qh;
+	uhci_desc_t *next_qh;       	// next helper QH
+	char use_loop;
+	char flags;
+} urb_priv_t, *purb_priv_t;
+
+struct virt_root_hub {
+	int devnum;		/* Address of Root Hub endpoint */
+	void *urb;
+	void *int_addr;
+	int send;
+	int interval;
+	int numports;
+	int c_p_r[8];
+	struct timer_list rh_int_timer;
+};
+
+typedef struct uhci {
+	int irq;
+	unsigned int io_addr;
+	unsigned int io_size;
+	unsigned int maxports;
+	int running;
+
+	int apm_state;
+
+	struct uhci *next;	// chain of uhci device contexts
+
+	struct list_head urb_list;	// list of all pending urbs
+
+	spinlock_t urb_list_lock;	// lock to keep consistency 
+
+	int unlink_urb_done;
+	atomic_t avoid_bulk;
+	
+	struct usb_bus *bus;	// our bus
+
+	__u32 *framelist;
+	dma_addr_t framelist_dma;
+	uhci_desc_t **iso_td;
+	uhci_desc_t *int_chain[8];
+	uhci_desc_t *ls_control_chain;
+	uhci_desc_t *control_chain;
+	uhci_desc_t *bulk_chain;
+	uhci_desc_t *chain_end;
+	uhci_desc_t *td1ms;
+	uhci_desc_t *td32ms;
+	struct list_head free_desc;
+	spinlock_t qh_lock;
+	spinlock_t td_lock;
+	struct virt_root_hub rh;	//private data of the virtual root hub
+	int loop_usage;            // URBs using bandwidth reclamation
+
+	struct list_head urb_unlinked;	// list of all unlinked  urbs
+	long timeout_check;
+	int timeout_urbs;
+	struct pci_dev *uhci_pci;
+	struct pci_pool *desc_pool;
+	long last_error_time;          // last error output in uhci_interrupt()
+} uhci_t, *puhci_t;
+
+
+#define MAKE_TD_ADDR(a) ((a)->dma_addr&~UHCI_PTR_QH)
+#define MAKE_QH_ADDR(a) ((a)->dma_addr|UHCI_PTR_QH)
+#define UHCI_GET_CURRENT_FRAME(uhci) (inw ((uhci)->io_addr + USBFRNUM))
+
+#define CLEAN_TRANSFER_NO_DELETION 0
+#define CLEAN_TRANSFER_REGULAR 1
+#define CLEAN_TRANSFER_DELETION_MARK 2
+
+#define CLEAN_NOT_FORCED 0
+#define CLEAN_FORCED 1
+
+#define PROCESS_ISO_REGULAR 0
+#define PROCESS_ISO_FORCE 1
+
+#define UNLINK_ASYNC_STORE_URB 0
+#define UNLINK_ASYNC_DONT_STORE 1
+
+#define is_td_active(desc) (desc->hw.td.status & cpu_to_le32(TD_CTRL_ACTIVE))
+
+#define set_qh_head(desc,val) (desc)->hw.qh.head=cpu_to_le32(val)
+#define set_qh_element(desc,val) (desc)->hw.qh.element=cpu_to_le32(val)
+#define set_td_link(desc,val) (desc)->hw.td.link=cpu_to_le32(val)
+#define set_td_ioc(desc) (desc)->hw.td.status |= cpu_to_le32(TD_CTRL_IOC)
+#define clr_td_ioc(desc) (desc)->hw.td.status &= cpu_to_le32(~TD_CTRL_IOC)
+
+
+/* ------------------------------------------------------------------------------------ 
+   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
+
+#endif
diff -Nru a/drivers/usb/uhci-debug.h b/drivers/usb/uhci-debug.h
--- a/drivers/usb/uhci-debug.h	Thu Mar  6 14:22:16 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,573 +0,0 @@
-/*
- * 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/proc_fs.h>
-#include <asm/io.h>
-
-#include "uhci.h"
-
-/* Handle REALLY large printk's so we don't overflow buffers */
-static void inline lprintk(char *buf)
-{
-	char *p;
-
-	/* Just write one line at a time */
-	while (buf) {
-		p = strchr(buf, '\n');
-		if (p)
-			*p = 0;
-		printk("%s\n", buf);
-		buf = p;
-		if (buf)
-			buf++;
-	}
-}
-
-static int inline uhci_is_skeleton_td(struct uhci *uhci, struct uhci_td *td)
-{
-	int i;
-
-	for (i = 0; i < UHCI_NUM_SKELTD; i++)
-		if (td == uhci->skeltd[i])
-			return 1;
-
-	return 0;
-}
-
-static int inline uhci_is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh)
-{
-	int i;
-
-	for (i = 0; i < UHCI_NUM_SKELQH; i++)
-		if (qh == uhci->skelqh[i])
-			return 1;
-
-	return 0;
-}
-
-static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
-{
-	char *out = buf;
-	char *spid;
-
-	/* Try to make sure there's enough memory */
-	if (len < 160)
-		return 0;
-
-	out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td, td->link);
-	out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
-		((td->status >> 27) & 3),
-		(td->status & TD_CTRL_SPD) ?      "SPD " : "",
-		(td->status & TD_CTRL_LS) ?       "LS " : "",
-		(td->status & TD_CTRL_IOC) ?      "IOC " : "",
-		(td->status & TD_CTRL_ACTIVE) ?   "Active " : "",
-		(td->status & TD_CTRL_STALLED) ?  "Stalled " : "",
-		(td->status & TD_CTRL_DBUFERR) ?  "DataBufErr " : "",
-		(td->status & TD_CTRL_BABBLE) ?   "Babble " : "",
-		(td->status & TD_CTRL_NAK) ?      "NAK " : "",
-		(td->status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
-		(td->status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
-		td->status & 0x7ff);
-
-	switch (td->info & 0xff) {
-		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) ",
-		td->info >> 21,
-		((td->info >> 19) & 1),
-		(td->info >> 15) & 15,
-		(td->info >> 8) & 127,
-		(td->info & 0xff),
-		spid);
-	out += sprintf(out, "(buf=%08x)\n", td->buffer);
-
-	return out - buf;
-}
-
-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 < 80)
-		return 0;
-
-	out += sprintf(out, "  stat%d     =     %04x   %s%s%s%s%s%s%s%s\n",
-		port,
-		status,
-		(status & USBPORTSC_SUSP) ? "PortSuspend " : "",
-		(status & USBPORTSC_PR) ?   "PortReset " : "",
-		(status & USBPORTSC_LSDA) ? "LowSpeed " : "",
-		(status & USBPORTSC_RD) ?   "ResumeDetect " : "",
-		(status & USBPORTSC_PEC) ?  "EnableChange " : "",
-		(status & USBPORTSC_PE) ?   "PortEnabled " : "",
-		(status & USBPORTSC_CSC) ?  "ConnectChange " : "",
-		(status & USBPORTSC_CCS) ?  "PortConnected " : "");
-
-	return out - buf;
-}
-
-static int uhci_show_status(struct uhci *uhci, char *buf, int len)
-{
-	char *out = buf;
-	unsigned int 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_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;
-
-	/* 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, qh->link, qh->element);
-
-	if (qh->element & UHCI_PTR_QH)
-		out += sprintf(out, "%*s  Element points to QH (bug?)\n", space, "");
-
-	if (qh->element & UHCI_PTR_DEPTH)
-		out += sprintf(out, "%*s  Depth traverse\n", space, "");
-
-	if (qh->element & 8)
-		out += sprintf(out, "%*s  Bit 3 set (bug?)\n", space, "");
-
-	if (!(qh->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 (td->dma_handle != (qh->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 = ntd->status & 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_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;
-}
-
-static const char *td_names[] = {"skel_int1_td", "skel_int2_td",
-				 "skel_int4_td", "skel_int8_td",
-				 "skel_int16_td", "skel_int32_td",
-				 "skel_int64_td", "skel_int128_td",
-				 "skel_int256_td", "skel_term_td" };
-static const char *qh_names[] = { "skel_ls_control_qh", "skel_hs_control_qh",
-				  "skel_bulk_qh", "skel_term_qh" };
-
-#define show_frame_num()	\
-	if (!shown) {		\
-	  shown = 1;		\
-	  out += sprintf(out, "- Frame %d\n", i); \
-	}
-
-#define show_td_name()		\
-	if (!shown) {		\
-	  shown = 1;		\
-	  out += sprintf(out, "- %s\n", td_names[i]); \
-	}
-
-#define show_qh_name()		\
-	if (!shown) {		\
-	  shown = 1;		\
-	  out += sprintf(out, "- %s\n", qh_names[i]); \
-	}
-
-static int uhci_sprint_schedule(struct uhci *uhci, char *buf, int len)
-{
-	char *out = buf;
-	int i;
-	struct uhci_qh *qh;
-	struct uhci_td *td;
-	struct list_head *tmp, *head;
-
-	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");
-		}
-		if (uhci_is_skeleton_td(uhci, td))
-			continue;
-		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 TD's\n");
-	for (i = UHCI_NUM_SKELTD - 1; i >= 0; i--) {
-		int shown = 0;
-
-		td = uhci->skeltd[i];
-
-		if (debug > 1) {
-			show_td_name();
-			out += uhci_show_td(td, out, len - (out - buf), 4);
-		}
-
-		if (list_empty(&td->fl_list)) {
-			/* TD 0 is the int1 TD and links to control_ls_qh */
-			if (!i) {
-				if (td->link !=
-				    (uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH)) {
-					show_td_name();
-					out += sprintf(out, "    skeleton TD not linked to ls_control QH!\n");
-				}
-			} else if (i < 9) {
-				if (td->link != uhci->skeltd[i - 1]->dma_handle) {
-					show_td_name();
-					out += sprintf(out, "    skeleton TD not linked to next skeleton TD!\n");
-				}
-			} else {
-				show_td_name();
-
-				if (td->link != td->dma_handle)
-					out += sprintf(out, "    skel_term_td does not link to self\n");
-
-				/* Don't show it twice */
-				if (debug <= 1)
-					out += uhci_show_td(td, out, len - (out - buf), 4);
-			}
-
-			continue;
-		}
-
-		show_td_name();
-
-		head = &td->fl_list;
-		tmp = head->next;
-
-		while (tmp != head) {
-			td = list_entry(tmp, struct uhci_td, fl_list);
-
-			tmp = tmp->next;
-
-			out += uhci_show_td(td, out, len - (out - buf), 4);
-		}
-
-		if (!i) {
-			if (td->link !=
-			    (uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH))
-				out += sprintf(out, "    last TD not linked to ls_control QH!\n");
-		} else if (i < 9) {
-			if (td->link != uhci->skeltd[i - 1]->dma_handle)
-				out += sprintf(out, "    last TD not linked to next skeleton!\n");
-		}
-	}
-
-	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);
-		}
-
-		/* QH 3 is the Terminating QH, it's different */
-		if (i == 3) {
-			if (qh->link != UHCI_PTR_TERM) {
-				show_qh_name();
-				out += sprintf(out, "    bandwidth reclamation on!\n");
-			}
-
-			if (qh->element != uhci->skel_term_td->dma_handle) {
-				show_qh_name();
-				out += sprintf(out, "    skel_term_qh element is not set to skel_term_td\n");
-			}
-		}
-
-		if (list_empty(&qh->list)) {
-			if (i < 3) {
-				if (qh->link !=
-				    (uhci->skelqh[i + 1]->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 < 3) {
-			if (qh->link !=
-			    (uhci->skelqh[i + 1]->dma_handle | UHCI_PTR_QH))
-				out += sprintf(out, "    last QH not linked to next skeleton!\n");
-		}
-	}
-
-	return out - buf;
-}
-
-#ifdef CONFIG_PROC_FS
-#define MAX_OUTPUT	(PAGE_SIZE * 8)
-
-static struct proc_dir_entry *uhci_proc_root = NULL;
-
-struct uhci_proc {
-	int size;
-	char *data;
-	struct uhci *uhci;
-};
-
-static int uhci_proc_open(struct inode *inode, struct file *file)
-{
-	const struct proc_dir_entry *dp = inode->u.generic_ip;
-	struct uhci *uhci = dp->data;
-	struct uhci_proc *up;
-	unsigned long flags;
-	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;
-	}
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-
-	file->private_data = up;
-
-	ret = 0;
-out:
-	unlock_kernel();
-	return ret;
-}
-
-static loff_t uhci_proc_lseek(struct file *file, loff_t off, int whence)
-{
-	struct uhci_proc *up = file->private_data;
-	loff_t new;
-
-	switch (whence) {
-	case 0:
-		new = off;
-		break;
-	case 1:
-		new = file->f_pos + off;
-		break;
-	case 2:
-	default:
-		return -EINVAL;
-	}
-	if (new < 0 || new > up->size)
-		return -EINVAL;
-	return (file->f_pos = new);
-}
-
-static ssize_t uhci_proc_read(struct file *file, char *buf, size_t nbytes,
-			loff_t *ppos)
-{
-	struct uhci_proc *up = file->private_data;
-	unsigned int pos;
-	unsigned int size;
-
-	pos = *ppos;
-	size = up->size;
-	if (pos >= size)
-		return 0;
-	if (nbytes >= size)
-		nbytes = size;
-	if (pos + nbytes > size)
-		nbytes = size - pos;
-
-	if (!access_ok(VERIFY_WRITE, buf, nbytes))
-		return -EINVAL;
-
-	copy_to_user(buf, up->data + pos, nbytes);
-
-	*ppos += nbytes;
-
-	return nbytes;
-}
-
-static int uhci_proc_release(struct inode *inode, struct file *file)
-{
-	struct uhci_proc *up = file->private_data;
-
-	kfree(up->data);
-	kfree(up);
-
-	return 0;
-}
-
-static struct file_operations uhci_proc_operations = {
-	open:		uhci_proc_open,
-	llseek:		uhci_proc_lseek,
-	read:		uhci_proc_read,
-//	write:		uhci_proc_write,
-	release:	uhci_proc_release,
-};
-#endif
-
diff -Nru a/drivers/usb/uhci.c b/drivers/usb/uhci.c
--- a/drivers/usb/uhci.c	Thu Mar  6 14:22:16 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,3172 +0,0 @@
-/*
- * Universal Host Controller Interface driver for USB.
- *
- * Maintainer: Johannes Erdfelt <johannes@erdfelt.com>
- *
- * (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)
- *
- * 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>
-#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/proc_fs.h>
-#ifdef CONFIG_USB_DEBUG
-#define DEBUG
-#else
-#undef DEBUG
-#endif
-#include <linux/usb.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#include "uhci.h"
-
-#include <linux/pm.h>
-
-#include "hcd.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.1"
-#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
-#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 /proc/uhci/hc*
- * debug = 3, show all TD's in URB's when dumping
- */
-#ifdef DEBUG
-static int debug = 1;
-#else
-static int debug = 0;
-#endif
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "Debug level");
-static char *errbuf;
-#define ERRBUF_LEN    (PAGE_SIZE * 8)
-
-#include "uhci-debug.h"
-
-static kmem_cache_t *uhci_up_cachep;	/* urb_priv */
-
-static int rh_submit_urb(struct urb *urb);
-static int rh_unlink_urb(struct urb *urb);
-static int uhci_get_current_frame_number(struct usb_device *dev);
-static int uhci_unlink_urb(struct urb *urb);
-static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb);
-static void uhci_call_completion(struct urb *urb);
-
-static int  ports_active(struct uhci *uhci);
-static void suspend_hc(struct uhci *uhci);
-static void wakeup_hc(struct uhci *uhci);
-
-/* If a transfer is still active after this much time, turn off FSBR */
-#define IDLE_TIMEOUT	(HZ / 20)	/* 50 ms */
-#define FSBR_DELAY	(HZ / 20)	/* 50 ms */
-
-/* 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
-
-#define MAX_URB_LOOP	2048		/* Maximum number of linked URB's */
-
-/*
- * Only the USB core should call uhci_alloc_dev and uhci_free_dev
- */
-static int uhci_alloc_dev(struct usb_device *dev)
-{
-	return 0;
-}
-
-static int uhci_free_dev(struct usb_device *dev)
-{
-	return 0;
-}
-
-/*
- * 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 spurios 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 *uhci)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	uhci->skel_term_td->status |= TD_CTRL_IOC;
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static inline void uhci_clear_next_interrupt(struct uhci *uhci)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	uhci->skel_term_td->status &= ~TD_CTRL_IOC;
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static inline void uhci_add_complete(struct urb *urb)
-{
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->complete_list_lock, flags);
-	list_add(&urbp->complete_list, &uhci->complete_list);
-	spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
-}
-
-static struct uhci_td *uhci_alloc_td(struct uhci *uhci, struct usb_device *dev)
-{
-	dma_addr_t dma_handle;
-	struct uhci_td *td;
-
-	td = pci_pool_alloc(uhci->td_pool, GFP_DMA | 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->fl_list);
-
-	usb_inc_dev_use(dev);
-
-	return td;
-}
-
-static void inline uhci_fill_td(struct uhci_td *td, __u32 status,
-		__u32 info, __u32 buffer)
-{
-	td->status = status;
-	td->info = info;
-	td->buffer = buffer;
-}
-
-static void uhci_insert_td(struct uhci *uhci, struct uhci_td *skeltd, struct uhci_td *td)
-{
-	unsigned long flags;
-	struct uhci_td *ltd;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
-	ltd = list_entry(skeltd->fl_list.prev, struct uhci_td, fl_list);
-
-	td->link = ltd->link;
-	mb();
-	ltd->link = td->dma_handle;
-
-	list_add_tail(&td->fl_list, &skeltd->fl_list);
-
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-/*
- * We insert Isochronous transfers directly into the frame list at the
- * beginning
- * The layout looks as follows:
- * frame list pointer -> iso td's (if any) ->
- * periodic interrupt td (if frame 0) -> irq td's -> control qh -> bulk qh
- */
-static void uhci_insert_td_frame_list(struct uhci *uhci, struct uhci_td *td, unsigned framenum)
-{
-	unsigned long flags;
-
-	framenum %= UHCI_NUMFRAMES;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
-	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;
-		mb();
-		ltd->link = td->dma_handle;
-	} else {
-		td->link = uhci->fl->frame[framenum];
-		mb();
-		uhci->fl->frame[framenum] = td->dma_handle;
-		uhci->fl->frame_cpu[framenum] = td;
-	}
-
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static void uhci_remove_td(struct uhci *uhci, struct uhci_td *td)
-{
-	unsigned long flags;
-
-	/* If it's not inserted, don't remove it */
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	if (td->frame == -1 && list_empty(&td->fl_list))
-		goto out;
-
-	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] = 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;
-	}
-
-	mb();
-	td->link = UHCI_PTR_TERM;
-
-	list_del_init(&td->fl_list);
-	td->frame = -1;
-
-out:
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-/*
- * Inserts a td into qh list at the top.
- */
-static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, int breadth)
-{
-	struct list_head *tmp, *head;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci_td *td, *ptd;
-
-	if (list_empty(&urbp->td_list))
-		return;
-
-	head = &urbp->td_list;
-	tmp = head->next;
-
-	/* Ordering isn't important here yet since the QH hasn't been */
-	/*  inserted into the schedule yet */
-	td = list_entry(tmp, struct uhci_td, list);
-
-	/* Add the first TD to the QH element pointer */
-	qh->element = td->dma_handle | (breadth ? 0 : UHCI_PTR_DEPTH);
-
-	ptd = td;
-
-	/* Then link the rest of the TD's */
-	tmp = tmp->next;
-	while (tmp != head) {
-		td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		ptd->link = td->dma_handle | (breadth ? 0 : UHCI_PTR_DEPTH);
-
-		ptd = td;
-	}
-
-	ptd->link = UHCI_PTR_TERM;
-}
-
-static void uhci_free_td(struct uhci *uhci, struct uhci_td *td)
-{
-	if (!list_empty(&td->list) || !list_empty(&td->fl_list))
-		dbg("td is still in URB list!");
-
-	if (td->dev)
-		usb_dec_dev_use(td->dev);
-
-	pci_pool_free(uhci->td_pool, td, td->dma_handle);
-}
-
-static struct uhci_qh *uhci_alloc_qh(struct uhci *uhci, struct usb_device *dev)
-{
-	dma_addr_t dma_handle;
-	struct uhci_qh *qh;
-
-	qh = pci_pool_alloc(uhci->qh_pool, GFP_DMA | 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_inc_dev_use(dev);
-
-	return qh;
-}
-
-static void uhci_free_qh(struct uhci *uhci, struct uhci_qh *qh)
-{
-	if (!list_empty(&qh->list))
-		dbg("qh list not empty!");
-	if (!list_empty(&qh->remove_list))
-		dbg("qh still in remove_list!");
-
-	if (qh->dev)
-		usb_dec_dev_use(qh->dev);
-
-	pci_pool_free(uhci->qh_pool, qh, qh->dma_handle);
-}
-
-/*
- * MUST be called with uhci->frame_list_lock acquired
- */
-static void _uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb *urb)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct list_head *head, *tmp;
-	struct uhci_qh *lqh;
-
-	/* Grab the last QH */
-	lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
-
-	if (lqh->urbp) {
-		head = &lqh->urbp->queue_list;
-		tmp = head->next;
-		while (head != tmp) {
-			struct urb_priv *turbp =
-				list_entry(tmp, struct urb_priv, queue_list);
-
-			tmp = tmp->next;
-
-			turbp->qh->link = urbp->qh->dma_handle | UHCI_PTR_QH;
-		}
-	}
-
-	head = &urbp->queue_list;
-	tmp = head->next;
-	while (head != tmp) {
-		struct urb_priv *turbp =
-			list_entry(tmp, struct urb_priv, queue_list);
-
-		tmp = tmp->next;
-
-		turbp->qh->link = lqh->link;
-	}
-
-	urbp->qh->link = lqh->link;
-	mb();				/* Ordering is important */
-	lqh->link = urbp->qh->dma_handle | UHCI_PTR_QH;
-
-	list_add_tail(&urbp->qh->list, &skelqh->list);
-}
-
-static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb *urb)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	_uhci_insert_qh(uhci, skelqh, urb);
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
-{
-	unsigned long flags;
-	struct uhci_qh *pqh;
-
-	if (!qh)
-		return;
-
-	qh->urbp = NULL;
-
-	/* Only go through the hoops if it's actually linked in */
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	if (!list_empty(&qh->list)) {
-		pqh = list_entry(qh->list.prev, struct uhci_qh, list);
-
-		if (pqh->urbp) {
-			struct list_head *head, *tmp;
-
-			head = &pqh->urbp->queue_list;
-			tmp = head->next;
-			while (head != tmp) {
-				struct urb_priv *turbp =
-					list_entry(tmp, struct urb_priv, queue_list);
-
-				tmp = tmp->next;
-
-				turbp->qh->link = qh->link;
-			}
-		}
-
-		pqh->link = qh->link;
-		mb();
-		qh->element = qh->link = UHCI_PTR_TERM;
-
-		list_del_init(&qh->list);
-	}
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-
-	spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);
-
-	/* 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);
-
-	spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags);
-}
-
-static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct list_head *head, *tmp;
-
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (head != tmp) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		if (toggle)
-			td->info |= TD_TOKEN_TOGGLE;
-		else
-			td->info &= ~TD_TOKEN_TOGGLE;
-
-		toggle ^= 1;
-	}
-
-	return toggle;
-}
-
-/* This function will append one URB's QH to another URB's QH. This is for */
-/*  USB_QUEUE_BULK support for bulk transfers and soon implicitily for */
-/*  control transfers */
-static void uhci_append_queued_urb(struct uhci *uhci, struct urb *eurb, struct urb *urb)
-{
-	struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
-	struct list_head *tmp;
-	struct uhci_td *lltd;
-	unsigned long flags;
-
-	eurbp = eurb->hcpriv;
-	urbp = urb->hcpriv;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
-	/* Find the first URB in the queue */
-	if (eurbp->queued) {
-		struct list_head *head = &eurbp->queue_list;
-
-		tmp = head->next;
-		while (tmp != head) {
-			struct urb_priv *turbp =
-				list_entry(tmp, struct urb_priv, queue_list);
-
-			if (!turbp->queued)
-				break;
-
-			tmp = tmp->next;
-		}
-	} else
-		tmp = &eurbp->queue_list;
-
-	furbp = list_entry(tmp, struct urb_priv, queue_list);
-	lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list);
-
-	lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
-
-	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe),
-		uhci_fixup_toggle(urb, uhci_toggle(lltd->info) ^ 1));
-
-	/* All qh's in the queue need to link to the next queue */
-	urbp->qh->link = eurbp->qh->link;
-
-	mb();			/* Make sure we flush everything */
-	/* Only support bulk right now, so no depth */
-	lltd->link = urbp->qh->dma_handle | UHCI_PTR_QH;
-
-	list_add_tail(&urbp->queue_list, &furbp->queue_list);
-
-	urbp->queued = 1;
-
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static void uhci_delete_queued_urb(struct uhci *uhci, struct urb *urb)
-{
-	struct urb_priv *urbp, *nurbp;
-	struct list_head *head, *tmp;
-	struct urb_priv *purbp;
-	struct uhci_td *pltd;
-	unsigned int toggle;
-	unsigned long flags;
-
-	urbp = urb->hcpriv;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
-	if (list_empty(&urbp->queue_list))
-		goto out;
-
-	nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list);
-
-	/* Fix up the toggle for the next URB's */
-	if (!urbp->queued)
-		/* We set the toggle when we unlink */
-		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(pltd->info) ^ 1;
-	}
-
-	head = &urbp->queue_list;
-	tmp = head->next;
-	while (head != tmp) {
-		struct urb_priv *turbp;
-
-		turbp = list_entry(tmp, struct urb_priv, queue_list);
-
-		tmp = tmp->next;
-
-		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) {
-		nurbp->queued = 0;
-
-		_uhci_insert_qh(uhci, uhci->skel_bulk_qh, nurbp->urb);
-	} else {
-		/* We're somewhere in the middle (or end). A bit trickier */
-		/*  than the head scenario */
-		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 = 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;
-	}
-
-	list_del_init(&urbp->queue_list);
-
-out:
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static struct urb_priv *uhci_alloc_urb_priv(struct uhci *uhci, struct urb *urb)
-{
-	struct urb_priv *urbp;
-
-	urbp = kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC);
-	if (!urbp) {
-		err("uhci_alloc_urb_priv: couldn't allocate memory for urb_priv\n");
-		return NULL;
-	}
-
-	memset((void *)urbp, 0, sizeof(*urbp));
-
-	urbp->inserttime = jiffies;
-	urbp->fsbrtime = jiffies;
-	urbp->urb = urb;
-	urbp->dev = urb->dev;
-	
-	INIT_LIST_HEAD(&urbp->td_list);
-	INIT_LIST_HEAD(&urbp->queue_list);
-	INIT_LIST_HEAD(&urbp->complete_list);
-
-	urb->hcpriv = urbp;
-
-	if (urb->dev != uhci->rh.dev) {
-		if (urb->transfer_buffer_length) {
-			urbp->transfer_buffer_dma_handle = pci_map_single(uhci->dev,
-				urb->transfer_buffer, urb->transfer_buffer_length,
-				usb_pipein(urb->pipe) ? PCI_DMA_FROMDEVICE :
-				PCI_DMA_TODEVICE);
-			if (!urbp->transfer_buffer_dma_handle)
-				return NULL;
-		}
-
-		if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet) {
-			urbp->setup_packet_dma_handle = pci_map_single(uhci->dev,
-				urb->setup_packet, sizeof(struct usb_ctrlrequest),
-				PCI_DMA_TODEVICE);
-			if (!urbp->setup_packet_dma_handle)
-				return NULL;
-		}
-	}
-
-	return urbp;
-}
-
-/*
- * MUST be called with urb->lock acquired
- */
-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);
-}
-
-/*
- * MUST be called with urb->lock acquired
- */
-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;
-}
-
-/*
- * MUST be called with urb->lock acquired
- */
-static void uhci_destroy_urb_priv(struct urb *urb)
-{
-	struct list_head *head, *tmp;
-	struct urb_priv *urbp;
-	struct uhci *uhci;
-
-	urbp = (struct urb_priv *)urb->hcpriv;
-	if (!urbp)
-		return;
-
-	if (!urbp->dev || !urbp->dev->bus || !urbp->dev->bus->hcpriv) {
-		warn("uhci_destroy_urb_priv: urb %p belongs to disconnected device or bus?", urb);
-		return;
-	}
-
-	if (!list_empty(&urb->urb_list))
-		warn("uhci_destroy_urb_priv: urb %p still on uhci->urb_list or uhci->remove_list", urb);
-
-	if (!list_empty(&urbp->complete_list))
-		warn("uhci_destroy_urb_priv: urb %p still on uhci->complete_list", urb);
-
-	uhci = urbp->dev->bus->hcpriv;
-
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		uhci_remove_td_from_urb(td);
-		uhci_remove_td(uhci, td);
-		uhci_free_td(uhci, td);
-	}
-
-	if (urbp->setup_packet_dma_handle) {
-		pci_unmap_single(uhci->dev, urbp->setup_packet_dma_handle,
-			sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
-		urbp->setup_packet_dma_handle = 0;
-	}
-
-	if (urbp->transfer_buffer_dma_handle) {
-		pci_unmap_single(uhci->dev, urbp->transfer_buffer_dma_handle,
-			urb->transfer_buffer_length, usb_pipein(urb->pipe) ?
-			PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
-		urbp->transfer_buffer_dma_handle = 0;
-	}
-
-	urb->hcpriv = NULL;
-	kmem_cache_free(uhci_up_cachep, urbp);
-}
-
-static void uhci_inc_fsbr(struct uhci *uhci, struct urb *urb)
-{
-	unsigned long flags;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
-	if ((!(urb->transfer_flags & USB_NO_FSBR)) && !urbp->fsbr) {
-		urbp->fsbr = 1;
-		if (!uhci->fsbr++ && !uhci->fsbrtimeout)
-			uhci->skel_term_qh->link = uhci->skel_hs_control_qh->dma_handle | UHCI_PTR_QH;
-	}
-
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static void uhci_dec_fsbr(struct uhci *uhci, struct urb *urb)
-{
-	unsigned long flags;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
-	if ((!(urb->transfer_flags & USB_NO_FSBR)) && urbp->fsbr) {
-		urbp->fsbr = 0;
-		if (!--uhci->fsbr)
-			uhci->fsbrtimeout = jiffies + FSBR_DELAY;
-	}
-
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-/*
- * Map status to standard result codes
- *
- * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)]
- * <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 -ETIMEDOUT;
-		else
-			return -EILSEQ;
-	}
-	if (status & TD_CTRL_NAK)			/* NAK */
-		return -ETIMEDOUT;
-	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;
-	if (status & TD_CTRL_ACTIVE)			/* Active */
-		return 0;
-
-	return -EINVAL;
-}
-
-/*
- * Control transfers
- */
-static int uhci_submit_control(struct urb *urb)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	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;
-	dma_addr_t data = urbp->transfer_buffer_dma_handle;
-
-	/* The "pipe" thing contains the destination in bits 8--18 */
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
-
-	/* 3 errors */
-	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
-
-	/*
-	 * Build the TD for the control request
-	 */
-	td = uhci_alloc_td(uhci, urb->dev);
-	if (!td)
-		return -ENOMEM;
-
-	uhci_add_td_to_urb(urb, td);
-	uhci_fill_td(td, status, destination | (7 << 21),
-		urbp->setup_packet_dma_handle);
-
-	/*
-	 * If direction is "send", change the frame from SETUP (0x2D)
-	 * to OUT (0xE1). Else change it from SETUP to IN (0x69).
-	 */
-	destination ^= (USB_PID_SETUP ^ usb_packetid(urb->pipe));
-
-	if (!(urb->transfer_flags & USB_DISABLE_SPD))
-		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 | ((pktsze - 1) << 21),
-			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_NULL_DATA_SIZE << 21), 0);
-
-	qh = uhci_alloc_qh(uhci, urb->dev);
-	if (!qh)
-		return -ENOMEM;
-
-	urbp->qh = qh;
-	qh->urbp = urbp;
-
-	/* Low speed or small transfers gets a different queue and treatment */
-	if (urb->pipe & TD_CTRL_LS) {
-		uhci_insert_tds_in_qh(qh, urb, 0);
-		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
-	} else {
-		uhci_insert_tds_in_qh(qh, urb, 1);
-		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
-		uhci_inc_fsbr(uhci, urb);
-	}
-
-	return -EINPROGRESS;
-}
-
-static int usb_control_retrigger_status(struct urb *urb);
-
-static int uhci_result_control(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_phase;
-	}
-
-	tmp = head->next;
-	td = list_entry(tmp, struct uhci_td, list);
-
-	/* The first TD is the SETUP phase, check the status, but skip */
-	/*  the count */
-	status = uhci_status_bits(td->status);
-	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) {
-		td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		status = uhci_status_bits(td->status);
-		if (status & TD_CTRL_ACTIVE)
-			return -EINPROGRESS;
-
-		urb->actual_length += uhci_actual_length(td->status);
-
-		if (status)
-			goto td_error;
-
-		/* Check to see if we received a short packet */
-		if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) {
-			if (urb->transfer_flags & USB_DISABLE_SPD) {
-				ret = -EREMOTEIO;
-				goto err;
-			}
-
-			if (uhci_packetid(td->info) == USB_PID_IN)
-				return usb_control_retrigger_status(urb);
-			else
-				return 0;
-		}
-	}
-
-status_phase:
-	td = list_entry(tmp, struct uhci_td, list);
-
-	/* Control status phase */
-	status = uhci_status_bits(td->status);
-
-#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 (td->status & TD_CTRL_IOC &&	/* IOC is masked out by uhci_status_bits */
-	    status & TD_CTRL_ACTIVE &&
-	    status & TD_CTRL_NAK)
-		return 0;
-#endif
-
-	if (status & TD_CTRL_ACTIVE)
-		return -EINPROGRESS;
-
-	if (status)
-		goto td_error;
-
-	return 0;
-
-td_error:
-	ret = uhci_map_status(status, uhci_packetout(td->info));
-	if (ret == -EPIPE)
-		/* endpoint has stalled - mark it halted */
-		usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
-	    			uhci_packetout(td->info));
-
-err:
-	if ((debug == 1 && ret != -EPIPE) || debug > 1) {
-		/* Some debugging code */
-		dbg("uhci_result_control() failed with status %x", status);
-
-		if (errbuf) {
-			/* Print the chain for debugging purposes */
-			uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
-
-			lprintk(errbuf);
-		}
-	}
-
-	return ret;
-}
-
-static int usb_control_retrigger_status(struct urb *urb)
-{
-	struct list_head *tmp, *head;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci *uhci = urb->dev->bus->hcpriv;
-
-	urbp->short_control_packet = 1;
-
-	/* Create a new QH to avoid pointer overwriting problems */
-	uhci_remove_qh(uhci, urbp->qh);
-
-	/* Delete all of the TD's except for the status TD at the end */
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (tmp != head && tmp->next != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		uhci_remove_td_from_urb(td);
-		uhci_remove_td(uhci, td);
-		uhci_free_td(uhci, td);
-	}
-
-	urbp->qh = uhci_alloc_qh(uhci, urb->dev);
-	if (!urbp->qh) {
-		err("unable to allocate new QH for control retrigger");
-		return -ENOMEM;
-	}
-
-	urbp->qh->urbp = urbp;
-
-	/* One TD, who cares about Breadth first? */
-	uhci_insert_tds_in_qh(urbp->qh, urb, 0);
-
-	/* Low speed or small transfers gets a different queue and treatment */
-	if (urb->pipe & TD_CTRL_LS)
-		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
-	else
-		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
-
-	return -EINPROGRESS;
-}
-
-/*
- * Interrupt transfers
- */
-static int uhci_submit_interrupt(struct urb *urb)
-{
-	struct uhci_td *td;
-	unsigned long destination, status;
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-	if (urb->transfer_buffer_length > usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))
-		return -EINVAL;
-
-	/* The "pipe" thing contains the destination in bits 8--18 */
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
-
-	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
-
-	td = uhci_alloc_td(uhci, urb->dev);
-	if (!td)
-		return -ENOMEM;
-
-	destination |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT);
-	destination |= ((urb->transfer_buffer_length - 1) << 21);
-
-	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
-
-	uhci_add_td_to_urb(urb, td);
-	uhci_fill_td(td, status, destination, urbp->transfer_buffer_dma_handle);
-
-	uhci_insert_td(uhci, uhci->skeltd[__interval_to_skel(urb->interval)], td);
-
-	return -EINPROGRESS;
-}
-
-static int uhci_result_interrupt(struct urb *urb)
-{
-	struct list_head *tmp, *head;
-	struct urb_priv *urbp = urb->hcpriv;
-	struct uhci_td *td;
-	unsigned int status;
-	int ret = 0;
-
-	urb->actual_length = 0;
-
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (tmp != head) {
-		td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		status = uhci_status_bits(td->status);
-		if (status & TD_CTRL_ACTIVE)
-			return -EINPROGRESS;
-
-		urb->actual_length += uhci_actual_length(td->status);
-
-		if (status)
-			goto td_error;
-
-		if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) {
-			if (urb->transfer_flags & USB_DISABLE_SPD) {
-				ret = -EREMOTEIO;
-				goto err;
-			} else
-				return 0;
-		}
-	}
-
-	return 0;
-
-td_error:
-	ret = uhci_map_status(status, uhci_packetout(td->info));
-	if (ret == -EPIPE)
-		/* endpoint has stalled - mark it halted */
-		usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
-	    			uhci_packetout(td->info));
-
-err:
-	if ((debug == 1 && ret != -EPIPE) || debug > 1) {
-		/* Some debugging code */
-		dbg("uhci_result_interrupt/bulk() failed with status %x",
-			status);
-
-		if (errbuf) {
-			/* Print the chain for debugging purposes */
-			if (urbp->qh)
-				uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
-			else
-				uhci_show_td(td, errbuf, ERRBUF_LEN, 0);
-
-			lprintk(errbuf);
-		}
-	}
-
-	return ret;
-}
-
-static void uhci_reset_interrupt(struct urb *urb)
-{
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci_td *td;
-	unsigned long flags;
-
-	spin_lock_irqsave(&urb->lock, flags);
-
-	/* Root hub is special */
-	if (urb->dev == uhci->rh.dev)
-		goto out;
-
-	td = list_entry(urbp->td_list.next, struct uhci_td, list);
-
-	td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
-	td->info &= ~TD_TOKEN_TOGGLE;
-	td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT);
-	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
-
-out:
-	urb->status = -EINPROGRESS;
-
-	spin_unlock_irqrestore(&urb->lock, flags);
-}
-
-/*
- * Bulk transfers
- */
-static int uhci_submit_bulk(struct urb *urb, struct urb *eurb)
-{
-	struct uhci_td *td;
-	struct uhci_qh *qh;
-	unsigned long destination, status;
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	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 = urbp->transfer_buffer_dma_handle;
-
-	if (len < 0)
-		return -EINVAL;
-
-	/* Can't have low speed bulk transfers */
-	if (urb->pipe & TD_CTRL_LS)
-		return -EINVAL;
-
-	/* The "pipe" thing contains the destination in bits 8--18 */
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
-
-	/* 3 errors */
-	status = TD_CTRL_ACTIVE | (3 << TD_CTRL_C_ERR_SHIFT);
-
-	if (!(urb->transfer_flags & USB_DISABLE_SPD))
-		status |= TD_CTRL_SPD;
-
-	/*
-	 * Build the DATA TD's
-	 */
-	do {	/* Allow zero length packets */
-		int pktsze = len;
-
-		if (pktsze > maxsze)
-			pktsze = maxsze;
-
-		td = uhci_alloc_td(uhci, urb->dev);
-		if (!td)
-			return -ENOMEM;
-
-		uhci_add_td_to_urb(urb, td);
-		uhci_fill_td(td, status, destination |
-			(((pktsze - 1) & UHCI_NULL_DATA_SIZE) << 21) |
-			(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);
-
-	/*
-	 * USB_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 & USB_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_NULL_DATA_SIZE << 21) |
-			(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 flag on the last packet */
-	td->status |= TD_CTRL_IOC;
-
-	qh = uhci_alloc_qh(uhci, urb->dev);
-	if (!qh)
-		return -ENOMEM;
-
-	urbp->qh = qh;
-	qh->urbp = urbp;
-
-	/* Always assume breadth first */
-	uhci_insert_tds_in_qh(qh, urb, 1);
-
-	if (urb->transfer_flags & USB_QUEUE_BULK && eurb)
-		uhci_append_queued_urb(uhci, eurb, urb);
-	else
-		uhci_insert_qh(uhci, uhci->skel_bulk_qh, urb);
-
-	uhci_inc_fsbr(uhci, urb);
-
-	return -EINPROGRESS;
-}
-
-/* We can use the result interrupt since they're identical */
-#define uhci_result_bulk uhci_result_interrupt
-
-/*
- * Isochronous transfers
- */
-static int isochronous_find_limits(struct urb *urb, unsigned int *start, unsigned int *end)
-{
-	struct urb *last_urb = NULL;
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct list_head *tmp, *head;
-	int ret = 0;
-
-	head = &uhci->urb_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *u = list_entry(tmp, struct urb, urb_list);
-
-		tmp = tmp->next;
-
-		/* 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) & 1023;
-		ret = 0;
-	} else
-		ret = -1;	/* no previous urb found */
-
-	return ret;
-}
-
-static int isochronous_find_start(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(urb, &start, &end);
-
-	if (urb->transfer_flags & USB_ISO_ASAP) {
-		if (limits) {
-			int curframe;
-
-			curframe = uhci_get_current_frame_number(urb->dev) % UHCI_NUMFRAMES;
-			urb->start_frame = (curframe + 10) % UHCI_NUMFRAMES;
-		} else
-			urb->start_frame = end;
-	} else {
-		urb->start_frame %= UHCI_NUMFRAMES;
-		/* FIXME: Sanity check */
-	}
-
-	return 0;
-}
-
-/*
- * Isochronous transfers
- */
-static int uhci_submit_isochronous(struct urb *urb)
-{
-	struct uhci_td *td;
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	int i, ret, framenum;
-	int status, destination;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
-
-	ret = isochronous_find_start(urb);
-	if (ret)
-		return ret;
-
-	framenum = urb->start_frame;
-	for (i = 0; i < urb->number_of_packets; i++, framenum++) {
-		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 | ((urb->iso_frame_desc[i].length - 1) << 21),
-			urbp->transfer_buffer_dma_handle + urb->iso_frame_desc[i].offset);
-
-		if (i + 1 >= urb->number_of_packets)
-			td->status |= TD_CTRL_IOC;
-
-		uhci_insert_td_frame_list(uhci, td, framenum);
-	}
-
-	return -EINPROGRESS;
-}
-
-static int uhci_result_isochronous(struct urb *urb)
-{
-	struct list_head *tmp, *head;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	int status;
-	int i, ret = 0;
-
-	urb->actual_length = 0;
-
-	i = 0;
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-		int actlength;
-
-		tmp = tmp->next;
-
-		if (td->status & TD_CTRL_ACTIVE)
-			return -EINPROGRESS;
-
-		actlength = uhci_actual_length(td->status);
-		urb->iso_frame_desc[i].actual_length = actlength;
-		urb->actual_length += actlength;
-
-		status = uhci_map_status(uhci_status_bits(td->status), usb_pipeout(urb->pipe));
-		urb->iso_frame_desc[i].status = status;
-		if (status) {
-			urb->error_count++;
-			ret = status;
-		}
-
-		i++;
-	}
-
-	return ret;
-}
-
-/*
- * MUST be called with uhci->urb_list_lock acquired
- */
-static struct urb *uhci_find_urb_ep(struct uhci *uhci, struct urb *urb)
-{
-	struct list_head *tmp, *head;
-
-	/* We don't match Isoc transfers since they are special */
-	if (usb_pipeisoc(urb->pipe))
-		return NULL;
-
-	head = &uhci->urb_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *u = list_entry(tmp, struct urb, urb_list);
-
-		tmp = tmp->next;
-
-		if (u->dev == urb->dev && u->pipe == urb->pipe &&
-		    u->status == -EINPROGRESS)
-			return u;
-	}
-
-	return NULL;
-}
-
-static int uhci_submit_urb(struct urb *urb)
-{
-	int ret = -EINVAL;
-	struct uhci *uhci;
-	unsigned long flags;
-	struct urb *eurb;
-	int bustime;
-
-	if (!urb)
-		return -EINVAL;
-
-	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) {
-		warn("uhci_submit_urb: urb %p belongs to disconnected device or bus?", urb);
-		return -ENODEV;
-	}
-
-	uhci = (struct uhci *)urb->dev->bus->hcpriv;
-
-	usb_inc_dev_use(urb->dev);
-
-	spin_lock_irqsave(&uhci->urb_list_lock, flags);
-	spin_lock(&urb->lock);
-
-	if (urb->status == -EINPROGRESS || urb->status == -ECONNRESET ||
-	    urb->status == -ECONNABORTED) {
-		dbg("uhci_submit_urb: urb not available to submit (status = %d)", urb->status);
-		/* Since we can have problems on the out path */
-		spin_unlock(&urb->lock);
-		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-		usb_dec_dev_use(urb->dev);
-
-		return ret;
-	}
-
-	INIT_LIST_HEAD(&urb->urb_list);
-	if (!uhci_alloc_urb_priv(uhci, urb)) {
-		ret = -ENOMEM;
-
-		goto out;
-	}
-
-	eurb = uhci_find_urb_ep(uhci, urb);
-	if (eurb && !(urb->transfer_flags & USB_QUEUE_BULK)) {
-		ret = -ENXIO;
-
-		goto out;
-	}
-
-	/* Short circuit the virtual root hub */
-	if (urb->dev == uhci->rh.dev) {
-		ret = rh_submit_urb(urb);
-
-		goto out;
-	}
-
-	switch (usb_pipetype(urb->pipe)) {
-	case PIPE_CONTROL:
-		ret = uhci_submit_control(urb);
-		break;
-	case PIPE_INTERRUPT:
-		if (urb->bandwidth == 0) {	/* not yet checked/allocated */
-			bustime = usb_check_bandwidth(urb->dev, urb);
-			if (bustime < 0)
-				ret = bustime;
-			else {
-				ret = uhci_submit_interrupt(urb);
-				if (ret == -EINPROGRESS)
-					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
-			}
-		} else		/* bandwidth is already set */
-			ret = uhci_submit_interrupt(urb);
-		break;
-	case PIPE_BULK:
-		ret = uhci_submit_bulk(urb, eurb);
-		break;
-	case PIPE_ISOCHRONOUS:
-		if (urb->bandwidth == 0) {	/* not yet checked/allocated */
-			if (urb->number_of_packets <= 0) {
-				ret = -EINVAL;
-				break;
-			}
-			bustime = usb_check_bandwidth(urb->dev, urb);
-			if (bustime < 0) {
-				ret = bustime;
-				break;
-			}
-
-			ret = uhci_submit_isochronous(urb);
-			if (ret == -EINPROGRESS)
-				usb_claim_bandwidth(urb->dev, urb, bustime, 1);
-		} else		/* bandwidth is already set */
-			ret = uhci_submit_isochronous(urb);
-		break;
-	}
-
-out:
-	urb->status = ret;
-
-	if (ret == -EINPROGRESS) {
-		/* We use _tail to make find_urb_ep more efficient */
-		list_add_tail(&urb->urb_list, &uhci->urb_list);
-
-		spin_unlock(&urb->lock);
-		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-		return 0;
-	}
-
-	uhci_unlink_generic(uhci, urb);
-
-	spin_unlock(&urb->lock);
-	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-	/* Only call completion if it was successful */
-	if (!ret)
-		uhci_call_completion(urb);
-
-	return ret;
-}
-
-/*
- * Return the result of a transfer
- *
- * MUST be called with urb_list_lock acquired
- */
-static void uhci_transfer_result(struct uhci *uhci, struct urb *urb)
-{
-	int ret = -EINVAL;
-	unsigned long flags;
-	struct urb_priv *urbp;
-
-	/* The root hub is special */
-	if (urb->dev == uhci->rh.dev)
-		return;
-
-	spin_lock_irqsave(&urb->lock, flags);
-
-	urbp = (struct urb_priv *)urb->hcpriv;
-
-	if (urb->status != -EINPROGRESS) {
-		info("uhci_transfer_result: called for URB %p not in flight?", urb);
-		goto out;
-	}
-
-	switch (usb_pipetype(urb->pipe)) {
-	case PIPE_CONTROL:
-		ret = uhci_result_control(urb);
-		break;
-	case PIPE_INTERRUPT:
-		ret = uhci_result_interrupt(urb);
-		break;
-	case PIPE_BULK:
-		ret = uhci_result_bulk(urb);
-		break;
-	case PIPE_ISOCHRONOUS:
-		ret = uhci_result_isochronous(urb);
-		break;
-	}
-
-	urbp->status = ret;
-
-	if (ret == -EINPROGRESS)
-		goto out;
-
-	switch (usb_pipetype(urb->pipe)) {
-	case PIPE_CONTROL:
-	case PIPE_BULK:
-	case PIPE_ISOCHRONOUS:
-		/* Release bandwidth for Interrupt or Isoc. transfers */
-		/* Spinlock needed ? */
-		if (urb->bandwidth)
-			usb_release_bandwidth(urb->dev, urb, 1);
-		uhci_unlink_generic(uhci, urb);
-		break;
-	case PIPE_INTERRUPT:
-		/* Interrupts are an exception */
-		if (urb->interval)
-			goto out_complete;
-
-		/* Release bandwidth for Interrupt or Isoc. transfers */
-		/* Spinlock needed ? */
-		if (urb->bandwidth)
-			usb_release_bandwidth(urb->dev, urb, 0);
-		uhci_unlink_generic(uhci, urb);
-		break;
-	default:
-		info("uhci_transfer_result: unknown pipe type %d for urb %p\n",
-			usb_pipetype(urb->pipe), urb);
-	}
-
-	/* Remove it from uhci->urb_list */
-	list_del_init(&urb->urb_list);
-
-out_complete:
-	uhci_add_complete(urb);
-
-out:
-	spin_unlock_irqrestore(&urb->lock, flags);
-}
-
-/*
- * MUST be called with urb->lock acquired
- */
-static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb)
-{
-	struct list_head *head, *tmp;
-	struct urb_priv *urbp = urb->hcpriv;
-	int prevactive = 1;
-
-	/* We can get called when urbp allocation fails, so check */
-	if (!urbp)
-		return;
-
-	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's 3 way's 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
-	 * 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
-	 */
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		if (!(td->status & TD_CTRL_ACTIVE) &&
-		    (uhci_actual_length(td->status) < uhci_expected_length(td->info) ||
-		    tmp == head))
-			usb_settoggle(urb->dev, uhci_endpoint(td->info),
-				uhci_packetout(td->info),
-				uhci_toggle(td->info) ^ 1);
-		else if ((td->status & TD_CTRL_ACTIVE) && !prevactive)
-			usb_settoggle(urb->dev, uhci_endpoint(td->info),
-				uhci_packetout(td->info),
-				uhci_toggle(td->info));
-
-		prevactive = td->status & 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_unlink_urb(struct urb *urb)
-{
-	struct uhci *uhci;
-	unsigned long flags;
-	struct urb_priv *urbp = urb->hcpriv;
-
-	if (!urb)
-		return -EINVAL;
-
-	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
-		return -ENODEV;
-
-	uhci = (struct uhci *)urb->dev->bus->hcpriv;
-
-	spin_lock_irqsave(&uhci->urb_list_lock, flags);
-	spin_lock(&urb->lock);
-
-	/* Release bandwidth for Interrupt or Isoc. transfers */
-	/* Spinlock needed ? */
-	if (urb->bandwidth) {
-		switch (usb_pipetype(urb->pipe)) {
-		case PIPE_INTERRUPT:
-			usb_release_bandwidth(urb->dev, urb, 0);
-			break;
-		case PIPE_ISOCHRONOUS:
-			usb_release_bandwidth(urb->dev, urb, 1);
-			break;
-		default:
-			break;
-		}
-	}
-
-	if (urb->status != -EINPROGRESS) {
-		spin_unlock(&urb->lock);
-		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-		return 0;
-	}
-
-	list_del_init(&urb->urb_list);
-
-	uhci_unlink_generic(uhci, urb);
-
-	/* Short circuit the virtual root hub */
-	if (urb->dev == uhci->rh.dev) {
-		rh_unlink_urb(urb);
-
-		spin_unlock(&urb->lock);
-		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-		uhci_call_completion(urb);
-	} else {
-		if (urb->transfer_flags & USB_ASYNC_UNLINK) {
-			urbp->status = urb->status = -ECONNABORTED;
-
-			spin_lock(&uhci->urb_remove_list_lock);
-
-			/* If we're the first, set the next interrupt bit */
-			if (list_empty(&uhci->urb_remove_list))
-				uhci_set_next_interrupt(uhci);
-			
-			list_add(&urb->urb_list, &uhci->urb_remove_list);
-
-			spin_unlock(&uhci->urb_remove_list_lock);
-
-			spin_unlock(&urb->lock);
-			spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-		} else {
-			urb->status = -ENOENT;
-
-			spin_unlock(&urb->lock);
-			spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-			if (in_interrupt()) {	/* wait at least 1 frame */
-				static int errorcount = 10;
-
-				if (errorcount--)
-					dbg("uhci_unlink_urb called from interrupt for urb %p", urb);
-				udelay(1000);
-			} else
-				schedule_timeout(1+1*HZ/1000); 
-
-			uhci_call_completion(urb);
-		}
-	}
-
-	return 0;
-}
-
-static int uhci_fsbr_timeout(struct uhci *uhci, struct urb *urb)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct list_head *head, *tmp;
-	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;
-	tmp = head->next;
-	while (tmp != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		/*
-		 * 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 (tmp != head && (count % DEPTH_INTERVAL) == (DEPTH_INTERVAL - 1))
-			td->link |= UHCI_PTR_DEPTH;
-
-		count++;
-	}
-
-	return 0;
-}
-
-/*
- * uhci_get_current_frame_number()
- *
- * returns the current frame number for a USB bus/controller.
- */
-static int uhci_get_current_frame_number(struct usb_device *dev)
-{
-	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
-
-	return inw(uhci->io_addr + USBFRNUM);
-}
-
-struct usb_operations uhci_device_operations = {
-	uhci_alloc_dev,
-	uhci_free_dev,
-	uhci_get_current_frame_number,
-	uhci_submit_urb,
-	uhci_unlink_urb
-};
-
-/* Virtual Root Hub */
-
-static __u8 root_hub_dev_des[] =
-{
- 	0x12,			/*  __u8  bLength; */
-	0x01,			/*  __u8  bDescriptorType; Device */
-	0x00,			/*  __u16 bcdUSB; v1.0 */
-	0x01,
-	0x09,			/*  __u8  bDeviceClass; HUB_CLASSCODE */
-	0x00,			/*  __u8  bDeviceSubClass; */
-	0x00,			/*  __u8  bDeviceProtocol; */
-	0x08,			/*  __u8  bMaxPacketSize0; 8 Bytes */
-	0x00,			/*  __u16 idVendor; */
-	0x00,
-	0x00,			/*  __u16 idProduct; */
-	0x00,
-	0x00,			/*  __u16 bcdDevice; */
-	0x00,
-	0x00,			/*  __u8  iManufacturer; */
-	0x02,			/*  __u8  iProduct; */
-	0x01,			/*  __u8  iSerialNumber; */
-	0x01			/*  __u8  bNumConfigurations; */
-};
-
-
-/* Configuration descriptor */
-static __u8 root_hub_config_des[] =
-{
-	0x09,			/*  __u8  bLength; */
-	0x02,			/*  __u8  bDescriptorType; Configuration */
-	0x19,			/*  __u16 wTotalLength; */
-	0x00,
-	0x01,			/*  __u8  bNumInterfaces; */
-	0x01,			/*  __u8  bConfigurationValue; */
-	0x00,			/*  __u8  iConfiguration; */
-	0x40,			/*  __u8  bmAttributes;
-					Bit 7: Bus-powered, 6: Self-powered,
-					Bit 5 Remote-wakeup, 4..0: resvd */
-	0x00,			/*  __u8  MaxPower; */
-
-	/* interface */
-	0x09,			/*  __u8  if_bLength; */
-	0x04,			/*  __u8  if_bDescriptorType; Interface */
-	0x00,			/*  __u8  if_bInterfaceNumber; */
-	0x00,			/*  __u8  if_bAlternateSetting; */
-	0x01,			/*  __u8  if_bNumEndpoints; */
-	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
-	0x00,			/*  __u8  if_bInterfaceSubClass; */
-	0x00,			/*  __u8  if_bInterfaceProtocol; */
-	0x00,			/*  __u8  if_iInterface; */
-
-	/* endpoint */
-	0x07,			/*  __u8  ep_bLength; */
-	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */
-	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
-	0x03,			/*  __u8  ep_bmAttributes; Interrupt */
-	0x08,			/*  __u16 ep_wMaxPacketSize; 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 *** */
-};
-
-/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
-static int rh_send_irq(struct urb *urb)
-{
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	unsigned int io_addr = uhci->io_addr;
-	unsigned long flags;
-	int i, len = 1;
-	__u16 data = 0;
-
-	spin_lock_irqsave(&urb->lock, flags);
-	for (i = 0; i < uhci->rh.numports; i++) {
-		data |= ((inw(io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);
-		len = (i + 1) / 8 + 1;
-	}
-
-	*(__u16 *) urb->transfer_buffer = cpu_to_le16(data);
-	urb->actual_length = len;
-	urbp->status = 0;
-
-	spin_unlock_irqrestore(&urb->lock, flags);
-
-	if ((data > 0) && (uhci->rh.send != 0)) {
-		dbg("root-hub INT complete: port1: %x port2: %x data: %x",
-			inw(io_addr + USBPORTSC1), inw(io_addr + USBPORTSC2), data);
-		uhci_call_completion(urb);
-	}
-
-	return 0;
-}
-
-/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
-static int rh_init_int_timer(struct urb *urb);
-
-static void rh_int_timer_do(unsigned long ptr)
-{
-	struct urb *urb = (struct urb *)ptr;
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct list_head list, *tmp, *head;
-	unsigned long flags;
-
-	if (uhci->rh.send)
-		rh_send_irq(urb);
-
-	INIT_LIST_HEAD(&list);
-
-	spin_lock_irqsave(&uhci->urb_list_lock, flags);
-	head = &uhci->urb_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *u = list_entry(tmp, struct urb, urb_list);
-		struct urb_priv *up = (struct urb_priv *)u->hcpriv;
-
-		tmp = tmp->next;
-
-		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);
-
-		/* Check if the URB timed out */
-		if (u->timeout && time_after_eq(jiffies, up->inserttime + u->timeout)) {
-			list_del(&u->urb_list);
-			list_add_tail(&u->urb_list, &list);
-		}
-
-		spin_unlock(&u->lock);
-	}
-	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-	head = &list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *u = list_entry(tmp, struct urb, urb_list);
-
-		tmp = tmp->next;
-
-		u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
-		uhci_unlink_urb(u);
-	}
-
-	/* 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;
-	}
-
-	/* enter global suspend if nothing connected */
-	if (!uhci->is_suspended && !ports_active(uhci))
-		suspend_hc(uhci);
-
-	rh_init_int_timer(urb);
-}
-
-/* Root Hub INTs are polled by this timer */
-static int rh_init_int_timer(struct urb *urb)
-{
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-
-	uhci->rh.interval = urb->interval;
-	init_timer(&uhci->rh.rh_int_timer);
-	uhci->rh.rh_int_timer.function = rh_int_timer_do;
-	uhci->rh.rh_int_timer.data = (unsigned long)urb;
-	uhci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000;
-	add_timer(&uhci->rh.rh_int_timer);
-
-	return 0;
-}
-
-#define OK(x)			len = (x); break
-
-#define CLR_RH_PORTSTAT(x) \
-	status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
-	status = (status & 0xfff5) & ~(x); \
-	outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
-
-#define SET_RH_PORTSTAT(x) \
-	status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
-	status = (status & 0xfff5) | (x); \
-	outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
-
-
-/* Root Hub Control Pipe */
-static int rh_submit_urb(struct urb *urb)
-{
-	struct uhci *uhci = (struct uhci *)urb->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 status = 0;
-	int stat = 0;
-	int i;
-	unsigned int io_addr = uhci->io_addr;
-	__u16 cstatus;
-	__u16 bmRType_bReq;
-	__u16 wValue;
-	__u16 wIndex;
-	__u16 wLength;
-
-	if (usb_pipetype(pipe) == PIPE_INTERRUPT) {
-		uhci->rh.urb = urb;
-		uhci->rh.send = 1;
-		uhci->rh.interval = urb->interval;
-		rh_init_int_timer(urb);
-
-		return -EINPROGRESS;
-	}
-
-	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);
-
-	for (i = 0; i < 8; i++)
-		uhci->rh.c_p_r[i] = 0;
-
-	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:
-		status = inw(io_addr + USBPORTSC1 + 2 * (wIndex - 1));
-		cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
-			((status & USBPORTSC_PEC) >> (3 - 1)) |
-			(uhci->rh.c_p_r[wIndex - 1] << (0 + 4));
-			status = (status & USBPORTSC_CCS) |
-			((status & USBPORTSC_PE) >> (2 - 1)) |
-			((status & USBPORTSC_SUSP) >> (12 - 2)) |
-			((status & USBPORTSC_PR) >> (9 - 4)) |
-			(1 << 8) |      /* power on */
-			((status & USBPORTSC_LSDA) << (-8 + 9));
-
-		*(__u16 *)data = cpu_to_le16(status);
-		*(__u16 *)(data + 2) = cpu_to_le16(cstatus);
-		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:
-			CLR_RH_PORTSTAT(USBPORTSC_PE);
-			OK(0);
-		case RH_PORT_SUSPEND:
-			CLR_RH_PORTSTAT(USBPORTSC_SUSP);
-			OK(0);
-		case RH_PORT_POWER:
-			OK(0);	/* port power */
-		case RH_C_PORT_CONNECTION:
-			SET_RH_PORTSTAT(USBPORTSC_CSC);
-			OK(0);
-		case RH_C_PORT_ENABLE:
-			SET_RH_PORTSTAT(USBPORTSC_PEC);
-			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:
-			uhci->rh.c_p_r[wIndex - 1] = 0;
-			OK(0);
-		}
-		break;
-	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
-		switch (wValue) {
-		case RH_PORT_SUSPEND:
-			SET_RH_PORTSTAT(USBPORTSC_SUSP);
-			OK(0);
-		case RH_PORT_RESET:
-			SET_RH_PORTSTAT(USBPORTSC_PR);
-			mdelay(50);	/* USB v1.1 7.1.7.3 */
-			uhci->rh.c_p_r[wIndex - 1] = 1;
-			CLR_RH_PORTSTAT(USBPORTSC_PR);
-			udelay(10);
-			SET_RH_PORTSTAT(USBPORTSC_PE);
-			mdelay(10);
-			SET_RH_PORTSTAT(0xa);
-			OK(0);
-		case RH_PORT_POWER:
-			OK(0); /* port power ** */
-		case RH_PORT_ENABLE:
-			SET_RH_PORTSTAT(USBPORTSC_PE);
-			OK(0);
-		}
-		break;
-	case RH_SET_ADDRESS:
-		uhci->rh.devnum = wValue;
-		OK(0);
-	case RH_GET_DESCRIPTOR:
-		switch ((wValue & 0xff00) >> 8) {
-		case 0x01:	/* device descriptor */
-			len = min_t(unsigned int, leni,
-				  min_t(unsigned int,
-				      sizeof(root_hub_dev_des), wLength));
-			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,
-				uhci->io_addr, "UHCI-alt",
-				data, wLength);
-			if (len > 0) {
-				OK(min_t(int, leni, len));
-			} else 
-				stat = -EPIPE;
-		}
-		break;
-	case RH_GET_DESCRIPTOR | RH_CLASS:
-		root_hub_hub_des[2] = uhci->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);
-	case RH_GET_INTERFACE | RH_INTERFACE:
-		*(__u8 *)data = 0x00;
-		OK(1);
-	case RH_SET_INTERFACE | RH_INTERFACE:
-		OK(0);
-	default:
-		stat = -EPIPE;
-	}
-
-	urb->actual_length = len;
-
-	return stat;
-}
-
-/*
- * MUST be called with urb->lock acquired
- */
-static int rh_unlink_urb(struct urb *urb)
-{
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-
-	if (uhci->rh.urb == urb) {
-		urb->status = -ENOENT;
-		uhci->rh.send = 0;
-		uhci->rh.urb = NULL;
-		del_timer(&uhci->rh.rh_int_timer);
-	}
-	return 0;
-}
-
-static void uhci_free_pending_qhs(struct uhci *uhci)
-{
-	struct list_head *tmp, *head;
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);
-	head = &uhci->qh_remove_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct uhci_qh *qh = list_entry(tmp, struct uhci_qh, remove_list);
-
-		tmp = tmp->next;
-
-		list_del_init(&qh->remove_list);
-
-		uhci_free_qh(uhci, qh);
-	}
-	spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags);
-}
-
-static void uhci_call_completion(struct urb *urb)
-{
-	struct urb_priv *urbp;
-	struct usb_device *dev = urb->dev;
-	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
-	int is_ring = 0, killed, resubmit_interrupt, status;
-	struct urb *nurb;
-	unsigned long flags;
-
-	spin_lock_irqsave(&urb->lock, flags);
-
-	urbp = (struct urb_priv *)urb->hcpriv;
-	if (!urbp || !urb->dev) {
-		spin_unlock_irqrestore(&urb->lock, flags);
-		return;
-	}
-
-	killed = (urb->status == -ENOENT || urb->status == -ECONNABORTED ||
-			urb->status == -ECONNRESET);
-	resubmit_interrupt = (usb_pipetype(urb->pipe) == PIPE_INTERRUPT &&
-			urb->interval);
-
-	nurb = urb->next;
-	if (nurb && !killed) {
-		int count = 0;
-
-		while (nurb && nurb != urb && count < MAX_URB_LOOP) {
-			if (nurb->status == -ENOENT ||
-			    nurb->status == -ECONNABORTED ||
-			    nurb->status == -ECONNRESET) {
-				killed = 1;
-				break;
-			}
-
-			nurb = nurb->next;
-			count++;
-		}
-
-		if (count == MAX_URB_LOOP)
-			err("uhci_call_completion: too many linked URB's, loop? (first loop)");
-
-		/* Check to see if chain is a ring */
-		is_ring = (nurb == urb);
-	}
-
-	if (urbp->transfer_buffer_dma_handle)
-		pci_dma_sync_single(uhci->dev, urbp->transfer_buffer_dma_handle,
-			urb->transfer_buffer_length, usb_pipein(urb->pipe) ?
-			PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
-
-	if (urbp->setup_packet_dma_handle)
-		pci_dma_sync_single(uhci->dev, urbp->setup_packet_dma_handle,
-			sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
-
-	status = urbp->status;
-	if (!resubmit_interrupt || killed)
-		/* We don't need urb_priv anymore */
-		uhci_destroy_urb_priv(urb);
-
-	if (!killed)
-		urb->status = status;
-
-	urb->dev = NULL;
-	spin_unlock_irqrestore(&urb->lock, flags);
-
-	if (urb->complete)
-		urb->complete(urb);
-
-	if (resubmit_interrupt)
-		/* Recheck the status. The completion handler may have */
-		/*  unlinked the resubmitting interrupt URB */
-		killed = (urb->status == -ENOENT ||
-			  urb->status == -ECONNABORTED ||
-			  urb->status == -ECONNRESET);
-
-	if (resubmit_interrupt && !killed) {
-		urb->dev = dev;
-		uhci_reset_interrupt(urb);
-	} else {
-		if (is_ring && !killed) {
-			urb->dev = dev;
-			uhci_submit_urb(urb);
-		} else {
-			/* We decrement the usage count after we're done */
-			/*  with everything */
-			usb_dec_dev_use(dev);
-		}
-	}
-}
-
-static void uhci_finish_completion(struct uhci *uhci)
-{
-	struct list_head *tmp, *head;
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->complete_list_lock, flags);
-	head = &uhci->complete_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list);
-		struct urb *urb = urbp->urb;
-
-		list_del_init(&urbp->complete_list);
-		spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
-
-		uhci_call_completion(urb);
-
-		spin_lock_irqsave(&uhci->complete_list_lock, flags);
-		head = &uhci->complete_list;
-		tmp = head->next;
-	}
-	spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
-}
-
-static void uhci_remove_pending_qhs(struct uhci *uhci)
-{
-	struct list_head *tmp, *head;
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->urb_remove_list_lock, flags);
-	head = &uhci->urb_remove_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *urb = list_entry(tmp, struct urb, urb_list);
-		struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-		tmp = tmp->next;
-
-		list_del_init(&urb->urb_list);
-
-		urbp->status = urb->status = -ECONNRESET;
-
-		uhci_add_complete(urb);
-	}
-	spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags);
-}
-
-static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
-{
-	struct uhci *uhci = __uhci;
-	unsigned int io_addr = uhci->io_addr;
-	unsigned short status;
-	struct list_head *tmp, *head;
-
-	/*
-	 * Read the interrupt status, and write it back to clear the
-	 * interrupt cause
-	 */
-	status = inw(io_addr + USBSTS);
-	if (!status)	/* shared interrupt, not mine */
-		return;
-	outw(status, io_addr + USBSTS);		/* Clear it */
-
-	if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
-		if (status & USBSTS_HSE)
-			err("%x: host system error, PCI problems?", io_addr);
-		if (status & USBSTS_HCPE)
-			err("%x: host controller process error. something bad happened", io_addr);
-		if ((status & USBSTS_HCH) && !uhci->is_suspended) {
-			err("%x: host controller halted. very bad", io_addr);
-			/* FIXME: Reset the controller, fix the offending TD */
-		}
-	}
-
-	if (status & USBSTS_RD)
-		wakeup_hc(uhci);
-
-	uhci_free_pending_qhs(uhci);
-
-	uhci_remove_pending_qhs(uhci);
-
-	uhci_clear_next_interrupt(uhci);
-
-	/* Walk the list of pending URB's to see which ones completed */
-	spin_lock(&uhci->urb_list_lock);
-	head = &uhci->urb_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *urb = list_entry(tmp, struct urb, urb_list);
-
-		tmp = tmp->next;
-
-		/* Checks the status and does all of the magic necessary */
-		uhci_transfer_result(uhci, urb);
-	}
-	spin_unlock(&uhci->urb_list_lock);
-
-	uhci_finish_completion(uhci);
-}
-
-static void reset_hc(struct uhci *uhci)
-{
-	unsigned int io_addr = uhci->io_addr;
-
-	/* Global reset for 50ms */
-	outw(USBCMD_GRESET, io_addr + USBCMD);
-	wait_ms(50);
-	outw(0, io_addr + USBCMD);
-	wait_ms(10);
-}
-
-static void suspend_hc(struct uhci *uhci)
-{
-	unsigned int io_addr = uhci->io_addr;
-
-	dbg("%x: suspend_hc", io_addr);
-
-	outw(USBCMD_EGSM, io_addr + USBCMD);
-
-	uhci->is_suspended = 1;
-}
-
-static void wakeup_hc(struct uhci *uhci)
-{
-	unsigned int io_addr = uhci->io_addr;
-	unsigned int status;
-
-	dbg("%x: wakeup_hc", io_addr);
-
-	outw(0, io_addr + USBCMD);
-	
-	/* wait for EOP to be sent */
-	status = inw(io_addr + USBCMD);
-	while (status & USBCMD_FGR)
-		status = inw(io_addr + USBCMD);
-
-	uhci->is_suspended = 0;
-
-	/* Run and mark it configured with a 64-byte max packet */
-	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
-}
-
-static int ports_active(struct uhci *uhci)
-{
-	unsigned int 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) & 0x1);
-
-	return connection;
-}
-
-static void start_hc(struct uhci *uhci)
-{
-	unsigned int io_addr = uhci->io_addr;
-	int timeout = 1000;
-
-	/*
-	 * 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) {
-			printk(KERN_ERR "uhci: USBCMD_HCRESET timed out!\n");
-			break;
-		}
-	}
-
-	/* Turn on all interrupts */
-	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 */
-	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
-}
-
-#ifdef CONFIG_PROC_FS
-static int uhci_num = 0;
-#endif
-
-static void free_uhci(struct uhci *uhci)
-{
-	kfree(uhci);
-}
-
-/*
- * De-allocate all resources..
- */
-static void release_uhci(struct uhci *uhci)
-{
-	int i;
-#ifdef CONFIG_PROC_FS
-	char buf[8];
-#endif
-
-	if (uhci->irq >= 0) {
-		free_irq(uhci->irq, uhci);
-		uhci->irq = -1;
-	}
-
-	for (i = 0; i < UHCI_NUM_SKELQH; i++)
-		if (uhci->skelqh[i]) {
-			uhci_free_qh(uhci, uhci->skelqh[i]);
-			uhci->skelqh[i] = NULL;
-		}
-
-	for (i = 0; i < UHCI_NUM_SKELTD; i++)
-		if (uhci->skeltd[i]) {
-			uhci_free_td(uhci, uhci->skeltd[i]);
-			uhci->skeltd[i] = NULL;
-		}
-
-	if (uhci->qh_pool) {
-		pci_pool_destroy(uhci->qh_pool);
-		uhci->qh_pool = NULL;
-	}
-
-	if (uhci->td_pool) {
-		pci_pool_destroy(uhci->td_pool);
-		uhci->td_pool = NULL;
-	}
-
-	if (uhci->fl) {
-		pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
-		uhci->fl = NULL;
-	}
-
-	if (uhci->bus) {
-		usb_free_bus(uhci->bus);
-		uhci->bus = NULL;
-	}
-
-#ifdef CONFIG_PROC_FS
-	if (uhci->proc_entry) {
-		sprintf(buf, "hc%d", uhci->num);
-
-		remove_proc_entry(buf, uhci_proc_root);
-		uhci->proc_entry = NULL;
-	}
-#endif
-
-	free_uhci(uhci);
-}
-
-/*
- * 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 high speed
- *  - The third queue is bulk queue.
- *  - The fourth queue is the bandwidth reclamation queue, which loops back
- *    to the high speed control queue.
- */
-static int alloc_uhci(struct pci_dev *dev, unsigned int io_addr, unsigned int io_size)
-{
-	struct uhci *uhci;
-	int retval;
-	char buf[8], *bufp = buf;
-	int i, port;
-	struct usb_bus *bus;
-	dma_addr_t dma_handle;
-#ifdef CONFIG_PROC_FS
-	struct proc_dir_entry *ent;
-#endif
-
-	retval = -ENODEV;
-	if (pci_enable_device(dev) < 0) {
-		err("couldn't enable PCI device");
-		goto err_enable_device;
-	}
-
-	if (!dev->irq) {
-		err("found UHCI device with no IRQ assigned. check BIOS settings!");
-		goto err_invalid_irq;
-	}
-
-	if (!pci_dma_supported(dev, 0xFFFFFFFF)) {
-		err("PCI subsystem doesn't support 32 bit addressing?");
-		goto err_pci_dma_supported;
-	}
-
-	retval = -EBUSY;
-	if (!request_region(io_addr, io_size, "usb-uhci")) {
-		err("couldn't allocate I/O range %x - %x", io_addr,
-			io_addr + io_size - 1);
-		goto err_request_region;
-	}
-
-	pci_set_master(dev);
-
-#ifndef __sparc__
-	sprintf(buf, "%d", dev->irq);
-#else
-	bufp = __irq_itoa(dev->irq);
-#endif
-	printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n",
-		io_addr, bufp);
-
-	if (pci_set_dma_mask(dev, 0xFFFFFFFF)) {
-		err("couldn't set PCI dma mask");
-		retval = -ENODEV;
-		goto err_pci_set_dma_mask;
-	}
-
-	uhci = kmalloc(sizeof(*uhci), GFP_KERNEL);
-	if (!uhci) {
-		err("couldn't allocate uhci structure");
-		retval = -ENOMEM;
-		goto err_alloc_uhci;
-	}
-
-	uhci->dev = dev;
-	uhci->irq = dev->irq;
-	uhci->io_addr = io_addr;
-	uhci->io_size = io_size;
-	pci_set_drvdata(dev, uhci);
-
-#ifdef CONFIG_PROC_FS
-	uhci->num = uhci_num++;
-
-	sprintf(buf, "hc%d", uhci->num);
-
-	ent = create_proc_entry(buf, S_IFREG|S_IRUGO|S_IWUSR, uhci_proc_root);
-	if (!ent) {
-		err("couldn't create uhci proc entry");
-		retval = -ENOMEM;
-		goto err_create_proc_entry;
-	}
-
-	ent->data = uhci;
-	ent->proc_fops = &uhci_proc_operations;
-	ent->size = 0;
-	uhci->proc_entry = ent;
-#endif
-
-	/* Reset here so we don't get any interrupts from an old setup */
-	/*  or broken setup */
-	reset_hc(uhci);
-
-	uhci->fsbr = 0;
-	uhci->fsbrtimeout = 0;
-
-	uhci->is_suspended = 0;
-
-	spin_lock_init(&uhci->qh_remove_list_lock);
-	INIT_LIST_HEAD(&uhci->qh_remove_list);
-
-	spin_lock_init(&uhci->urb_remove_list_lock);
-	INIT_LIST_HEAD(&uhci->urb_remove_list);
-
-	spin_lock_init(&uhci->urb_list_lock);
-	INIT_LIST_HEAD(&uhci->urb_list);
-
-	spin_lock_init(&uhci->complete_list_lock);
-	INIT_LIST_HEAD(&uhci->complete_list);
-
-	spin_lock_init(&uhci->frame_list_lock);
-
-	/* We need exactly one page (per UHCI specs), how convenient */
-	/* We assume that one page is atleast 4k (1024 frames * 4 bytes) */
-#if PAGE_SIZE < (4 * 1024)
-#error PAGE_SIZE is not atleast 4k
-#endif
-	uhci->fl = pci_alloc_consistent(uhci->dev, sizeof(*uhci->fl), &dma_handle);
-	if (!uhci->fl) {
-		err("unable to allocate consistent memory for frame list");
-		goto err_alloc_fl;
-	}
-
-	memset((void *)uhci->fl, 0, sizeof(*uhci->fl));
-
-	uhci->fl->dma_handle = dma_handle;
-
-	uhci->td_pool = pci_pool_create("uhci_td", uhci->dev,
-		sizeof(struct uhci_td), 16, 0, GFP_DMA | GFP_ATOMIC);
-	if (!uhci->td_pool) {
-		err("unable to create td pci_pool");
-		goto err_create_td_pool;
-	}
-
-	uhci->qh_pool = pci_pool_create("uhci_qh", uhci->dev,
-		sizeof(struct uhci_qh), 16, 0, GFP_DMA | GFP_ATOMIC);
-	if (!uhci->qh_pool) {
-		err("unable to create qh pci_pool");
-		goto err_create_qh_pool;
-	}
-
-	bus = usb_alloc_bus(&uhci_device_operations);
-	if (!bus) {
-		err("unable to allocate bus");
-		goto err_alloc_bus;
-	}
-
-	uhci->bus = bus;
-	bus->bus_name = dev->slot_name;
-	bus->hcpriv = uhci;
-
-	usb_register_bus(uhci->bus);
-
-	/* 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 < (uhci->io_size - 0x10) / 2; port++) {
-		unsigned int portstatus;
-
-		portstatus = inw(uhci->io_addr + 0x10 + (port * 2));
-		if (!(portstatus & 0x0080))
-			break;
-	}
-	if (debug)
-		info("detected %d ports", 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 > 8) {
-		info("port count misdetected? forcing to 2 ports");
-		port = 2;
-	}
-
-	uhci->rh.numports = port;
-
-	uhci->bus->root_hub = uhci->rh.dev = usb_alloc_dev(NULL, uhci->bus);
-	if (!uhci->rh.dev) {
-		err("unable to allocate root hub");
-		goto err_alloc_root_hub;
-	}
-
-	uhci->skeltd[0] = uhci_alloc_td(uhci, uhci->rh.dev);
-	if (!uhci->skeltd[0]) {
-		err("unable to allocate TD 0");
-		goto err_alloc_skeltd;
-	}
-
-	/*
-	 * 9 Interrupt queues; link int2 to int1, int4 to int2, etc
-	 * then link int1 to control and control to bulk
-	 */
-	for (i = 1; i < 9; i++) {
-		struct uhci_td *td;
-
-		td = uhci->skeltd[i] = uhci_alloc_td(uhci, uhci->rh.dev);
-		if (!td) {
-			err("unable to allocate TD %d", i);
-			goto err_alloc_skeltd;
-		}
-
-		uhci_fill_td(td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
-		td->link = uhci->skeltd[i - 1]->dma_handle;
-	}
-
-	uhci->skel_term_td = uhci_alloc_td(uhci, uhci->rh.dev);
-	if (!uhci->skel_term_td) {
-		err("unable to allocate skel TD term");
-		goto err_alloc_skeltd;
-	}
-
-	for (i = 0; i < UHCI_NUM_SKELQH; i++) {
-		uhci->skelqh[i] = uhci_alloc_qh(uhci, uhci->rh.dev);
-		if (!uhci->skelqh[i]) {
-			err("unable to allocate QH %d", i);
-			goto err_alloc_skelqh;
-		}
-	}
-
-	uhci_fill_td(uhci->skel_int1_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
-	uhci->skel_int1_td->link = uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH;
-
-	uhci->skel_ls_control_qh->link = uhci->skel_hs_control_qh->dma_handle | UHCI_PTR_QH;
-	uhci->skel_ls_control_qh->element = UHCI_PTR_TERM;
-
-	uhci->skel_hs_control_qh->link = uhci->skel_bulk_qh->dma_handle | UHCI_PTR_QH;
-	uhci->skel_hs_control_qh->element = UHCI_PTR_TERM;
-
-	uhci->skel_bulk_qh->link = uhci->skel_term_qh->dma_handle | UHCI_PTR_QH;
-	uhci->skel_bulk_qh->element = UHCI_PTR_TERM;
-
-	/* This dummy TD is to work around a bug in Intel PIIX controllers */
-	uhci_fill_td(uhci->skel_term_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
-	uhci->skel_term_td->link = uhci->skel_term_td->dma_handle;
-
-	uhci->skel_term_qh->link = UHCI_PTR_TERM;
-	uhci->skel_term_qh->element = uhci->skel_term_td->dma_handle;
-
-	/*
-	 * Fill the frame list: make all entries point to
-	 * the proper interrupt queue.
-	 *
-	 * This is probably silly, but it's a simple way to
-	 * scatter the interrupt queues in a way that gives
-	 * us a reasonable dynamic range for irq latencies.
-	 */
-	for (i = 0; i < UHCI_NUMFRAMES; i++) {
-		int irq = 0;
-
-		if (i & 1) {
-			irq++;
-			if (i & 2) {
-				irq++;
-				if (i & 4) { 
-					irq++;
-					if (i & 8) { 
-						irq++;
-						if (i & 16) {
-							irq++;
-							if (i & 32) {
-								irq++;
-								if (i & 64)
-									irq++;
-							}
-						}
-					}
-				}
-			}
-		}
-
-		/* Only place we don't use the frame list routines */
-		uhci->fl->frame[i] =  uhci->skeltd[irq]->dma_handle;
-	}
-
-	start_hc(uhci);
-
-	if (request_irq(dev->irq, uhci_interrupt, SA_SHIRQ, "usb-uhci", uhci))
-		goto err_request_irq;
-
-	/* disable legacy emulation */
-	pci_write_config_word(uhci->dev, USBLEGSUP, USBLEGSUP_DEFAULT);
-
-	usb_connect(uhci->rh.dev);
-
-	if (usb_new_device(uhci->rh.dev) != 0) {
-		err("unable to start root hub");
-		retval = -ENOMEM;
-		goto err_start_root_hub;
-	}
-
-	return 0;
-
-/*
- * error exits:
- */
-err_start_root_hub:
-	free_irq(uhci->irq, uhci);
-	uhci->irq = -1;
-
-err_request_irq:
-	for (i = 0; i < UHCI_NUM_SKELQH; i++)
-		if (uhci->skelqh[i]) {
-			uhci_free_qh(uhci, uhci->skelqh[i]);
-			uhci->skelqh[i] = NULL;
-		}
-
-err_alloc_skelqh:
-	for (i = 0; i < UHCI_NUM_SKELTD; i++)
-		if (uhci->skeltd[i]) {
-			uhci_free_td(uhci, uhci->skeltd[i]);
-			uhci->skeltd[i] = NULL;
-		}
-
-err_alloc_skeltd:
-	usb_free_dev(uhci->rh.dev);
-	uhci->rh.dev = NULL;
-
-err_alloc_root_hub:
-	usb_free_bus(uhci->bus);
-	uhci->bus = NULL;
-
-err_alloc_bus:
-	pci_pool_destroy(uhci->qh_pool);
-	uhci->qh_pool = NULL;
-
-err_create_qh_pool:
-	pci_pool_destroy(uhci->td_pool);
-	uhci->td_pool = NULL;
-
-err_create_td_pool:
-	pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
-	uhci->fl = NULL;
-
-err_alloc_fl:
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry(buf, uhci_proc_root);
-	uhci->proc_entry = NULL;
-
-err_create_proc_entry:
-	free_uhci(uhci);
-#endif
-
-err_alloc_uhci:
-
-err_pci_set_dma_mask:
-	release_region(io_addr, io_size);
-
-err_request_region:
-
-err_pci_dma_supported:
-
-err_invalid_irq:
-
-err_enable_device:
-
-	return retval;
-}
-
-static int __devinit uhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
-	int i;
-
-	/* Search for the IO base address.. */
-	for (i = 0; i < 6; i++) {
-		unsigned int io_addr = pci_resource_start(dev, i);
-		unsigned int io_size = pci_resource_len(dev, i);
-
-		/* IO address? */
-		if (!(pci_resource_flags(dev, i) & IORESOURCE_IO))
-			continue;
-
-		return alloc_uhci(dev, io_addr, io_size);
-	}
-
-	return -ENODEV;
-}
-
-static void __devexit uhci_pci_remove(struct pci_dev *dev)
-{
-	struct uhci *uhci = pci_get_drvdata(dev);
-
-	if (uhci->bus->root_hub)
-		usb_disconnect(&uhci->bus->root_hub);
-
-	usb_deregister_bus(uhci->bus);
-
-	/*
-	 * At this point, we're guaranteed that no new connects can be made
-	 * to this bus since there are no more parents
-	 */
-	uhci_free_pending_qhs(uhci);
-	uhci_remove_pending_qhs(uhci);
-
-	reset_hc(uhci);
-	release_region(uhci->io_addr, uhci->io_size);
-
-	uhci_free_pending_qhs(uhci);
-
-	release_uhci(uhci);
-}
-
-#ifdef CONFIG_PM
-static int uhci_pci_suspend(struct pci_dev *dev, u32 state)
-{
-	suspend_hc((struct uhci *) pci_get_drvdata(dev));
-	return 0;
-}
-
-static int uhci_pci_resume(struct pci_dev *dev)
-{
-	reset_hc((struct uhci *) pci_get_drvdata(dev));
-	start_hc((struct uhci *) pci_get_drvdata(dev));
-	return 0;
-}
-#endif
-
-static const struct pci_device_id __devinitdata uhci_pci_ids[] = { {
-
-	/* handle any USB UHCI controller */
-	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x00),
-	class_mask: 	~0,
-
-	/* no matter who makes it */
-	vendor:		PCI_ANY_ID,
-	device:		PCI_ANY_ID,
-	subvendor:	PCI_ANY_ID,
-	subdevice:	PCI_ANY_ID,
-
-	}, { /* end: all zeroes */ }
-};
-
-MODULE_DEVICE_TABLE(pci, uhci_pci_ids);
-
-static struct pci_driver uhci_pci_driver = {
-	name:		"usb-uhci",
-	id_table:	uhci_pci_ids,
-
-	probe:		uhci_pci_probe,
-	remove:		__devexit_p(uhci_pci_remove),
-
-#ifdef	CONFIG_PM
-	suspend:	uhci_pci_suspend,
-	resume:		uhci_pci_resume,
-#endif	/* PM */
-};
-
- 
-static int __init uhci_hcd_init(void)
-{
-	int retval = -ENOMEM;
-
-	info(DRIVER_DESC " " DRIVER_VERSION);
-
-	if (debug) {
-		errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
-		if (!errbuf)
-			goto errbuf_failed;
-	}
-
-#ifdef CONFIG_PROC_FS
-	uhci_proc_root = create_proc_entry("driver/uhci", S_IFDIR, 0);
-	if (!uhci_proc_root)
-		goto proc_failed;
-#endif
-
-	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_module_init(&uhci_pci_driver);
-	if (retval)
-		goto init_failed;
-
-	return 0;
-
-init_failed:
-	if (kmem_cache_destroy(uhci_up_cachep))
-		printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
-
-up_failed:
-
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry("driver/uhci", 0);
-
-proc_failed:
-#endif
-	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))
-		printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
-
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry("driver/uhci", 0);
-#endif
-
-	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 -Nru a/drivers/usb/uhci.h b/drivers/usb/uhci.h
--- a/drivers/usb/uhci.h	Thu Mar  6 14:22:16 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,441 +0,0 @@
-#ifndef __LINUX_UHCI_H
-#define __LINUX_UHCI_H
-
-#include <linux/list.h>
-#include <linux/usb.h>
-
-/*
- * 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_LS		0x0030	/* Line Status */
-#define   USBPORTSC_RD		0x0040	/* Resume Detect */
-#define   USBPORTSC_LSDA	0x0100	/* Low Speed Device Attached */
-#define   USBPORTSC_PR		0x0200	/* Port Reset */
-#define   USBPORTSC_SUSP	0x1000	/* Suspend */
-
-/* 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		0x000F
-#define UHCI_PTR_TERM		0x0001
-#define UHCI_PTR_QH		0x0002
-#define UHCI_PTR_DEPTH		0x0004
-
-#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 {
-	__u32 frame[UHCI_NUMFRAMES];
-
-	void *frame_cpu[UHCI_NUMFRAMES];
-
-	dma_addr_t dma_handle;
-};
-
-struct urb_priv;
-
-struct uhci_qh {
-	/* Hardware fields */
-	__u32 link;			/* Next queue */
-	__u32 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)));
-
-/*
- * 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_status_bits(ctrl_sts)	(ctrl_sts & 0xFE0000)
-#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_TOGGLE_SHIFT	19
-#define TD_TOKEN_TOGGLE		(1 << 19)
-#define TD_TOKEN_PID_MASK	0xFF
-#define TD_TOKEN_EXPLEN_MASK	0x7FF		/* expected length, encoded as n - 1 */
-
-#define uhci_maxlen(token)	((token) >> 21)
-#define uhci_expected_length(info) (((info >> 21) + 1) & TD_TOKEN_EXPLEN_MASK) /* 1-based */
-#define uhci_toggle(token)	(((token) >> TD_TOKEN_TOGGLE_SHIFT) & 1)
-#define uhci_endpoint(token)	(((token) >> 15) & 0xf)
-#define uhci_devaddr(token)	(((token) >> 8) & 0x7f)
-#define uhci_devep(token)	(((token) >> 8) & 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
- */
-struct uhci_td {
-	/* Hardware fields */
-	__u32 link;
-	__u32 status;
-	__u32 info;
-	__u32 buffer;
-
-	/* Software fields */
-	dma_addr_t dma_handle;
-
-	struct usb_device *dev;
-	struct urb *urb;
-
-	struct list_head list;		/* P: urb->lock */
-
-	int frame;
-	struct list_head fl_list;	/* P: uhci->frame_list_lock */
-} __attribute__((aligned(16)));
-
-/*
- * There are various standard queues. We set up several different
- * queues for each of the three basic queue types: interrupt,
- * control, and bulk.
- *
- *  - There are various different interrupt latencies: ranging from
- *    every other USB frame (2 ms apart) to every 256 USB frames (ie
- *    256 ms apart). Make your choice according to how obnoxious you
- *    want to be on the wire, vs how critical latency is for you.
- *  - The control list is done every frame.
- *  - There are 4 bulk lists, so that up to four devices can have a
- *    bulk list of their own and when run concurrently all four lists
- *    will be be serviced.
- *
- * This is a bit misleading, there are various interrupt latencies, but they
- * vary a bit, interrupt2 isn't exactly 2ms, it can vary up to 4ms since the
- * other queues can "override" it. interrupt4 can vary up to 8ms, etc. Minor
- * problem
- *
- * In the case of the root hub, these QH's are just head's of qh's. Don't
- * be scared, it kinda makes sense. Look at this wonderful picture care of
- * Linus:
- *
- *  generic-  ->  dev1-  ->  generic-  ->  dev1-  ->  control-  ->  bulk- -> ...
- *   iso-QH      iso-QH       irq-QH      irq-QH        QH           QH
- *      |           |            |           |           |            |
- *     End     dev1-iso-TD1     End     dev1-irq-TD1    ...          ... 
- *                  |
- *             dev1-iso-TD2
- *                  |
- *                ....
- *
- * This may vary a bit (the UHCI docs don't explicitly say you can put iso
- * transfers in QH's and all of their pictures don't have that either) but
- * other than that, that is what we're doing now
- *
- * And now we don't put Iso transfers in QH's, so we don't waste one on it
- * --jerdfelt
- *
- * To keep with Linus' nomenclature, this is called the QH skeleton. These
- * labels (below) are only signficant to the root hub's QH's
- */
-
-#define UHCI_NUM_SKELTD		10
-#define skel_int1_td		skeltd[0]
-#define skel_int2_td		skeltd[1]
-#define skel_int4_td		skeltd[2]
-#define skel_int8_td		skeltd[3]
-#define skel_int16_td		skeltd[4]
-#define skel_int32_td		skeltd[5]
-#define skel_int64_td		skeltd[6]
-#define skel_int128_td		skeltd[7]
-#define skel_int256_td		skeltd[8]
-#define skel_term_td		skeltd[9]	/* To work around PIIX UHCI bug */
-
-#define UHCI_NUM_SKELQH		4
-#define skel_ls_control_qh	skelqh[0]
-#define skel_hs_control_qh	skelqh[1]
-#define skel_bulk_qh		skelqh[2]
-#define skel_term_qh		skelqh[3]
-
-/*
- * 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.
- *
- * NOTE: For UHCI, we don't really need int256_qh since the maximum interval
- * is 255 ms.  However, we do need an int1_qh since 1 is a valid interval
- * and we should meet that frequency when requested to do so.
- * This will require some change(s) to the UHCI skeleton.
- */
-static inline int __interval_to_skel(int interval)
-{
-	if (interval < 16) {
-		if (interval < 4) {
-			if (interval < 2)
-				return 0;	/* int1 for 0-1 ms */
-			return 1;		/* int2 for 2-3 ms */
-		}
-		if (interval < 8)
-			return 2;		/* int4 for 4-7 ms */
-		return 3;			/* int8 for 8-15 ms */
-	}
-	if (interval < 64) {
-		if (interval < 32)
-			return 4;		/* int16 for 16-31 ms */
-		return 5;			/* int32 for 32-63 ms */
-	}
-	if (interval < 128)
-		return 6;			/* int64 for 64-127 ms */
-	return 7;				/* int128 for 128-255 ms (Max.) */
-}
-
-struct virt_root_hub {
-	struct usb_device *dev;
-	int devnum;		/* Address of Root Hub endpoint */
-	struct urb *urb;
-	void *int_addr;
-	int send;
-	int interval;
-	int numports;
-	int c_p_r[8];
-	struct timer_list rh_int_timer;
-};
-
-/*
- * This describes the full uhci information.
- *
- * Note how the "proper" USB information is just
- * a subset of what the full implementation needs.
- */
-struct uhci {
-	struct pci_dev *dev;
-
-#ifdef CONFIG_PROC_FS
-	/* procfs */
-	int num;
-	struct proc_dir_entry *proc_entry;
-#endif
-
-	/* Grabbed from PCI */
-	int irq;
-	unsigned int io_addr;
-	unsigned int io_size;
-
-	struct pci_pool *qh_pool;
-	struct pci_pool *td_pool;
-
-	struct usb_bus *bus;
-
-	struct uhci_td *skeltd[UHCI_NUM_SKELTD];	/* Skeleton TD's */
-	struct uhci_qh *skelqh[UHCI_NUM_SKELQH];	/* Skeleton QH's */
-
-	spinlock_t frame_list_lock;
-	struct uhci_frame_list *fl;		/* P: uhci->frame_list_lock */
-	int fsbr;				/* Full speed bandwidth reclamation */
-	unsigned long fsbrtimeout;		/* FSBR delay */
-	int is_suspended;
-
-	/* Main list of URB's currently controlled by this HC */
-	spinlock_t urb_list_lock;
-	struct list_head urb_list;		/* P: uhci->urb_list_lock */
-
-	/* List of QH's that are done, but waiting to be unlinked (race) */
-	spinlock_t qh_remove_list_lock;
-	struct list_head qh_remove_list;	/* P: uhci->qh_remove_list_lock */
-
-	/* List of asynchronously unlinked URB's */
-	spinlock_t urb_remove_list_lock;
-	struct list_head urb_remove_list;	/* P: uhci->urb_remove_list_lock */
-
-	/* List of URB's awaiting completion callback */
-	spinlock_t complete_list_lock;
-	struct list_head complete_list;		/* P: uhci->complete_list_lock */
-
-	struct virt_root_hub rh;	/* private data of the virtual root hub */
-};
-
-struct urb_priv {
-	struct urb *urb;
-	struct usb_device *dev;
-
-	dma_addr_t setup_packet_dma_handle;
-	dma_addr_t transfer_buffer_dma_handle;
-
-	struct uhci_qh *qh;		/* QH for this URB */
-	struct list_head td_list;	/* P: urb->lock */
-
-	int fsbr : 1;			/* URB turned on FSBR */
-	int fsbr_timeout : 1;		/* URB timed out on FSBR */
-	int queued : 1;			/* QH was queued (not linked in) */
-	int short_control_packet : 1;	/* If we get a short packet during */
-					/*  a control transfer, retrigger */
-					/*  the status phase */
-
-	int status;			/* Final status */
-
-	unsigned long inserttime;	/* In jiffies */
-	unsigned long fsbrtime;		/* In jiffies */
-
-	struct list_head queue_list;	/* P: uhci->frame_list_lock */
-	struct list_head complete_list;	/* P: uhci->complete_list_lock */
-};
-
-/*
- * Locking in uhci.c
- *
- * spinlocks are used extensively to protect the many lists and data
- * structures we have. It's not that pretty, but it's necessary. We
- * need to be done with all of the locks (except complete_list_lock) when
- * we call urb->complete. I've tried to make it simple enough so I don't
- * have to spend hours racking my brain trying to figure out if the
- * locking is safe.
- *
- * Here's the safe locking order to prevent deadlocks:
- *
- * #1 uhci->urb_list_lock
- * #2 urb->lock
- * #3 uhci->urb_remove_list_lock, uhci->frame_list_lock, 
- *   uhci->qh_remove_list_lock
- * #4 uhci->complete_list_lock
- *
- * If you're going to grab 2 or more locks at once, ALWAYS grab the lock
- * at the lowest level FIRST and NEVER grab locks at the same level at the
- * same time.
- * 
- * So, if you need uhci->urb_list_lock, grab it before you grab urb->lock
- */
-
-/* -------------------------------------------------------------------------
-   Virtual Root HUB
-   ------------------------------------------------------------------------- */
-/* destination of request */
-#define RH_DEVICE		0x00
-#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
-
-#endif
-
diff -Nru a/drivers/usb/usb-uhci-debug.h b/drivers/usb/usb-uhci-debug.h
--- a/drivers/usb/usb-uhci-debug.h	Thu Mar  6 14:22:16 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,195 +0,0 @@
-#ifdef DEBUG
-static void __attribute__((__unused__)) uhci_show_qh (puhci_desc_t qh)
-{
-	if (qh->type != QH_TYPE) {
-		dbg("qh has not QH_TYPE");
-		return;
-	}
-	dbg("QH @ %p/%08llX:", qh, (unsigned long long)qh->dma_addr);
-
-	if (qh->hw.qh.head & UHCI_PTR_TERM)
-		dbg("    Head Terminate");
-	else 
-		dbg("    Head: %s @ %08X",
-		    (qh->hw.qh.head & UHCI_PTR_QH?"QH":"TD"),
-		    qh->hw.qh.head & ~UHCI_PTR_BITS);
-
-	if (qh->hw.qh.element & UHCI_PTR_TERM)
-		dbg("    Element Terminate");
-	else 
-		dbg("    Element: %s @ %08X",
-		    (qh->hw.qh.element & UHCI_PTR_QH?"QH":"TD"),
-		    qh->hw.qh.element & ~UHCI_PTR_BITS);
-}
-#endif
-
-#if 0
-static void uhci_show_td (puhci_desc_t td)
-{
-	char *spid;
-	
-	switch (td->hw.td.info & 0xff) {
-	case USB_PID_SETUP:
-		spid = "SETUP";
-		break;
-	case USB_PID_OUT:
-		spid = " OUT ";
-		break;
-	case USB_PID_IN:
-		spid = " IN  ";
-		break;
-	default:
-		spid = "  ?  ";
-		break;
-	}
-
-	warn("  TD @ %p/%08X, MaxLen=%02x DT%d EP=%x Dev=%x PID=(%s) buf=%08x",
-	     td, td->dma_addr,
-	     td->hw.td.info >> 21,
-	     ((td->hw.td.info >> 19) & 1),
-	     (td->hw.td.info >> 15) & 15,
-	     (td->hw.td.info >> 8) & 127,
-	     spid,
-	     td->hw.td.buffer);
-
-	warn("    Len=%02x e%d %s%s%s%s%s%s%s%s%s%s",
-	     td->hw.td.status & 0x7ff,
-	     ((td->hw.td.status >> 27) & 3),
-	     (td->hw.td.status & TD_CTRL_SPD) ? "SPD " : "",
-	     (td->hw.td.status & TD_CTRL_LS) ? "LS " : "",
-	     (td->hw.td.status & TD_CTRL_IOC) ? "IOC " : "",
-	     (td->hw.td.status & TD_CTRL_ACTIVE) ? "Active " : "",
-	     (td->hw.td.status & TD_CTRL_STALLED) ? "Stalled " : "",
-	     (td->hw.td.status & TD_CTRL_DBUFERR) ? "DataBufErr " : "",
-	     (td->hw.td.status & TD_CTRL_BABBLE) ? "Babble " : "",
-	     (td->hw.td.status & TD_CTRL_NAK) ? "NAK " : "",
-	     (td->hw.td.status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
-	     (td->hw.td.status & TD_CTRL_BITSTUFF) ? "BitStuff " : ""
-		);
-
-	if (td->hw.td.link & UHCI_PTR_TERM)
-		warn("   TD Link Terminate");
-	else 
-		warn("    Link points to %s @ %08x, %s",
-		     (td->hw.td.link & UHCI_PTR_QH?"QH":"TD"),
-		     td->hw.td.link & ~UHCI_PTR_BITS,
-		     (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : "Breadth first"));
-}
-#endif
-
-#ifdef DEBUG
-static void __attribute__((__unused__)) uhci_show_td_queue (puhci_desc_t td)
-{
-	//dbg("uhci_show_td_queue %p (%08lX):", td, td->dma_addr);
-#if 1
-	return;
-#else
-	while (1) {
-		uhci_show_td (td);
-		if (td->hw.td.link & UHCI_PTR_TERM)
-			break;
-		if (td != bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS))
-			td = bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS);
-		else {
-			dbg("td points to itself!");
-			break;
-		}
-	}
-#endif
-}
-
-static void __attribute__((__unused__)) uhci_show_queue (puhci_desc_t qh)
-{
-#if 0
-	uhci_desc_t *start_qh=qh;
-#endif
-
-	dbg("uhci_show_queue %p:", qh);
-#if 1
-	return;
-#else
-	while (1) {
-		uhci_show_qh (qh);
-
-		if (!(qh->hw.qh.element & UHCI_PTR_TERM))
-			uhci_show_td_queue (bus_to_virt (qh->hw.qh.element & ~UHCI_PTR_BITS));
-
-		if (qh->hw.qh.head & UHCI_PTR_TERM)
-			break;
-
-		if (qh != bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS))
-			qh = bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS);
-		else {
-			dbg("qh points to itself!");
-			break;
-		}
-		
-		if (qh==start_qh) { // avoid loop
-			dbg("Loop detect");
-			break;
-		}
-	}		
-#endif
-}
-
-static void __attribute__((__unused__)) uhci_show_sc (int port, unsigned short status)
-{
-	dbg("  stat%d     =     %04x   %s%s%s%s%s%s%s%s",
-	     port,
-	     status,
-	     (status & USBPORTSC_SUSP) ? "PortSuspend " : "",
-	     (status & USBPORTSC_PR) ? "PortReset " : "",
-	     (status & USBPORTSC_LSDA) ? "LowSpeed " : "",
-	     (status & USBPORTSC_RD) ? "ResumeDetect " : "",
-	     (status & USBPORTSC_PEC) ? "EnableChange " : "",
-	     (status & USBPORTSC_PE) ? "PortEnabled " : "",
-	     (status & USBPORTSC_CSC) ? "ConnectChange " : "",
-	     (status & USBPORTSC_CCS) ? "PortConnected " : "");
-}
-
-void uhci_show_status (puhci_t s)
-{
-	unsigned int io_addr = s->io_addr;
-	unsigned short usbcmd, usbstat, usbint, usbfrnum;
-	unsigned int flbaseadd;
-	unsigned char sof;
-	unsigned short portsc1, portsc2;
-
-	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);
-
-	dbg("  usbcmd    =     %04x   %s%s%s%s%s%s%s%s",
-	     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 " : "");
-
-	dbg("  usbstat   =     %04x   %s%s%s%s%s%s",
-	     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 " : "");
-
-	dbg("  usbint    =     %04x", usbint);
-	dbg("  usbfrnum  =   (%d)%03x", (usbfrnum >> 10) & 1,
-	     0xfff & (4 * (unsigned int) usbfrnum));
-	dbg("  flbaseadd = %08x", flbaseadd);
-	dbg("  sof       =       %02x", sof);
-	uhci_show_sc (1, portsc1);
-	uhci_show_sc (2, portsc2);
-}
-#endif
diff -Nru a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
--- a/drivers/usb/usb-uhci.c	Thu Mar  6 14:22:16 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,3143 +0,0 @@
-/* 
- * Universal Host Controller Interface driver for USB (take II).
- *
- * (c) 1999-2001 Georg Acher, acher@in.tum.de (executive slave) (base guitar)
- *               Deti Fliegl, deti@fliegl.de (executive slave) (lead voice)
- *               Thomas Sailer, sailer@ife.ee.ethz.ch (chief consultant) (cheer leader)
- *               Roman Weissgaerber, weissg@vienna.at (virt root hub) (studio porter)
- * (c) 2000      Yggdrasil Computing, Inc. (port of new PCI interface support
- *               from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
- * (C) 2000      David Brownell, david-b@pacbell.net (usb-ohci.c)
- *          
- * HW-initalization based on material of
- *
- * (C) Copyright 1999 Linus Torvalds
- * (C) Copyright 1999 Johannes Erdfelt
- * (C) Copyright 1999 Randy Dunlap
- * (C) Copyright 1999 Gregory P. Smith
- *
- * $Id: usb-uhci.c,v 1.275 2002/01/19 20:57:33 acher Exp $
- */
-
-#include <linux/config.h>
-#include <linux/module.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/unistd.h>
-#include <linux/interrupt.h>	/* for in_interrupt() */
-#include <linux/init.h>
-#include <linux/version.h>
-#include <linux/pm.h>
-#include <linux/timer.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-/* This enables more detailed sanity checks in submit_iso */
-//#define ISO_SANITY_CHECK
-
-/* This enables debug printks */
-#define DEBUG
-
-/* This enables all symbols to be exported, to ease debugging oopses */
-//#define DEBUG_SYMBOLS
-
-/* This enables an extra UHCI slab for memory debugging */
-#define DEBUG_SLAB
-
-#define VERSTR "$Revision: 1.275 $ time " __TIME__ " " __DATE__
-
-#include <linux/usb.h>
-#include "usb-uhci.h"
-#include "usb-uhci-debug.h"
-
-#include "hcd.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.275"
-#define DRIVER_AUTHOR "Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
-#define DRIVER_DESC "USB Universal Host Controller Interface driver"
-
-#undef DEBUG
-#undef dbg
-#define dbg(format, arg...) do {} while (0)
-#define DEBUG_SYMBOLS
-#ifdef DEBUG_SYMBOLS
-	#define _static
-	#ifndef EXPORT_SYMTAB
-		#define EXPORT_SYMTAB
-	#endif
-#else
-	#define _static static
-#endif
-
-#define queue_dbg dbg //err
-#define async_dbg dbg //err
-
-#ifdef DEBUG_SLAB
-	static kmem_cache_t *urb_priv_kmem;
-#endif
-
-#define SLAB_FLAG     (in_interrupt () || current->state != TASK_RUNNING ? SLAB_ATOMIC : SLAB_KERNEL)
-#define KMALLOC_FLAG  (in_interrupt () || current->state != TASK_RUNNING ? GFP_ATOMIC : GFP_KERNEL)
-
-/* CONFIG_USB_UHCI_HIGH_BANDWITH turns on Full Speed Bandwidth
- * Reclamation: feature that puts loop on descriptor loop when
- * there's some transfer going on. With FSBR, USB performance
- * is optimal, but PCI can be slowed down up-to 5 times, slowing down
- * system performance (eg. framebuffer devices).
- */
-#define CONFIG_USB_UHCI_HIGH_BANDWIDTH
-
-/* *_DEPTH_FIRST puts descriptor in depth-first mode. This has
- * somehow similar effect to FSBR (higher speed), but does not
- * slow PCI down. OTOH USB performace is slightly slower than
- * in FSBR case and single device could hog whole USB, starving
- * other devices.
- */
-#define USE_CTRL_DEPTH_FIRST 0  // 0: Breadth first, 1: Depth first
-#define USE_BULK_DEPTH_FIRST 0  // 0: Breadth first, 1: Depth first
-
-/* Turning off both CONFIG_USB_UHCI_HIGH_BANDWITH and *_DEPTH_FIRST
- * will lead to <64KB/sec performance over USB for bulk transfers targeting
- * one device's endpoint. You probably do not want to do that.
- */
-
-// stop bandwidth reclamation after (roughly) 50ms
-#define IDLE_TIMEOUT  (HZ/20)
-
-// Suppress HC interrupt error messages for 5s
-#define ERROR_SUPPRESSION_TIME (HZ*5)
-
-_static int rh_submit_urb (struct urb *urb);
-_static int rh_unlink_urb (struct urb *urb);
-_static int delete_qh (uhci_t *s, uhci_desc_t *qh);
-_static int process_transfer (uhci_t *s, struct urb *urb, int mode);
-_static int process_interrupt (uhci_t *s, struct urb *urb);
-_static int process_iso (uhci_t *s, struct urb *urb, int force);
-
-// How much URBs with ->next are walked
-#define MAX_NEXT_COUNT 2048
-
-static uhci_t *devs = NULL;
-
-/* used by userspace UHCI data structure dumper */
-uhci_t **uhci_devices = &devs;
-
-/*-------------------------------------------------------------------*/
-// Cleans up collected QHs, but not more than 100 in one go
-void clean_descs(uhci_t *s, int force)
-{
-	struct list_head *q;
-	uhci_desc_t *qh;
-	int now=UHCI_GET_CURRENT_FRAME(s), n=0;
-
-	q=s->free_desc.prev;
-
-	while (q != &s->free_desc && (force || n<100)) {
-		qh = list_entry (q, uhci_desc_t, horizontal);
-		q=qh->horizontal.prev;
-
-		if ((qh->last_used!=now) || force)
-			delete_qh(s,qh);
-		n++;
-	}
-}
-/*-------------------------------------------------------------------*/
-_static void uhci_switch_timer_int(uhci_t *s)
-{
-
-	if (!list_empty(&s->urb_unlinked))
-		set_td_ioc(s->td1ms);
-	else
-		clr_td_ioc(s->td1ms);
-
-	if (s->timeout_urbs)
-		set_td_ioc(s->td32ms);
-	else
-		clr_td_ioc(s->td32ms);
-	wmb();
-}
-/*-------------------------------------------------------------------*/
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-_static void enable_desc_loop(uhci_t *s, struct urb *urb)
-{
-	unsigned long flags;
-
-	if (urb->transfer_flags & USB_NO_FSBR)
-		return;
-
-	spin_lock_irqsave (&s->qh_lock, flags);
-	s->chain_end->hw.qh.head&=cpu_to_le32(~UHCI_PTR_TERM);
-	mb();
-	s->loop_usage++;
-	((urb_priv_t*)urb->hcpriv)->use_loop=1;
-	spin_unlock_irqrestore (&s->qh_lock, flags);
-}
-/*-------------------------------------------------------------------*/
-_static void disable_desc_loop(uhci_t *s, struct urb *urb)
-{
-	unsigned long flags;
-
-	if (urb->transfer_flags & USB_NO_FSBR)
-		return;
-
-	spin_lock_irqsave (&s->qh_lock, flags);
-	if (((urb_priv_t*)urb->hcpriv)->use_loop) {
-		s->loop_usage--;
-
-		if (!s->loop_usage) {
-			s->chain_end->hw.qh.head|=cpu_to_le32(UHCI_PTR_TERM);
-			mb();
-		}
-		((urb_priv_t*)urb->hcpriv)->use_loop=0;
-	}
-	spin_unlock_irqrestore (&s->qh_lock, flags);
-}
-#endif
-/*-------------------------------------------------------------------*/
-_static void queue_urb_unlocked (uhci_t *s, struct urb *urb)
-{
-	struct list_head *p=&urb->urb_list;
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-	{
-		int type;
-		type=usb_pipetype (urb->pipe);
-
-		if ((type == PIPE_BULK) || (type == PIPE_CONTROL))
-			enable_desc_loop(s, urb);
-	}
-#endif
-	urb->status = -EINPROGRESS;
-	((urb_priv_t*)urb->hcpriv)->started=jiffies;
-	list_add (p, &s->urb_list);
-	if (urb->timeout)
-		s->timeout_urbs++;
-	uhci_switch_timer_int(s);
-}
-/*-------------------------------------------------------------------*/
-_static void queue_urb (uhci_t *s, struct urb *urb)
-{
-	unsigned long flags=0;
-
-	spin_lock_irqsave (&s->urb_list_lock, flags);
-	queue_urb_unlocked(s,urb);
-	spin_unlock_irqrestore (&s->urb_list_lock, flags);
-}
-/*-------------------------------------------------------------------*/
-_static void dequeue_urb (uhci_t *s, struct urb *urb)
-{
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-	int type;
-
-	type=usb_pipetype (urb->pipe);
-
-	if ((type == PIPE_BULK) || (type == PIPE_CONTROL))
-		disable_desc_loop(s, urb);
-#endif
-
-	list_del (&urb->urb_list);
-	if (urb->timeout && s->timeout_urbs)
-		s->timeout_urbs--;
-
-}
-/*-------------------------------------------------------------------*/
-_static int alloc_td (uhci_t *s, uhci_desc_t ** new, int flags)
-{
-	dma_addr_t dma_handle;
-
-	*new = pci_pool_alloc(s->desc_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
-	if (!*new)
-		return -ENOMEM;
-	memset (*new, 0, sizeof (uhci_desc_t));
-	(*new)->dma_addr = dma_handle;
-	set_td_link((*new), UHCI_PTR_TERM | (flags & UHCI_PTR_BITS));	// last by default
-	(*new)->type = TD_TYPE;
-	mb();
-	INIT_LIST_HEAD (&(*new)->vertical);
-	INIT_LIST_HEAD (&(*new)->horizontal);
-	
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-// append a qh to td.link physically, the SW linkage is not affected
-_static void append_qh(uhci_t *s, uhci_desc_t *td, uhci_desc_t* qh, int  flags)
-{
-	unsigned long xxx;
-	
-	spin_lock_irqsave (&s->td_lock, xxx);
-
-	set_td_link(td, qh->dma_addr | (flags & UHCI_PTR_DEPTH) | UHCI_PTR_QH);
-       
-	mb();
-	spin_unlock_irqrestore (&s->td_lock, xxx);
-}
-/*-------------------------------------------------------------------*/
-/* insert td at last position in td-list of qh (vertical) */
-_static int insert_td (uhci_t *s, uhci_desc_t *qh, uhci_desc_t* new, int flags)
-{
-	uhci_desc_t *prev;
-	unsigned long xxx;
-	
-	spin_lock_irqsave (&s->td_lock, xxx);
-
-	list_add_tail (&new->vertical, &qh->vertical);
-
-	prev = list_entry (new->vertical.prev, uhci_desc_t, vertical);
-
-	if (qh == prev ) {
-		// virgin qh without any tds
-		set_qh_element(qh, new->dma_addr | UHCI_PTR_TERM);
-	}
-	else {
-		// already tds inserted, implicitely remove TERM bit of prev
-		set_td_link(prev, new->dma_addr | (flags & UHCI_PTR_DEPTH));
-	}
-	mb();
-	spin_unlock_irqrestore (&s->td_lock, xxx);
-	
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-/* insert new_td after td (horizontal) */
-_static int insert_td_horizontal (uhci_t *s, uhci_desc_t *td, uhci_desc_t* new)
-{
-	uhci_desc_t *next;
-	unsigned long flags;
-	
-	spin_lock_irqsave (&s->td_lock, flags);
-
-	next = list_entry (td->horizontal.next, uhci_desc_t, horizontal);
-	list_add (&new->horizontal, &td->horizontal);
-	new->hw.td.link = td->hw.td.link;
-	set_td_link(td, new->dma_addr);
-	mb();
-	spin_unlock_irqrestore (&s->td_lock, flags);	
-	
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-_static int unlink_td (uhci_t *s, uhci_desc_t *element, int phys_unlink)
-{
-	uhci_desc_t *next, *prev;
-	int dir = 0;
-	unsigned long flags;
-	
-	spin_lock_irqsave (&s->td_lock, flags);
-	
-	next = list_entry (element->vertical.next, uhci_desc_t, vertical);
-	
-	if (next == element) {
-		dir = 1;
-		prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal);
-	}
-	else 
-		prev = list_entry (element->vertical.prev, uhci_desc_t, vertical);
-	
-	if (phys_unlink) {
-		// really remove HW linking
-		if (prev->type == TD_TYPE)
-			prev->hw.td.link = element->hw.td.link;
-		else
-			prev->hw.qh.element = element->hw.td.link;
-	}
-
-	mb ();
-
-	if (dir == 0)
-		list_del (&element->vertical);
-	else
-		list_del (&element->horizontal);
-	
-	spin_unlock_irqrestore (&s->td_lock, flags);	
-	
-	return 0;
-}
-
-/*-------------------------------------------------------------------*/
-_static int delete_desc (uhci_t *s, uhci_desc_t *element)
-{
-	pci_pool_free(s->desc_pool, element, element->dma_addr);
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-// Allocates qh element
-_static int alloc_qh (uhci_t *s, uhci_desc_t ** new)
-{
-	dma_addr_t dma_handle;
-
-	*new = pci_pool_alloc(s->desc_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
-	if (!*new)
-		return -ENOMEM;
-	memset (*new, 0, sizeof (uhci_desc_t));
-	(*new)->dma_addr = dma_handle;
-	set_qh_head(*new, UHCI_PTR_TERM);
-	set_qh_element(*new, UHCI_PTR_TERM);
-	(*new)->type = QH_TYPE;
-	
-	mb();
-	INIT_LIST_HEAD (&(*new)->horizontal);
-	INIT_LIST_HEAD (&(*new)->vertical);
-	
-	dbg("Allocated qh @ %p", *new);
-	
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-// inserts new qh before/after the qh at pos
-// flags: 0: insert before pos, 1: insert after pos (for low speed transfers)
-_static int insert_qh (uhci_t *s, uhci_desc_t *pos, uhci_desc_t *new, int order)
-{
-	uhci_desc_t *old;
-	unsigned long flags;
-
-	spin_lock_irqsave (&s->qh_lock, flags);
-
-	if (!order) {
-		// (OLD) (POS) -> (OLD) (NEW) (POS)
-		old = list_entry (pos->horizontal.prev, uhci_desc_t, horizontal);
-		list_add_tail (&new->horizontal, &pos->horizontal);
-		set_qh_head(new, MAKE_QH_ADDR (pos)) ;
-		if (!(old->hw.qh.head & cpu_to_le32(UHCI_PTR_TERM)))
-			set_qh_head(old, MAKE_QH_ADDR (new)) ;
-	}
-	else {
-		// (POS) (OLD) -> (POS) (NEW) (OLD)
-		old = list_entry (pos->horizontal.next, uhci_desc_t, horizontal);
-		list_add (&new->horizontal, &pos->horizontal);
-		set_qh_head(new, MAKE_QH_ADDR (old));
-		set_qh_head(pos, MAKE_QH_ADDR (new)) ;
-	}
-
-	mb ();
-	
-	spin_unlock_irqrestore (&s->qh_lock, flags);
-
-	return 0;
-}
-
-/*-------------------------------------------------------------------*/
-_static int unlink_qh (uhci_t *s, uhci_desc_t *element)
-{
-	uhci_desc_t  *prev;
-	unsigned long flags;
-
-	spin_lock_irqsave (&s->qh_lock, flags);
-	
-	prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal);
-	prev->hw.qh.head = element->hw.qh.head;
-
-	dbg("unlink qh %p, pqh %p, nxqh %p, to %08x", element, prev, 
-	    list_entry (element->horizontal.next, uhci_desc_t, horizontal),le32_to_cpu(element->hw.qh.head) &~15);
-	
-	list_del(&element->horizontal);
-
-	mb ();
-	spin_unlock_irqrestore (&s->qh_lock, flags);
-	
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-_static int delete_qh (uhci_t *s, uhci_desc_t *qh)
-{
-	uhci_desc_t *td;
-	struct list_head *p;
-	
-	list_del (&qh->horizontal);
-
-	while ((p = qh->vertical.next) != &qh->vertical) {
-		td = list_entry (p, uhci_desc_t, vertical);
-		dbg("unlink td @ %p",td);
-		unlink_td (s, td, 0); // no physical unlink
-		delete_desc (s, td);
-	}
-
-	delete_desc (s, qh);
-	
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-_static void clean_td_chain (uhci_t *s, uhci_desc_t *td)
-{
-	struct list_head *p;
-	uhci_desc_t *td1;
-
-	if (!td)
-		return;
-	
-	while ((p = td->horizontal.next) != &td->horizontal) {
-		td1 = list_entry (p, uhci_desc_t, horizontal);
-		delete_desc (s, td1);
-	}
-	
-	delete_desc (s, td);
-}
-
-/*-------------------------------------------------------------------*/
-_static void fill_td (uhci_desc_t *td, int status, int info, __u32 buffer)
-{
-	td->hw.td.status = cpu_to_le32(status);
-	td->hw.td.info = cpu_to_le32(info);
-	td->hw.td.buffer = cpu_to_le32(buffer);
-}
-/*-------------------------------------------------------------------*/
-// Removes ALL qhs in chain (paranoia!)
-_static void cleanup_skel (uhci_t *s)
-{
-	unsigned int n;
-	uhci_desc_t *td;
-
-	dbg("cleanup_skel");
-
-	clean_descs(s,1);
-
-	
-	if (s->td32ms) {
-	
-		unlink_td(s,s->td32ms,1);
-		delete_desc(s, s->td32ms);
-	}
-
-	for (n = 0; n < 8; n++) {
-		td = s->int_chain[n];
-		clean_td_chain (s, td);
-	}
-
-	if (s->iso_td) {
-		for (n = 0; n < 1024; n++) {
-			td = s->iso_td[n];
-			clean_td_chain (s, td);
-		}
-		kfree (s->iso_td);
-	}
-
-	if (s->framelist)
-		pci_free_consistent(s->uhci_pci, PAGE_SIZE,
-				    s->framelist, s->framelist_dma);
-
-	if (s->control_chain) {
-		// completed init_skel?
-		struct list_head *p;
-		uhci_desc_t *qh, *qh1;
-
-		qh = s->control_chain;
-		while ((p = qh->horizontal.next) != &qh->horizontal) {
-			qh1 = list_entry (p, uhci_desc_t, horizontal);
-			delete_qh (s, qh1);
-		}
-
-		delete_qh (s, qh);
-	}
-	else {
-		if (s->ls_control_chain)
-			delete_desc (s, s->ls_control_chain);
-		if (s->control_chain)
-			delete_desc (s, s->control_chain);
-		if (s->bulk_chain)
-			delete_desc (s, s->bulk_chain);
-		if (s->chain_end)
-			delete_desc (s, s->chain_end);
-	}
-
-	if (s->desc_pool) {
-		pci_pool_destroy(s->desc_pool);
-		s->desc_pool = NULL;
-	}
-
-	dbg("cleanup_skel finished");	
-}
-/*-------------------------------------------------------------------*/
-// allocates framelist and qh-skeletons
-// only HW-links provide continous linking, SW-links stay in their domain (ISO/INT)
-_static int init_skel (uhci_t *s)
-{
-	int n, ret;
-	uhci_desc_t *qh, *td;
-	
-	dbg("init_skel");
-	
-	s->framelist = pci_alloc_consistent(s->uhci_pci, PAGE_SIZE,
-					    &s->framelist_dma);
-
-	if (!s->framelist)
-		return -ENOMEM;
-
-	memset (s->framelist, 0, 4096);
-
-	dbg("creating descriptor pci_pool");
-
-	s->desc_pool = pci_pool_create("uhci_desc", s->uhci_pci,
-				       sizeof(uhci_desc_t), 16, 0,
-				       GFP_DMA | GFP_ATOMIC);	
-	if (!s->desc_pool)
-		goto init_skel_cleanup;
-
-	dbg("allocating iso desc pointer list");
-	s->iso_td = (uhci_desc_t **) kmalloc (1024 * sizeof (uhci_desc_t*), GFP_KERNEL);
-	
-	if (!s->iso_td)
-		goto init_skel_cleanup;
-
-	s->ls_control_chain = NULL;
-	s->control_chain = NULL;
-	s->bulk_chain = NULL;
-	s->chain_end = NULL;
-
-	dbg("allocating iso descs");
-	for (n = 0; n < 1024; n++) {
-	 	// allocate skeleton iso/irq-tds
-		if (alloc_td (s, &td, 0))
-			goto init_skel_cleanup;
-
-		s->iso_td[n] = td;
-		s->framelist[n] = cpu_to_le32((__u32) td->dma_addr);
-	}
-
-	dbg("allocating qh: chain_end");
-	if (alloc_qh (s, &qh))	
-		goto init_skel_cleanup;
-				
-	s->chain_end = qh;
-
-	if (alloc_td (s, &td, 0))
-		goto init_skel_cleanup;
-	
-	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 1ms interrupt (enabled on demand)
-	insert_td (s, qh, td, 0);
-	qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM); // remove TERM bit
-	s->td1ms=td;
-
-	dbg("allocating qh: bulk_chain");
-	if (alloc_qh (s, &qh))
-		goto init_skel_cleanup;
-	
-	insert_qh (s, s->chain_end, qh, 0);
-	s->bulk_chain = qh;
-
-	dbg("allocating qh: control_chain");
-	ret = alloc_qh (s, &qh);
-	if (ret)
-		goto init_skel_cleanup;
-	
-	insert_qh (s, s->bulk_chain, qh, 0);
-	s->control_chain = qh;
-
-#ifdef	CONFIG_USB_UHCI_HIGH_BANDWIDTH
-	// disabled reclamation loop
-	set_qh_head(s->chain_end, s->control_chain->dma_addr | UHCI_PTR_QH | UHCI_PTR_TERM);
-#endif
-
-	dbg("allocating qh: ls_control_chain");
-	if (alloc_qh (s, &qh))
-		goto init_skel_cleanup;
-	
-	insert_qh (s, s->control_chain, qh, 0);
-	s->ls_control_chain = qh;
-
-	for (n = 0; n < 8; n++)
-		s->int_chain[n] = 0;
-
-	dbg("allocating skeleton INT-TDs");
-	
-	for (n = 0; n < 8; n++) {
-		uhci_desc_t *td;
-
-		if (alloc_td (s, &td, 0))
-			goto init_skel_cleanup;
-
-		s->int_chain[n] = td;
-		if (n == 0) {
-			set_td_link(s->int_chain[0], s->ls_control_chain->dma_addr | UHCI_PTR_QH);
-		}
-		else {
-			set_td_link(s->int_chain[n], s->int_chain[0]->dma_addr);
-		}
-	}
-
-	dbg("Linking skeleton INT-TDs");
-	
-	for (n = 0; n < 1024; n++) {
-		// link all iso-tds to the interrupt chains
-		int m, o;
-		dbg("framelist[%i]=%x",n,le32_to_cpu(s->framelist[n]));
-		if ((n&127)==127) 
-			((uhci_desc_t*) s->iso_td[n])->hw.td.link = cpu_to_le32(s->int_chain[0]->dma_addr);
-		else 
-			for (o = 1, m = 2; m <= 128; o++, m += m)
-				if ((n & (m - 1)) == ((m - 1) / 2))
-					set_td_link(((uhci_desc_t*) s->iso_td[n]), s->int_chain[o]->dma_addr);
-	}
-
-	if (alloc_td (s, &td, 0))
-		goto init_skel_cleanup;
-	
-	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 32ms interrupt (activated later)
-	s->td32ms=td;
-
-	insert_td_horizontal (s, s->int_chain[5], td);
-
-	mb();
-	//uhci_show_queue(s->control_chain);   
-	dbg("init_skel exit");
-	return 0;
-
-      init_skel_cleanup:
-	cleanup_skel (s);
-	return -ENOMEM;
-}
-
-/*-------------------------------------------------------------------*/
-//                         LOW LEVEL STUFF
-//          assembles QHs und TDs for control, bulk and iso
-/*-------------------------------------------------------------------*/
-_static int uhci_submit_control_urb (struct urb *urb)
-{
-	uhci_desc_t *qh, *td;
-	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
-	urb_priv_t *urb_priv = urb->hcpriv;
-	unsigned long destination, status;
-	int maxsze = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
-	unsigned long len;
-	char *data;
-	int depth_first=USE_CTRL_DEPTH_FIRST;  // UHCI descriptor chasing method
-
-	dbg("uhci_submit_control start");
-	if (alloc_qh (s, &qh))		// alloc qh for this request
-		return -ENOMEM;
-
-	if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))		// get td for setup stage
-	{
-		delete_qh (s, qh);
-		return -ENOMEM;
-	}
-
-	/* The "pipe" thing contains the destination in bits 8--18 */
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
-
-	/* 3 errors */
-	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |
-		(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
-
-	/*  Build the TD for the control request, try forever, 8 bytes of data */
-	fill_td (td, status, destination | (7 << 21), urb_priv->setup_packet_dma);
-
-	insert_td (s, qh, td, 0);	// queue 'setup stage'-td in qh
-#if 0
-	{
-		char *sp=urb->setup_packet;
-		dbg("SETUP to pipe %x: %x %x %x %x %x %x %x %x", urb->pipe,
-		    sp[0],sp[1],sp[2],sp[3],sp[4],sp[5],sp[6],sp[7]);
-	}
-	//uhci_show_td(td);
-#endif
-
-	len = urb->transfer_buffer_length;
-	data = urb->transfer_buffer;
-
-	/* If direction is "send", change the frame from SETUP (0x2D)
-	   to OUT (0xE1). Else change it from SETUP to IN (0x69). */
-
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | (usb_pipeout (urb->pipe)?USB_PID_OUT:USB_PID_IN);
-
-	while (len > 0) {
-		int pktsze = len;
-
-		if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))
-			goto fail_unmap_enomem;
-
-		if (pktsze > maxsze)
-			pktsze = maxsze;
-
-		destination ^= 1 << TD_TOKEN_TOGGLE;	// toggle DATA0/1
-
-		// Status, pktsze bytes of data
-		fill_td (td, status, destination | ((pktsze - 1) << 21),
-			 urb_priv->transfer_buffer_dma + (data - (char *)urb->transfer_buffer));
-
-		insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);	// queue 'data stage'-td in qh
-
-		data += pktsze;
-		len -= pktsze;
-	}
-
-	/* Build the final TD for control status */
-	/* It's only IN if the pipe is out AND we aren't expecting data */
-
-	destination &= ~UHCI_PID;
-
-	if (usb_pipeout (urb->pipe) || (urb->transfer_buffer_length == 0))
-		destination |= USB_PID_IN;
-	else
-		destination |= USB_PID_OUT;
-
-	destination |= 1 << TD_TOKEN_TOGGLE;	/* End in Data1 */
-
-	if (alloc_td (s, &td, UHCI_PTR_DEPTH))
-		goto fail_unmap_enomem;
-
-	status &=~TD_CTRL_SPD;
-
-	/* no limit on errors on final packet , 0 bytes of data */
-	fill_td (td, status | TD_CTRL_IOC, destination | (UHCI_NULL_DATA_SIZE << 21),
-		 0);
-
-	insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);	// queue status td
-
-	list_add (&qh->desc_list, &urb_priv->desc_list);
-
-	queue_urb (s, urb);	// queue before inserting in desc chain
-
-	qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM);
-
-	//uhci_show_queue(qh);
-	/* Start it up... put low speed first */
-	if (urb->pipe & TD_CTRL_LS)
-		insert_qh (s, s->control_chain, qh, 0);
-	else
-		insert_qh (s, s->bulk_chain, qh, 0);
-
-	dbg("uhci_submit_control end");
-	return 0;
-
-fail_unmap_enomem:
-	delete_qh(s, qh);
-	return -ENOMEM;
-}
-/*-------------------------------------------------------------------*/
-// For queued bulk transfers, two additional QH helpers are allocated (nqh, bqh)
-// Due to the linking with other bulk urbs, it has to be locked with urb_list_lock!
-
-_static int uhci_submit_bulk_urb (struct urb *urb, struct urb *bulk_urb)
-{
-	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
-	urb_priv_t *urb_priv = urb->hcpriv, *upriv, *bpriv=NULL;
-	uhci_desc_t *qh, *td, *nqh=NULL, *bqh=NULL, *first_td=NULL;
-	unsigned long destination, status;
-	char *data;
-	unsigned int pipe = urb->pipe;
-	int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
-	int info, len, last;
-	int depth_first=USE_BULK_DEPTH_FIRST;  // UHCI descriptor chasing method
-
-	if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)))
-		return -EPIPE;
-
-	queue_dbg("uhci_submit_bulk_urb: urb %p, old %p, pipe %08x, len %i",
-		  urb,bulk_urb,urb->pipe,urb->transfer_buffer_length);
-
-	upriv = (urb_priv_t*)urb->hcpriv;
-
-	if (!bulk_urb) {
-		if (alloc_qh (s, &qh))		// get qh for this request
-			return -ENOMEM;
-
-		if (urb->transfer_flags & USB_QUEUE_BULK) {
-			if (alloc_qh(s, &nqh)) // placeholder for clean unlink
-			{
-				delete_desc (s, qh);
-				return -ENOMEM;
-			}
-			upriv->next_qh = nqh;
-			queue_dbg("new next qh %p",nqh);
-		}
-	}
-	else { 
-		bpriv = (urb_priv_t*)bulk_urb->hcpriv;
-		qh = bpriv->bottom_qh;  // re-use bottom qh and next qh
-		nqh = bpriv->next_qh;
-		upriv->next_qh=nqh;	
-		upriv->prev_queued_urb=bulk_urb;
-	}
-
-	if (urb->transfer_flags & USB_QUEUE_BULK) {
-		if (alloc_qh (s, &bqh))  // "bottom" QH
-		{
-			if (!bulk_urb) { 
-				delete_desc(s, qh);
-				delete_desc(s, nqh);
-			}
-			return -ENOMEM;
-		}
-		set_qh_element(bqh, UHCI_PTR_TERM);
-		set_qh_head(bqh, nqh->dma_addr | UHCI_PTR_QH); // element
-		upriv->bottom_qh = bqh;
-	}
-	queue_dbg("uhci_submit_bulk: qh %p bqh %p nqh %p",qh, bqh, nqh);
-
-	/* The "pipe" thing contains the destination in bits 8--18. */
-	destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
-
-	/* 3 errors */
-	status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |
-		((urb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD) | (3 << 27);
-
-	/* Build the TDs for the bulk request */
-	len = urb->transfer_buffer_length;
-	data = urb->transfer_buffer;
-	
-	do {					// TBD: Really allow zero-length packets?
-		int pktsze = len;
-
-		if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))
-		{
-			delete_qh (s, qh);
-			return -ENOMEM;
-		}
-
-		if (pktsze > maxsze)
-			pktsze = maxsze;
-
-		// pktsze bytes of data 
-		info = destination | (((pktsze - 1)&UHCI_NULL_DATA_SIZE) << 21) |
-			(usb_gettoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);
-
-		fill_td (td, status, info,
-			 urb_priv->transfer_buffer_dma + (data - (char *)urb->transfer_buffer));
-
-		data += pktsze;
-		len -= pktsze;
-		// Use USB_ZERO_PACKET to finish bulk OUTs always with a zero length packet
-		last = (len == 0 && (usb_pipein(pipe) || pktsze < maxsze || !(urb->transfer_flags & USB_ZERO_PACKET)));
-
-		if (last)
-			set_td_ioc(td);	// last one generates INT
-
-		insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);
-		if (!first_td)
-			first_td=td;
-		usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
-
-	} while (!last);
-
-	if (bulk_urb && bpriv)   // everything went OK, link with old bulk URB
-		bpriv->next_queued_urb=urb;
-
-	list_add (&qh->desc_list, &urb_priv->desc_list);
-
-	if (urb->transfer_flags & USB_QUEUE_BULK)
-		append_qh(s, td, bqh, UHCI_PTR_DEPTH * depth_first);
-
-	queue_urb_unlocked (s, urb);
-	
-	if (urb->transfer_flags & USB_QUEUE_BULK)
-		set_qh_element(qh, first_td->dma_addr);
-	else
-		qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM);    // arm QH
-
-	if (!bulk_urb) { 					// new bulk queue	
-		if (urb->transfer_flags & USB_QUEUE_BULK) {
-			spin_lock (&s->td_lock);		// both QHs in one go
-			insert_qh (s, s->chain_end, qh, 0);	// Main QH
-			insert_qh (s, s->chain_end, nqh, 0);	// Helper QH
-			spin_unlock (&s->td_lock);
-		}
-		else
-			insert_qh (s, s->chain_end, qh, 0);
-	}
-	
-	//uhci_show_queue(s->bulk_chain);
-	//dbg("uhci_submit_bulk_urb: exit\n");
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-_static void uhci_clean_iso_step1(uhci_t *s, urb_priv_t *urb_priv)
-{
-	struct list_head *p;
-	uhci_desc_t *td;
-
-	for (p = urb_priv->desc_list.next; p != &urb_priv->desc_list; p = p->next) {
-				td = list_entry (p, uhci_desc_t, desc_list);
-				unlink_td (s, td, 1);
-	}
-}
-/*-------------------------------------------------------------------*/
-_static void uhci_clean_iso_step2(uhci_t *s, urb_priv_t *urb_priv)
-{
-	struct list_head *p;
-	uhci_desc_t *td;
-
-	while ((p = urb_priv->desc_list.next) != &urb_priv->desc_list) {
-				td = list_entry (p, uhci_desc_t, desc_list);
-				list_del (p);
-				delete_desc (s, td);
-	}
-}
-/*-------------------------------------------------------------------*/
-/* mode: CLEAN_TRANSFER_NO_DELETION: unlink but no deletion mark (step 1 of async_unlink)
-         CLEAN_TRANSFER_REGULAR: regular (unlink/delete-mark)
-         CLEAN_TRANSFER_DELETION_MARK: deletion mark for QH (step 2 of async_unlink)
- looks a bit complicated because of all the bulk queueing goodies
-*/
-
-_static void uhci_clean_transfer (uhci_t *s, struct urb *urb, uhci_desc_t *qh, int mode)
-{
-	uhci_desc_t *bqh, *nqh, *prevqh, *prevtd;
-	int now;
-	urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
-
-	now=UHCI_GET_CURRENT_FRAME(s);
-
-	bqh=priv->bottom_qh;	
-	
-	if (!priv->next_queued_urb)  { // no more appended bulk queues
-
-		queue_dbg("uhci_clean_transfer: No more bulks for urb %p, qh %p, bqh %p, nqh %p", urb, qh, bqh, priv->next_qh);	
-	
-		if (priv->prev_queued_urb && mode != CLEAN_TRANSFER_DELETION_MARK) {  // qh not top of the queue
-				unsigned long flags; 
-				urb_priv_t* ppriv=(urb_priv_t*)priv->prev_queued_urb->hcpriv;
-
-				spin_lock_irqsave (&s->qh_lock, flags);
-				prevqh = list_entry (ppriv->desc_list.next, uhci_desc_t, desc_list);
-				prevtd = list_entry (prevqh->vertical.prev, uhci_desc_t, vertical);
-				set_td_link(prevtd, priv->bottom_qh->dma_addr | UHCI_PTR_QH); // skip current qh
-				mb();
-				queue_dbg("uhci_clean_transfer: relink pqh %p, ptd %p",prevqh, prevtd);
-				spin_unlock_irqrestore (&s->qh_lock, flags);
-
-				ppriv->bottom_qh = priv->bottom_qh;
-				ppriv->next_queued_urb = NULL;
-			}
-		else {   // queue is dead, qh is top of the queue
-			
-			if (mode != CLEAN_TRANSFER_DELETION_MARK) 				
-				unlink_qh(s, qh); // remove qh from horizontal chain
-
-			if (bqh) {  // remove remainings of bulk queue
-				nqh=priv->next_qh;
-
-				if (mode != CLEAN_TRANSFER_DELETION_MARK) 
-					unlink_qh(s, nqh);  // remove nqh from horizontal chain
-				
-				if (mode != CLEAN_TRANSFER_NO_DELETION) {  // add helper QHs to free desc list
-					nqh->last_used = bqh->last_used = now;
-					list_add_tail (&nqh->horizontal, &s->free_desc);
-					list_add_tail (&bqh->horizontal, &s->free_desc);
-				}			
-			}
-		}
-	}
-	else { // there are queued urbs following
-	
-	  queue_dbg("uhci_clean_transfer: urb %p, prevurb %p, nexturb %p, qh %p, bqh %p, nqh %p",
-		       urb, priv->prev_queued_urb,  priv->next_queued_urb, qh, bqh, priv->next_qh);	
-       	
-		if (mode != CLEAN_TRANSFER_DELETION_MARK) {	// no work for cleanup at unlink-completion
-			struct urb *nurb;
-			unsigned long flags;
-
-			nurb = priv->next_queued_urb;
-			spin_lock_irqsave (&s->qh_lock, flags);		
-
-			if (!priv->prev_queued_urb) { // top QH
-				
-				prevqh = list_entry (qh->horizontal.prev, uhci_desc_t, horizontal);
-				set_qh_head(prevqh, bqh->dma_addr | UHCI_PTR_QH);
-				list_del (&qh->horizontal);  // remove this qh form horizontal chain
-				list_add (&bqh->horizontal, &prevqh->horizontal); // insert next bqh in horizontal chain
-			}
-			else {		// intermediate QH
-				urb_priv_t* ppriv=(urb_priv_t*)priv->prev_queued_urb->hcpriv;
-				urb_priv_t* npriv=(urb_priv_t*)nurb->hcpriv;
-				uhci_desc_t * bnqh;
-				
-				bnqh = list_entry (npriv->desc_list.next, uhci_desc_t, desc_list);
-				ppriv->bottom_qh = bnqh;
-				ppriv->next_queued_urb = nurb;				
-				prevqh = list_entry (ppriv->desc_list.next, uhci_desc_t, desc_list);
-				set_qh_head(prevqh, bqh->dma_addr | UHCI_PTR_QH);
-			}
-
-			mb();
-			((urb_priv_t*)nurb->hcpriv)->prev_queued_urb=priv->prev_queued_urb;
-			spin_unlock_irqrestore (&s->qh_lock, flags);
-		}		
-	}
-
-	if (mode != CLEAN_TRANSFER_NO_DELETION) {
-		qh->last_used = now;	
-		list_add_tail (&qh->horizontal, &s->free_desc); // mark qh for later deletion/kfree
-	}
-}
-/*-------------------------------------------------------------------*/
-// Release bandwidth for Interrupt or Isoc. transfers 
-_static void uhci_release_bandwidth(struct urb *urb)
-{       
-	if (urb->bandwidth) {
-		switch (usb_pipetype(urb->pipe)) {
-		case PIPE_INTERRUPT:
-			usb_release_bandwidth (urb->dev, urb, 0);
-			break;
-		case PIPE_ISOCHRONOUS:
-			usb_release_bandwidth (urb->dev, urb, 1);
-			break;
-		default:
-			break;
-		}
-	}	
-}
-
-_static void uhci_urb_dma_sync(uhci_t *s, struct urb *urb, urb_priv_t *urb_priv)
-{
-	if (urb_priv->setup_packet_dma)
-		pci_dma_sync_single(s->uhci_pci, urb_priv->setup_packet_dma,
-				    sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
-
-	if (urb_priv->transfer_buffer_dma)
-		pci_dma_sync_single(s->uhci_pci, urb_priv->transfer_buffer_dma,
-				    urb->transfer_buffer_length,
-				    usb_pipein(urb->pipe) ?
-				    PCI_DMA_FROMDEVICE :
-				    PCI_DMA_TODEVICE);
-}
-
-_static void uhci_urb_dma_unmap(uhci_t *s, struct urb *urb, urb_priv_t *urb_priv)
-{
-	if (urb_priv->setup_packet_dma) {
-		pci_unmap_single(s->uhci_pci, urb_priv->setup_packet_dma,
-				 sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
-		urb_priv->setup_packet_dma = 0;
-	}
-	if (urb_priv->transfer_buffer_dma) {
-		pci_unmap_single(s->uhci_pci, urb_priv->transfer_buffer_dma,
-				 urb->transfer_buffer_length,
-				 usb_pipein(urb->pipe) ?
-				 PCI_DMA_FROMDEVICE :
-				 PCI_DMA_TODEVICE);
-		urb_priv->transfer_buffer_dma = 0;
-	}
-}
-/*-------------------------------------------------------------------*/
-/* needs urb_list_lock!
-   mode: UNLINK_ASYNC_STORE_URB: unlink and move URB into unlinked list
-         UNLINK_ASYNC_DONT_STORE: unlink, don't move URB into unlinked list
-*/
-_static int uhci_unlink_urb_async (uhci_t *s,struct urb *urb, int mode)
-{
-	uhci_desc_t *qh;
-	urb_priv_t *urb_priv;
-	
-	async_dbg("unlink_urb_async called %p",urb);
-
-	if ((urb->status == -EINPROGRESS) ||
-	    ((usb_pipetype (urb->pipe) ==  PIPE_INTERRUPT) && ((urb_priv_t*)urb->hcpriv)->flags))
-	{
-		((urb_priv_t*)urb->hcpriv)->started = ~0;  // mark
-		dequeue_urb (s, urb);
-
-		if (mode==UNLINK_ASYNC_STORE_URB)
-			list_add_tail (&urb->urb_list, &s->urb_unlinked); // store urb
-
-		uhci_switch_timer_int(s);
-       		s->unlink_urb_done = 1;
-		uhci_release_bandwidth(urb);
-
-		urb->status = -ECONNABORTED;	// mark urb as "waiting to be killed"	
-		urb_priv = (urb_priv_t*)urb->hcpriv;
-
-		switch (usb_pipetype (urb->pipe)) {
-		case PIPE_INTERRUPT:
-			usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
-
-		case PIPE_ISOCHRONOUS:
-			uhci_clean_iso_step1 (s, urb_priv);
-			break;
-
-		case PIPE_BULK:
-		case PIPE_CONTROL:
-			qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list);
-			uhci_clean_transfer (s, urb, qh, CLEAN_TRANSFER_NO_DELETION);
-			break;
-		}
-		((urb_priv_t*)urb->hcpriv)->started = UHCI_GET_CURRENT_FRAME(s);
-		return -EINPROGRESS;  // completion will follow
-	}		
-
-	return 0;    // URB already dead
-}
-/*-------------------------------------------------------------------*/
-// kills an urb by unlinking descriptors and waiting for at least one frame
-_static int uhci_unlink_urb_sync (uhci_t *s, struct urb *urb)
-{
-	uhci_desc_t *qh;
-	urb_priv_t *urb_priv;
-	unsigned long flags=0;
-	struct usb_device *usb_dev;
-
-	spin_lock_irqsave (&s->urb_list_lock, flags);
-
-	if (urb->status == -EINPROGRESS) {
-
-		// move descriptors out of the running chains, dequeue urb
-		uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_DONT_STORE);
-
-		urb_priv = urb->hcpriv;
-		urb->status = -ENOENT;	// prevent from double deletion after unlock		
-		spin_unlock_irqrestore (&s->urb_list_lock, flags);
-		
-		// cleanup the rest
-		switch (usb_pipetype (urb->pipe)) {
-
-		case PIPE_INTERRUPT:
-		case PIPE_ISOCHRONOUS:
-			uhci_wait_ms(1);
-			uhci_clean_iso_step2(s, urb_priv);
-			break;
-
-		case PIPE_BULK:
-		case PIPE_CONTROL:
-			qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list);
-			uhci_clean_transfer(s, urb, qh, CLEAN_TRANSFER_DELETION_MARK);
-			uhci_wait_ms(1);
-		}
-		urb->status = -ENOENT;	// mark urb as killed		
-					
-		uhci_urb_dma_unmap(s, urb, urb->hcpriv);
-
-#ifdef DEBUG_SLAB
-		kmem_cache_free (urb_priv_kmem, urb->hcpriv);
-#else
-		kfree (urb->hcpriv);
-#endif
-		usb_dev = urb->dev;
-		if (urb->complete) {
-			dbg("unlink_urb: calling completion");
-			urb->dev = NULL;
-			urb->complete ((struct urb *) urb);
-		}
-		usb_dec_dev_use (usb_dev);
-	}
-	else
-		spin_unlock_irqrestore (&s->urb_list_lock, flags);
-
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-// async unlink_urb completion/cleanup work
-// has to be protected by urb_list_lock!
-// features: if set in transfer_flags, the resulting status of the killed
-// transaction is not overwritten
-
-_static void uhci_cleanup_unlink(uhci_t *s, int force)
-{
-	struct list_head *q;
-	struct urb *urb;
-	struct usb_device *dev;
-	int now, type;
-	urb_priv_t *urb_priv;
-
-	q=s->urb_unlinked.next;
-	now=UHCI_GET_CURRENT_FRAME(s);
-
-	while (q != &s->urb_unlinked) {
-
-		urb = list_entry (q, struct urb, urb_list);
-
-		urb_priv = (urb_priv_t*)urb->hcpriv;
-		q = urb->urb_list.next;
-		
-		if (!urb_priv) // avoid crash when URB is corrupted
-			break;
-			
-		if (force || ((urb_priv->started != ~0) && (urb_priv->started != now))) {
-			async_dbg("async cleanup %p",urb);
-			type=usb_pipetype (urb->pipe);
-
-			switch (type) { // process descriptors
-			case PIPE_CONTROL:
-				process_transfer (s, urb, CLEAN_TRANSFER_DELETION_MARK);  // don't unlink (already done)
-				break;
-			case PIPE_BULK:
-				if (!s->avoid_bulk.counter)
-					process_transfer (s, urb, CLEAN_TRANSFER_DELETION_MARK); // don't unlink (already done)
-				else
-					continue;
-				break;
-			case PIPE_ISOCHRONOUS:
-				process_iso (s, urb, PROCESS_ISO_FORCE); // force, don't unlink
-				break;
-			case PIPE_INTERRUPT:
-				process_interrupt (s, urb);
-				break;
-			}
-
-			if (!(urb->transfer_flags & USB_TIMEOUT_KILLED))
-		  		urb->status = -ECONNRESET; // mark as asynchronously killed
-
-			dev = urb->dev;	// completion may destroy all...
-			urb_priv = urb->hcpriv;
-			list_del (&urb->urb_list);
-			
-			uhci_urb_dma_sync(s, urb, urb_priv);
-			if (urb->complete) {
-				spin_unlock(&s->urb_list_lock);
-				urb->dev = NULL;
-				urb->complete ((struct urb *) urb);
-				spin_lock(&s->urb_list_lock);
-			}
-
-			if (!(urb->transfer_flags & USB_TIMEOUT_KILLED))
-				urb->status = -ENOENT;  // now the urb is really dead
-
-			switch (type) {
-			case PIPE_ISOCHRONOUS:
-			case PIPE_INTERRUPT:
-				uhci_clean_iso_step2(s, urb_priv);
-				break;
-			}
-	
-			uhci_urb_dma_unmap(s, urb, urb_priv);
-
-			usb_dec_dev_use (dev);
-#ifdef DEBUG_SLAB
-			kmem_cache_free (urb_priv_kmem, urb_priv);
-#else
-			kfree (urb_priv);
-#endif
-
-		}
-	}
-}
- 
-/*-------------------------------------------------------------------*/
-_static int uhci_unlink_urb (struct urb *urb)
-{
-	uhci_t *s;
-	unsigned long flags=0;
-	dbg("uhci_unlink_urb called for %p",urb);
-	if (!urb || !urb->dev)		// you never know...
-		return -EINVAL;
-	
-	s = (uhci_t*) urb->dev->bus->hcpriv;
-
-	if (usb_pipedevice (urb->pipe) == s->rh.devnum)
-		return rh_unlink_urb (urb);
-
-	if (!urb->hcpriv)
-		return -EINVAL;
-
-	if (urb->transfer_flags & USB_ASYNC_UNLINK) {
-		int ret;
-       		spin_lock_irqsave (&s->urb_list_lock, flags);
-       		
-		uhci_release_bandwidth(urb);
-		ret = uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
-
-		spin_unlock_irqrestore (&s->urb_list_lock, flags);	
-		return ret;
-	}
-	else
-		return uhci_unlink_urb_sync(s, urb);
-}
-/*-------------------------------------------------------------------*/
-// In case of ASAP iso transfer, search the URB-list for already queued URBs
-// for this EP and calculate the earliest start frame for the new
-// URB (easy seamless URB continuation!)
-_static int find_iso_limits (struct urb *urb, unsigned int *start, unsigned int *end)
-{
-	struct urb *u, *last_urb = NULL;
-	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
-	struct list_head *p;
-	int ret=-1;
-	unsigned long flags;
-	
-	spin_lock_irqsave (&s->urb_list_lock, flags);
-	p=s->urb_list.prev;
-
-	for (; p != &s->urb_list; p = p->prev) {
-		u = list_entry (p, struct urb, urb_list);
-		// look for pending URBs with identical pipe handle
-		// works only because iso doesn't toggle the data bit!
-		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) && (u->status == -EINPROGRESS)) {
-			if (!last_urb)
-				*start = u->start_frame;
-			last_urb = u;
-		}
-	}
-	
-	if (last_urb) {
-		*end = (last_urb->start_frame + last_urb->number_of_packets) & 1023;
-		ret=0;
-	}
-	
-	spin_unlock_irqrestore(&s->urb_list_lock, flags);
-	
-	return ret;
-}
-/*-------------------------------------------------------------------*/
-// adjust start_frame according to scheduling constraints (ASAP etc)
-
-_static int iso_find_start (struct urb *urb)
-{
-	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
-	unsigned int now;
-	unsigned int start_limit = 0, stop_limit = 0, queued_size;
-	int limits;
-
-	now = UHCI_GET_CURRENT_FRAME (s) & 1023;
-
-	if ((unsigned) urb->number_of_packets > 900)
-		return -EFBIG;
-	
-	limits = find_iso_limits (urb, &start_limit, &stop_limit);
-	queued_size = (stop_limit - start_limit) & 1023;
-
-	if (urb->transfer_flags & USB_ISO_ASAP) {
-		// first iso
-		if (limits) {
-			// 10ms setup should be enough //FIXME!
-			urb->start_frame = (now + 10) & 1023;
-		}
-		else {
-			urb->start_frame = stop_limit;		//seamless linkage
-
-			if (((now - urb->start_frame) & 1023) <= (unsigned) urb->number_of_packets) {
-				info("iso_find_start: gap in seamless isochronous scheduling");
-				dbg("iso_find_start: now %u start_frame %u number_of_packets %u pipe 0x%08x",
-					now, urb->start_frame, urb->number_of_packets, urb->pipe);
-				urb->start_frame = (now + 5) & 1023;	// 5ms setup should be enough //FIXME!
-			}
-		}
-	}
-	else {
-		urb->start_frame &= 1023;
-		if (((now - urb->start_frame) & 1023) < (unsigned) urb->number_of_packets) {
-			dbg("iso_find_start: now between start_frame and end");
-			return -EAGAIN;
-		}
-	}
-
-	/* check if either start_frame or start_frame+number_of_packets-1 lies between start_limit and stop_limit */
-	if (limits)
-		return 0;
-
-	if (((urb->start_frame - start_limit) & 1023) < queued_size ||
-	    ((urb->start_frame + urb->number_of_packets - 1 - start_limit) & 1023) < queued_size) {
-		dbg("iso_find_start: start_frame %u number_of_packets %u start_limit %u stop_limit %u",
-			urb->start_frame, urb->number_of_packets, start_limit, stop_limit);
-		return -EAGAIN;
-	}
-
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-// submits USB interrupt (ie. polling ;-) 
-// ASAP-flag set implicitely
-// if period==0, the transfer is only done once
-
-_static int uhci_submit_int_urb (struct urb *urb)
-{
-	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
-	urb_priv_t *urb_priv = urb->hcpriv;
-	int nint, n;
-	uhci_desc_t *td;
-	int status, destination;
-	int info;
-	unsigned int pipe = urb->pipe;
-
-	if (urb->interval < 0 || urb->interval >= 256)
-		return -EINVAL;
-
-	if (urb->interval == 0)
-		nint = 0;
-	else {
-		for (nint = 0, n = 1; nint <= 8; nint++, n += n)	// round interval down to 2^n
-		 {
-			if (urb->interval < n) {
-				urb->interval = n / 2;
-				break;
-			}
-		}
-		nint--;
-	}
-
-	dbg("Rounded interval to %i, chain  %i", urb->interval, nint);
-
-	urb->start_frame = UHCI_GET_CURRENT_FRAME (s) & 1023;	// remember start frame, just in case...
-
-	urb->number_of_packets = 1;
-
-	// INT allows only one packet
-	if (urb->transfer_buffer_length > usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe)))
-		return -EINVAL;
-
-	if (alloc_td (s, &td, UHCI_PTR_DEPTH))
-		return -ENOMEM;
-
-	status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
-		(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
-
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe) |
-		(((urb->transfer_buffer_length - 1) & 0x7ff) << 21);
-
-
-	info = destination | (usb_gettoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);
-
-	fill_td (td, status, info, urb_priv->transfer_buffer_dma);
-	list_add_tail (&td->desc_list, &urb_priv->desc_list);
-
-	queue_urb (s, urb);
-
-	insert_td_horizontal (s, s->int_chain[nint], td);	// store in INT-TDs
-
-	usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
-
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-_static int uhci_submit_iso_urb (struct urb *urb)
-{
-	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
-	urb_priv_t *urb_priv = urb->hcpriv;
-#ifdef ISO_SANITY_CHECK
-	int pipe=urb->pipe;
-	int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
-#endif
-	int n, ret, last=0;
-	uhci_desc_t *td, **tdm;
-	int status, destination;
-	unsigned long flags;
-
-	__save_flags(flags);
-	__cli();		      // Disable IRQs to schedule all ISO-TDs in time
-	ret = iso_find_start (urb);	// adjusts urb->start_frame for later use
-	
-	if (ret)
-		goto err;
-
-	tdm = (uhci_desc_t **) kmalloc (urb->number_of_packets * sizeof (uhci_desc_t*), KMALLOC_FLAG);
-
-	if (!tdm) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	memset(tdm, 0, urb->number_of_packets * sizeof (uhci_desc_t*));
-
-	// First try to get all TDs. Cause: Removing already inserted TDs can only be done 
-	// racefree in three steps: unlink TDs, wait one frame, delete TDs. 
-	// So, this solutions seems simpler...
-
-	for (n = 0; n < urb->number_of_packets; n++) {
-		dbg("n:%d urb->iso_frame_desc[n].length:%d", n, urb->iso_frame_desc[n].length);
-		if (!urb->iso_frame_desc[n].length)
-			continue;  // allows ISO striping by setting length to zero in iso_descriptor
-
-
-#ifdef ISO_SANITY_CHECK
-		if(urb->iso_frame_desc[n].length > maxsze) {
-
-			err("submit_iso: urb->iso_frame_desc[%d].length(%d)>%d",n , urb->iso_frame_desc[n].length, maxsze);
-			ret=-EINVAL;		
-		}
-		else
-#endif
-		if (alloc_td (s, &td, UHCI_PTR_DEPTH)) {
-			int i;	// Cleanup allocated TDs
-
-			for (i = 0; i < n; n++)
-				if (tdm[i])
-					 delete_desc(s, tdm[i]);
-			kfree (tdm);
-			goto err;
-		}
-		last=n;
-		tdm[n] = td;
-	}
-
-	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
-
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe);
-
-	// Queue all allocated TDs
-	for (n = 0; n < urb->number_of_packets; n++) {
-		td = tdm[n];
-		if (!td)
-			continue;
-			
-		if (n  == last) {
-			status |= TD_CTRL_IOC;
-			queue_urb (s, urb);
-		}
-
-		fill_td (td, status, destination | (((urb->iso_frame_desc[n].length - 1) & 0x7ff) << 21),
-			 urb_priv->transfer_buffer_dma + urb->iso_frame_desc[n].offset);
-		list_add_tail (&td->desc_list, &urb_priv->desc_list);
-	
-		insert_td_horizontal (s, s->iso_td[(urb->start_frame + n) & 1023], td);	// store in iso-tds
-	}
-
-	kfree (tdm);
-	dbg("ISO-INT# %i, start %i, now %i", urb->number_of_packets, urb->start_frame, UHCI_GET_CURRENT_FRAME (s) & 1023);
-	ret = 0;
-
-      err:
-	__restore_flags(flags);
-	return ret;
-}
-/*-------------------------------------------------------------------*/
-// returns: 0 (no transfer queued), urb* (this urb already queued)
- 
-_static struct urb* search_dev_ep (uhci_t *s, struct urb *urb)
-{
-	struct list_head *p;
-	struct urb *tmp;
-	unsigned int mask = usb_pipecontrol(urb->pipe) ? (~USB_DIR_IN) : (~0);
-
-	dbg("search_dev_ep:");
-
-	p=s->urb_list.next;
-
-	for (; p != &s->urb_list; p = p->next) {
-		tmp = list_entry (p, struct urb, urb_list);
-		dbg("urb: %p", tmp);
-		// we can accept this urb if it is not queued at this time 
-		// or if non-iso transfer requests should be scheduled for the same device and pipe
-		if ((!usb_pipeisoc(urb->pipe) && (tmp->dev == urb->dev) && !((tmp->pipe ^ urb->pipe) & mask)) ||
-		    (urb == tmp)) {
-			return tmp;	// found another urb already queued for processing
-		}
-	}
-
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-_static int uhci_submit_urb (struct urb *urb)
-{
-	uhci_t *s;
-	urb_priv_t *urb_priv;
-	int ret = 0, type;
-	unsigned long flags;
-	struct urb *queued_urb=NULL;
-	int bustime;
-		
-	if (!urb->dev || !urb->dev->bus)
-		return -ENODEV;
-
-	s = (uhci_t*) urb->dev->bus->hcpriv;
-	//dbg("submit_urb: %p type %d",urb,usb_pipetype(urb->pipe));
-	
-	if (!s->running)
-		return -ENODEV;
-	
-	type = usb_pipetype (urb->pipe);
-
-	if (usb_pipedevice (urb->pipe) == s->rh.devnum)
-		return rh_submit_urb (urb);	/* virtual root hub */
-
-	// Sanity checks
-	if (usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe)) <= 0) {		
-		err("uhci_submit_urb: pipesize for pipe %x is zero", urb->pipe);
-		return -EMSGSIZE;
-	}
-
-	if (urb->transfer_buffer_length < 0 && type != PIPE_ISOCHRONOUS) {
-		err("uhci_submit_urb: Negative transfer length for urb %p", urb);
-		return -EINVAL;
-	}
-
-	usb_inc_dev_use (urb->dev);
-
-	spin_lock_irqsave (&s->urb_list_lock, flags);
-
-	queued_urb = search_dev_ep (s, urb); // returns already queued urb for that pipe
-
-	if (queued_urb) {
-
-		queue_dbg("found bulk urb %p\n", queued_urb);
-
-		if (( type != PIPE_BULK) ||
-		    ((type == PIPE_BULK) &&
-		     (!(urb->transfer_flags & USB_QUEUE_BULK) || !(queued_urb->transfer_flags & USB_QUEUE_BULK)))) {
-			spin_unlock_irqrestore (&s->urb_list_lock, flags);
-			usb_dec_dev_use (urb->dev);
-			err("ENXIO %08x, flags %x, urb %p, burb %p",urb->pipe,urb->transfer_flags,urb,queued_urb);
-			return -ENXIO;	// urb already queued
-		}
-	}
-
-#ifdef DEBUG_SLAB
-	urb_priv = kmem_cache_alloc(urb_priv_kmem, SLAB_FLAG);
-#else
-	urb_priv = kmalloc (sizeof (urb_priv_t), KMALLOC_FLAG);
-#endif
-	if (!urb_priv) {
-		usb_dec_dev_use (urb->dev);
-		spin_unlock_irqrestore (&s->urb_list_lock, flags);
-		return -ENOMEM;
-	}
-
-	memset(urb_priv, 0, sizeof(urb_priv_t));
-	urb->hcpriv = urb_priv;
-	INIT_LIST_HEAD (&urb_priv->desc_list);
-
-	dbg("submit_urb: scheduling %p", urb);
-	
-	if (type == PIPE_CONTROL)
-		urb_priv->setup_packet_dma = pci_map_single(s->uhci_pci, urb->setup_packet,
-							    sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
-
-	if (urb->transfer_buffer_length)
-		urb_priv->transfer_buffer_dma = pci_map_single(s->uhci_pci,
-							       urb->transfer_buffer,
-							       urb->transfer_buffer_length,
-							       usb_pipein(urb->pipe) ?
-							       PCI_DMA_FROMDEVICE :
-							       PCI_DMA_TODEVICE);
-
-	if (type == PIPE_BULK) {
-	
-		if (queued_urb) {
-			while (((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb)  // find last queued bulk
-				queued_urb=((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb;
-			
-			((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb=urb;
-		}
-		atomic_inc (&s->avoid_bulk);
-		ret = uhci_submit_bulk_urb (urb, queued_urb);
-		atomic_dec (&s->avoid_bulk);
-		spin_unlock_irqrestore (&s->urb_list_lock, flags);
-	}
-	else {
-		spin_unlock_irqrestore (&s->urb_list_lock, flags);
-		switch (type) {
-		case PIPE_ISOCHRONOUS:			
-			if (urb->bandwidth == 0) {      /* not yet checked/allocated */
-				if (urb->number_of_packets <= 0) {
-					ret = -EINVAL;
-					break;
-				}
-
-				bustime = usb_check_bandwidth (urb->dev, urb);
-				if (bustime < 0) 
-					ret = bustime;
-				else {
-					ret = uhci_submit_iso_urb(urb);
-					if (ret == 0)
-						usb_claim_bandwidth (urb->dev, urb, bustime, 1);
-				}
-			} else {        /* bandwidth is already set */
-				ret = uhci_submit_iso_urb(urb);
-			}
-			break;
-		case PIPE_INTERRUPT:
-			if (urb->bandwidth == 0) {      /* not yet checked/allocated */
-				bustime = usb_check_bandwidth (urb->dev, urb);
-				if (bustime < 0)
-					ret = bustime;
-				else {
-					ret = uhci_submit_int_urb(urb);
-					if (ret == 0)
-						usb_claim_bandwidth (urb->dev, urb, bustime, 0);
-				}
-			} else {        /* bandwidth is already set */
-				ret = uhci_submit_int_urb(urb);
-			}
-			break;
-		case PIPE_CONTROL:
-			ret = uhci_submit_control_urb (urb);
-			break;
-		default:
-			ret = -EINVAL;
-		}
-	}
-
-	dbg("submit_urb: scheduled with ret: %d", ret);
-	
-	if (ret != 0) {
-		uhci_urb_dma_unmap(s, urb, urb_priv);
-		usb_dec_dev_use (urb->dev);
-#ifdef DEBUG_SLAB
-		kmem_cache_free(urb_priv_kmem, urb_priv);
-#else
-		kfree (urb_priv);
-#endif
-		return ret;
-	}
-
-	return 0;
-}
-
-// Checks for URB timeout and removes bandwidth reclamation if URB idles too long
-_static void uhci_check_timeouts(uhci_t *s)
-{
-	struct list_head *p,*p2;
-	struct urb *urb;
-	int type;	
-
-	p = s->urb_list.prev;	
-
-	while (p != &s->urb_list) {
-		urb_priv_t *hcpriv;
-
-		p2 = p;
-		p = p->prev;
-		urb = list_entry (p2, struct urb, urb_list);
-		type = usb_pipetype (urb->pipe);
-
-		hcpriv = (urb_priv_t*)urb->hcpriv;
-		
-		if ( urb->timeout && time_after(jiffies, hcpriv->started + urb->timeout)) {
-			urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
-			async_dbg("uhci_check_timeout: timeout for %p",urb);
-			uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
-		}
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-		else if (((type == PIPE_BULK) || (type == PIPE_CONTROL)) &&  
-			 (hcpriv->use_loop) && time_after(jiffies, hcpriv->started + IDLE_TIMEOUT))
-			disable_desc_loop(s, urb);
-#endif
-
-	}
-	s->timeout_check=jiffies;
-}
-
-/*-------------------------------------------------------------------
- Virtual Root Hub
- -------------------------------------------------------------------*/
-
-_static __u8 root_hub_dev_des[] =
-{
-	0x12,			/*  __u8  bLength; */
-	0x01,			/*  __u8  bDescriptorType; Device */
-	0x00,			/*  __u16 bcdUSB; v1.0 */
-	0x01,
-	0x09,			/*  __u8  bDeviceClass; HUB_CLASSCODE */
-	0x00,			/*  __u8  bDeviceSubClass; */
-	0x00,			/*  __u8  bDeviceProtocol; */
-	0x08,			/*  __u8  bMaxPacketSize0; 8 Bytes */
-	0x00,			/*  __u16 idVendor; */
-	0x00,
-	0x00,			/*  __u16 idProduct; */
-	0x00,
-	0x00,			/*  __u16 bcdDevice; */
-	0x00,
-	0x00,			/*  __u8  iManufacturer; */
-	0x02,			/*  __u8  iProduct; */
-	0x01,			/*  __u8  iSerialNumber; */
-	0x01			/*  __u8  bNumConfigurations; */
-};
-
-
-/* Configuration descriptor */
-_static __u8 root_hub_config_des[] =
-{
-	0x09,			/*  __u8  bLength; */
-	0x02,			/*  __u8  bDescriptorType; Configuration */
-	0x19,			/*  __u16 wTotalLength; */
-	0x00,
-	0x01,			/*  __u8  bNumInterfaces; */
-	0x01,			/*  __u8  bConfigurationValue; */
-	0x00,			/*  __u8  iConfiguration; */
-	0x40,			/*  __u8  bmAttributes; 
-				   Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
-	0x00,			/*  __u8  MaxPower; */
-
-     /* interface */
-	0x09,			/*  __u8  if_bLength; */
-	0x04,			/*  __u8  if_bDescriptorType; Interface */
-	0x00,			/*  __u8  if_bInterfaceNumber; */
-	0x00,			/*  __u8  if_bAlternateSetting; */
-	0x01,			/*  __u8  if_bNumEndpoints; */
-	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
-	0x00,			/*  __u8  if_bInterfaceSubClass; */
-	0x00,			/*  __u8  if_bInterfaceProtocol; */
-	0x00,			/*  __u8  if_iInterface; */
-
-     /* endpoint */
-	0x07,			/*  __u8  ep_bLength; */
-	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */
-	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
-	0x03,			/*  __u8  ep_bmAttributes; Interrupt */
-	0x08,			/*  __u16 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 *** */
-};
-
-/*-------------------------------------------------------------------------*/
-/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
-_static int rh_send_irq (struct urb *urb)
-{
-	int len = 1;
-	int i;
-	uhci_t *uhci = urb->dev->bus->hcpriv;
-	unsigned int io_addr = uhci->io_addr;
-	__u16 data = 0;
-
-	for (i = 0; i < uhci->rh.numports; i++) {
-		data |= ((inw (io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);
-		len = (i + 1) / 8 + 1;
-	}
-
-	*(__u16 *) urb->transfer_buffer = cpu_to_le16 (data);
-	urb->actual_length = len;
-	urb->status = 0;
-	
-	if ((data > 0) && (uhci->rh.send != 0)) {
-		dbg("Root-Hub INT complete: port1: %x port2: %x data: %x",
-		     inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2), data);
-		urb->complete (urb);
-	}
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
-_static int rh_init_int_timer (struct urb *urb);
-
-_static void rh_int_timer_do (unsigned long ptr)
-{
-	int len;
-	struct urb *urb = (struct urb*) ptr;
-	uhci_t *uhci = urb->dev->bus->hcpriv;
-
-	if (uhci->rh.send) {
-		len = rh_send_irq (urb);
-		if (len > 0) {
-			urb->actual_length = len;
-			if (urb->complete)
-				urb->complete (urb);
-		}
-	}
-	rh_init_int_timer (urb);
-}
-
-/*-------------------------------------------------------------------------*/
-/* Root Hub INTs are polled by this timer, polling interval 20ms */
-
-_static int rh_init_int_timer (struct urb *urb)
-{
-	uhci_t *uhci = urb->dev->bus->hcpriv;
-
-	uhci->rh.interval = urb->interval;
-	init_timer (&uhci->rh.rh_int_timer);
-	uhci->rh.rh_int_timer.function = rh_int_timer_do;
-	uhci->rh.rh_int_timer.data = (unsigned long) urb;
-	uhci->rh.rh_int_timer.expires = jiffies + (HZ * 20) / 1000;
-	add_timer (&uhci->rh.rh_int_timer);
-
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-#define OK(x) 			len = (x); break
-
-#define CLR_RH_PORTSTAT(x) \
-		status = inw(io_addr+USBPORTSC1+2*(wIndex-1)); \
-		status = (status & 0xfff5) & ~(x); \
-		outw(status, io_addr+USBPORTSC1+2*(wIndex-1))
-
-#define SET_RH_PORTSTAT(x) \
-		status = inw(io_addr+USBPORTSC1+2*(wIndex-1)); \
-		status = (status & 0xfff5) | (x); \
-		outw(status, io_addr+USBPORTSC1+2*(wIndex-1))
-
-
-/*-------------------------------------------------------------------------*/
-/****
- ** Root Hub Control Pipe
- *************************/
-
-
-_static int rh_submit_urb (struct urb *urb)
-{
-	struct usb_device *usb_dev = urb->dev;
-	uhci_t *uhci = 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 status = 0;
-	int stat = 0;
-	int i;
-	unsigned int io_addr = uhci->io_addr;
-	__u16 cstatus;
-
-	__u16 bmRType_bReq;
-	__u16 wValue;
-	__u16 wIndex;
-	__u16 wLength;
-
-	if (usb_pipetype (pipe) == PIPE_INTERRUPT) {
-		dbg("Root-Hub submit IRQ: every %d ms", urb->interval);
-		uhci->rh.urb = urb;
-		uhci->rh.send = 1;
-		uhci->rh.interval = urb->interval;
-		rh_init_int_timer (urb);
-
-		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);
-
-	for (i = 0; i < 8; i++)
-		uhci->rh.c_p_r[i] = 0;
-
-	dbg("Root-Hub: adr: %2x cmd(%1x): %04x %04x %04x %04x",
-	     uhci->rh.devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
-
-	switch (bmRType_bReq) {
-		/* Request Destination:
-		   without flags: Device, 
-		   RH_INTERFACE: interface, 
-		   RH_ENDPOINT: endpoint,
-		   RH_CLASS means HUB here, 
-		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
-		 */
-
-	case RH_GET_STATUS:
-		*(__u16 *) data = 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:
-		status = inw (io_addr + USBPORTSC1 + 2 * (wIndex - 1));
-		cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
-			((status & USBPORTSC_PEC) >> (3 - 1)) |
-			(uhci->rh.c_p_r[wIndex - 1] << (0 + 4));
-		status = (status & USBPORTSC_CCS) |
-			((status & USBPORTSC_PE) >> (2 - 1)) |
-			((status & USBPORTSC_SUSP) >> (12 - 2)) |
-			((status & USBPORTSC_PR) >> (9 - 4)) |
-			(1 << 8) |	/* power on ** */
-			((status & USBPORTSC_LSDA) << (-8 + 9));
-
-		*(__u16 *) data = cpu_to_le16 (status);
-		*(__u16 *) (data + 2) = cpu_to_le16 (cstatus);
-		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):
-			CLR_RH_PORTSTAT (USBPORTSC_PE);
-			OK (0);
-		case (RH_PORT_SUSPEND):
-			CLR_RH_PORTSTAT (USBPORTSC_SUSP);
-			OK (0);
-		case (RH_PORT_POWER):
-			OK (0);	/* port power ** */
-		case (RH_C_PORT_CONNECTION):
-			SET_RH_PORTSTAT (USBPORTSC_CSC);
-			OK (0);
-		case (RH_C_PORT_ENABLE):
-			SET_RH_PORTSTAT (USBPORTSC_PEC);
-			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):
-			uhci->rh.c_p_r[wIndex - 1] = 0;
-			OK (0);
-		}
-		break;
-
-	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
-		switch (wValue) {
-		case (RH_PORT_SUSPEND):
-			SET_RH_PORTSTAT (USBPORTSC_SUSP);
-			OK (0);
-		case (RH_PORT_RESET):
-			SET_RH_PORTSTAT (USBPORTSC_PR);
-			uhci_wait_ms (10);
-			uhci->rh.c_p_r[wIndex - 1] = 1;
-			CLR_RH_PORTSTAT (USBPORTSC_PR);
-			udelay (10);
-			SET_RH_PORTSTAT (USBPORTSC_PE);
-			uhci_wait_ms (10);
-			SET_RH_PORTSTAT (0xa);
-			OK (0);
-		case (RH_PORT_POWER):
-			OK (0);	/* port power ** */
-		case (RH_PORT_ENABLE):
-			SET_RH_PORTSTAT (USBPORTSC_PE);
-			OK (0);
-		}
-		break;
-
-	case RH_SET_ADDRESS:
-		uhci->rh.devnum = wValue;
-		OK (0);
-
-	case RH_GET_DESCRIPTOR:
-		switch ((wValue & 0xff00) >> 8) {
-		case (0x01):	/* device descriptor */
-			len = min_t(unsigned int, leni,
-				  min_t(unsigned int,
-				      sizeof (root_hub_dev_des), wLength));
-			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,
-			        uhci->io_addr, "UHCI",
-				data, wLength);
-			if (len > 0) {
-				OK(min_t(int, leni, len));
-			} else 
-				stat = -EPIPE;
-		}
-		break;
-
-	case RH_GET_DESCRIPTOR | RH_CLASS:
-		root_hub_hub_des[2] = uhci->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;
-	}
-
-	dbg("Root-Hub stat port1: %x port2: %x",
-	     inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2));
-
-	urb->actual_length = len;
-	urb->status = stat;
-	urb->dev=NULL;
-	if (urb->complete)
-		urb->complete (urb);
-	return 0;
-}
-/*-------------------------------------------------------------------------*/
-
-_static int rh_unlink_urb (struct urb *urb)
-{
-	uhci_t *uhci = urb->dev->bus->hcpriv;
-
-	if (uhci->rh.urb==urb) {
-		dbg("Root-Hub unlink IRQ");
-		uhci->rh.send = 0;
-		del_timer (&uhci->rh.rh_int_timer);
-	}
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-
-/*
- * Map status to standard result codes
- *
- * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)
- * <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 -ETIMEDOUT;
-		else
-			return -EILSEQ;
-	}
-	if (status & TD_CTRL_NAK)	/* NAK */
-		return -ETIMEDOUT;
-	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;
-	if (status & TD_CTRL_ACTIVE)	/* Active */
-		return 0;
-
-	return -EPROTO;
-}
-
-/*
- * Only the USB core should call uhci_alloc_dev and uhci_free_dev
- */
-_static int uhci_alloc_dev (struct usb_device *usb_dev)
-{
-	return 0;
-}
-
-_static void uhci_unlink_urbs(uhci_t *s, struct usb_device *usb_dev, int remove_all)
-{
-	unsigned long flags;
-	struct list_head *p;
-	struct list_head *p2;
-	struct urb *urb;
-
-	spin_lock_irqsave (&s->urb_list_lock, flags);
-	p = s->urb_list.prev;	
-	while (p != &s->urb_list) {
-		p2 = p;
-		p = p->prev ;
-		urb = list_entry (p2, struct urb, urb_list);
-		dbg("urb: %p, dev %p, %p", urb, usb_dev,urb->dev);
-		
-		//urb->transfer_flags |=USB_ASYNC_UNLINK; 
-			
-		if (remove_all || (usb_dev == urb->dev)) {
-			spin_unlock_irqrestore (&s->urb_list_lock, flags);
-			warn("forced removing of queued URB %p due to disconnect",urb);
-			uhci_unlink_urb(urb);
-			urb->dev = NULL; // avoid further processing of this URB
-			spin_lock_irqsave (&s->urb_list_lock, flags);
-			p = s->urb_list.prev;	
-		}
-	}
-	spin_unlock_irqrestore (&s->urb_list_lock, flags);
-}
-
-_static int uhci_free_dev (struct usb_device *usb_dev)
-{
-	uhci_t *s;
-	
-
-	if(!usb_dev || !usb_dev->bus || !usb_dev->bus->hcpriv)
-		return -EINVAL;
-	
-	s=(uhci_t*) usb_dev->bus->hcpriv;	
-	uhci_unlink_urbs(s, usb_dev, 0);
-
-	return 0;
-}
-
-/*
- * uhci_get_current_frame_number()
- *
- * returns the current frame number for a USB bus/controller.
- */
-_static int uhci_get_current_frame_number (struct usb_device *usb_dev)
-{
-	return UHCI_GET_CURRENT_FRAME ((uhci_t*) usb_dev->bus->hcpriv);
-}
-
-struct usb_operations uhci_device_operations =
-{
-	uhci_alloc_dev,
-	uhci_free_dev,
-	uhci_get_current_frame_number,
-	uhci_submit_urb,
-	uhci_unlink_urb
-};
-
-_static void correct_data_toggles(struct urb *urb)
-{
-	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), 
-		       !usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)));
-
-	while(urb) {
-		urb_priv_t *priv=urb->hcpriv;		
-		uhci_desc_t *qh = list_entry (priv->desc_list.next, uhci_desc_t, desc_list);
-		struct list_head *p = qh->vertical.next;
-		uhci_desc_t *td;
-		dbg("URB to correct %p\n", urb);
-	
-		for (; p != &qh->vertical; p = p->next) {
-			td = list_entry (p, uhci_desc_t, vertical);
-			td->hw.td.info^=cpu_to_le32(1<<TD_TOKEN_TOGGLE);
-		}
-		urb=priv->next_queued_urb;
-	}
-}
-
-/* 
- * For IN-control transfers, process_transfer gets a bit more complicated,
- * since there are devices that return less data (eg. strings) than they
- * have announced. This leads to a queue abort due to the short packet,
- * the status stage is not executed. If this happens, the status stage
- * is manually re-executed.
- * mode: PROCESS_TRANSFER_REGULAR: regular (unlink QH)
- *       PROCESS_TRANSFER_DONT_UNLINK: QHs already unlinked (for async unlink_urb)
- */
-
-_static int process_transfer (uhci_t *s, struct urb *urb, int mode)
-{
-	int ret = 0;
-	urb_priv_t *urb_priv = urb->hcpriv;
-	struct list_head *qhl = urb_priv->desc_list.next;
-	uhci_desc_t *qh = list_entry (qhl, uhci_desc_t, desc_list);
-	struct list_head *p = qh->vertical.next;
-	uhci_desc_t *desc= list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
-	uhci_desc_t *last_desc = list_entry (desc->vertical.prev, uhci_desc_t, vertical);
-	int data_toggle = usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));	// save initial data_toggle
-	int maxlength; 	// extracted and remapped info from TD
-	int actual_length;
-	int status = 0;
-
-	//dbg("process_transfer: urb %p, urb_priv %p, qh %p last_desc %p\n",urb,urb_priv, qh, last_desc);
-
-	/* if the status phase has been retriggered and the
-	   queue is empty or the last status-TD is inactive, the retriggered
-	   status stage is completed
-	 */
-
-	if (urb_priv->flags && 
-	    ((qh->hw.qh.element == cpu_to_le32(UHCI_PTR_TERM)) || !is_td_active(desc)))
-		goto transfer_finished;
-
-	urb->actual_length=0;
-
-	for (; p != &qh->vertical; p = p->next) {
-		desc = list_entry (p, uhci_desc_t, vertical);
-
-		if (is_td_active(desc)) {	// do not process active TDs
-			if (mode == CLEAN_TRANSFER_DELETION_MARK) // if called from async_unlink
-				uhci_clean_transfer(s, urb, qh, CLEAN_TRANSFER_DELETION_MARK);
-			return ret;
-		}
-	
-		actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status));		// extract transfer parameters from TD
-		maxlength = (((le32_to_cpu(desc->hw.td.info) >> 21) & 0x7ff) + 1) & 0x7ff;
-		status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
-
-		if (status == -EPIPE) { 		// see if EP is stalled
-			// set up stalled condition
-			usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
-		}
-
-		if (status && (status != -EPIPE)) {	// if any error occurred stop processing of further TDs
-			// only set ret if status returned an error
-  is_error:
-			ret = status;
-			urb->error_count++;
-			break;
-		}
-		else if ((le32_to_cpu(desc->hw.td.info) & 0xff) != USB_PID_SETUP)
-			urb->actual_length += actual_length;
-
-		// got less data than requested
-		if ( (actual_length < maxlength)) {
-			if (urb->transfer_flags & USB_DISABLE_SPD) {
-				status = -EREMOTEIO;	// treat as real error
-				dbg("process_transfer: SPD!!");
-				break;	// exit after this TD because SP was detected
-			}
-
-			// short read during control-IN: re-start status stage
-			if ((usb_pipetype (urb->pipe) == PIPE_CONTROL)) {
-				if (uhci_packetid(le32_to_cpu(last_desc->hw.td.info)) == USB_PID_OUT) {
-			
-					set_qh_element(qh, last_desc->dma_addr);  // re-trigger status stage
-					dbg("short packet during control transfer, retrigger status stage @ %p",last_desc);
-					urb_priv->flags = 1; // mark as short control packet
-					return 0;
-				}
-			}
-			// all other cases: short read is OK
-			data_toggle = uhci_toggle (le32_to_cpu(desc->hw.td.info));
-			break;
-		}
-		else if (status)
-			goto is_error;
-
-		data_toggle = uhci_toggle (le32_to_cpu(desc->hw.td.info));
-		queue_dbg("process_transfer: len:%d status:%x mapped:%x toggle:%d", actual_length, le32_to_cpu(desc->hw.td.status),status, data_toggle);      
-
-	}
-
-	if (usb_pipetype (urb->pipe) == PIPE_BULK ) {  /* toggle correction for short bulk transfers (nonqueued/queued) */
-
-		urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
-		struct urb *next_queued_urb=priv->next_queued_urb;
-
-		if (next_queued_urb) {
-			urb_priv_t *next_priv=(urb_priv_t*)next_queued_urb->hcpriv;
-			uhci_desc_t *qh = list_entry (next_priv->desc_list.next, uhci_desc_t, desc_list);
-			uhci_desc_t *first_td=list_entry (qh->vertical.next, uhci_desc_t, vertical);
-
-			if (data_toggle == uhci_toggle (le32_to_cpu(first_td->hw.td.info))) {
-				err("process_transfer: fixed toggle");
-				correct_data_toggles(next_queued_urb);
-			}						
-		}
-		else
-			usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), !data_toggle);		
-	}
-
- transfer_finished:
-	
-	uhci_clean_transfer(s, urb, qh, mode);
-
-	urb->status = status;
-
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH	
-	disable_desc_loop(s,urb);
-#endif	
-
-	queue_dbg("process_transfer: (end) urb %p, wanted len %d, len %d status %x err %d",
-		urb,urb->transfer_buffer_length,urb->actual_length, urb->status, urb->error_count);
-	return ret;
-}
-
-_static int process_interrupt (uhci_t *s, struct urb *urb)
-{
-	int i, ret = -EINPROGRESS;
-	urb_priv_t *urb_priv = urb->hcpriv;
-	struct list_head *p = urb_priv->desc_list.next;
-	uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
-
-	int actual_length;
-	int status = 0;
-
-	//dbg("urb contains interrupt request");
-
-	for (i = 0; p != &urb_priv->desc_list; p = p->next, i++)	// Maybe we allow more than one TD later ;-)
-	{
-		desc = list_entry (p, uhci_desc_t, desc_list);
-
-		if (is_td_active(desc)) {
-			// do not process active TDs
-			//dbg("TD ACT Status @%p %08x",desc,le32_to_cpu(desc->hw.td.status));
-			break;
-		}
-
-		if (!(desc->hw.td.status & cpu_to_le32(TD_CTRL_IOC))) {
-			// do not process one-shot TDs, no recycling
-			break;
-		}
-		// extract transfer parameters from TD
-
-		actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status));
-		status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
-
-		// see if EP is stalled
-		if (status == -EPIPE) {
-			// set up stalled condition
-			usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
-		}
-
-		// if any error occurred: ignore this td, and continue
-		if (status != 0) {
-			//uhci_show_td (desc);
-			urb->error_count++;
-			goto recycle;
-		}
-		else
-			urb->actual_length = actual_length;
-
-	recycle:
-		uhci_urb_dma_sync(s, urb, urb->hcpriv);
-		if (urb->complete) {
-			//dbg("process_interrupt: calling completion, status %i",status);
-			urb->status = status;
-			((urb_priv_t*)urb->hcpriv)->flags=1; // if unlink_urb is called during completion
-
-			spin_unlock(&s->urb_list_lock);
-			
-			urb->complete ((struct urb *) urb);
-			
-			spin_lock(&s->urb_list_lock);
-
-			((urb_priv_t*)urb->hcpriv)->flags=0;		       			
-		}
-		
-		if ((urb->status != -ECONNABORTED) && (urb->status != ECONNRESET) &&
-			    (urb->status != -ENOENT)) {
-
-			urb->status = -EINPROGRESS;
-
-			// Recycle INT-TD if interval!=0, else mark TD as one-shot
-			if (urb->interval) {
-				
-				desc->hw.td.info &= cpu_to_le32(~(1 << TD_TOKEN_TOGGLE));
-				if (status==0) {
-					((urb_priv_t*)urb->hcpriv)->started=jiffies;
-					desc->hw.td.info |= cpu_to_le32((usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
-									    usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE));
-					usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
-				} else {
-					desc->hw.td.info |= cpu_to_le32((!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
-									     usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE));
-				}
-				desc->hw.td.status= cpu_to_le32((urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
-					(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27));
-				mb();
-			}
-			else {
-				uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
-				uhci_clean_iso_step2(s, urb_priv);
-				// correct toggle after unlink
-				usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
-				clr_td_ioc(desc); // inactivate TD
-			}
-		}
-	}
-
-	return ret;
-}
-
-// mode: PROCESS_ISO_REGULAR: processing only for done TDs, unlink TDs
-// mode: PROCESS_ISO_FORCE: force processing, don't unlink TDs (already unlinked)
-
-_static int process_iso (uhci_t *s, struct urb *urb, int mode)
-{
-	int i;
-	int ret = 0;
-	urb_priv_t *urb_priv = urb->hcpriv;
-	struct list_head *p = urb_priv->desc_list.next, *p_tmp;
-	uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
-
-	dbg("urb contains iso request");
-	if (is_td_active(desc) && mode==PROCESS_ISO_REGULAR)
-		return -EXDEV;	// last TD not finished
-
-	urb->error_count = 0;
-	urb->actual_length = 0;
-	urb->status = 0;
-	dbg("process iso urb %p, %li, %i, %i, %i %08x",urb,jiffies,UHCI_GET_CURRENT_FRAME(s),
-	    urb->number_of_packets,mode,le32_to_cpu(desc->hw.td.status));
-
-	for (i = 0; p != &urb_priv->desc_list;  i++) {
-		desc = list_entry (p, uhci_desc_t, desc_list);
-		
-		//uhci_show_td(desc);
-		if (is_td_active(desc)) {
-			// means we have completed the last TD, but not the TDs before
-			desc->hw.td.status &= cpu_to_le32(~TD_CTRL_ACTIVE);
-			dbg("TD still active (%x)- grrr. paranoia!", le32_to_cpu(desc->hw.td.status));
-			ret = -EXDEV;
-			urb->iso_frame_desc[i].status = ret;
-			unlink_td (s, desc, 1);
-			// FIXME: immediate deletion may be dangerous
-			goto err;
-		}
-
-		if (mode == PROCESS_ISO_REGULAR)
-			unlink_td (s, desc, 1);
-
-		if (urb->number_of_packets <= i) {
-			dbg("urb->number_of_packets (%d)<=(%d)", urb->number_of_packets, i);
-			ret = -EINVAL;
-			goto err;
-		}
-
-		urb->iso_frame_desc[i].actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status));
-		urb->iso_frame_desc[i].status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
-		urb->actual_length += urb->iso_frame_desc[i].actual_length;
-
-	      err:
-
-		if (urb->iso_frame_desc[i].status != 0) {
-			urb->error_count++;
-			urb->status = urb->iso_frame_desc[i].status;
-		}
-		dbg("process_iso: %i: len:%d %08x status:%x",
-		     i, urb->iso_frame_desc[i].actual_length, le32_to_cpu(desc->hw.td.status),urb->iso_frame_desc[i].status);
-
-		p_tmp = p;
-		p = p->next;
-		list_del (p_tmp);
-		delete_desc (s, desc);
-	}
-	
-	dbg("process_iso: exit %i (%d), actual_len %i", i, ret,urb->actual_length);
-	return ret;
-}
-
-
-_static int process_urb (uhci_t *s, struct list_head *p)
-{
-	int ret = 0;
-	struct urb *urb;
-
-	urb=list_entry (p, struct urb, urb_list);
-	//dbg("process_urb: found queued urb: %p", urb);
-
-	switch (usb_pipetype (urb->pipe)) {
-	case PIPE_CONTROL:
-		ret = process_transfer (s, urb, CLEAN_TRANSFER_REGULAR);
-		break;
-	case PIPE_BULK:
-		if (!s->avoid_bulk.counter)
-			ret = process_transfer (s, urb, CLEAN_TRANSFER_REGULAR);
-		else
-			return 0;
-		break;
-	case PIPE_ISOCHRONOUS:
-		ret = process_iso (s, urb, PROCESS_ISO_REGULAR);
-		break;
-	case PIPE_INTERRUPT:
-		ret = process_interrupt (s, urb);
-		break;
-	}
-
-	if (urb->status != -EINPROGRESS) {
-		urb_priv_t *urb_priv;
-		struct usb_device *usb_dev;
-		
-		usb_dev=urb->dev;
-
-		/* Release bandwidth for Interrupt or Iso transfers */
-		if (urb->bandwidth) {
-			if (usb_pipetype(urb->pipe)==PIPE_ISOCHRONOUS)
-				usb_release_bandwidth (urb->dev, urb, 1);
-			else if (usb_pipetype(urb->pipe)==PIPE_INTERRUPT && urb->interval)
-				usb_release_bandwidth (urb->dev, urb, 0);
-		}
-
-		dbg("dequeued urb: %p", urb);
-		dequeue_urb (s, urb);
-
-		urb_priv = urb->hcpriv;
-
-		uhci_urb_dma_unmap(s, urb, urb_priv);
-
-#ifdef DEBUG_SLAB
-		kmem_cache_free(urb_priv_kmem, urb_priv);
-#else
-		kfree (urb_priv);
-#endif
-
-		if ((usb_pipetype (urb->pipe) != PIPE_INTERRUPT)) {  // process_interrupt does completion on its own		
-			struct urb *next_urb = urb->next;
-			int is_ring = 0;
-			int contains_killed = 0;
-			int loop_count=0;
-			
-			if (next_urb) {
-				// Find out if the URBs are linked to a ring
-				while  (next_urb != NULL && next_urb != urb && loop_count < MAX_NEXT_COUNT) {
-					if (next_urb->status == -ENOENT) {// killed URBs break ring structure & resubmission
-						contains_killed = 1;
-						break;
-					}	
-					next_urb = next_urb->next;
-					loop_count++;
-				}
-				
-				if (loop_count == MAX_NEXT_COUNT)
-					err("process_urb: Too much linked URBs in ring detection!");
-
-				if (next_urb == urb)
-					is_ring=1;
-			}			
-
-			// Submit idle/non-killed URBs linked with urb->next
-			// Stop before the current URB				
-			
-			next_urb = urb->next;	
-			if (next_urb && !contains_killed) {
-				int ret_submit;
-				next_urb = urb->next;	
-				
-				loop_count=0;
-				while (next_urb != NULL && next_urb != urb && loop_count < MAX_NEXT_COUNT) {
-					if (next_urb->status != -EINPROGRESS) {
-					
-						if (next_urb->status == -ENOENT) 
-							break;
-
-						spin_unlock(&s->urb_list_lock);
-
-						ret_submit=uhci_submit_urb(next_urb);
-						spin_lock(&s->urb_list_lock);
-						
-						if (ret_submit)
-							break;						
-					}
-					loop_count++;
-					next_urb = next_urb->next;
-				}
-				if (loop_count == MAX_NEXT_COUNT)
-					err("process_urb: Too much linked URBs in resubmission!");
-			}
-
-			// Completion
-			if (urb->complete) {
-				int was_unlinked = (urb->status == -ENOENT);
-				urb->dev = NULL;
-				spin_unlock(&s->urb_list_lock);
-
-				urb->complete ((struct urb *) urb);
-
-				// Re-submit the URB if ring-linked
-				if (is_ring && !was_unlinked && !contains_killed) {
-					urb->dev=usb_dev;
-					uhci_submit_urb (urb);
-				}
-				spin_lock(&s->urb_list_lock);
-			}
-			
-			usb_dec_dev_use (usb_dev);
-		}
-	}
-
-	return ret;
-}
-
-_static void uhci_interrupt (int irq, void *__uhci, struct pt_regs *regs)
-{
-	uhci_t *s = __uhci;
-	unsigned int io_addr = s->io_addr;
-	unsigned short status;
-	struct list_head *p, *p2;
-	int restarts, work_done;
-	
-	/*
-	 * Read the interrupt status, and write it back to clear the
-	 * interrupt cause
-	 */
-
-	status = inw (io_addr + USBSTS);
-
-	if (!status)		/* shared interrupt, not mine */
-		return;
-
-	dbg("interrupt");
-
-	if (status != 1) {
-		// Avoid too much error messages at a time
-		if (time_after(jiffies, s->last_error_time + ERROR_SUPPRESSION_TIME)) {
-			warn("interrupt, status %x, frame# %i", status, 
-			     UHCI_GET_CURRENT_FRAME(s));
-			s->last_error_time = jiffies;
-		}
-		
-		// remove host controller halted state
-		if ((status&0x20) && (s->running)) {
-			err("Host controller halted, trying to restart.");
-			outw (USBCMD_RS | inw(io_addr + USBCMD), io_addr + USBCMD);
-		}
-		//uhci_show_status (s);
-	}
-	/*
-	 * traverse the list in *reverse* direction, because new entries
-	 * may be added at the end.
-	 * also, because process_urb may unlink the current urb,
-	 * we need to advance the list before
-	 * New: check for max. workload and restart count
-	 */
-
-	spin_lock (&s->urb_list_lock);
-
-	restarts=0;
-	work_done=0;
-
-restart:
-	s->unlink_urb_done=0;
-	p = s->urb_list.prev;	
-
-	while (p != &s->urb_list && (work_done < 1024)) {
-		p2 = p;
-		p = p->prev;
-
-		process_urb (s, p2);
-		
-		work_done++;
-
-		if (s->unlink_urb_done) {
-			s->unlink_urb_done=0;
-			restarts++;
-			
-			if (restarts<16)	// avoid endless restarts
-				goto restart;
-			else 
-				break;
-		}
-	}
-	if (time_after(jiffies, s->timeout_check + (HZ/30)))
-		uhci_check_timeouts(s);
-
-	clean_descs(s, CLEAN_NOT_FORCED);
-	uhci_cleanup_unlink(s, CLEAN_NOT_FORCED);
-	uhci_switch_timer_int(s);
-							
-	spin_unlock (&s->urb_list_lock);
-	
-	outw (status, io_addr + USBSTS);
-
-	//dbg("uhci_interrupt: done");
-}
-
-_static void reset_hc (uhci_t *s)
-{
-	unsigned int io_addr = s->io_addr;
-
-	s->apm_state = 0;
-	/* Global reset for 50ms */
-	outw (USBCMD_GRESET, io_addr + USBCMD);
-	uhci_wait_ms (50);
-	outw (0, io_addr + USBCMD);
-	uhci_wait_ms (10);
-}
-
-_static void start_hc (uhci_t *s)
-{
-	unsigned int io_addr = s->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) {
-			err("USBCMD_HCRESET timed out!");
-			break;
-		}
-		udelay(1);
-	}
-
-	/* Turn on all interrupts */
-	outw (USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR);
-
-	/* Start at frame 0 */
-	outw (0, io_addr + USBFRNUM);
-	outl (s->framelist_dma, io_addr + USBFLBASEADD);
-
-	/* Run and mark it configured with a 64-byte max packet */
-	outw (USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
-	s->apm_state = 1;
-	s->running = 1;
-}
-
-/* No  __devexit, since it maybe called from alloc_uhci() */
-_static void
-uhci_pci_remove (struct pci_dev *dev)
-{
-	uhci_t *s = pci_get_drvdata(dev);
-	struct usb_device *root_hub = s->bus->root_hub;
-
-	s->running = 0;		    // Don't allow submit_urb
-
-	if (root_hub)
-		usb_disconnect (&root_hub);
-
-	reset_hc (s);
-	wait_ms (1);
-
-	uhci_unlink_urbs (s, 0, CLEAN_FORCED);  // Forced unlink of remaining URBs
-	uhci_cleanup_unlink (s, CLEAN_FORCED);  // force cleanup of async killed URBs
-	
-	usb_deregister_bus (s->bus);
-
-	release_region (s->io_addr, s->io_size);
-	free_irq (s->irq, s);
-	usb_free_bus (s->bus);
-	cleanup_skel (s);
-	kfree (s);
-}
-
-_static int __init uhci_start_usb (uhci_t *s)
-{				/* start it up */
-	/* connect the virtual root hub */
-	struct usb_device *usb_dev;
-
-	usb_dev = usb_alloc_dev (NULL, s->bus);
-	if (!usb_dev)
-		return -1;
-
-	s->bus->root_hub = usb_dev;
-	usb_connect (usb_dev);
-
-	if (usb_new_device (usb_dev) != 0) {
-		usb_free_dev (usb_dev);
-		return -1;
-	}
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-_static int
-uhci_pci_suspend (struct pci_dev *dev, u32 state)
-{
-	reset_hc((uhci_t *) pci_get_drvdata(dev));
-	return 0;
-}
-
-_static int
-uhci_pci_resume (struct pci_dev *dev)
-{
-	start_hc((uhci_t *) pci_get_drvdata(dev));
-	return 0;
-}
-#endif
-
-_static int __devinit alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size)
-{
-	uhci_t *s;
-	struct usb_bus *bus;
-	char buf[8], *bufp = buf;
-
-#ifndef __sparc__
-	sprintf(buf, "%d", irq);
-#else
-	bufp = __irq_itoa(irq);
-#endif
-	printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n",
-		io_addr, bufp);
-
-	s = kmalloc (sizeof (uhci_t), GFP_KERNEL);
-	if (!s)
-		return -1;
-
-	memset (s, 0, sizeof (uhci_t));
-	INIT_LIST_HEAD (&s->free_desc);
-	INIT_LIST_HEAD (&s->urb_list);
-	INIT_LIST_HEAD (&s->urb_unlinked);
-	spin_lock_init (&s->urb_list_lock);
-	spin_lock_init (&s->qh_lock);
-	spin_lock_init (&s->td_lock);
-	atomic_set(&s->avoid_bulk, 0);
-	s->irq = -1;
-	s->io_addr = io_addr;
-	s->io_size = io_size;
-	s->uhci_pci=dev;
-
-	bus = usb_alloc_bus (&uhci_device_operations);
-	if (!bus) {
-		kfree (s);
-		return -1;
-	}
-
-	s->bus = bus;
-	bus->bus_name = dev->slot_name;
-	bus->hcpriv = s;
-
-	/* 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, so default to 2 */
-	/* According to the UHCI spec, Bit 7 is always set to 1. So we try */
-	/* to use this to our advantage */
-
-	for (s->maxports = 0; s->maxports < (io_size - 0x10) / 2; s->maxports++) {
-		unsigned int portstatus;
-
-		portstatus = inw (io_addr + 0x10 + (s->maxports * 2));
-		dbg("port %i, adr %x status %x", s->maxports,
-			io_addr + 0x10 + (s->maxports * 2), portstatus);
-		if (!(portstatus & 0x0080))
-			break;
-	}
-	warn("Detected %d ports", s->maxports);
-
-	/* This is experimental so anything less than 2 or greater than 8 is */
-	/*  something weird and we'll ignore it */
-	if (s->maxports < 2 || s->maxports > 8) {
-		dbg("Port count misdetected, forcing to 2 ports");
-		s->maxports = 2;
-	}
-
-	s->rh.numports = s->maxports;
-	s->loop_usage=0;
-	if (init_skel (s)) {
-		usb_free_bus (bus);
-		kfree(s);
-		return -1;
-	}
-
-	request_region (s->io_addr, io_size, MODNAME);
-	reset_hc (s);
-	usb_register_bus (s->bus);
-
-	start_hc (s);
-
-	if (request_irq (irq, uhci_interrupt, SA_SHIRQ, MODNAME, s)) {
-		err("request_irq %d failed!",irq);
-		usb_free_bus (bus);
-		reset_hc (s);
-		release_region (s->io_addr, s->io_size);
-		cleanup_skel(s);
-		kfree(s);
-		return -1;
-	}
-
-	/* Enable PIRQ */
-	pci_write_config_word (dev, USBLEGSUP, USBLEGSUP_DEFAULT);
-
-	s->irq = irq;
-
-	if(uhci_start_usb (s) < 0) {
-		uhci_pci_remove(dev);
-		return -1;
-	}
-
-	//chain new uhci device into global list
-	pci_set_drvdata(dev, s);
-	devs=s;
-
-	return 0;
-}
-
-_static int __devinit
-uhci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
-{
-	int i;
-
-	if (pci_enable_device(dev) < 0)
-		return -ENODEV;
-		
-	if (!dev->irq) {
-		err("found UHCI device with no IRQ assigned. check BIOS settings!");
-		return -ENODEV;
-	}
-	
-	pci_set_master(dev);
-
-	/* Search for the IO base address.. */
-	for (i = 0; i < 6; i++) {
-
-		unsigned int io_addr = pci_resource_start(dev, i);
-		unsigned int io_size = pci_resource_len(dev, i);
-		if (!(pci_resource_flags(dev,i) & IORESOURCE_IO))
-			continue;
-
-		/* Is it already in use? */
-		if (check_region (io_addr, io_size))
-			break;
-		/* disable legacy emulation */
-		pci_write_config_word (dev, USBLEGSUP, 0);
-	
-		return alloc_uhci(dev, dev->irq, io_addr, io_size);
-	}
-	return -ENODEV;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static const struct pci_device_id __devinitdata uhci_pci_ids [] = { {
-
-	/* handle any USB UHCI controller */
-	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x00),
-	class_mask: 	~0,
-
-	/* no matter who makes it */
-	vendor:		PCI_ANY_ID,
-	device:		PCI_ANY_ID,
-	subvendor:	PCI_ANY_ID,
-	subdevice:	PCI_ANY_ID,
-
-	}, { /* end: all zeroes */ }
-};
-
-MODULE_DEVICE_TABLE (pci, uhci_pci_ids);
-
-static struct pci_driver uhci_pci_driver = {
-	name:		"usb-uhci",
-	id_table:	&uhci_pci_ids [0],
-
-	probe:		uhci_pci_probe,
-	remove:		uhci_pci_remove,
-
-#ifdef	CONFIG_PM
-	suspend:	uhci_pci_suspend,
-	resume:		uhci_pci_resume,
-#endif	/* PM */
-
-};
-
-/*-------------------------------------------------------------------------*/
-
-static int __init uhci_hcd_init (void) 
-{
-	int retval;
-
-#ifdef DEBUG_SLAB
-	urb_priv_kmem = kmem_cache_create("urb_priv", sizeof(urb_priv_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
-	
-	if(!urb_priv_kmem) {
-		err("kmem_cache_create for urb_priv_t failed (out of memory)");
-		return -ENOMEM;
-	}
-#endif	
-	info(VERSTR);
-
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-	info("High bandwidth mode enabled");	
-#endif
-
-	retval = pci_module_init (&uhci_pci_driver);
-
-#ifdef DEBUG_SLAB
-	if (retval < 0 ) {
-		if (kmem_cache_destroy(urb_priv_kmem))
-			err("urb_priv_kmem remained");
-	}
-#endif
-	
-	info(DRIVER_VERSION ":" DRIVER_DESC);
-
-	return retval;
-}
-
-static void __exit uhci_hcd_cleanup (void) 
-{      
-	pci_unregister_driver (&uhci_pci_driver);
-	
-#ifdef DEBUG_SLAB
-	if(kmem_cache_destroy(urb_priv_kmem))
-		err("urb_priv_kmem remained");
-#endif
-}
-
-module_init (uhci_hcd_init);
-module_exit (uhci_hcd_cleanup);
-
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/usb/usb-uhci.h b/drivers/usb/usb-uhci.h
--- a/drivers/usb/usb-uhci.h	Thu Mar  6 14:22:16 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,308 +0,0 @@
-#ifndef __LINUX_UHCI_H
-#define __LINUX_UHCI_H
-
-/*
-   $Id: usb-uhci.h,v 1.58 2001/08/28 16:45:00 acher Exp $
- */
-#define MODNAME "usb-uhci"
-#define UHCI_LATENCY_TIMER 0
-
-static __inline__ void uhci_wait_ms(unsigned int ms)
-{
-	if(!in_interrupt())
-	{
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(1 + ms * HZ / 1000);
-	}
-	else
-		mdelay(ms);
-}
-
-/* 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_LS		0x0030	/* Line Status */
-#define   USBPORTSC_RD		0x0040	/* Resume Detect */
-#define   USBPORTSC_LSDA	0x0100	/* Low Speed Device Attached */
-#define   USBPORTSC_PR		0x0200	/* Port Reset */
-#define   USBPORTSC_SUSP	0x1000	/* Suspend */
-
-/* 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_PID 		0xff	/* PID MASK */
-
-#define UHCI_PTR_BITS		0x000F
-#define UHCI_PTR_TERM		0x0001
-#define UHCI_PTR_QH		0x0002
-#define UHCI_PTR_DEPTH		0x0004
-
-#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 */
-
-/*
- * 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_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_status_bits(ctrl_sts)	(ctrl_sts & 0xFE0000)
-#define uhci_actual_length(ctrl_sts)	((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK)	/* 1-based */
-#define uhci_ptr_to_virt(x)	bus_to_virt(x & ~UHCI_PTR_BITS)
-
-/*
- * for TD <flags>:
- */
-#define UHCI_TD_REMOVE		0x0001	/* Remove when done */
-
-/*
- * for TD <info>: (a.k.a. Token)
- */
-#define TD_TOKEN_TOGGLE		19
-
-#define uhci_maxlen(token)	((token) >> 21)
-#define uhci_toggle(token)	(((token) >> TD_TOKEN_TOGGLE) & 1)
-#define uhci_endpoint(token)	(((token) >> 15) & 0xf)
-#define uhci_devaddr(token)	(((token) >> 8) & 0x7f)
-#define uhci_devep(token)	(((token) >> 8) & 0x7ff)
-#define uhci_packetid(token)	((token) & 0xff)
-#define uhci_packetout(token)	(uhci_packetid(token) != USB_PID_IN)
-#define uhci_packetin(token)	(uhci_packetid(token) == USB_PID_IN)
-
-/* ------------------------------------------------------------------------------------
-   New TD/QH-structures
-   ------------------------------------------------------------------------------------ */
-typedef enum {
-	TD_TYPE, QH_TYPE
-} uhci_desc_type_t;
-
-typedef struct {
-	__u32 link;
-	__u32 status;
-	__u32 info;
-	__u32 buffer;
-} uhci_td_t, *puhci_td_t;
-
-typedef struct {
-	__u32 head;
-	__u32 element;		/* Queue element pointer */
-} uhci_qh_t, *puhci_qh_t;
-
-typedef struct {
-	union {
-		uhci_td_t td;
-		uhci_qh_t qh;
-	} hw;
-	uhci_desc_type_t type;
-	dma_addr_t dma_addr;
-	struct list_head horizontal;
-	struct list_head vertical;
-	struct list_head desc_list;
-	int last_used;
-} uhci_desc_t, *puhci_desc_t;
-
-typedef struct {
-	struct list_head desc_list;	// list pointer to all corresponding TDs/QHs associated with this request
-	dma_addr_t setup_packet_dma;
-	dma_addr_t transfer_buffer_dma;
-	unsigned long started;
-	struct urb *next_queued_urb;	// next queued urb for this EP
-	struct urb *prev_queued_urb;
-	uhci_desc_t *bottom_qh;
-	uhci_desc_t *next_qh;       	// next helper QH
-	char use_loop;
-	char flags;
-} urb_priv_t, *purb_priv_t;
-
-struct virt_root_hub {
-	int devnum;		/* Address of Root Hub endpoint */
-	void *urb;
-	void *int_addr;
-	int send;
-	int interval;
-	int numports;
-	int c_p_r[8];
-	struct timer_list rh_int_timer;
-};
-
-typedef struct uhci {
-	int irq;
-	unsigned int io_addr;
-	unsigned int io_size;
-	unsigned int maxports;
-	int running;
-
-	int apm_state;
-
-	struct uhci *next;	// chain of uhci device contexts
-
-	struct list_head urb_list;	// list of all pending urbs
-
-	spinlock_t urb_list_lock;	// lock to keep consistency 
-
-	int unlink_urb_done;
-	atomic_t avoid_bulk;
-	
-	struct usb_bus *bus;	// our bus
-
-	__u32 *framelist;
-	dma_addr_t framelist_dma;
-	uhci_desc_t **iso_td;
-	uhci_desc_t *int_chain[8];
-	uhci_desc_t *ls_control_chain;
-	uhci_desc_t *control_chain;
-	uhci_desc_t *bulk_chain;
-	uhci_desc_t *chain_end;
-	uhci_desc_t *td1ms;
-	uhci_desc_t *td32ms;
-	struct list_head free_desc;
-	spinlock_t qh_lock;
-	spinlock_t td_lock;
-	struct virt_root_hub rh;	//private data of the virtual root hub
-	int loop_usage;            // URBs using bandwidth reclamation
-
-	struct list_head urb_unlinked;	// list of all unlinked  urbs
-	long timeout_check;
-	int timeout_urbs;
-	struct pci_dev *uhci_pci;
-	struct pci_pool *desc_pool;
-	long last_error_time;          // last error output in uhci_interrupt()
-} uhci_t, *puhci_t;
-
-
-#define MAKE_TD_ADDR(a) ((a)->dma_addr&~UHCI_PTR_QH)
-#define MAKE_QH_ADDR(a) ((a)->dma_addr|UHCI_PTR_QH)
-#define UHCI_GET_CURRENT_FRAME(uhci) (inw ((uhci)->io_addr + USBFRNUM))
-
-#define CLEAN_TRANSFER_NO_DELETION 0
-#define CLEAN_TRANSFER_REGULAR 1
-#define CLEAN_TRANSFER_DELETION_MARK 2
-
-#define CLEAN_NOT_FORCED 0
-#define CLEAN_FORCED 1
-
-#define PROCESS_ISO_REGULAR 0
-#define PROCESS_ISO_FORCE 1
-
-#define UNLINK_ASYNC_STORE_URB 0
-#define UNLINK_ASYNC_DONT_STORE 1
-
-#define is_td_active(desc) (desc->hw.td.status & cpu_to_le32(TD_CTRL_ACTIVE))
-
-#define set_qh_head(desc,val) (desc)->hw.qh.head=cpu_to_le32(val)
-#define set_qh_element(desc,val) (desc)->hw.qh.element=cpu_to_le32(val)
-#define set_td_link(desc,val) (desc)->hw.td.link=cpu_to_le32(val)
-#define set_td_ioc(desc) (desc)->hw.td.status |= cpu_to_le32(TD_CTRL_IOC)
-#define clr_td_ioc(desc) (desc)->hw.td.status &= cpu_to_le32(~TD_CTRL_IOC)
-
-
-/* ------------------------------------------------------------------------------------ 
-   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
-
-#endif
