aboutsummaryrefslogtreecommitdiffstats
path: root/usb
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2005-12-22 12:36:39 -0800
committerGreg Kroah-Hartman <gregkh@suse.de>2005-12-22 12:36:39 -0800
commit87c5263ad6176dc271c0d2f03ffadfe215aa426b (patch)
tree4b8489e17ec749398b7e424ed81f02faa19b5815 /usb
parent0e7d257c166adee881b7af917821cd4f0813095f (diff)
downloadpatches-87c5263ad6176dc271c0d2f03ffadfe215aa426b.tar.gz
uhci patches and an i2c update
Diffstat (limited to 'usb')
-rw-r--r--usb/uhci-don-t-log-short-transfers.patch37
-rw-r--r--usb/uhci-improve-debugging-code.patch285
-rw-r--r--usb/uhci-remove-main-list-of-urbs.patch927
-rw-r--r--usb/uhci-use-dummy-tds.patch320
-rw-r--r--usb/uhci-use-one-qh-per-endpoint-not-per-urb.patch2397
5 files changed, 3966 insertions, 0 deletions
diff --git a/usb/uhci-don-t-log-short-transfers.patch b/usb/uhci-don-t-log-short-transfers.patch
new file mode 100644
index 00000000000000..1b0ed73980c59d
--- /dev/null
+++ b/usb/uhci-don-t-log-short-transfers.patch
@@ -0,0 +1,37 @@
+From stern@rowland.harvard.edu Tue Dec 20 07:01:47 2005
+Date: Tue, 20 Dec 2005 09:58:08 -0500 (EST)
+From: Alan Stern <stern@rowland.harvard.edu>
+To: Greg KH <greg@kroah.com>
+Subject: [PATCH] UHCI: Don't log short transfers
+Message-ID: <Pine.LNX.4.44L0.0512200953140.5250-100000@iolanthe.rowland.org>
+
+Even when the URB_SHORT_NOT_OK flag is set, a short transfer shouldn't
+generate a debugging log message. Especially not one with the confusing
+claim that the transfer "failed with status 0". This patch (as627)
+fixes that behavior in uhci-hcd.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/uhci-q.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- gregkh-2.6.orig/drivers/usb/host/uhci-q.c
++++ gregkh-2.6/drivers/usb/host/uhci-q.c
+@@ -922,7 +922,6 @@ static int uhci_result_common(struct uhc
+ td_error:
+ ret = uhci_map_status(status, uhci_packetout(td_token(td)));
+
+-err:
+ if ((debug == 1 && ret != -EPIPE) || debug > 1) {
+ /* Some debugging code */
+ dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
+@@ -934,6 +933,7 @@ err:
+ lprintk(errbuf);
+ }
+ }
++err:
+
+ /* Note that the queue has stopped and save the next toggle value */
+ urbp->qh->element = UHCI_PTR_TERM;
diff --git a/usb/uhci-improve-debugging-code.patch b/usb/uhci-improve-debugging-code.patch
new file mode 100644
index 00000000000000..2b8c9e5b2c3b0d
--- /dev/null
+++ b/usb/uhci-improve-debugging-code.patch
@@ -0,0 +1,285 @@
+From stern@rowland.harvard.edu Sat Dec 17 15:14:04 2005
+Date: Sat, 17 Dec 2005 18:03:37 -0500 (EST)
+From: Alan Stern <stern@rowland.harvard.edu>
+To: Greg KH <greg@kroah.com>
+Subject: [PATCH 4/4] UHCI: improve debugging code
+Message-ID: <Pine.LNX.4.44L0.0512171732300.14730-100000@netrider.rowland.org>
+
+This patch (as626) makes some improvements to the debugging code in
+uhci-hcd. The main change is that now the code won't get compiled if
+CONFIG_USB_DEBUG isn't set. But there are other changes too, like
+adding a missing .owner field and printing a debugging dump if the
+controller dies.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/uhci-debug.c | 36 ++++++++++++++++++++-----
+ drivers/usb/host/uhci-hcd.c | 60 +++++++++++++++++++++++++++---------------
+ drivers/usb/host/uhci-hcd.h | 1
+ drivers/usb/host/uhci-q.c | 12 --------
+ 4 files changed, 70 insertions(+), 39 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/host/uhci-q.c
++++ gregkh-2.6/drivers/usb/host/uhci-q.c
+@@ -736,7 +736,6 @@ err:
+ if (errbuf) {
+ /* Print the chain for debugging purposes */
+ uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
+-
+ lprintk(errbuf);
+ }
+ }
+@@ -924,26 +923,17 @@ td_error:
+ ret = uhci_map_status(status, uhci_packetout(td_token(td)));
+
+ err:
+- /*
+- * Enable this chunk of code if you want to see some more debugging.
+- * But be careful, it has the tendancy to starve out khubd and prevent
+- * disconnects from happening successfully if you have a slow debug
+- * log interface (like a serial console.
+- */
+-#if 0
+ if ((debug == 1 && ret != -EPIPE) || debug > 1) {
+ /* Some debugging code */
+ dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
+ __FUNCTION__, status);
+
+- if (errbuf) {
++ if (debug > 1 && errbuf) {
+ /* Print the chain for debugging purposes */
+ uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
+-
+ lprintk(errbuf);
+ }
+ }
+-#endif
+
+ /* Note that the queue has stopped and save the next toggle value */
+ urbp->qh->element = UHCI_PTR_TERM;
+--- gregkh-2.6.orig/drivers/usb/host/uhci-hcd.c
++++ gregkh-2.6/drivers/usb/host/uhci-hcd.c
+@@ -68,12 +68,16 @@ Alan Stern"
+ * debug = 3, show all TDs in URBs when dumping
+ */
+ #ifdef DEBUG
++#define DEBUG_CONFIGURED 1
+ static int debug = 1;
+-#else
+-static int debug = 0;
+-#endif
+ module_param(debug, int, S_IRUGO | S_IWUSR);
+ MODULE_PARM_DESC(debug, "Debug level");
++
++#else
++#define DEBUG_CONFIGURED 0
++#define debug 0
++#endif
++
+ static char *errbuf;
+ #define ERRBUF_LEN (32 * 1024)
+
+@@ -338,6 +342,12 @@ static irqreturn_t uhci_irq(struct usb_h
+ dev_err(uhci_dev(uhci),
+ "host controller halted, "
+ "very bad!\n");
++ if (debug > 1 && errbuf) {
++ /* Print the schedule for debugging */
++ uhci_sprint_schedule(uhci,
++ errbuf, ERRBUF_LEN);
++ lprintk(errbuf);
++ }
+ hc_died(uhci);
+
+ /* Force a callback in case there are
+@@ -376,6 +386,14 @@ static void release_uhci(struct uhci_hcd
+ {
+ int i;
+
++ if (DEBUG_CONFIGURED) {
++ spin_lock_irq(&uhci->lock);
++ uhci->is_initialized = 0;
++ spin_unlock_irq(&uhci->lock);
++
++ debugfs_remove(uhci->dentry);
++ }
++
+ for (i = 0; i < UHCI_NUM_SKELQH; i++)
+ uhci_free_qh(uhci, uhci->skelqh[i]);
+
+@@ -390,8 +408,6 @@ static void release_uhci(struct uhci_hcd
+ dma_free_coherent(uhci_dev(uhci),
+ UHCI_NUMFRAMES * sizeof(*uhci->frame),
+ uhci->frame, uhci->frame_dma_handle);
+-
+- debugfs_remove(uhci->dentry);
+ }
+
+ static int uhci_reset(struct usb_hcd *hcd)
+@@ -474,17 +490,6 @@ static int uhci_start(struct usb_hcd *hc
+
+ hcd->uses_new_polling = 1;
+
+- dentry = debugfs_create_file(hcd->self.bus_name,
+- S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci,
+- &uhci_debug_operations);
+- if (!dentry) {
+- dev_err(uhci_dev(uhci),
+- "couldn't create uhci debugfs entry\n");
+- retval = -ENOMEM;
+- goto err_create_debug_entry;
+- }
+- uhci->dentry = dentry;
+-
+ uhci->fsbr = 0;
+ uhci->fsbrtimeout = 0;
+
+@@ -495,6 +500,19 @@ static int uhci_start(struct usb_hcd *hc
+
+ init_waitqueue_head(&uhci->waitqh);
+
++ if (DEBUG_CONFIGURED) {
++ dentry = debugfs_create_file(hcd->self.bus_name,
++ S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root,
++ uhci, &uhci_debug_operations);
++ if (!dentry) {
++ dev_err(uhci_dev(uhci), "couldn't create uhci "
++ "debugfs entry\n");
++ retval = -ENOMEM;
++ goto err_create_debug_entry;
++ }
++ uhci->dentry = dentry;
++ }
++
+ uhci->frame = dma_alloc_coherent(uhci_dev(uhci),
+ UHCI_NUMFRAMES * sizeof(*uhci->frame),
+ &uhci->frame_dma_handle, 0);
+@@ -609,6 +627,7 @@ static int uhci_start(struct usb_hcd *hc
+ mb();
+
+ configure_hc(uhci);
++ uhci->is_initialized = 1;
+ start_rh(uhci);
+ return 0;
+
+@@ -872,16 +891,15 @@ static int __init uhci_hcd_init(void)
+ if (usb_disabled())
+ return -ENODEV;
+
+- if (debug) {
++ if (DEBUG_CONFIGURED) {
+ errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
+ if (!errbuf)
+ goto errbuf_failed;
++ uhci_debugfs_root = debugfs_create_dir("uhci", NULL);
++ if (!uhci_debugfs_root)
++ goto debug_failed;
+ }
+
+- uhci_debugfs_root = debugfs_create_dir("uhci", NULL);
+- if (!uhci_debugfs_root)
+- goto debug_failed;
+-
+ uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
+ sizeof(struct urb_priv), 0, 0, NULL, NULL);
+ if (!uhci_up_cachep)
+--- gregkh-2.6.orig/drivers/usb/host/uhci-debug.c
++++ gregkh-2.6/drivers/usb/host/uhci-debug.c
+@@ -17,10 +17,13 @@
+
+ #include "uhci-hcd.h"
+
+-static struct dentry *uhci_debugfs_root = NULL;
++#define uhci_debug_operations (* (struct file_operations *) NULL)
++static struct dentry *uhci_debugfs_root;
++
++#ifdef DEBUG
+
+ /* Handle REALLY large printks so we don't overflow buffers */
+-static inline void lprintk(char *buf)
++static void lprintk(char *buf)
+ {
+ char *p;
+
+@@ -196,7 +199,6 @@ static int uhci_show_qh(struct uhci_qh *
+ return out - buf;
+ }
+
+-#ifdef CONFIG_PROC_FS
+ static const char * const qh_names[] = {
+ "skel_unlink_qh", "skel_iso_qh",
+ "skel_int128_qh", "skel_int64_qh",
+@@ -393,12 +395,13 @@ static int uhci_sprint_schedule(struct u
+ return out - buf;
+ }
+
++#ifdef CONFIG_DEBUG_FS
++
+ #define MAX_OUTPUT (64 * 1024)
+
+ struct uhci_debug {
+ int size;
+ char *data;
+- struct uhci_hcd *uhci;
+ };
+
+ static int uhci_debug_open(struct inode *inode, struct file *file)
+@@ -419,8 +422,10 @@ static int uhci_debug_open(struct inode
+ goto out;
+ }
+
++ up->size = 0;
+ spin_lock_irqsave(&uhci->lock, flags);
+- up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
++ if (uhci->is_initialized)
++ up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
+ spin_unlock_irqrestore(&uhci->lock, flags);
+
+ file->private_data = up;
+@@ -472,15 +477,32 @@ static int uhci_debug_release(struct ino
+ return 0;
+ }
+
++#undef uhci_debug_operations
+ static struct file_operations uhci_debug_operations = {
++ .owner = THIS_MODULE,
+ .open = uhci_debug_open,
+ .llseek = uhci_debug_lseek,
+ .read = uhci_debug_read,
+ .release = uhci_debug_release,
+ };
+
+-#else /* CONFIG_DEBUG_FS */
++#endif /* CONFIG_DEBUG_FS */
+
+-#define uhci_debug_operations (* (struct file_operations *) NULL)
++#else /* DEBUG */
++
++static inline void lprintk(char *buf)
++{}
++
++static inline int uhci_show_qh(struct uhci_qh *qh, char *buf,
++ int len, int space)
++{
++ return 0;
++}
++
++static inline int uhci_sprint_schedule(struct uhci_hcd *uhci,
++ char *buf, int len)
++{
++ return 0;
++}
+
+ #endif
+--- gregkh-2.6.orig/drivers/usb/host/uhci-hcd.h
++++ gregkh-2.6/drivers/usb/host/uhci-hcd.h
+@@ -411,6 +411,7 @@ struct uhci_hcd {
+ unsigned int hc_inaccessible:1; /* HC is suspended or dead */
+ unsigned int working_RD:1; /* Suspended root hub doesn't
+ need to be polled */
++ unsigned int is_initialized:1; /* Data structure is usable */
+
+ /* Support for port suspend/resume/reset */
+ unsigned long port_c_suspend; /* Bit-arrays of ports */
diff --git a/usb/uhci-remove-main-list-of-urbs.patch b/usb/uhci-remove-main-list-of-urbs.patch
new file mode 100644
index 00000000000000..01234c586a90c1
--- /dev/null
+++ b/usb/uhci-remove-main-list-of-urbs.patch
@@ -0,0 +1,927 @@
+From stern@rowland.harvard.edu Sat Dec 17 15:13:57 2005
+Date: Sat, 17 Dec 2005 18:02:38 -0500 (EST)
+From: Alan Stern <stern@rowland.harvard.edu>
+To: Greg KH <greg@kroah.com>
+Subject: [PATCH 3/4] UHCI: remove main list of URBs
+Message-ID: <Pine.LNX.4.44L0.0512171728000.14730-100000@netrider.rowland.org>
+
+As part of reorienting uhci-hcd away from URBs and toward endpoint
+queues, this patch (as625) eliminates the driver's main list of URBs.
+The list wsa used mainly in checking for URB completions; now the driver
+goes through the list of active endpoints and checks the members of the
+queues.
+
+As a side effect, I had to remove the code that looks for FSBR timeouts.
+For now, FSBR will remain on so long as any URBs on a full-speed control
+or bulk queue request it, even if the queue isn't advancing. A later
+patch can add more intelligent handling. This isn't a huge drawback;
+it's pretty rare for an URB to get stuck for more than a fraction of a
+second. (And it will help the people trying to use those insane HP USB
+devices.)
+
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/uhci-debug.c | 1
+ drivers/usb/host/uhci-hcd.c | 2
+ drivers/usb/host/uhci-hcd.h | 15
+ drivers/usb/host/uhci-q.c | 633 ++++++++++++++++++------------------------
+ 4 files changed, 280 insertions(+), 371 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/host/uhci-q.c
++++ gregkh-2.6/drivers/usb/host/uhci-q.c
+@@ -151,53 +151,6 @@ static void uhci_unlink_isochronous_tds(
+ wmb();
+ }
+
+-/*
+- * Remove an URB's TDs from the hardware schedule
+- */
+-static void uhci_remove_tds_from_schedule(struct uhci_hcd *uhci,
+- struct urb *urb, int status)
+-{
+- struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
+-
+- /* Isochronous TDs get unlinked directly from the frame list */
+- if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+- uhci_unlink_isochronous_tds(uhci, urb);
+- return;
+- }
+-
+- /* If the URB isn't first on its queue, adjust the link pointer
+- * of the last TD in the previous URB. */
+- if (urbp->node.prev != &urbp->qh->queue) {
+- struct urb_priv *purbp;
+- struct uhci_td *ptd, *ltd;
+-
+- if (status == -EINPROGRESS)
+- status = 0;
+- purbp = list_entry(urbp->node.prev, struct urb_priv, node);
+- ptd = list_entry(purbp->td_list.prev, struct uhci_td,
+- list);
+- ltd = list_entry(urbp->td_list.prev, struct uhci_td,
+- list);
+- ptd->link = ltd->link;
+- }
+-
+- /* If the URB completed with an error, then the QH element certainly
+- * points to one of the URB's TDs. If it completed normally then
+- * the QH element has certainly moved on to the next URB. And if
+- * the URB is still in progress then it must have been dequeued.
+- * The QH element either hasn't reached it yet or is somewhere in
+- * the middle. If the URB wasn't first we can assume that it
+- * hasn't started yet (see above): Otherwise all the preceding URBs
+- * would have completed and been removed from the queue, so this one
+- * _would_ be first.
+- *
+- * If the QH element is inside this URB, clear it. It will be
+- * set properly when the QH is activated.
+- */
+- if (status < 0)
+- urbp->qh->element = UHCI_PTR_TERM;
+-}
+-
+ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
+ struct usb_device *udev, struct usb_host_endpoint *hep)
+ {
+@@ -251,6 +204,90 @@ static void uhci_free_qh(struct uhci_hcd
+ }
+
+ /*
++ * When the currently executing URB is dequeued, save its current toggle value
++ */
++static void uhci_save_toggle(struct uhci_qh *qh, struct urb *urb)
++{
++ struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
++ struct uhci_td *td;
++
++ /* If the QH element pointer is UHCI_PTR_TERM then then currently
++ * executing URB has already been unlinked, so this one isn't it. */
++ if (qh_element(qh) == UHCI_PTR_TERM ||
++ qh->queue.next != &urbp->node)
++ return;
++ qh->element = UHCI_PTR_TERM;
++
++ /* Only bulk and interrupt pipes have to worry about toggles */
++ if (!(usb_pipetype(urb->pipe) == PIPE_BULK ||
++ usb_pipetype(urb->pipe) == PIPE_INTERRUPT))
++ return;
++
++ /* Find the first active TD; that's the device's toggle state */
++ list_for_each_entry(td, &urbp->td_list, list) {
++ if (td_status(td) & TD_CTRL_ACTIVE) {
++ qh->needs_fixup = 1;
++ qh->initial_toggle = uhci_toggle(td_token(td));
++ return;
++ }
++ }
++
++ WARN_ON(1);
++}
++
++/*
++ * Fix up the data toggles for URBs in a queue, when one of them
++ * terminates early (short transfer, error, or dequeued).
++ */
++static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first)
++{
++ struct urb_priv *urbp = NULL;
++ struct uhci_td *td;
++ unsigned int toggle = qh->initial_toggle;
++ unsigned int pipe;
++
++ /* Fixups for a short transfer start with the second URB in the
++ * queue (the short URB is the first). */
++ if (skip_first)
++ urbp = list_entry(qh->queue.next, struct urb_priv, node);
++
++ /* When starting with the first URB, if the QH element pointer is
++ * still valid then we know the URB's toggles are okay. */
++ else if (qh_element(qh) != UHCI_PTR_TERM)
++ toggle = 2;
++
++ /* Fix up the toggle for the URBs in the queue. Normally this
++ * loop won't run more than once: When an error or short transfer
++ * occurs, the queue usually gets emptied. */
++ list_prepare_entry(urbp, &qh->queue, node);
++ list_for_each_entry_continue(urbp, &qh->queue, node) {
++
++ /* If the first TD has the right toggle value, we don't
++ * need to change any toggles in this URB */
++ td = list_entry(urbp->td_list.next, struct uhci_td, list);
++ if (toggle > 1 || uhci_toggle(td_token(td)) == toggle) {
++ td = list_entry(urbp->td_list.next, struct uhci_td,
++ list);
++ toggle = uhci_toggle(td_token(td)) ^ 1;
++
++ /* Otherwise all the toggles in the URB have to be switched */
++ } else {
++ list_for_each_entry(td, &urbp->td_list, list) {
++ td->token ^= __constant_cpu_to_le32(
++ TD_TOKEN_TOGGLE);
++ toggle ^= 1;
++ }
++ }
++ }
++
++ wmb();
++ pipe = list_entry(qh->queue.next, struct urb_priv, node)->urb->pipe;
++ usb_settoggle(qh->udev, usb_pipeendpoint(pipe),
++ usb_pipeout(pipe), toggle);
++ qh->needs_fixup = 0;
++}
++
++/*
+ * Put a QH on the schedule in both hardware and software
+ */
+ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+@@ -276,6 +313,9 @@ static void uhci_activate_qh(struct uhci
+
+ /* Move the QH from its old list to the end of the appropriate
+ * skeleton's list */
++ if (qh == uhci->next_qh)
++ uhci->next_qh = list_entry(qh->node.next, struct uhci_qh,
++ node);
+ list_move_tail(&qh->node, &qh->skel->node);
+
+ /* Link it into the schedule */
+@@ -310,6 +350,9 @@ static void uhci_unlink_qh(struct uhci_h
+ uhci_set_next_interrupt(uhci);
+
+ /* Move the QH from its old list to the end of the unlinking list */
++ if (qh == uhci->next_qh)
++ uhci->next_qh = list_entry(qh->node.next, struct uhci_qh,
++ node);
+ list_move_tail(&qh->node, &uhci->skel_unlink_qh->node);
+ }
+
+@@ -323,6 +366,9 @@ static void uhci_make_qh_idle(struct uhc
+ {
+ WARN_ON(qh->state == QH_STATE_ACTIVE);
+
++ if (qh == uhci->next_qh)
++ uhci->next_qh = list_entry(qh->node.next, struct uhci_qh,
++ node);
+ list_move(&qh->node, &uhci->idle_qh_list);
+ qh->state = QH_STATE_IDLE;
+
+@@ -344,11 +390,9 @@ static inline struct urb_priv *uhci_allo
+
+ urbp->urb = urb;
+ urb->hcpriv = urbp;
+- urbp->fsbrtime = jiffies;
+
+ INIT_LIST_HEAD(&urbp->node);
+ INIT_LIST_HEAD(&urbp->td_list);
+- INIT_LIST_HEAD(&urbp->urb_list);
+
+ return urbp;
+ }
+@@ -373,9 +417,6 @@ static void uhci_free_urb_priv(struct uh
+ {
+ struct uhci_td *td, *tmp;
+
+- if (!list_empty(&urbp->urb_list))
+- dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list!\n",
+- urbp->urb);
+ if (!list_empty(&urbp->node))
+ dev_warn(uhci_dev(uhci), "urb %p still on QH's list!\n",
+ urbp->urb);
+@@ -453,71 +494,6 @@ static int uhci_map_status(int status, i
+ }
+
+ /*
+- * Fix up the data toggles for URBs in a queue, when one of them
+- * terminates early (short transfer, error, or dequeued).
+- */
+-static void uhci_fixup_toggles(struct urb *urb)
+-{
+- struct list_head *head;
+- struct uhci_td *td;
+- struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
+- int prevactive = 0;
+- unsigned int toggle = 0;
+- struct urb_priv *turbp, *list_end;
+-
+- /*
+- * We need to find out what the last successful toggle was so
+- * we can update the data toggles for the following transfers.
+- *
+- * There are 2 ways the last successful completed TD is found:
+- *
+- * 1) The TD is NOT active and the actual length < expected length
+- * 2) The TD is NOT active and it's the last TD in the chain
+- *
+- * and a third way the first uncompleted TD is found:
+- *
+- * 3) The TD is active and the previous TD is NOT active
+- */
+- head = &urbp->td_list;
+- list_for_each_entry(td, head, list) {
+- unsigned int ctrlstat = td_status(td);
+-
+- if (!(ctrlstat & TD_CTRL_ACTIVE) &&
+- (uhci_actual_length(ctrlstat) <
+- uhci_expected_length(td_token(td)) ||
+- td->list.next == head))
+- toggle = uhci_toggle(td_token(td)) ^ 1;
+- else if ((ctrlstat & TD_CTRL_ACTIVE) && !prevactive)
+- toggle = uhci_toggle(td_token(td));
+-
+- prevactive = ctrlstat & TD_CTRL_ACTIVE;
+- }
+-
+- /*
+- * Fix up the toggle for the following URBs in the queue.
+- *
+- * We can stop as soon as we find an URB with toggles set correctly,
+- * because then all the following URBs will be correct also.
+- */
+- list_end = list_entry(&urbp->qh->queue, struct urb_priv, node);
+- turbp = urbp;
+- while ((turbp = list_entry(turbp->node.next, struct urb_priv, node))
+- != list_end) {
+- td = list_entry(turbp->td_list.next, struct uhci_td, list);
+- if (uhci_toggle(td_token(td)) == toggle)
+- return;
+-
+- list_for_each_entry(td, &turbp->td_list, list) {
+- td->token ^= __constant_cpu_to_le32(TD_TOKEN_TOGGLE);
+- toggle ^= 1;
+- }
+- }
+-
+- usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+- usb_pipeout(urb->pipe), toggle);
+-}
+-
+-/*
+ * Control transfers
+ */
+ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
+@@ -765,6 +741,9 @@ err:
+ }
+ }
+
++ /* Note that the queue has stopped */
++ urbp->qh->element = UHCI_PTR_TERM;
++ urbp->qh->is_stopped = 1;
+ return ret;
+ }
+
+@@ -927,7 +906,10 @@ static int uhci_result_common(struct uhc
+ */
+ if (!urbp->short_transfer) {
+ urbp->short_transfer = 1;
+- uhci_fixup_toggles(urb);
++ urbp->qh->initial_toggle =
++ uhci_toggle(td_token(td)) ^ 1;
++ uhci_fixup_toggles(urbp->qh, 1);
++
+ td = list_entry(urbp->td_list.prev,
+ struct uhci_td, list);
+ urbp->qh->element = td->link;
+@@ -962,6 +944,13 @@ err:
+ }
+ }
+ #endif
++
++ /* Note that the queue has stopped and save the next toggle value */
++ urbp->qh->element = UHCI_PTR_TERM;
++ urbp->qh->is_stopped = 1;
++ urbp->qh->needs_fixup = 1;
++ urbp->qh->initial_toggle = uhci_toggle(td_token(td)) ^
++ (ret == -EREMOTEIO);
+ return ret;
+ }
+
+@@ -995,76 +984,39 @@ static inline int uhci_submit_interrupt(
+ /*
+ * Isochronous transfers
+ */
+-static int isochronous_find_limits(struct uhci_hcd *uhci, struct urb *urb, unsigned int *start, unsigned int *end)
+-{
+- struct urb *last_urb = NULL;
+- struct urb_priv *up;
+- int ret = 0;
+-
+- list_for_each_entry(up, &uhci->urb_list, urb_list) {
+- struct urb *u = up->urb;
+-
+- /* look for pending URBs with identical pipe handle */
+- if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
+- (u->status == -EINPROGRESS) && (u != urb)) {
+- if (!last_urb)
+- *start = u->start_frame;
+- last_urb = u;
+- }
+- }
+-
+- if (last_urb) {
+- *end = (last_urb->start_frame + last_urb->number_of_packets *
+- last_urb->interval) & (UHCI_NUMFRAMES-1);
+- ret = 0;
+- } else
+- ret = -1; /* no previous urb found */
+-
+- return ret;
+-}
+-
+-static int isochronous_find_start(struct uhci_hcd *uhci, struct urb *urb)
++static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
++ struct uhci_qh *qh)
+ {
+- int limits;
+- unsigned int start = 0, end = 0;
++ struct uhci_td *td = NULL; /* Since urb->number_of_packets > 0 */
++ int i, frame;
++ unsigned long destination, status;
++ struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
+
+ if (urb->number_of_packets > 900) /* 900? Why? */
+ return -EFBIG;
+
+- limits = isochronous_find_limits(uhci, urb, &start, &end);
++ status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
++ destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
++ /* Figure out the starting frame number */
+ if (urb->transfer_flags & URB_ISO_ASAP) {
+- if (limits) {
++ if (list_empty(&qh->queue)) {
+ uhci_get_current_frame_number(uhci);
+- urb->start_frame = (uhci->frame_number + 10)
+- & (UHCI_NUMFRAMES - 1);
+- } else
+- urb->start_frame = end;
++ urb->start_frame = (uhci->frame_number + 10);
++
++ } else { /* Go right after the last one */
++ struct urb *last_urb;
++
++ last_urb = list_entry(qh->queue.prev,
++ struct urb_priv, node)->urb;
++ urb->start_frame = (last_urb->start_frame +
++ last_urb->number_of_packets *
++ last_urb->interval);
++ }
+ } else {
+- urb->start_frame &= (UHCI_NUMFRAMES - 1);
+ /* FIXME: Sanity check */
+ }
+-
+- return 0;
+-}
+-
+-/*
+- * Isochronous transfers
+- */
+-static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
+- struct uhci_qh *qh)
+-{
+- struct uhci_td *td = NULL; /* Since urb->number_of_packets > 0 */
+- int i, ret, frame;
+- unsigned long destination, status;
+- 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(uhci, urb);
+- if (ret)
+- return ret;
++ urb->start_frame &= (UHCI_NUMFRAMES - 1);
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ td = uhci_alloc_td(uhci);
+@@ -1203,7 +1155,6 @@ static int uhci_urb_enqueue(struct usb_h
+ /* Add this URB to the QH */
+ urbp->qh = qh;
+ list_add_tail(&urbp->node, &qh->queue);
+- list_add_tail(&urbp->urb_list, &uhci->urb_list);
+
+ /* If the new URB is the first and only one on this QH then either
+ * the QH is new and idle or else it's unlinked and waiting to
+@@ -1224,49 +1175,66 @@ done:
+ return ret;
+ }
+
++static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
++{
++ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
++ unsigned long flags;
++ struct urb_priv *urbp;
++
++ spin_lock_irqsave(&uhci->lock, flags);
++ urbp = urb->hcpriv;
++ if (!urbp) /* URB was never linked! */
++ goto done;
++
++ /* Remove Isochronous TDs from the frame list ASAP */
++ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
++ uhci_unlink_isochronous_tds(uhci, urb);
++ uhci_unlink_qh(uhci, urbp->qh);
++
++done:
++ spin_unlock_irqrestore(&uhci->lock, flags);
++ return 0;
++}
++
+ /*
+- * Return the result of a transfer
++ * Finish unlinking an URB and give it back
+ */
+-static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb)
++static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh,
++ struct urb *urb, struct pt_regs *regs)
++__releases(uhci->lock)
++__acquires(uhci->lock)
+ {
+- int status;
+- int okay_to_giveback = 0;
+ struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
+
+- switch (usb_pipetype(urb->pipe)) {
+- case PIPE_CONTROL:
+- status = uhci_result_control(uhci, urb);
+- break;
+- case PIPE_ISOCHRONOUS:
+- status = uhci_result_isochronous(uhci, urb);
+- break;
+- default: /* PIPE_BULK or PIPE_INTERRUPT */
+- status = uhci_result_common(uhci, urb);
+- break;
+- }
++ /* Isochronous TDs get unlinked directly from the frame list */
++ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
++ uhci_unlink_isochronous_tds(uhci, urb);
+
+- spin_lock(&urb->lock);
+- if (urb->status == -EINPROGRESS) { /* Not yet dequeued */
+- if (status != -EINPROGRESS) { /* URB has completed */
+- urb->status = status;
++ /* If the URB isn't first on its queue, adjust the link pointer
++ * of the last TD in the previous URB. */
++ else if (qh->queue.next != &urbp->node) {
++ struct urb_priv *purbp;
++ struct uhci_td *ptd, *ltd;
+
+- /* If the URB got a real error (as opposed to
+- * simply being dequeued), we don't have to
+- * unlink the QH. Fix this later... */
+- if (status < 0)
+- uhci_unlink_qh(uhci, urbp->qh);
+- else
+- okay_to_giveback = 1;
+- }
+- } else { /* Already dequeued */
+- if (urbp->qh->state == QH_STATE_UNLINKING &&
+- uhci->frame_number + uhci->is_stopped !=
+- urbp->qh->unlink_frame)
+- okay_to_giveback = 1;
++ purbp = list_entry(urbp->node.prev, struct urb_priv, node);
++ ptd = list_entry(purbp->td_list.prev, struct uhci_td,
++ list);
++ ltd = list_entry(urbp->td_list.prev, struct uhci_td,
++ list);
++ ptd->link = ltd->link;
+ }
+- spin_unlock(&urb->lock);
+- if (!okay_to_giveback)
+- return;
++
++ /* Take the URB off the QH's queue. If the queue is now empty,
++ * this is a perfect time for a toggle fixup. */
++ list_del_init(&urbp->node);
++ if (list_empty(&qh->queue) && qh->needs_fixup) {
++ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
++ usb_pipeout(urb->pipe), qh->initial_toggle);
++ qh->needs_fixup = 0;
++ }
++
++ uhci_dec_fsbr(uhci, urb); /* Safe since it checks */
++ uhci_free_urb_priv(uhci, urbp);
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_ISOCHRONOUS:
+@@ -1277,122 +1245,107 @@ static void uhci_transfer_result(struct
+ case PIPE_INTERRUPT:
+ /* Release bandwidth for Interrupt or Isoc. transfers */
+ /* Make sure we don't release if we have a queued URB */
+- if (list_empty(&urbp->qh->queue) && urb->bandwidth)
++ if (list_empty(&qh->queue) && urb->bandwidth)
+ usb_release_bandwidth(urb->dev, urb, 0);
+ else
+ /* bandwidth was passed on to queued URB, */
+ /* so don't let usb_unlink_urb() release it */
+ urb->bandwidth = 0;
+- /* Falls through */
+- case PIPE_BULK:
+- if (status < 0)
+- uhci_fixup_toggles(urb);
+- break;
+- default: /* PIPE_CONTROL */
+ break;
+ }
+
+- /* Take the URB's TDs off the hardware schedule */
+- uhci_remove_tds_from_schedule(uhci, urb, status);
+-
+- /* Take the URB off the QH's queue and see if the QH is now unused */
+- list_del_init(&urbp->node);
+- if (list_empty(&urbp->qh->queue))
+- uhci_unlink_qh(uhci, urbp->qh);
++ spin_unlock(&uhci->lock);
++ usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, regs);
++ spin_lock(&uhci->lock);
+
+- uhci_dec_fsbr(uhci, urb); /* Safe since it checks */
++ /* If the queue is now empty, we can unlink the QH and give up its
++ * reserved bandwidth. */
++ if (list_empty(&qh->queue)) {
++ uhci_unlink_qh(uhci, qh);
+
+- /* Queue it for giving back */
+- list_move_tail(&urbp->urb_list, &uhci->complete_list);
++ /* Bandwidth stuff not yet implemented */
++ }
+ }
+
+ /*
+- * Check out the QHs waiting to be fully unlinked
++ * Scan the URBs in a QH's queue
+ */
+-static void uhci_scan_unlinking_qhs(struct uhci_hcd *uhci)
+-{
+- struct uhci_qh *qh, *tmp;
++#define QH_FINISHED_UNLINKING(qh) \
++ (qh->state == QH_STATE_UNLINKING && \
++ uhci->frame_number + uhci->is_stopped != qh->unlink_frame)
+
+- list_for_each_entry_safe(qh, tmp, &uhci->skel_unlink_qh->node, node) {
+-
+- /* If the queue is empty and the QH is fully unlinked then
+- * it can become IDLE. */
+- if (list_empty(&qh->queue)) {
+- if (uhci->frame_number + uhci->is_stopped !=
+- qh->unlink_frame)
+- uhci_make_qh_idle(uhci, qh);
+-
+- /* If none of the QH's URBs have been dequeued then the QH
+- * should be re-activated. */
+- } else {
+- struct urb_priv *urbp;
+- int any_dequeued = 0;
+-
+- list_for_each_entry(urbp, &qh->queue, node) {
+- if (urbp->urb->status != -EINPROGRESS) {
+- any_dequeued = 1;
+- break;
+- }
+- }
+- if (!any_dequeued)
+- uhci_activate_qh(uhci, qh);
+- }
+- }
+-}
+-
+-static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
++static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh,
++ struct pt_regs *regs)
+ {
+- struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+- unsigned long flags;
+ struct urb_priv *urbp;
++ struct urb *urb;
++ int status;
+
+- spin_lock_irqsave(&uhci->lock, flags);
+- urbp = urb->hcpriv;
+- if (!urbp) /* URB was never linked! */
+- goto done;
+-
+- /* Remove Isochronous TDs from the frame list ASAP */
+- if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
+- uhci_unlink_isochronous_tds(uhci, urb);
+- uhci_unlink_qh(uhci, urbp->qh);
+-
+-done:
+- spin_unlock_irqrestore(&uhci->lock, flags);
+- return 0;
+-}
++ while (!list_empty(&qh->queue)) {
++ urbp = list_entry(qh->queue.next, struct urb_priv, node);
++ urb = urbp->urb;
++
++ switch (usb_pipetype(urb->pipe)) {
++ case PIPE_CONTROL:
++ status = uhci_result_control(uhci, urb);
++ break;
++ case PIPE_ISOCHRONOUS:
++ status = uhci_result_isochronous(uhci, urb);
++ break;
++ default: /* PIPE_BULK or PIPE_INTERRUPT */
++ status = uhci_result_common(uhci, urb);
++ break;
++ }
++ if (status == -EINPROGRESS)
++ break;
+
+-static int uhci_fsbr_timeout(struct uhci_hcd *uhci, struct urb *urb)
+-{
+- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+- struct list_head *head;
+- struct uhci_td *td;
+- int count = 0;
++ spin_lock(&urb->lock);
++ if (urb->status == -EINPROGRESS) /* Not dequeued */
++ urb->status = status;
++ else
++ status = -ECONNRESET;
++ spin_unlock(&urb->lock);
+
+- uhci_dec_fsbr(uhci, urb);
++ /* Dequeued but completed URBs can't be given back unless
++ * the QH is stopped or has finished unlinking. */
++ if (status == -ECONNRESET &&
++ !(qh->is_stopped || QH_FINISHED_UNLINKING(qh)))
++ return;
+
+- urbp->fsbr_timeout = 1;
++ uhci_giveback_urb(uhci, qh, urb, regs);
++ if (qh->is_stopped)
++ break;
++ }
+
+- /*
+- * 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
+- */
++ /* If the QH is neither stopped nor finished unlinking (normal case),
++ * our work here is done. */
++ restart:
++ if (!(qh->is_stopped || QH_FINISHED_UNLINKING(qh)))
++ return;
+
+- head = &urbp->td_list;
+- list_for_each_entry(td, head, list) {
+- /*
+- * Make sure we don't do the last one (since it'll have the
+- * TERM bit set) as well as we skip every so many TDs to
+- * make sure it doesn't hog the bandwidth
+- */
+- if (td->list.next != head && (count % DEPTH_INTERVAL) ==
+- (DEPTH_INTERVAL - 1))
+- td->link |= UHCI_PTR_DEPTH;
++ /* Otherwise give back each of the dequeued URBs */
++ list_for_each_entry(urbp, &qh->queue, node) {
++ urb = urbp->urb;
++ if (urb->status != -EINPROGRESS) {
++ uhci_save_toggle(qh, urb);
++ uhci_giveback_urb(uhci, qh, urb, regs);
++ goto restart;
++ }
++ }
++ qh->is_stopped = 0;
+
+- count++;
++ /* There are no more dequeued URBs. If there are still URBs on the
++ * queue, the QH can now be re-activated. */
++ if (!list_empty(&qh->queue)) {
++ if (qh->needs_fixup)
++ uhci_fixup_toggles(qh, 0);
++ uhci_activate_qh(uhci, qh);
+ }
+
+- return 0;
++ /* The queue is empty. The QH can become idle if it is fully
++ * unlinked. */
++ else if (QH_FINISHED_UNLINKING(qh))
++ uhci_make_qh_idle(uhci, qh);
+ }
+
+ static void uhci_free_pending_tds(struct uhci_hcd *uhci)
+@@ -1406,36 +1359,13 @@ static void uhci_free_pending_tds(struct
+ }
+ }
+
+-static void
+-uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
+-__releases(uhci->lock)
+-__acquires(uhci->lock)
+-{
+- struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+-
+- uhci_free_urb_priv(uhci, (struct urb_priv *) (urb->hcpriv));
+-
+- spin_unlock(&uhci->lock);
+- usb_hcd_giveback_urb(hcd, urb, regs);
+- spin_lock(&uhci->lock);
+-}
+-
+-static void uhci_finish_completion(struct uhci_hcd *uhci, struct pt_regs *regs)
+-{
+- struct urb_priv *urbp, *tmp;
+-
+- list_for_each_entry_safe(urbp, tmp, &uhci->complete_list, urb_list) {
+- struct urb *urb = urbp->urb;
+-
+- list_del_init(&urbp->urb_list);
+- uhci_finish_urb(uhci_to_hcd(uhci), urb, regs);
+- }
+-}
+-
+-/* Process events in the schedule, but only in one thread at a time */
++/*
++ * Process events in the schedule, but only in one thread at a time
++ */
+ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
+ {
+- struct urb_priv *urbp, *tmp;
++ int i;
++ struct uhci_qh *qh;
+
+ /* Don't allow re-entrant calls */
+ if (uhci->scan_in_progress) {
+@@ -1452,26 +1382,24 @@ static void uhci_scan_schedule(struct uh
+ if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age)
+ uhci_free_pending_tds(uhci);
+
+- /* Walk the list of pending URBs to see which ones completed
+- * (must be _safe because uhci_transfer_result() dequeues URBs) */
+- list_for_each_entry_safe(urbp, tmp, &uhci->urb_list, urb_list) {
+- struct urb *urb = urbp->urb;
+-
+- /* Checks the status and does all of the magic necessary */
+- uhci_transfer_result(uhci, urb);
++ /* Go through all the QH queues and process the URBs in each one */
++ for (i = 0; i < UHCI_NUM_SKELQH - 1; ++i) {
++ uhci->next_qh = list_entry(uhci->skelqh[i]->node.next,
++ struct uhci_qh, node);
++ while ((qh = uhci->next_qh) != uhci->skelqh[i]) {
++ uhci->next_qh = list_entry(qh->node.next,
++ struct uhci_qh, node);
++ uhci_scan_qh(uhci, qh, regs);
++ }
+ }
+- uhci_finish_completion(uhci, regs);
+-
+- /* If the controller is stopped, we can finish these off right now */
+- if (uhci->is_stopped)
+- uhci_free_pending_tds(uhci);
+
+ if (uhci->need_rescan)
+ goto rescan;
+ uhci->scan_in_progress = 0;
+
+- /* Check out the QHs waiting for unlinking */
+- uhci_scan_unlinking_qhs(uhci);
++ /* If the controller is stopped, we can finish these off right now */
++ if (uhci->is_stopped)
++ uhci_free_pending_tds(uhci);
+
+ if (list_empty(&uhci->td_remove_list) &&
+ list_empty(&uhci->skel_unlink_qh->node))
+@@ -1482,19 +1410,8 @@ static void uhci_scan_schedule(struct uh
+
+ static void check_fsbr(struct uhci_hcd *uhci)
+ {
+- struct urb_priv *up;
+-
+- list_for_each_entry(up, &uhci->urb_list, urb_list) {
+- struct urb *u = up->urb;
+-
+- spin_lock(&u->lock);
+-
+- /* Check if the FSBR timed out */
+- if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT))
+- uhci_fsbr_timeout(uhci, u);
+-
+- spin_unlock(&u->lock);
+- }
++ /* For now, don't scan URBs for FSBR timeouts.
++ * Add it back in later... */
+
+ /* Really disable FSBR */
+ if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {
+--- gregkh-2.6.orig/drivers/usb/host/uhci-hcd.h
++++ gregkh-2.6/drivers/usb/host/uhci-hcd.h
+@@ -132,6 +132,10 @@ struct uhci_qh {
+
+ unsigned int unlink_frame; /* When the QH was unlinked */
+ int state; /* QH_STATE_xxx; see above */
++
++ unsigned int initial_toggle:1; /* Endpoint's current toggle value */
++ unsigned int needs_fixup:1; /* Must fix the TD toggle values */
++ unsigned int is_stopped:1; /* Queue was stopped by an error */
+ } __attribute__((aligned(16)));
+
+ /*
+@@ -384,6 +388,7 @@ struct uhci_hcd {
+
+ struct uhci_td *term_td; /* Terminating TD, see UHCI bug */
+ struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QHs */
++ struct uhci_qh *next_qh; /* Next QH to scan */
+
+ spinlock_t lock;
+
+@@ -413,16 +418,10 @@ struct uhci_hcd {
+ unsigned long resuming_ports;
+ unsigned long ports_timeout; /* Time to stop signalling */
+
+- /* Main list of URBs currently controlled by this HC */
+- struct list_head urb_list;
+-
+ /* List of TDs that are done, but waiting to be freed (race) */
+ struct list_head td_remove_list;
+ unsigned int td_remove_age; /* Age in frames */
+
+- /* List of URBs awaiting completion callback */
+- struct list_head complete_list;
+-
+ struct list_head idle_qh_list; /* Where the idle QHs live */
+
+ int rh_numports; /* Number of root-hub ports */
+@@ -448,7 +447,6 @@ static inline struct usb_hcd *uhci_to_hc
+ * Private per-URB data
+ */
+ struct urb_priv {
+- struct list_head urb_list;
+ struct list_head node; /* Node in the QH's urbp list */
+
+ struct urb *urb;
+@@ -456,10 +454,7 @@ struct urb_priv {
+ struct uhci_qh *qh; /* QH for this URB */
+ struct list_head td_list;
+
+- unsigned long fsbrtime; /* In jiffies */
+-
+ unsigned fsbr : 1; /* URB turned on FSBR */
+- unsigned fsbr_timeout : 1; /* URB timed out on FSBR */
+ unsigned short_transfer : 1; /* URB got a short transfer, no
+ * need to rescan */
+ };
+--- gregkh-2.6.orig/drivers/usb/host/uhci-hcd.c
++++ gregkh-2.6/drivers/usb/host/uhci-hcd.c
+@@ -491,8 +491,6 @@ static int uhci_start(struct usb_hcd *hc
+ spin_lock_init(&uhci->lock);
+
+ INIT_LIST_HEAD(&uhci->td_remove_list);
+- INIT_LIST_HEAD(&uhci->urb_list);
+- INIT_LIST_HEAD(&uhci->complete_list);
+ INIT_LIST_HEAD(&uhci->idle_qh_list);
+
+ init_waitqueue_head(&uhci->waitqh);
+--- gregkh-2.6.orig/drivers/usb/host/uhci-debug.c
++++ gregkh-2.6/drivers/usb/host/uhci-debug.c
+@@ -114,7 +114,6 @@ static int uhci_show_urbp(struct urb_pri
+ }
+
+ out += sprintf(out, "%s", (urbp->fsbr ? " FSBR" : ""));
+- out += sprintf(out, "%s", (urbp->fsbr_timeout ? " FSBR_TO" : ""));
+
+ if (urbp->urb->status != -EINPROGRESS)
+ out += sprintf(out, " Status=%d", urbp->urb->status);
diff --git a/usb/uhci-use-dummy-tds.patch b/usb/uhci-use-dummy-tds.patch
new file mode 100644
index 00000000000000..139f0093ff5833
--- /dev/null
+++ b/usb/uhci-use-dummy-tds.patch
@@ -0,0 +1,320 @@
+From stern@rowland.harvard.edu Sat Dec 17 15:13:52 2005
+Date: Sat, 17 Dec 2005 18:00:12 -0500 (EST)
+From: Alan Stern <stern@rowland.harvard.edu>
+To: Greg KH <greg@kroah.com>
+Subject: [PATCH 2/4] UHCI: use dummy TDs
+Message-ID: <Pine.LNX.4.44L0.0512171722380.14730-100000@netrider.rowland.org>
+
+This patch (as624) fixes a hardware race in uhci-hcd by adding a dummy
+TD to the end of each endpoint's queue. Without the dummy the host
+controller will effectively turn off the queue when it reaches the end,
+which happens asynchronously. This leads to a potential problem when
+new transfer descriptors are added to the end of the queue; they may
+never get used.
+
+With a dummy TD present the controller never turns off the queue;
+instead it just stops at the dummy and leaves the queue on but inactive.
+When new TDs are added to the end of the queue, the first new one gets
+written over the dummy. Thus there's never any question about whether
+the queue is running or needs to be restarted.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/uhci-debug.c | 5 +
+ drivers/usb/host/uhci-hcd.h | 1
+ drivers/usb/host/uhci-q.c | 138 +++++++++++++++++++++++-------------------
+ 3 files changed, 83 insertions(+), 61 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/host/uhci-q.c
++++ gregkh-2.6/drivers/usb/host/uhci-q.c
+@@ -48,10 +48,6 @@ static struct uhci_td *uhci_alloc_td(str
+ return NULL;
+
+ td->dma_handle = dma_handle;
+-
+- td->link = UHCI_PTR_TERM;
+- td->buffer = 0;
+-
+ td->frame = -1;
+
+ INIT_LIST_HEAD(&td->list);
+@@ -221,6 +217,11 @@ static struct uhci_qh *uhci_alloc_qh(str
+ INIT_LIST_HEAD(&qh->node);
+
+ if (udev) { /* Normal QH */
++ qh->dummy_td = uhci_alloc_td(uhci);
++ if (!qh->dummy_td) {
++ dma_pool_free(uhci->qh_pool, qh, dma_handle);
++ return NULL;
++ }
+ qh->state = QH_STATE_IDLE;
+ qh->hep = hep;
+ qh->udev = udev;
+@@ -244,6 +245,7 @@ static void uhci_free_qh(struct uhci_hcd
+ if (qh->udev) {
+ qh->hep->hcpriv = NULL;
+ usb_put_dev(qh->udev);
++ uhci_free_td(uhci, qh->dummy_td);
+ }
+ dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
+ }
+@@ -531,22 +533,20 @@ static int uhci_submit_control(struct uh
+ /* The "pipe" thing contains the destination in bits 8--18 */
+ destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
+
+- /* 3 errors */
+- status = TD_CTRL_ACTIVE | uhci_maxerr(3);
++ /* 3 errors, dummy TD remains inactive */
++ status = uhci_maxerr(3);
+ if (urb->dev->speed == USB_SPEED_LOW)
+ status |= TD_CTRL_LS;
+
+ /*
+ * Build the TD for the control request setup packet
+ */
+- td = uhci_alloc_td(uhci);
+- if (!td)
+- return -ENOMEM;
+-
++ td = qh->dummy_td;
+ uhci_add_td_to_urb(urb, td);
+ uhci_fill_td(td, status, destination | uhci_explen(8),
+ urb->setup_dma);
+ plink = &td->link;
++ status |= TD_CTRL_ACTIVE;
+
+ /*
+ * If direction is "send", change the packet ID from SETUP (0x2D)
+@@ -568,7 +568,7 @@ static int uhci_submit_control(struct uh
+
+ td = uhci_alloc_td(uhci);
+ if (!td)
+- return -ENOMEM;
++ goto nomem;
+ *plink = cpu_to_le32(td->dma_handle);
+
+ /* Alternate Data0/1 (start with Data1) */
+@@ -588,7 +588,7 @@ static int uhci_submit_control(struct uh
+ */
+ td = uhci_alloc_td(uhci);
+ if (!td)
+- return -ENOMEM;
++ goto nomem;
+ *plink = cpu_to_le32(td->dma_handle);
+
+ /*
+@@ -608,6 +608,20 @@ static int uhci_submit_control(struct uh
+ uhci_add_td_to_urb(urb, td);
+ uhci_fill_td(td, status | TD_CTRL_IOC,
+ destination | uhci_explen(0), 0);
++ plink = &td->link;
++
++ /*
++ * Build the new dummy TD and activate the old one
++ */
++ td = uhci_alloc_td(uhci);
++ if (!td)
++ goto nomem;
++ *plink = cpu_to_le32(td->dma_handle);
++
++ uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
++ wmb();
++ qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
++ qh->dummy_td = td;
+
+ /* Low-speed transfers get a different queue, and won't hog the bus.
+ * Also, some devices enumerate better without FSBR; the easiest way
+@@ -620,8 +634,12 @@ static int uhci_submit_control(struct uh
+ qh->skel = uhci->skel_fs_control_qh;
+ uhci_inc_fsbr(uhci, urb);
+ }
+-
+ return 0;
++
++nomem:
++ /* Remove the dummy TD from the td_list so it doesn't get freed */
++ uhci_remove_td_from_urb(qh->dummy_td);
++ return -ENOMEM;
+ }
+
+ /*
+@@ -761,16 +779,19 @@ static int uhci_submit_common(struct uhc
+ int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
+ int len = urb->transfer_buffer_length;
+ dma_addr_t data = urb->transfer_dma;
+- __le32 *plink, fake_link;
++ __le32 *plink;
++ unsigned int toggle;
+
+ if (len < 0)
+ return -EINVAL;
+
+ /* The "pipe" thing contains the destination in bits 8--18 */
+ destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
++ toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
++ usb_pipeout(urb->pipe));
+
+- /* 3 errors */
+- status = TD_CTRL_ACTIVE | uhci_maxerr(3);
++ /* 3 errors, dummy TD remains inactive */
++ status = uhci_maxerr(3);
+ if (urb->dev->speed == USB_SPEED_LOW)
+ status |= TD_CTRL_LS;
+ if (usb_pipein(urb->pipe))
+@@ -779,7 +800,8 @@ static int uhci_submit_common(struct uhc
+ /*
+ * Build the DATA TDs
+ */
+- plink = &fake_link;
++ plink = NULL;
++ td = qh->dummy_td;
+ do { /* Allow zero length packets */
+ int pktsze = maxsze;
+
+@@ -789,24 +811,23 @@ static int uhci_submit_common(struct uhc
+ status &= ~TD_CTRL_SPD;
+ }
+
+- td = uhci_alloc_td(uhci);
+- if (!td)
+- return -ENOMEM;
+- *plink = cpu_to_le32(td->dma_handle);
+-
++ if (plink) {
++ td = uhci_alloc_td(uhci);
++ if (!td)
++ goto nomem;
++ *plink = cpu_to_le32(td->dma_handle);
++ }
+ uhci_add_td_to_urb(urb, td);
+ uhci_fill_td(td, status,
+- destination | uhci_explen(pktsze) |
+- (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+- usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
+- data);
++ destination | uhci_explen(pktsze) |
++ (toggle << TD_TOKEN_TOGGLE_SHIFT),
++ data);
+ plink = &td->link;
++ status |= TD_CTRL_ACTIVE;
+
+ data += pktsze;
+ len -= maxsze;
+-
+- usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+- usb_pipeout(urb->pipe));
++ toggle ^= 1;
+ } while (len > 0);
+
+ /*
+@@ -821,17 +842,17 @@ static int uhci_submit_common(struct uhc
+ urb->transfer_buffer_length > 0) {
+ td = uhci_alloc_td(uhci);
+ if (!td)
+- return -ENOMEM;
++ goto nomem;
+ *plink = cpu_to_le32(td->dma_handle);
+
+ uhci_add_td_to_urb(urb, td);
+- uhci_fill_td(td, status, destination | uhci_explen(0) |
+- (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+- usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
+- data);
++ uhci_fill_td(td, status,
++ destination | uhci_explen(0) |
++ (toggle << TD_TOKEN_TOGGLE_SHIFT),
++ data);
++ plink = &td->link;
+
+- usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+- usb_pipeout(urb->pipe));
++ toggle ^= 1;
+ }
+
+ /* Set the interrupt-on-completion flag on the last packet.
+@@ -842,7 +863,27 @@ static int uhci_submit_common(struct uhc
+ * flag setting. */
+ td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
+
++ /*
++ * Build the new dummy TD and activate the old one
++ */
++ td = uhci_alloc_td(uhci);
++ if (!td)
++ goto nomem;
++ *plink = cpu_to_le32(td->dma_handle);
++
++ uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
++ wmb();
++ qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
++ qh->dummy_td = td;
++
++ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
++ usb_pipeout(urb->pipe), toggle);
+ return 0;
++
++nomem:
++ /* Remove the dummy TD from the td_list so it doesn't get freed */
++ uhci_remove_td_from_urb(qh->dummy_td);
++ return -ENOMEM;
+ }
+
+ /*
+@@ -1169,31 +1210,6 @@ static int uhci_urb_enqueue(struct usb_h
+ * become idle, so we can activate it right away. */
+ if (qh->queue.next == &urbp->node)
+ uhci_activate_qh(uhci, qh);
+-
+- /* If the QH is already active, we have a race with the hardware.
+- * This won't get fixed until dummy TDs are added. */
+- else if (qh->state == QH_STATE_ACTIVE) {
+-
+- /* If the URB isn't first on its queue, adjust the link pointer
+- * of the last TD in the previous URB. */
+- if (urbp->node.prev != &urbp->qh->queue) {
+- struct urb_priv *purbp = list_entry(urbp->node.prev,
+- struct urb_priv, node);
+- struct uhci_td *ptd = list_entry(purbp->td_list.prev,
+- struct uhci_td, list);
+- struct uhci_td *td = list_entry(urbp->td_list.next,
+- struct uhci_td, list);
+-
+- ptd->link = cpu_to_le32(td->dma_handle);
+-
+- }
+- if (qh_element(qh) == UHCI_PTR_TERM) {
+- struct uhci_td *td = list_entry(urbp->td_list.next,
+- struct uhci_td, list);
+-
+- qh->element = cpu_to_le32(td->dma_handle);
+- }
+- }
+ goto done;
+
+ err_submit_failed:
+--- gregkh-2.6.orig/drivers/usb/host/uhci-hcd.h
++++ gregkh-2.6/drivers/usb/host/uhci-hcd.h
+@@ -128,6 +128,7 @@ struct uhci_qh {
+ struct usb_device *udev;
+ struct list_head queue; /* Queue of urbps for this QH */
+ struct uhci_qh *skel; /* Skeleton for this QH */
++ struct uhci_td *dummy_td; /* Dummy TD to end the queue */
+
+ unsigned int unlink_frame; /* When the QH was unlinked */
+ int state; /* QH_STATE_xxx; see above */
+--- gregkh-2.6.orig/drivers/usb/host/uhci-debug.c
++++ gregkh-2.6/drivers/usb/host/uhci-debug.c
+@@ -189,6 +189,11 @@ static int uhci_show_qh(struct uhci_qh *
+ space, "", nurbs);
+ }
+
++ if (qh->udev) {
++ out += sprintf(out, "%*s Dummy TD\n", space, "");
++ out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0);
++ }
++
+ return out - buf;
+ }
+
diff --git a/usb/uhci-use-one-qh-per-endpoint-not-per-urb.patch b/usb/uhci-use-one-qh-per-endpoint-not-per-urb.patch
new file mode 100644
index 00000000000000..0515d1b4491e25
--- /dev/null
+++ b/usb/uhci-use-one-qh-per-endpoint-not-per-urb.patch
@@ -0,0 +1,2397 @@
+From stern@rowland.harvard.edu Sat Dec 17 15:13:30 2005
+Date: Sat, 17 Dec 2005 17:58:46 -0500 (EST)
+From: Alan Stern <stern@rowland.harvard.edu>
+To: Greg KH <greg@kroah.com>
+Subject: [PATCH 1/4] UHCI: use one QH per endpoint, not per URB
+Message-ID: <Pine.LNX.4.44L0.0512171718340.14730-100000@netrider.rowland.org>
+
+This patch (as623) changes the uhci-hcd driver to make it use one QH per
+device endpoint, instead of a QH per URB as it does now. Numerous areas
+of the code are affected by this. For example, the distinction between
+"queued" URBs and non-"queued" URBs no longer exists; all URBs belong to
+a queue and some just happen to be at the queue's head.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/uhci-debug.c | 320 +++----------
+ drivers/usb/host/uhci-hcd.c | 65 +-
+ drivers/usb/host/uhci-hcd.h | 183 ++++---
+ drivers/usb/host/uhci-q.c | 987 +++++++++++++++++++-----------------------
+ 4 files changed, 689 insertions(+), 866 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/host/uhci-hcd.h
++++ gregkh-2.6/drivers/usb/host/uhci-hcd.h
+@@ -28,8 +28,9 @@
+ #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_HSE 0x0008 /* Host System Error: PCI problems */
++#define USBSTS_HCPE 0x0010 /* Host Controller Process Error:
++ * the schedule is buggy */
+ #define USBSTS_HCH 0x0020 /* HC Halted */
+
+ /* Interrupt enable register */
+@@ -47,7 +48,8 @@
+ /* USB port status and control registers */
+ #define USBPORTSC1 16
+ #define USBPORTSC2 18
+-#define USBPORTSC_CCS 0x0001 /* Current Connect Status ("device present") */
++#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 */
+@@ -71,15 +73,16 @@
+ #define USBLEGSUP_RWC 0x8f00 /* the R/WC bits */
+ #define USBLEGSUP_RO 0x5040 /* R/O and reserved bits */
+
+-#define UHCI_PTR_BITS cpu_to_le32(0x000F)
+-#define UHCI_PTR_TERM cpu_to_le32(0x0001)
+-#define UHCI_PTR_QH cpu_to_le32(0x0002)
+-#define UHCI_PTR_DEPTH cpu_to_le32(0x0004)
+-#define UHCI_PTR_BREADTH cpu_to_le32(0x0000)
++#define UHCI_PTR_BITS __constant_cpu_to_le32(0x000F)
++#define UHCI_PTR_TERM __constant_cpu_to_le32(0x0001)
++#define UHCI_PTR_QH __constant_cpu_to_le32(0x0002)
++#define UHCI_PTR_DEPTH __constant_cpu_to_le32(0x0004)
++#define UHCI_PTR_BREADTH __constant_cpu_to_le32(0x0000)
+
+ #define UHCI_NUMFRAMES 1024 /* in the frame list [array] */
+ #define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */
+-#define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */
++#define CAN_SCHEDULE_FRAMES 1000 /* how far in the future frames
++ * can be scheduled */
+
+
+ /*
+@@ -87,38 +90,54 @@
+ */
+
+ /*
+- * One role of a QH is to hold a queue of TDs for some endpoint. Each QH is
+- * used with one URB, and qh->element (updated by the HC) is either:
+- * - the next unprocessed TD for the URB, or
+- * - UHCI_PTR_TERM (when there's no more traffic for this endpoint), or
+- * - the QH for the next URB queued to the same endpoint.
++ * One role of a QH is to hold a queue of TDs for some endpoint. One QH goes
++ * with each endpoint, and qh->element (updated by the HC) is either:
++ * - the next unprocessed TD in the endpoint's queue, or
++ * - UHCI_PTR_TERM (when there's no more traffic for this endpoint).
+ *
+ * The other role of a QH is to serve as a "skeleton" framelist entry, so we
+ * can easily splice a QH for some endpoint into the schedule at the right
+ * place. Then qh->element is UHCI_PTR_TERM.
+ *
+- * In the frame list, qh->link maintains a list of QHs seen by the HC:
++ * In the schedule, qh->link maintains a list of QHs seen by the HC:
+ * skel1 --> ep1-qh --> ep2-qh --> ... --> skel2 --> ...
+- */
++ *
++ * qh->node is the software equivalent of qh->link. The differences
++ * are that the software list is doubly-linked and QHs in the UNLINKING
++ * state are on the software list but not the hardware schedule.
++ *
++ * For bookkeeping purposes we maintain QHs even for Isochronous endpoints,
++ * but they never get added to the hardware schedule.
++ */
++#define QH_STATE_IDLE 1 /* QH is not being used */
++#define QH_STATE_UNLINKING 2 /* QH has been removed from the
++ * schedule but the hardware may
++ * still be using it */
++#define QH_STATE_ACTIVE 3 /* QH is on the schedule */
++
+ struct uhci_qh {
+ /* Hardware fields */
+- __le32 link; /* Next queue */
+- __le32 element; /* Queue element pointer */
++ __le32 link; /* Next QH in the schedule */
++ __le32 element; /* Queue element (TD) pointer */
+
+ /* Software fields */
+ dma_addr_t dma_handle;
+
+- struct urb_priv *urbp;
++ struct list_head node; /* Node in the list of QHs */
++ struct usb_host_endpoint *hep; /* Endpoint information */
++ struct usb_device *udev;
++ struct list_head queue; /* Queue of urbps for this QH */
++ struct uhci_qh *skel; /* Skeleton for this QH */
+
+- struct list_head list;
+- struct list_head remove_list;
++ unsigned int unlink_frame; /* When the QH was unlinked */
++ int state; /* QH_STATE_xxx; see above */
+ } __attribute__((aligned(16)));
+
+ /*
+ * We need a special accessor for the element pointer because it is
+ * subject to asynchronous updates by the controller.
+ */
+-static __le32 inline qh_element(struct uhci_qh *qh) {
++static inline __le32 qh_element(struct uhci_qh *qh) {
+ __le32 element = qh->element;
+
+ barrier();
+@@ -149,11 +168,13 @@ static __le32 inline qh_element(struct u
+ #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)
++ TD_CTRL_BABBLE | TD_CTRL_CRCTIME | \
++ TD_CTRL_BITSTUFF)
+
+ #define uhci_maxerr(err) ((err) << TD_CTRL_C_ERR_SHIFT)
+ #define uhci_status_bits(ctrl_sts) ((ctrl_sts) & 0xF60000)
+-#define uhci_actual_length(ctrl_sts) (((ctrl_sts) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
++#define uhci_actual_length(ctrl_sts) (((ctrl_sts) + 1) & \
++ TD_CTRL_ACTLEN_MASK) /* 1-based */
+
+ /*
+ * for TD <info>: (a.k.a. Token)
+@@ -163,7 +184,7 @@ static __le32 inline qh_element(struct u
+ #define TD_TOKEN_TOGGLE_SHIFT 19
+ #define TD_TOKEN_TOGGLE (1 << 19)
+ #define TD_TOKEN_EXPLEN_SHIFT 21
+-#define TD_TOKEN_EXPLEN_MASK 0x7FF /* expected length, encoded as n - 1 */
++#define TD_TOKEN_EXPLEN_MASK 0x7FF /* expected length, encoded as n-1 */
+ #define TD_TOKEN_PID_MASK 0xFF
+
+ #define uhci_explen(len) ((((len) - 1) & TD_TOKEN_EXPLEN_MASK) << \
+@@ -187,7 +208,7 @@ static __le32 inline qh_element(struct u
+ * sw space after the TD entry.
+ *
+ * td->link points to either another TD (not necessarily for the same urb or
+- * even the same endpoint), or nothing (PTR_TERM), or a QH (for queued urbs).
++ * even the same endpoint), or nothing (PTR_TERM), or a QH.
+ */
+ struct uhci_td {
+ /* Hardware fields */
+@@ -210,7 +231,7 @@ struct uhci_td {
+ * We need a special accessor for the control/status word because it is
+ * subject to asynchronous updates by the controller.
+ */
+-static u32 inline td_status(struct uhci_td *td) {
++static inline u32 td_status(struct uhci_td *td) {
+ __le32 status = td->status;
+
+ barrier();
+@@ -223,17 +244,14 @@ static u32 inline td_status(struct uhci_
+ */
+
+ /*
+- * The UHCI driver places Interrupt, Control and Bulk into QHs both
+- * to group together TDs for one transfer, and also to facilitate queuing
+- * of URBs. To make it easy to insert entries into the schedule, we have
+- * a skeleton of QHs for each predefined Interrupt latency, low-speed
+- * control, full-speed control and terminating QH (see explanation for
+- * the terminating QH below).
++ * The UHCI driver uses QHs with Interrupt, Control and Bulk URBs for
++ * automatic queuing. To make it easy to insert entries into the schedule,
++ * we have a skeleton of QHs for each predefined Interrupt latency,
++ * low-speed control, full-speed control, bulk, and terminating QH
++ * (see explanation for the terminating QH below).
+ *
+ * When we want to add a new QH, we add it to the end of the list for the
+- * skeleton QH.
+- *
+- * For instance, the queue can look like this:
++ * skeleton QH. For instance, the schedule list can look like this:
+ *
+ * skel int128 QH
+ * dev 1 interrupt QH
+@@ -256,26 +274,31 @@ static u32 inline td_status(struct uhci_
+ * - To loop back to the full-speed control queue for full-speed bandwidth
+ * reclamation.
+ *
+- * Isochronous transfers are stored before the start of the skeleton
+- * schedule and don't use QHs. While the UHCI spec doesn't forbid the
+- * use of QHs for Isochronous, it doesn't use them either. And the spec
+- * says that queues never advance on an error completion status, which
+- * makes them totally unsuitable for Isochronous transfers.
+- */
+-
+-#define UHCI_NUM_SKELQH 12
+-#define skel_int128_qh skelqh[0]
+-#define skel_int64_qh skelqh[1]
+-#define skel_int32_qh skelqh[2]
+-#define skel_int16_qh skelqh[3]
+-#define skel_int8_qh skelqh[4]
+-#define skel_int4_qh skelqh[5]
+-#define skel_int2_qh skelqh[6]
+-#define skel_int1_qh skelqh[7]
+-#define skel_ls_control_qh skelqh[8]
+-#define skel_fs_control_qh skelqh[9]
+-#define skel_bulk_qh skelqh[10]
+-#define skel_term_qh skelqh[11]
++ * There's a special skeleton QH for Isochronous QHs. It never appears
++ * on the schedule, and Isochronous TDs go on the schedule before the
++ * the skeleton QHs. The hardware accesses them directly rather than
++ * through their QH, which is used only for bookkeeping purposes.
++ * While the UHCI spec doesn't forbid the use of QHs for Isochronous,
++ * it doesn't use them either. And the spec says that queues never
++ * advance on an error completion status, which makes them totally
++ * unsuitable for Isochronous transfers.
++ */
++
++#define UHCI_NUM_SKELQH 14
++#define skel_unlink_qh skelqh[0]
++#define skel_iso_qh skelqh[1]
++#define skel_int128_qh skelqh[2]
++#define skel_int64_qh skelqh[3]
++#define skel_int32_qh skelqh[4]
++#define skel_int16_qh skelqh[5]
++#define skel_int8_qh skelqh[6]
++#define skel_int4_qh skelqh[7]
++#define skel_int2_qh skelqh[8]
++#define skel_int1_qh skelqh[9]
++#define skel_ls_control_qh skelqh[10]
++#define skel_fs_control_qh skelqh[11]
++#define skel_bulk_qh skelqh[12]
++#define skel_term_qh skelqh[13]
+
+ /*
+ * Search tree for determining where <interval> fits in the skelqh[]
+@@ -293,21 +316,21 @@ static inline int __interval_to_skel(int
+ if (interval < 16) {
+ if (interval < 4) {
+ if (interval < 2)
+- return 7; /* int1 for 0-1 ms */
+- return 6; /* int2 for 2-3 ms */
++ return 9; /* int1 for 0-1 ms */
++ return 8; /* int2 for 2-3 ms */
+ }
+ if (interval < 8)
+- return 5; /* int4 for 4-7 ms */
+- return 4; /* int8 for 8-15 ms */
++ return 7; /* int4 for 4-7 ms */
++ return 6; /* int8 for 8-15 ms */
+ }
+ if (interval < 64) {
+ if (interval < 32)
+- return 3; /* int16 for 16-31 ms */
+- return 2; /* int32 for 32-63 ms */
++ return 5; /* int16 for 16-31 ms */
++ return 4; /* int32 for 32-63 ms */
+ }
+ if (interval < 128)
+- return 1; /* int64 for 64-127 ms */
+- return 0; /* int128 for 128-255 ms (Max.) */
++ return 3; /* int64 for 64-127 ms */
++ return 2; /* int128 for 128-255 ms (Max.) */
+ }
+
+
+@@ -363,12 +386,12 @@ struct uhci_hcd {
+
+ spinlock_t lock;
+
+- dma_addr_t frame_dma_handle; /* Hardware frame list */
++ dma_addr_t frame_dma_handle; /* Hardware frame list */
+ __le32 *frame;
+- void **frame_cpu; /* CPU's frame list */
++ void **frame_cpu; /* CPU's frame list */
+
+- int fsbr; /* Full-speed bandwidth reclamation */
+- unsigned long fsbrtimeout; /* FSBR delay */
++ int fsbr; /* Full-speed bandwidth reclamation */
++ unsigned long fsbrtimeout; /* FSBR delay */
+
+ enum uhci_rh_state rh_state;
+ unsigned long auto_stop_time; /* When to AUTO_STOP */
+@@ -392,24 +415,19 @@ struct uhci_hcd {
+ /* Main list of URBs currently controlled by this HC */
+ struct list_head urb_list;
+
+- /* List of QHs that are done, but waiting to be unlinked (race) */
+- struct list_head qh_remove_list;
+- unsigned int qh_remove_age; /* Age in frames */
+-
+ /* List of TDs that are done, but waiting to be freed (race) */
+ struct list_head td_remove_list;
+ unsigned int td_remove_age; /* Age in frames */
+
+- /* List of asynchronously unlinked URBs */
+- struct list_head urb_remove_list;
+- unsigned int urb_remove_age; /* Age in frames */
+-
+ /* List of URBs awaiting completion callback */
+ struct list_head complete_list;
+
++ struct list_head idle_qh_list; /* Where the idle QHs live */
++
+ int rh_numports; /* Number of root-hub ports */
+
+ wait_queue_head_t waitqh; /* endpoint_disable waiters */
++ int num_waiting; /* Number of waiters */
+ };
+
+ /* Convert between a usb_hcd pointer and the corresponding uhci_hcd */
+@@ -430,22 +448,19 @@ static inline struct usb_hcd *uhci_to_hc
+ */
+ struct urb_priv {
+ struct list_head urb_list;
++ struct list_head node; /* Node in the QH's urbp list */
+
+ struct urb *urb;
+
+ struct uhci_qh *qh; /* QH for this URB */
+ struct list_head td_list;
+
+- unsigned fsbr : 1; /* URB turned on FSBR */
+- unsigned fsbr_timeout : 1; /* URB timed out on FSBR */
+- unsigned queued : 1; /* QH was queued (not linked in) */
+- unsigned short_control_packet : 1; /* If we get a short packet during */
+- /* a control transfer, retrigger */
+- /* the status phase */
+-
+ unsigned long fsbrtime; /* In jiffies */
+
+- struct list_head queue_list;
++ unsigned fsbr : 1; /* URB turned on FSBR */
++ unsigned fsbr_timeout : 1; /* URB timed out on FSBR */
++ unsigned short_transfer : 1; /* URB got a short transfer, no
++ * need to rescan */
+ };
+
+
+--- gregkh-2.6.orig/drivers/usb/host/uhci-q.c
++++ gregkh-2.6/drivers/usb/host/uhci-q.c
+@@ -13,13 +13,9 @@
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+- * (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu
++ * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu
+ */
+
+-static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
+-static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb);
+-static void uhci_remove_pending_urbps(struct uhci_hcd *uhci);
+-static void uhci_free_pending_qhs(struct uhci_hcd *uhci);
+ static void uhci_free_pending_tds(struct uhci_hcd *uhci);
+
+ /*
+@@ -30,7 +26,7 @@ static void uhci_free_pending_tds(struct
+ * games with the FSBR code to make sure we get the correct order in all
+ * the cases. I don't think it's worth the effort
+ */
+-static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci)
++static void uhci_set_next_interrupt(struct uhci_hcd *uhci)
+ {
+ if (uhci->is_stopped)
+ mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
+@@ -42,12 +38,6 @@ static inline void uhci_clear_next_inter
+ uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC);
+ }
+
+-static inline void uhci_moveto_complete(struct uhci_hcd *uhci,
+- struct urb_priv *urbp)
+-{
+- list_move_tail(&urbp->urb_list, &uhci->complete_list);
+-}
+-
+ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci)
+ {
+ dma_addr_t dma_handle;
+@@ -71,6 +61,18 @@ static struct uhci_td *uhci_alloc_td(str
+ return td;
+ }
+
++static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
++{
++ if (!list_empty(&td->list))
++ dev_warn(uhci_dev(uhci), "td %p still in list!\n", td);
++ if (!list_empty(&td->remove_list))
++ dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td);
++ if (!list_empty(&td->fl_list))
++ dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
++
++ dma_pool_free(uhci->td_pool, td, td->dma_handle);
++}
++
+ static inline void uhci_fill_td(struct uhci_td *td, u32 status,
+ u32 token, u32 buffer)
+ {
+@@ -82,7 +84,8 @@ static inline void uhci_fill_td(struct u
+ /*
+ * We insert Isochronous URBs directly into the frame list at the beginning
+ */
+-static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, unsigned framenum)
++static inline void uhci_insert_td_in_frame_list(struct uhci_hcd *uhci,
++ struct uhci_td *td, unsigned framenum)
+ {
+ framenum &= (UHCI_NUMFRAMES - 1);
+
+@@ -108,7 +111,7 @@ static void uhci_insert_td_frame_list(st
+ }
+ }
+
+-static inline void uhci_remove_td_frame_list(struct uhci_hcd *uhci,
++static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci,
+ struct uhci_td *td)
+ {
+ /* If it's not inserted, don't remove it */
+@@ -139,48 +142,68 @@ static inline void uhci_remove_td_frame_
+ td->frame = -1;
+ }
+
+-static void unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb)
++/*
++ * Remove all the TDs for an Isochronous URB from the frame list
++ */
++static void uhci_unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb)
+ {
+ struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
+ struct uhci_td *td;
+
+ list_for_each_entry(td, &urbp->td_list, list)
+- uhci_remove_td_frame_list(uhci, td);
++ uhci_remove_td_from_frame_list(uhci, td);
+ wmb();
+ }
+
+ /*
+- * Inserts a td list into qh.
++ * Remove an URB's TDs from the hardware schedule
+ */
+-static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, __le32 breadth)
++static void uhci_remove_tds_from_schedule(struct uhci_hcd *uhci,
++ struct urb *urb, int status)
+ {
+- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+- struct uhci_td *td;
+- __le32 *plink;
++ struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
+
+- /* Ordering isn't important here yet since the QH hasn't been */
+- /* inserted into the schedule yet */
+- plink = &qh->element;
+- list_for_each_entry(td, &urbp->td_list, list) {
+- *plink = cpu_to_le32(td->dma_handle) | breadth;
+- plink = &td->link;
++ /* Isochronous TDs get unlinked directly from the frame list */
++ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
++ uhci_unlink_isochronous_tds(uhci, urb);
++ return;
+ }
+- *plink = UHCI_PTR_TERM;
+-}
+
+-static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
+-{
+- if (!list_empty(&td->list))
+- dev_warn(uhci_dev(uhci), "td %p still in list!\n", td);
+- if (!list_empty(&td->remove_list))
+- dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td);
+- if (!list_empty(&td->fl_list))
+- dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
+-
+- dma_pool_free(uhci->td_pool, td, td->dma_handle);
++ /* If the URB isn't first on its queue, adjust the link pointer
++ * of the last TD in the previous URB. */
++ if (urbp->node.prev != &urbp->qh->queue) {
++ struct urb_priv *purbp;
++ struct uhci_td *ptd, *ltd;
++
++ if (status == -EINPROGRESS)
++ status = 0;
++ purbp = list_entry(urbp->node.prev, struct urb_priv, node);
++ ptd = list_entry(purbp->td_list.prev, struct uhci_td,
++ list);
++ ltd = list_entry(urbp->td_list.prev, struct uhci_td,
++ list);
++ ptd->link = ltd->link;
++ }
++
++ /* If the URB completed with an error, then the QH element certainly
++ * points to one of the URB's TDs. If it completed normally then
++ * the QH element has certainly moved on to the next URB. And if
++ * the URB is still in progress then it must have been dequeued.
++ * The QH element either hasn't reached it yet or is somewhere in
++ * the middle. If the URB wasn't first we can assume that it
++ * hasn't started yet (see above): Otherwise all the preceding URBs
++ * would have completed and been removed from the queue, so this one
++ * _would_ be first.
++ *
++ * If the QH element is inside this URB, clear it. It will be
++ * set properly when the QH is activated.
++ */
++ if (status < 0)
++ urbp->qh->element = UHCI_PTR_TERM;
+ }
+
+-static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci)
++static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
++ struct usb_device *udev, struct usb_host_endpoint *hep)
+ {
+ dma_addr_t dma_handle;
+ struct uhci_qh *qh;
+@@ -194,256 +217,120 @@ static struct uhci_qh *uhci_alloc_qh(str
+ qh->element = UHCI_PTR_TERM;
+ qh->link = UHCI_PTR_TERM;
+
+- qh->urbp = NULL;
+-
+- INIT_LIST_HEAD(&qh->list);
+- INIT_LIST_HEAD(&qh->remove_list);
++ INIT_LIST_HEAD(&qh->queue);
++ INIT_LIST_HEAD(&qh->node);
+
++ if (udev) { /* Normal QH */
++ qh->state = QH_STATE_IDLE;
++ qh->hep = hep;
++ qh->udev = udev;
++ hep->hcpriv = qh;
++ usb_get_dev(udev);
++
++ } else { /* Skeleton QH */
++ qh->state = QH_STATE_ACTIVE;
++ qh->udev = NULL;
++ }
+ return qh;
+ }
+
+ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+ {
+- if (!list_empty(&qh->list))
++ WARN_ON(qh->state != QH_STATE_IDLE && qh->udev);
++ if (!list_empty(&qh->queue))
+ dev_warn(uhci_dev(uhci), "qh %p list not empty!\n", qh);
+- if (!list_empty(&qh->remove_list))
+- dev_warn(uhci_dev(uhci), "qh %p still in remove_list!\n", qh);
+
++ list_del(&qh->node);
++ if (qh->udev) {
++ qh->hep->hcpriv = NULL;
++ usb_put_dev(qh->udev);
++ }
+ dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
+ }
+
+ /*
+- * Append this urb's qh after the last qh in skelqh->list
+- *
+- * Note that urb_priv.queue_list doesn't have a separate queue head;
+- * it's a ring with every element "live".
++ * Put a QH on the schedule in both hardware and software
+ */
+-static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb)
++static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+ {
+- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+- struct urb_priv *turbp;
+- struct uhci_qh *lqh;
++ struct uhci_qh *pqh;
+
+- /* Grab the last QH */
+- lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
++ WARN_ON(list_empty(&qh->queue));
+
+- /* Point to the next skelqh */
+- urbp->qh->link = lqh->link;
+- wmb(); /* Ordering is important */
++ /* Set the element pointer if it isn't set already.
++ * This isn't needed for Isochronous queues, but it doesn't hurt. */
++ if (qh_element(qh) == UHCI_PTR_TERM) {
++ struct urb_priv *urbp = list_entry(qh->queue.next,
++ struct urb_priv, node);
++ struct uhci_td *td = list_entry(urbp->td_list.next,
++ struct uhci_td, list);
+
+- /*
+- * Patch QHs for previous endpoint's queued URBs? HC goes
+- * here next, not to the next skelqh it now points to.
+- *
+- * lqh --> td ... --> qh ... --> td --> qh ... --> td
+- * | | |
+- * v v v
+- * +<----------------+-----------------+
+- * v
+- * newqh --> td ... --> td
+- * |
+- * v
+- * ...
+- *
+- * The HC could see (and use!) any of these as we write them.
+- */
+- lqh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
+- if (lqh->urbp) {
+- list_for_each_entry(turbp, &lqh->urbp->queue_list, queue_list)
+- turbp->qh->link = lqh->link;
++ qh->element = cpu_to_le32(td->dma_handle);
+ }
+
+- list_add_tail(&urbp->qh->list, &skelqh->list);
++ if (qh->state == QH_STATE_ACTIVE)
++ return;
++ qh->state = QH_STATE_ACTIVE;
++
++ /* Move the QH from its old list to the end of the appropriate
++ * skeleton's list */
++ list_move_tail(&qh->node, &qh->skel->node);
++
++ /* Link it into the schedule */
++ pqh = list_entry(qh->node.prev, struct uhci_qh, node);
++ qh->link = pqh->link;
++ wmb();
++ pqh->link = UHCI_PTR_QH | cpu_to_le32(qh->dma_handle);
+ }
+
+ /*
+- * Start removal of QH from schedule; it finishes next frame.
+- * TDs should be unlinked before this is called.
++ * Take a QH off the hardware schedule
+ */
+-static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
++static void uhci_unlink_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+ {
+ struct uhci_qh *pqh;
+- __le32 newlink;
+
+- if (!qh)
++ if (qh->state == QH_STATE_UNLINKING)
+ return;
++ WARN_ON(qh->state != QH_STATE_ACTIVE || !qh->udev);
++ qh->state = QH_STATE_UNLINKING;
+
+- /*
+- * Only go through the hoops if it's actually linked in
+- */
+- if (!list_empty(&qh->list)) {
+-
+- /* If our queue is nonempty, make the next URB the head */
+- if (!list_empty(&qh->urbp->queue_list)) {
+- struct urb_priv *nurbp;
+-
+- nurbp = list_entry(qh->urbp->queue_list.next,
+- struct urb_priv, queue_list);
+- nurbp->queued = 0;
+- list_add(&nurbp->qh->list, &qh->list);
+- newlink = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
+- } else
+- newlink = qh->link;
+-
+- /* Fix up the previous QH's queue to link to either
+- * the new head of this queue or the start of the
+- * next endpoint's queue. */
+- pqh = list_entry(qh->list.prev, struct uhci_qh, list);
+- pqh->link = newlink;
+- if (pqh->urbp) {
+- struct urb_priv *turbp;
+-
+- list_for_each_entry(turbp, &pqh->urbp->queue_list,
+- queue_list)
+- turbp->qh->link = newlink;
+- }
+- wmb();
+-
+- /* Leave qh->link in case the HC is on the QH now, it will */
+- /* continue the rest of the schedule */
+- qh->element = UHCI_PTR_TERM;
+-
+- list_del_init(&qh->list);
+- }
+-
+- list_del_init(&qh->urbp->queue_list);
+- qh->urbp = NULL;
++ /* Unlink the QH from the schedule and record when we did it */
++ pqh = list_entry(qh->node.prev, struct uhci_qh, node);
++ pqh->link = qh->link;
++ mb();
+
+ uhci_get_current_frame_number(uhci);
+- if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age) {
+- uhci_free_pending_qhs(uhci);
+- uhci->qh_remove_age = uhci->frame_number;
+- }
++ qh->unlink_frame = uhci->frame_number;
+
+- /* Check to see if the remove list is empty. Set the IOC bit */
+- /* to force an interrupt so we can remove the QH */
+- if (list_empty(&uhci->qh_remove_list))
++ /* Force an interrupt so we know when the QH is fully unlinked */
++ if (list_empty(&uhci->skel_unlink_qh->node))
+ uhci_set_next_interrupt(uhci);
+
+- list_add(&qh->remove_list, &uhci->qh_remove_list);
+-}
+-
+-static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle)
+-{
+- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+- struct uhci_td *td;
+-
+- list_for_each_entry(td, &urbp->td_list, list) {
+- if (toggle)
+- td->token |= cpu_to_le32(TD_TOKEN_TOGGLE);
+- else
+- td->token &= ~cpu_to_le32(TD_TOKEN_TOGGLE);
+-
+- toggle ^= 1;
+- }
+-
+- return toggle;
+-}
+-
+-/* This function will append one URB's QH to another URB's QH. This is for */
+-/* queuing interrupt, control or bulk transfers */
+-static void uhci_append_queued_urb(struct uhci_hcd *uhci, struct urb *eurb, struct urb *urb)
+-{
+- struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
+- struct uhci_td *lltd;
+-
+- eurbp = eurb->hcpriv;
+- urbp = urb->hcpriv;
+-
+- /* Find the first URB in the queue */
+- furbp = eurbp;
+- if (eurbp->queued) {
+- list_for_each_entry(furbp, &eurbp->queue_list, queue_list)
+- if (!furbp->queued)
+- break;
+- }
+-
+- lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list);
+-
+- lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
+-
+- /* Control transfers always start with toggle 0 */
+- if (!usb_pipecontrol(urb->pipe))
+- usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+- usb_pipeout(urb->pipe),
+- uhci_fixup_toggle(urb,
+- uhci_toggle(td_token(lltd)) ^ 1));
+-
+- /* All qhs in the queue need to link to the next queue */
+- urbp->qh->link = eurbp->qh->link;
+-
+- wmb(); /* Make sure we flush everything */
+-
+- lltd->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
+-
+- list_add_tail(&urbp->queue_list, &furbp->queue_list);
+-
+- urbp->queued = 1;
++ /* Move the QH from its old list to the end of the unlinking list */
++ list_move_tail(&qh->node, &uhci->skel_unlink_qh->node);
+ }
+
+-static void uhci_delete_queued_urb(struct uhci_hcd *uhci, struct urb *urb)
++/*
++ * When we and the controller are through with a QH, it becomes IDLE.
++ * This happens when a QH has been off the schedule (on the unlinking
++ * list) for more than one frame, or when an error occurs while adding
++ * the first URB onto a new QH.
++ */
++static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh)
+ {
+- struct urb_priv *urbp, *nurbp, *purbp, *turbp;
+- struct uhci_td *pltd;
+- unsigned int toggle;
+-
+- urbp = urb->hcpriv;
+-
+- if (list_empty(&urbp->queue_list))
+- return;
+-
+- nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list);
+-
+- /*
+- * Fix up the toggle for the following URBs in the queue.
+- * Only needed for bulk and interrupt: control and isochronous
+- * endpoints don't propagate toggles between messages.
+- */
+- if (usb_pipebulk(urb->pipe) || usb_pipeint(urb->pipe)) {
+- if (!urbp->queued)
+- /* We just set the toggle in uhci_unlink_generic */
+- toggle = usb_gettoggle(urb->dev,
+- usb_pipeendpoint(urb->pipe),
+- usb_pipeout(urb->pipe));
+- else {
+- /* If we're in the middle of the queue, grab the */
+- /* toggle from the TD previous to us */
+- purbp = list_entry(urbp->queue_list.prev,
+- struct urb_priv, queue_list);
+- pltd = list_entry(purbp->td_list.prev,
+- struct uhci_td, list);
+- toggle = uhci_toggle(td_token(pltd)) ^ 1;
+- }
+-
+- list_for_each_entry(turbp, &urbp->queue_list, queue_list) {
+- if (!turbp->queued)
+- break;
+- toggle = uhci_fixup_toggle(turbp->urb, toggle);
+- }
+-
+- usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+- usb_pipeout(urb->pipe), toggle);
+- }
++ WARN_ON(qh->state == QH_STATE_ACTIVE);
+
+- if (urbp->queued) {
+- /* We're somewhere in the middle (or end). The case where
+- * we're at the head is handled in uhci_remove_qh(). */
+- purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
+- queue_list);
+-
+- pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
+- if (nurbp->queued)
+- pltd->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
+- else
+- /* The next URB happens to be the beginning, so */
+- /* we're the last, end the chain */
+- pltd->link = UHCI_PTR_TERM;
+- }
++ list_move(&qh->node, &uhci->idle_qh_list);
++ qh->state = QH_STATE_IDLE;
+
+- /* urbp->queue_list is handled in uhci_remove_qh() */
++ /* If anyone is waiting for a QH to become idle, wake them up */
++ if (uhci->num_waiting)
++ wake_up_all(&uhci->waitqh);
+ }
+
+-static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
++static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci,
++ struct urb *urb)
+ {
+ struct urb_priv *urbp;
+
+@@ -453,17 +340,14 @@ static struct urb_priv *uhci_alloc_urb_p
+
+ memset((void *)urbp, 0, sizeof(*urbp));
+
+- urbp->fsbrtime = jiffies;
+ urbp->urb = urb;
++ urb->hcpriv = urbp;
++ urbp->fsbrtime = jiffies;
+
++ INIT_LIST_HEAD(&urbp->node);
+ INIT_LIST_HEAD(&urbp->td_list);
+- INIT_LIST_HEAD(&urbp->queue_list);
+ INIT_LIST_HEAD(&urbp->urb_list);
+
+- list_add_tail(&urbp->urb_list, &uhci->urb_list);
+-
+- urb->hcpriv = urbp;
+-
+ return urbp;
+ }
+
+@@ -482,18 +366,17 @@ static void uhci_remove_td_from_urb(stru
+ list_del_init(&td->list);
+ }
+
+-static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
++static void uhci_free_urb_priv(struct uhci_hcd *uhci,
++ struct urb_priv *urbp)
+ {
+ struct uhci_td *td, *tmp;
+- struct urb_priv *urbp;
+-
+- urbp = (struct urb_priv *)urb->hcpriv;
+- if (!urbp)
+- return;
+
+ if (!list_empty(&urbp->urb_list))
+- dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list "
+- "or uhci->remove_list!\n", urb);
++ dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list!\n",
++ urbp->urb);
++ if (!list_empty(&urbp->node))
++ dev_warn(uhci_dev(uhci), "urb %p still on QH's list!\n",
++ urbp->urb);
+
+ uhci_get_current_frame_number(uhci);
+ if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age) {
+@@ -502,7 +385,7 @@ static void uhci_destroy_urb_priv(struct
+ }
+
+ /* Check to see if the remove list is empty. Set the IOC bit */
+- /* to force an interrupt so we can remove the TDs*/
++ /* to force an interrupt so we can remove the TDs. */
+ if (list_empty(&uhci->td_remove_list))
+ uhci_set_next_interrupt(uhci);
+
+@@ -511,7 +394,7 @@ static void uhci_destroy_urb_priv(struct
+ list_add(&td->remove_list, &uhci->td_remove_list);
+ }
+
+- urb->hcpriv = NULL;
++ urbp->urb->hcpriv = NULL;
+ kmem_cache_free(uhci_up_cachep, urbp);
+ }
+
+@@ -568,17 +451,82 @@ static int uhci_map_status(int status, i
+ }
+
+ /*
++ * Fix up the data toggles for URBs in a queue, when one of them
++ * terminates early (short transfer, error, or dequeued).
++ */
++static void uhci_fixup_toggles(struct urb *urb)
++{
++ struct list_head *head;
++ struct uhci_td *td;
++ struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
++ int prevactive = 0;
++ unsigned int toggle = 0;
++ struct urb_priv *turbp, *list_end;
++
++ /*
++ * We need to find out what the last successful toggle was so
++ * we can update the data toggles for the following transfers.
++ *
++ * There are 2 ways the last successful completed TD is found:
++ *
++ * 1) The TD is NOT active and the actual length < expected length
++ * 2) The TD is NOT active and it's the last TD in the chain
++ *
++ * and a third way the first uncompleted TD is found:
++ *
++ * 3) The TD is active and the previous TD is NOT active
++ */
++ head = &urbp->td_list;
++ list_for_each_entry(td, head, list) {
++ unsigned int ctrlstat = td_status(td);
++
++ if (!(ctrlstat & TD_CTRL_ACTIVE) &&
++ (uhci_actual_length(ctrlstat) <
++ uhci_expected_length(td_token(td)) ||
++ td->list.next == head))
++ toggle = uhci_toggle(td_token(td)) ^ 1;
++ else if ((ctrlstat & TD_CTRL_ACTIVE) && !prevactive)
++ toggle = uhci_toggle(td_token(td));
++
++ prevactive = ctrlstat & TD_CTRL_ACTIVE;
++ }
++
++ /*
++ * Fix up the toggle for the following URBs in the queue.
++ *
++ * We can stop as soon as we find an URB with toggles set correctly,
++ * because then all the following URBs will be correct also.
++ */
++ list_end = list_entry(&urbp->qh->queue, struct urb_priv, node);
++ turbp = urbp;
++ while ((turbp = list_entry(turbp->node.next, struct urb_priv, node))
++ != list_end) {
++ td = list_entry(turbp->td_list.next, struct uhci_td, list);
++ if (uhci_toggle(td_token(td)) == toggle)
++ return;
++
++ list_for_each_entry(td, &turbp->td_list, list) {
++ td->token ^= __constant_cpu_to_le32(TD_TOKEN_TOGGLE);
++ toggle ^= 1;
++ }
++ }
++
++ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
++ usb_pipeout(urb->pipe), toggle);
++}
++
++/*
+ * Control transfers
+ */
+-static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
++static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
++ struct uhci_qh *qh)
+ {
+- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ struct uhci_td *td;
+- struct uhci_qh *qh, *skelqh;
+ unsigned long destination, status;
+- int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
++ int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
+ int len = urb->transfer_buffer_length;
+ dma_addr_t data = urb->transfer_dma;
++ __le32 *plink;
+
+ /* The "pipe" thing contains the destination in bits 8--18 */
+ destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
+@@ -597,7 +545,8 @@ static int uhci_submit_control(struct uh
+
+ uhci_add_td_to_urb(urb, td);
+ uhci_fill_td(td, status, destination | uhci_explen(8),
+- urb->setup_dma);
++ urb->setup_dma);
++ plink = &td->link;
+
+ /*
+ * If direction is "send", change the packet ID from SETUP (0x2D)
+@@ -615,21 +564,20 @@ static int uhci_submit_control(struct uh
+ * Build the DATA TDs
+ */
+ while (len > 0) {
+- int pktsze = len;
+-
+- if (pktsze > maxsze)
+- pktsze = maxsze;
++ int pktsze = min(len, maxsze);
+
+ td = uhci_alloc_td(uhci);
+ if (!td)
+ return -ENOMEM;
++ *plink = cpu_to_le32(td->dma_handle);
+
+ /* Alternate Data0/1 (start with Data1) */
+ destination ^= TD_TOKEN_TOGGLE;
+
+ uhci_add_td_to_urb(urb, td);
+ uhci_fill_td(td, status, destination | uhci_explen(pktsze),
+- data);
++ data);
++ plink = &td->link;
+
+ data += pktsze;
+ len -= pktsze;
+@@ -641,6 +589,7 @@ static int uhci_submit_control(struct uh
+ td = uhci_alloc_td(uhci);
+ if (!td)
+ return -ENOMEM;
++ *plink = cpu_to_le32(td->dma_handle);
+
+ /*
+ * It's IN if the pipe is an output pipe or we're not expecting
+@@ -658,16 +607,7 @@ static int uhci_submit_control(struct uh
+
+ uhci_add_td_to_urb(urb, td);
+ uhci_fill_td(td, status | TD_CTRL_IOC,
+- destination | uhci_explen(0), 0);
+-
+- qh = uhci_alloc_qh(uhci);
+- if (!qh)
+- return -ENOMEM;
+-
+- urbp->qh = qh;
+- qh->urbp = urbp;
+-
+- uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
++ destination | uhci_explen(0), 0);
+
+ /* Low-speed transfers get a different queue, and won't hog the bus.
+ * Also, some devices enumerate better without FSBR; the easiest way
+@@ -675,18 +615,13 @@ static int uhci_submit_control(struct uh
+ * is in the DEFAULT state. */
+ if (urb->dev->speed == USB_SPEED_LOW ||
+ urb->dev->state == USB_STATE_DEFAULT)
+- skelqh = uhci->skel_ls_control_qh;
++ qh->skel = uhci->skel_ls_control_qh;
+ else {
+- skelqh = uhci->skel_fs_control_qh;
++ qh->skel = uhci->skel_fs_control_qh;
+ uhci_inc_fsbr(uhci, urb);
+ }
+
+- if (eurb)
+- uhci_append_queued_urb(uhci, eurb, urb);
+- else
+- uhci_insert_qh(uhci, skelqh, urb);
+-
+- return -EINPROGRESS;
++ return 0;
+ }
+
+ /*
+@@ -703,7 +638,7 @@ static int usb_control_retrigger_status(
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ struct uhci_td *td;
+
+- urbp->short_control_packet = 1;
++ urbp->short_transfer = 1;
+
+ td = list_entry(urbp->td_list.prev, struct uhci_td, list);
+ urbp->qh->element = cpu_to_le32(td->dma_handle);
+@@ -720,16 +655,14 @@ static int uhci_result_control(struct uh
+ unsigned int status;
+ int ret = 0;
+
+- if (list_empty(&urbp->td_list))
+- return -EINVAL;
+-
+ head = &urbp->td_list;
+-
+- if (urbp->short_control_packet) {
++ if (urbp->short_transfer) {
+ tmp = head->prev;
+ goto status_stage;
+ }
+
++ urb->actual_length = 0;
++
+ tmp = head->next;
+ td = list_entry(tmp, struct uhci_td, list);
+
+@@ -742,8 +675,6 @@ static int uhci_result_control(struct uh
+ if (status)
+ goto td_error;
+
+- urb->actual_length = 0;
+-
+ /* The rest of the TDs (but the last) are data */
+ tmp = tmp->next;
+ while (tmp != head && tmp->next != head) {
+@@ -770,10 +701,7 @@ static int uhci_result_control(struct uh
+ goto err;
+ }
+
+- if (uhci_packetid(td_token(td)) == USB_PID_IN)
+- return usb_control_retrigger_status(uhci, urb);
+- else
+- return 0;
++ return usb_control_retrigger_status(uhci, urb);
+ }
+ }
+
+@@ -825,15 +753,15 @@ err:
+ /*
+ * Common submit for bulk and interrupt
+ */
+-static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb, struct uhci_qh *skelqh)
++static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
++ struct uhci_qh *qh)
+ {
+ 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 maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
+ int len = urb->transfer_buffer_length;
+- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ dma_addr_t data = urb->transfer_dma;
++ __le32 *plink, fake_link;
+
+ if (len < 0)
+ return -EINVAL;
+@@ -841,7 +769,8 @@ static int uhci_submit_common(struct uhc
+ /* The "pipe" thing contains the destination in bits 8--18 */
+ destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+- status = uhci_maxerr(3) | TD_CTRL_ACTIVE;
++ /* 3 errors */
++ status = TD_CTRL_ACTIVE | uhci_maxerr(3);
+ if (urb->dev->speed == USB_SPEED_LOW)
+ status |= TD_CTRL_LS;
+ if (usb_pipein(urb->pipe))
+@@ -850,10 +779,11 @@ static int uhci_submit_common(struct uhc
+ /*
+ * Build the DATA TDs
+ */
++ plink = &fake_link;
+ do { /* Allow zero length packets */
+ int pktsze = maxsze;
+
+- if (pktsze >= len) {
++ if (len <= pktsze) { /* The last packet */
+ pktsze = len;
+ if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
+ status &= ~TD_CTRL_SPD;
+@@ -862,12 +792,15 @@ static int uhci_submit_common(struct uhc
+ td = uhci_alloc_td(uhci);
+ if (!td)
+ return -ENOMEM;
++ *plink = cpu_to_le32(td->dma_handle);
+
+ uhci_add_td_to_urb(urb, td);
+- uhci_fill_td(td, status, destination | uhci_explen(pktsze) |
++ uhci_fill_td(td, status,
++ destination | uhci_explen(pktsze) |
+ (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
+ data);
++ plink = &td->link;
+
+ data += pktsze;
+ len -= maxsze;
+@@ -883,11 +816,13 @@ static int uhci_submit_common(struct uhc
+ * however, if transfer_length == 0, the zero packet was already
+ * prepared above.
+ */
+- if (usb_pipeout(urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) &&
+- !len && urb->transfer_buffer_length) {
++ if ((urb->transfer_flags & URB_ZERO_PACKET) &&
++ usb_pipeout(urb->pipe) && len == 0 &&
++ urb->transfer_buffer_length > 0) {
+ td = uhci_alloc_td(uhci);
+ if (!td)
+ return -ENOMEM;
++ *plink = cpu_to_le32(td->dma_handle);
+
+ uhci_add_td_to_urb(urb, td);
+ uhci_fill_td(td, status, destination | uhci_explen(0) |
+@@ -905,24 +840,9 @@ static int uhci_submit_common(struct uhc
+ * fast side but not enough to justify delaying an interrupt
+ * more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT
+ * flag setting. */
+- td->status |= cpu_to_le32(TD_CTRL_IOC);
+-
+- qh = uhci_alloc_qh(uhci);
+- if (!qh)
+- return -ENOMEM;
+-
+- urbp->qh = qh;
+- qh->urbp = urbp;
++ td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
+
+- /* Always breadth first */
+- uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
+-
+- if (eurb)
+- uhci_append_queued_urb(uhci, eurb, urb);
+- else
+- uhci_insert_qh(uhci, skelqh, urb);
+-
+- return -EINPROGRESS;
++ return 0;
+ }
+
+ /*
+@@ -954,8 +874,24 @@ static int uhci_result_common(struct uhc
+ if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+ ret = -EREMOTEIO;
+ goto err;
+- } else
+- return 0;
++ }
++
++ /*
++ * This URB stopped short of its end. We have to
++ * fix up the toggles of the following URBs on the
++ * queue and restart the queue.
++ *
++ * Do this only the first time we encounter the
++ * short URB.
++ */
++ if (!urbp->short_transfer) {
++ urbp->short_transfer = 1;
++ uhci_fixup_toggles(urb);
++ td = list_entry(urbp->td_list.prev,
++ struct uhci_td, list);
++ urbp->qh->element = td->link;
++ }
++ break;
+ }
+ }
+
+@@ -988,7 +924,8 @@ err:
+ return ret;
+ }
+
+-static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
++static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
++ struct uhci_qh *qh)
+ {
+ int ret;
+
+@@ -996,21 +933,22 @@ static inline int uhci_submit_bulk(struc
+ if (urb->dev->speed == USB_SPEED_LOW)
+ return -EINVAL;
+
+- ret = uhci_submit_common(uhci, urb, eurb, uhci->skel_bulk_qh);
+- if (ret == -EINPROGRESS)
++ qh->skel = uhci->skel_bulk_qh;
++ ret = uhci_submit_common(uhci, urb, qh);
++ if (ret == 0)
+ uhci_inc_fsbr(uhci, urb);
+-
+ return ret;
+ }
+
+-static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
++static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
++ struct uhci_qh *qh)
+ {
+- /* USB 1.1 interrupt transfers only involve one packet per interval;
+- * that's the uhci_submit_common() "breadth first" policy. Drivers
+- * can submit urbs of any length, but longer ones might need many
+- * intervals to complete.
++ /* USB 1.1 interrupt transfers only involve one packet per interval.
++ * Drivers can submit URBs of any length, but longer ones will need
++ * multiple intervals to complete.
+ */
+- return uhci_submit_common(uhci, urb, eurb, uhci->skelqh[__interval_to_skel(urb->interval)]);
++ qh->skel = uhci->skelqh[__interval_to_skel(urb->interval)];
++ return uhci_submit_common(uhci, urb, qh);
+ }
+
+ /*
+@@ -1072,11 +1010,12 @@ static int isochronous_find_start(struct
+ /*
+ * Isochronous transfers
+ */
+-static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
++static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
++ struct uhci_qh *qh)
+ {
+- struct uhci_td *td;
++ struct uhci_td *td = NULL; /* Since urb->number_of_packets > 0 */
+ int i, ret, frame;
+- int status, destination;
++ unsigned long destination, status;
+ struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
+
+ status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
+@@ -1092,20 +1031,25 @@ static int uhci_submit_isochronous(struc
+ return -ENOMEM;
+
+ uhci_add_td_to_urb(urb, td);
+- uhci_fill_td(td, status, destination | uhci_explen(urb->iso_frame_desc[i].length),
+- urb->transfer_dma + urb->iso_frame_desc[i].offset);
+-
+- if (i + 1 >= urb->number_of_packets)
+- td->status |= cpu_to_le32(TD_CTRL_IOC);
++ uhci_fill_td(td, status, destination |
++ uhci_explen(urb->iso_frame_desc[i].length),
++ urb->transfer_dma +
++ urb->iso_frame_desc[i].offset);
+ }
+
++ /* Set the interrupt-on-completion flag on the last packet. */
++ td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
++
++ qh->skel = uhci->skel_iso_qh;
++
++ /* Add the TDs to the frame list */
+ frame = urb->start_frame;
+ list_for_each_entry(td, &urbp->td_list, list) {
+- uhci_insert_td_frame_list(uhci, td, frame);
++ uhci_insert_td_in_frame_list(uhci, td, frame);
+ frame += urb->interval;
+ }
+
+- return -EINPROGRESS;
++ return 0;
+ }
+
+ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
+@@ -1139,80 +1083,67 @@ static int uhci_result_isochronous(struc
+
+ i++;
+ }
+- unlink_isochronous_tds(uhci, urb);
+
+ return ret;
+ }
+
+-static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb)
+-{
+- struct urb_priv *up;
+-
+- /* We don't match Isoc transfers since they are special */
+- if (usb_pipeisoc(urb->pipe))
+- return NULL;
+-
+- list_for_each_entry(up, &uhci->urb_list, urb_list) {
+- struct urb *u = up->urb;
+-
+- if (u->dev == urb->dev && u->status == -EINPROGRESS) {
+- /* For control, ignore the direction */
+- if (usb_pipecontrol(urb->pipe) &&
+- (u->pipe & ~USB_DIR_IN) == (urb->pipe & ~USB_DIR_IN))
+- return u;
+- else if (u->pipe == urb->pipe)
+- return u;
+- }
+- }
+-
+- return NULL;
+-}
+-
+ static int uhci_urb_enqueue(struct usb_hcd *hcd,
+- struct usb_host_endpoint *ep,
++ struct usb_host_endpoint *hep,
+ struct urb *urb, gfp_t mem_flags)
+ {
+ int ret;
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+ unsigned long flags;
+- struct urb *eurb;
++ struct urb_priv *urbp;
++ struct uhci_qh *qh;
+ int bustime;
+
+ spin_lock_irqsave(&uhci->lock, flags);
+
+ ret = urb->status;
+ if (ret != -EINPROGRESS) /* URB already unlinked! */
+- goto out;
++ goto done;
+
+- eurb = uhci_find_urb_ep(uhci, urb);
++ ret = -ENOMEM;
++ urbp = uhci_alloc_urb_priv(uhci, urb);
++ if (!urbp)
++ goto done;
+
+- if (!uhci_alloc_urb_priv(uhci, urb)) {
+- ret = -ENOMEM;
+- goto out;
++ if (hep->hcpriv)
++ qh = (struct uhci_qh *) hep->hcpriv;
++ else {
++ qh = uhci_alloc_qh(uhci, urb->dev, hep);
++ if (!qh)
++ goto err_no_qh;
+ }
++ urbp->qh = qh;
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+- ret = uhci_submit_control(uhci, urb, eurb);
++ ret = uhci_submit_control(uhci, urb, qh);
++ break;
++ case PIPE_BULK:
++ ret = uhci_submit_bulk(uhci, urb, qh);
+ break;
+ case PIPE_INTERRUPT:
+- if (!eurb) {
++ if (list_empty(&qh->queue)) {
+ bustime = usb_check_bandwidth(urb->dev, urb);
+ if (bustime < 0)
+ ret = bustime;
+ else {
+- ret = uhci_submit_interrupt(uhci, urb, eurb);
+- if (ret == -EINPROGRESS)
++ ret = uhci_submit_interrupt(uhci, urb, qh);
++ if (ret == 0)
+ usb_claim_bandwidth(urb->dev, urb, bustime, 0);
+ }
+ } else { /* inherit from parent */
+- urb->bandwidth = eurb->bandwidth;
+- ret = uhci_submit_interrupt(uhci, urb, eurb);
++ struct urb_priv *eurbp;
++
++ eurbp = list_entry(qh->queue.prev, struct urb_priv,
++ node);
++ urb->bandwidth = eurbp->urb->bandwidth;
++ ret = uhci_submit_interrupt(uhci, urb, qh);
+ }
+ break;
+- case PIPE_BULK:
+- ret = uhci_submit_bulk(uhci, urb, eurb);
+- break;
+ case PIPE_ISOCHRONOUS:
+ bustime = usb_check_bandwidth(urb->dev, urb);
+ if (bustime < 0) {
+@@ -1220,22 +1151,59 @@ static int uhci_urb_enqueue(struct usb_h
+ break;
+ }
+
+- ret = uhci_submit_isochronous(uhci, urb);
+- if (ret == -EINPROGRESS)
++ ret = uhci_submit_isochronous(uhci, urb, qh);
++ if (ret == 0)
+ usb_claim_bandwidth(urb->dev, urb, bustime, 1);
+ break;
+ }
++ if (ret != 0)
++ goto err_submit_failed;
+
+- if (ret != -EINPROGRESS) {
+- /* Submit failed, so delete it from the urb_list */
+- struct urb_priv *urbp = urb->hcpriv;
++ /* Add this URB to the QH */
++ urbp->qh = qh;
++ list_add_tail(&urbp->node, &qh->queue);
++ list_add_tail(&urbp->urb_list, &uhci->urb_list);
+
+- list_del_init(&urbp->urb_list);
+- uhci_destroy_urb_priv(uhci, urb);
+- } else
+- ret = 0;
++ /* If the new URB is the first and only one on this QH then either
++ * the QH is new and idle or else it's unlinked and waiting to
++ * become idle, so we can activate it right away. */
++ if (qh->queue.next == &urbp->node)
++ uhci_activate_qh(uhci, qh);
++
++ /* If the QH is already active, we have a race with the hardware.
++ * This won't get fixed until dummy TDs are added. */
++ else if (qh->state == QH_STATE_ACTIVE) {
++
++ /* If the URB isn't first on its queue, adjust the link pointer
++ * of the last TD in the previous URB. */
++ if (urbp->node.prev != &urbp->qh->queue) {
++ struct urb_priv *purbp = list_entry(urbp->node.prev,
++ struct urb_priv, node);
++ struct uhci_td *ptd = list_entry(purbp->td_list.prev,
++ struct uhci_td, list);
++ struct uhci_td *td = list_entry(urbp->td_list.next,
++ struct uhci_td, list);
++
++ ptd->link = cpu_to_le32(td->dma_handle);
++
++ }
++ if (qh_element(qh) == UHCI_PTR_TERM) {
++ struct uhci_td *td = list_entry(urbp->td_list.next,
++ struct uhci_td, list);
++
++ qh->element = cpu_to_le32(td->dma_handle);
++ }
++ }
++ goto done;
++
++err_submit_failed:
++ if (qh->state == QH_STATE_IDLE)
++ uhci_make_qh_idle(uhci, qh); /* Reclaim unused QH */
+
+-out:
++err_no_qh:
++ uhci_free_urb_priv(uhci, urbp);
++
++done:
+ spin_unlock_irqrestore(&uhci->lock, flags);
+ return ret;
+ }
+@@ -1245,119 +1213,115 @@ out:
+ */
+ static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb)
+ {
+- int ret = -EINPROGRESS;
+- struct urb_priv *urbp;
+-
+- spin_lock(&urb->lock);
+-
+- urbp = (struct urb_priv *)urb->hcpriv;
+-
+- if (urb->status != -EINPROGRESS) /* URB already dequeued */
+- goto out;
++ int status;
++ int okay_to_giveback = 0;
++ struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+- ret = uhci_result_control(uhci, urb);
+- break;
+- case PIPE_BULK:
+- case PIPE_INTERRUPT:
+- ret = uhci_result_common(uhci, urb);
++ status = uhci_result_control(uhci, urb);
+ break;
+ case PIPE_ISOCHRONOUS:
+- ret = uhci_result_isochronous(uhci, urb);
++ status = uhci_result_isochronous(uhci, urb);
++ break;
++ default: /* PIPE_BULK or PIPE_INTERRUPT */
++ status = uhci_result_common(uhci, urb);
+ break;
+ }
+
+- if (ret == -EINPROGRESS)
+- goto out;
+- urb->status = ret;
++ spin_lock(&urb->lock);
++ if (urb->status == -EINPROGRESS) { /* Not yet dequeued */
++ if (status != -EINPROGRESS) { /* URB has completed */
++ urb->status = status;
++
++ /* If the URB got a real error (as opposed to
++ * simply being dequeued), we don't have to
++ * unlink the QH. Fix this later... */
++ if (status < 0)
++ uhci_unlink_qh(uhci, urbp->qh);
++ else
++ okay_to_giveback = 1;
++ }
++ } else { /* Already dequeued */
++ if (urbp->qh->state == QH_STATE_UNLINKING &&
++ uhci->frame_number + uhci->is_stopped !=
++ urbp->qh->unlink_frame)
++ okay_to_giveback = 1;
++ }
++ spin_unlock(&urb->lock);
++ if (!okay_to_giveback)
++ return;
+
+ switch (usb_pipetype(urb->pipe)) {
+- case PIPE_CONTROL:
+- case PIPE_BULK:
+ case PIPE_ISOCHRONOUS:
+ /* Release bandwidth for Interrupt or Isoc. transfers */
+ if (urb->bandwidth)
+ usb_release_bandwidth(urb->dev, urb, 1);
+- uhci_unlink_generic(uhci, urb);
+ break;
+ case PIPE_INTERRUPT:
+ /* Release bandwidth for Interrupt or Isoc. transfers */
+ /* Make sure we don't release if we have a queued URB */
+- if (list_empty(&urbp->queue_list) && urb->bandwidth)
++ if (list_empty(&urbp->qh->queue) && urb->bandwidth)
+ usb_release_bandwidth(urb->dev, urb, 0);
+ else
+ /* bandwidth was passed on to queued URB, */
+ /* so don't let usb_unlink_urb() release it */
+ urb->bandwidth = 0;
+- uhci_unlink_generic(uhci, urb);
++ /* Falls through */
++ case PIPE_BULK:
++ if (status < 0)
++ uhci_fixup_toggles(urb);
++ break;
++ default: /* PIPE_CONTROL */
+ break;
+- default:
+- dev_info(uhci_dev(uhci), "%s: unknown pipe type %d "
+- "for urb %p\n",
+- __FUNCTION__, usb_pipetype(urb->pipe), urb);
+ }
+
+- /* Move it from uhci->urb_list to uhci->complete_list */
+- uhci_moveto_complete(uhci, urbp);
++ /* Take the URB's TDs off the hardware schedule */
++ uhci_remove_tds_from_schedule(uhci, urb, status);
+
+-out:
+- spin_unlock(&urb->lock);
++ /* Take the URB off the QH's queue and see if the QH is now unused */
++ list_del_init(&urbp->node);
++ if (list_empty(&urbp->qh->queue))
++ uhci_unlink_qh(uhci, urbp->qh);
++
++ uhci_dec_fsbr(uhci, urb); /* Safe since it checks */
++
++ /* Queue it for giving back */
++ list_move_tail(&urbp->urb_list, &uhci->complete_list);
+ }
+
+-static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb)
++/*
++ * Check out the QHs waiting to be fully unlinked
++ */
++static void uhci_scan_unlinking_qhs(struct uhci_hcd *uhci)
+ {
+- struct list_head *head;
+- struct uhci_td *td;
+- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+- int prevactive = 0;
++ struct uhci_qh *qh, *tmp;
+
+- uhci_dec_fsbr(uhci, urb); /* Safe since it checks */
++ list_for_each_entry_safe(qh, tmp, &uhci->skel_unlink_qh->node, node) {
+
+- /*
+- * Now we need to find out what the last successful toggle was
+- * so we can update the local data toggle for the next transfer
+- *
+- * There are 2 ways the last successful completed TD is found:
+- *
+- * 1) The TD is NOT active and the actual length < expected length
+- * 2) The TD is NOT active and it's the last TD in the chain
+- *
+- * and a third way the first uncompleted TD is found:
+- *
+- * 3) The TD is active and the previous TD is NOT active
+- *
+- * Control and Isochronous ignore the toggle, so this is safe
+- * for all types
+- *
+- * FIXME: The toggle fixups won't be 100% reliable until we
+- * change over to using a single queue for each endpoint and
+- * stop the queue before unlinking.
+- */
+- head = &urbp->td_list;
+- list_for_each_entry(td, head, list) {
+- unsigned int ctrlstat = td_status(td);
++ /* If the queue is empty and the QH is fully unlinked then
++ * it can become IDLE. */
++ if (list_empty(&qh->queue)) {
++ if (uhci->frame_number + uhci->is_stopped !=
++ qh->unlink_frame)
++ uhci_make_qh_idle(uhci, qh);
+
+- if (!(ctrlstat & TD_CTRL_ACTIVE) &&
+- (uhci_actual_length(ctrlstat) <
+- uhci_expected_length(td_token(td)) ||
+- td->list.next == head))
+- usb_settoggle(urb->dev, uhci_endpoint(td_token(td)),
+- uhci_packetout(td_token(td)),
+- uhci_toggle(td_token(td)) ^ 1);
+- else if ((ctrlstat & TD_CTRL_ACTIVE) && !prevactive)
+- usb_settoggle(urb->dev, uhci_endpoint(td_token(td)),
+- uhci_packetout(td_token(td)),
+- uhci_toggle(td_token(td)));
++ /* If none of the QH's URBs have been dequeued then the QH
++ * should be re-activated. */
++ } else {
++ struct urb_priv *urbp;
++ int any_dequeued = 0;
+
+- prevactive = ctrlstat & TD_CTRL_ACTIVE;
++ list_for_each_entry(urbp, &qh->queue, node) {
++ if (urbp->urb->status != -EINPROGRESS) {
++ any_dequeued = 1;
++ break;
++ }
++ }
++ if (!any_dequeued)
++ uhci_activate_qh(uhci, qh);
++ }
+ }
+-
+- uhci_delete_queued_urb(uhci, urb);
+-
+- /* The interrupt loop will reclaim the QHs */
+- uhci_remove_qh(uhci, urbp->qh);
+- urbp->qh = NULL;
+ }
+
+ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+@@ -1370,22 +1334,11 @@ static int uhci_urb_dequeue(struct usb_h
+ urbp = urb->hcpriv;
+ if (!urbp) /* URB was never linked! */
+ goto done;
+- list_del_init(&urbp->urb_list);
+
++ /* Remove Isochronous TDs from the frame list ASAP */
+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
+- unlink_isochronous_tds(uhci, urb);
+- uhci_unlink_generic(uhci, urb);
+-
+- uhci_get_current_frame_number(uhci);
+- if (uhci->frame_number + uhci->is_stopped != uhci->urb_remove_age) {
+- uhci_remove_pending_urbps(uhci);
+- uhci->urb_remove_age = uhci->frame_number;
+- }
+-
+- /* If we're the first, set the next interrupt bit */
+- if (list_empty(&uhci->urb_remove_list))
+- uhci_set_next_interrupt(uhci);
+- list_add_tail(&urbp->urb_list, &uhci->urb_remove_list);
++ uhci_unlink_isochronous_tds(uhci, urb);
++ uhci_unlink_qh(uhci, urbp->qh);
+
+ done:
+ spin_unlock_irqrestore(&uhci->lock, flags);
+@@ -1426,17 +1379,6 @@ static int uhci_fsbr_timeout(struct uhci
+ return 0;
+ }
+
+-static void uhci_free_pending_qhs(struct uhci_hcd *uhci)
+-{
+- struct uhci_qh *qh, *tmp;
+-
+- list_for_each_entry_safe(qh, tmp, &uhci->qh_remove_list, remove_list) {
+- list_del_init(&qh->remove_list);
+-
+- uhci_free_qh(uhci, qh);
+- }
+-}
+-
+ static void uhci_free_pending_tds(struct uhci_hcd *uhci)
+ {
+ struct uhci_td *td, *tmp;
+@@ -1455,7 +1397,7 @@ __acquires(uhci->lock)
+ {
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+
+- uhci_destroy_urb_priv(uhci, urb);
++ uhci_free_urb_priv(uhci, (struct urb_priv *) (urb->hcpriv));
+
+ spin_unlock(&uhci->lock);
+ usb_hcd_giveback_urb(hcd, urb, regs);
+@@ -1474,13 +1416,6 @@ static void uhci_finish_completion(struc
+ }
+ }
+
+-static void uhci_remove_pending_urbps(struct uhci_hcd *uhci)
+-{
+-
+- /* Splice the urb_remove_list onto the end of the complete_list */
+- list_splice_init(&uhci->urb_remove_list, uhci->complete_list.prev);
+-}
+-
+ /* Process events in the schedule, but only in one thread at a time */
+ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
+ {
+@@ -1498,12 +1433,8 @@ static void uhci_scan_schedule(struct uh
+ uhci_clear_next_interrupt(uhci);
+ uhci_get_current_frame_number(uhci);
+
+- if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age)
+- uhci_free_pending_qhs(uhci);
+ if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age)
+ uhci_free_pending_tds(uhci);
+- if (uhci->frame_number + uhci->is_stopped != uhci->urb_remove_age)
+- uhci_remove_pending_urbps(uhci);
+
+ /* Walk the list of pending URBs to see which ones completed
+ * (must be _safe because uhci_transfer_result() dequeues URBs) */
+@@ -1516,25 +1447,21 @@ static void uhci_scan_schedule(struct uh
+ uhci_finish_completion(uhci, regs);
+
+ /* If the controller is stopped, we can finish these off right now */
+- if (uhci->is_stopped) {
+- uhci_free_pending_qhs(uhci);
++ if (uhci->is_stopped)
+ uhci_free_pending_tds(uhci);
+- uhci_remove_pending_urbps(uhci);
+- }
+
+ if (uhci->need_rescan)
+ goto rescan;
+ uhci->scan_in_progress = 0;
+
+- if (list_empty(&uhci->urb_remove_list) &&
+- list_empty(&uhci->td_remove_list) &&
+- list_empty(&uhci->qh_remove_list))
++ /* Check out the QHs waiting for unlinking */
++ uhci_scan_unlinking_qhs(uhci);
++
++ if (list_empty(&uhci->td_remove_list) &&
++ list_empty(&uhci->skel_unlink_qh->node))
+ uhci_clear_next_interrupt(uhci);
+ else
+ uhci_set_next_interrupt(uhci);
+-
+- /* Wake up anyone waiting for an URB to complete */
+- wake_up_all(&uhci->waitqh);
+ }
+
+ static void check_fsbr(struct uhci_hcd *uhci)
+--- gregkh-2.6.orig/drivers/usb/host/uhci-hcd.c
++++ gregkh-2.6/drivers/usb/host/uhci-hcd.c
+@@ -54,7 +54,7 @@
+ /*
+ * Version Information
+ */
+-#define DRIVER_VERSION "v2.3"
++#define DRIVER_VERSION "v3.0"
+ #define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \
+ Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \
+ Alan Stern"
+@@ -489,15 +489,11 @@ static int uhci_start(struct usb_hcd *hc
+ uhci->fsbrtimeout = 0;
+
+ spin_lock_init(&uhci->lock);
+- INIT_LIST_HEAD(&uhci->qh_remove_list);
+
+ INIT_LIST_HEAD(&uhci->td_remove_list);
+-
+- INIT_LIST_HEAD(&uhci->urb_remove_list);
+-
+ INIT_LIST_HEAD(&uhci->urb_list);
+-
+ INIT_LIST_HEAD(&uhci->complete_list);
++ INIT_LIST_HEAD(&uhci->idle_qh_list);
+
+ init_waitqueue_head(&uhci->waitqh);
+
+@@ -540,7 +536,7 @@ static int uhci_start(struct usb_hcd *hc
+ }
+
+ for (i = 0; i < UHCI_NUM_SKELQH; i++) {
+- uhci->skelqh[i] = uhci_alloc_qh(uhci);
++ uhci->skelqh[i] = uhci_alloc_qh(uhci, NULL, NULL);
+ if (!uhci->skelqh[i]) {
+ dev_err(uhci_dev(uhci), "unable to allocate QH\n");
+ goto err_alloc_skelqh;
+@@ -557,13 +553,17 @@ static int uhci_start(struct usb_hcd *hc
+ uhci->skel_int16_qh->link =
+ uhci->skel_int8_qh->link =
+ uhci->skel_int4_qh->link =
+- uhci->skel_int2_qh->link =
+- cpu_to_le32(uhci->skel_int1_qh->dma_handle) | UHCI_PTR_QH;
+- uhci->skel_int1_qh->link = cpu_to_le32(uhci->skel_ls_control_qh->dma_handle) | UHCI_PTR_QH;
+-
+- uhci->skel_ls_control_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;
+- uhci->skel_fs_control_qh->link = cpu_to_le32(uhci->skel_bulk_qh->dma_handle) | UHCI_PTR_QH;
+- uhci->skel_bulk_qh->link = cpu_to_le32(uhci->skel_term_qh->dma_handle) | UHCI_PTR_QH;
++ uhci->skel_int2_qh->link = UHCI_PTR_QH |
++ cpu_to_le32(uhci->skel_int1_qh->dma_handle);
++
++ uhci->skel_int1_qh->link = UHCI_PTR_QH |
++ cpu_to_le32(uhci->skel_ls_control_qh->dma_handle);
++ uhci->skel_ls_control_qh->link = UHCI_PTR_QH |
++ cpu_to_le32(uhci->skel_fs_control_qh->dma_handle);
++ uhci->skel_fs_control_qh->link = UHCI_PTR_QH |
++ cpu_to_le32(uhci->skel_bulk_qh->dma_handle);
++ uhci->skel_bulk_qh->link = UHCI_PTR_QH |
++ cpu_to_le32(uhci->skel_term_qh->dma_handle);
+
+ /* This dummy TD is to work around a bug in Intel PIIX controllers */
+ uhci_fill_td(uhci->term_td, 0, uhci_explen(0) |
+@@ -589,15 +589,15 @@ static int uhci_start(struct usb_hcd *hc
+
+ /*
+ * ffs (Find First bit Set) does exactly what we need:
+- * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[6],
+- * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[5], etc.
+- * ffs > 6 => not on any high-period queue, so use
+- * skel_int1_qh = skelqh[7].
++ * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8],
++ * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
++ * ffs >= 7 => not on any high-period queue, so use
++ * skel_int1_qh = skelqh[9].
+ * Add UHCI_NUMFRAMES to insure at least one bit is set.
+ */
+- irq = 6 - (int) __ffs(i + UHCI_NUMFRAMES);
+- if (irq < 0)
+- irq = 7;
++ irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES);
++ if (irq <= 1)
++ irq = 9;
+
+ /* Only place we don't use the frame list routines */
+ uhci->frame[i] = UHCI_PTR_QH |
+@@ -767,13 +767,30 @@ static int uhci_resume(struct usb_hcd *h
+ }
+ #endif
+
+-/* Wait until all the URBs for a particular device/endpoint are gone */
++/* Wait until a particular device/endpoint's QH is idle, and free it */
+ static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd,
+- struct usb_host_endpoint *ep)
++ struct usb_host_endpoint *hep)
+ {
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
++ struct uhci_qh *qh;
++
++ spin_lock_irq(&uhci->lock);
++ qh = (struct uhci_qh *) hep->hcpriv;
++ if (qh == NULL)
++ goto done;
+
+- wait_event_interruptible(uhci->waitqh, list_empty(&ep->urb_list));
++ while (qh->state != QH_STATE_IDLE) {
++ ++uhci->num_waiting;
++ spin_unlock_irq(&uhci->lock);
++ wait_event_interruptible(uhci->waitqh,
++ qh->state == QH_STATE_IDLE);
++ spin_lock_irq(&uhci->lock);
++ --uhci->num_waiting;
++ }
++
++ uhci_free_qh(uhci, qh);
++done:
++ spin_unlock_irq(&uhci->lock);
+ }
+
+ static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
+--- gregkh-2.6.orig/drivers/usb/host/uhci-debug.c
++++ gregkh-2.6/drivers/usb/host/uhci-debug.c
+@@ -90,13 +90,60 @@ static int uhci_show_td(struct uhci_td *
+ return out - buf;
+ }
+
+-static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
++static int uhci_show_urbp(struct urb_priv *urbp, 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;
++ int i, nactive, ninactive;
++
++ if (len < 200)
++ return 0;
++
++ out += sprintf(out, "urb_priv [%p] ", urbp);
++ out += sprintf(out, "urb [%p] ", urbp->urb);
++ out += sprintf(out, "qh [%p] ", urbp->qh);
++ out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe));
++ out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe),
++ (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT"));
++
++ switch (usb_pipetype(urbp->urb->pipe)) {
++ case PIPE_ISOCHRONOUS: out += sprintf(out, "ISO"); break;
++ case PIPE_INTERRUPT: out += sprintf(out, "INT"); break;
++ case PIPE_BULK: out += sprintf(out, "BLK"); break;
++ case PIPE_CONTROL: out += sprintf(out, "CTL"); break;
++ }
++
++ out += sprintf(out, "%s", (urbp->fsbr ? " FSBR" : ""));
++ out += sprintf(out, "%s", (urbp->fsbr_timeout ? " FSBR_TO" : ""));
++
++ if (urbp->urb->status != -EINPROGRESS)
++ out += sprintf(out, " Status=%d", urbp->urb->status);
++ out += sprintf(out, "\n");
++
++ i = nactive = ninactive = 0;
++ list_for_each_entry(td, &urbp->td_list, list) {
++ if (++i <= 10 || debug > 2) {
++ out += sprintf(out, "%*s%d: ", space + 2, "", i);
++ out += uhci_show_td(td, out, len - (out - buf), 0);
++ } else {
++ if (td_status(td) & TD_CTRL_ACTIVE)
++ ++nactive;
++ else
++ ++ninactive;
++ }
++ }
++ if (nactive + ninactive > 0)
++ out += sprintf(out, "%*s[skipped %d inactive and %d active "
++ "TDs]\n",
++ space, "", ninactive, nactive);
++
++ return out - buf;
++}
++
++static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
++{
++ char *out = buf;
++ int i, nurbs;
+ __le32 element = qh_element(qh);
+
+ /* Try to make sure there's enough memory */
+@@ -118,86 +165,36 @@ static int uhci_show_qh(struct uhci_qh *
+ if (!(element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH)))
+ out += sprintf(out, "%*s Element is NULL (bug?)\n", space, "");
+
+- if (!qh->urbp) {
+- out += sprintf(out, "%*s urbp == NULL\n", space, "");
+- goto out;
+- }
+-
+- urbp = qh->urbp;
+-
+- head = &urbp->td_list;
+- tmp = head->next;
+-
+- td = list_entry(tmp, struct uhci_td, list);
+-
+- if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS))
+- out += sprintf(out, "%*s Element != First TD\n", space, "");
+-
+- while (tmp != head) {
+- struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+-
+- tmp = tmp->next;
+-
+- out += sprintf(out, "%*s%d: ", space + 2, "", i++);
+- out += uhci_show_td(td, out, len - (out - buf), 0);
+-
+- if (i > 10 && !checked && prevactive && tmp != head &&
+- debug <= 2) {
+- struct list_head *ntmp = tmp;
+- struct uhci_td *ntd = td;
+- int active = 1, ni = i;
+-
+- checked = 1;
+-
+- while (ntmp != head && ntmp->next != head && active) {
+- ntd = list_entry(ntmp, struct uhci_td, list);
+-
+- ntmp = ntmp->next;
+-
+- active = td_status(ntd) & TD_CTRL_ACTIVE;
+-
+- ni++;
+- }
+-
+- if (active && ni > i) {
+- out += sprintf(out, "%*s[skipped %d active TDs]\n", space, "", ni - i);
+- tmp = ntmp;
+- td = ntd;
+- i = ni;
+- }
++ if (list_empty(&qh->queue)) {
++ out += sprintf(out, "%*s queue is empty\n", space, "");
++ } else {
++ struct urb_priv *urbp = list_entry(qh->queue.next,
++ struct urb_priv, node);
++ struct uhci_td *td = list_entry(urbp->td_list.next,
++ struct uhci_td, list);
++
++ if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS))
++ out += sprintf(out, "%*s Element != First TD\n",
++ space, "");
++ i = nurbs = 0;
++ list_for_each_entry(urbp, &qh->queue, node) {
++ if (++i <= 10)
++ out += uhci_show_urbp(urbp, out,
++ len - (out - buf), space + 2);
++ else
++ ++nurbs;
+ }
+-
+- prevactive = td_status(td) & TD_CTRL_ACTIVE;
+- }
+-
+- if (list_empty(&urbp->queue_list) || urbp->queued)
+- goto out;
+-
+- out += sprintf(out, "%*sQueued QHs:\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);
++ if (nurbs > 0)
++ out += sprintf(out, "%*s Skipped %d URBs\n",
++ space, "", nurbs);
+ }
+
+-out:
+ return out - buf;
+ }
+
+-#define show_frame_num() \
+- if (!shown) { \
+- shown = 1; \
+- out += sprintf(out, "- Frame %d\n", i); \
+- }
+-
+ #ifdef CONFIG_PROC_FS
+ static const char * const qh_names[] = {
++ "skel_unlink_qh", "skel_iso_qh",
+ "skel_int128_qh", "skel_int64_qh",
+ "skel_int32_qh", "skel_int16_qh",
+ "skel_int8_qh", "skel_int4_qh",
+@@ -206,12 +203,6 @@ static const char * const qh_names[] = {
+ "skel_bulk_qh", "skel_term_qh"
+ };
+
+-#define show_qh_name() \
+- if (!shown) { \
+- shown = 1; \
+- out += sprintf(out, "- %s\n", qh_names[i]); \
+- }
+-
+ static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
+ {
+ char *out = buf;
+@@ -321,139 +312,29 @@ static int uhci_show_status(struct uhci_
+ return out - buf;
+ }
+
+-static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp, char *buf, int len)
+-{
+- struct list_head *tmp;
+- char *out = buf;
+- int count = 0;
+-
+- if (len < 200)
+- return 0;
+-
+- out += sprintf(out, "urb_priv [%p] ", urbp);
+- out += sprintf(out, "urb [%p] ", urbp->urb);
+- out += sprintf(out, "qh [%p] ", urbp->qh);
+- out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe));
+- out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe), (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT"));
+-
+- switch (usb_pipetype(urbp->urb->pipe)) {
+- case PIPE_ISOCHRONOUS: out += sprintf(out, "ISO "); break;
+- case PIPE_INTERRUPT: out += sprintf(out, "INT "); break;
+- case PIPE_BULK: out += sprintf(out, "BLK "); break;
+- case PIPE_CONTROL: out += sprintf(out, "CTL "); break;
+- }
+-
+- out += sprintf(out, "%s", (urbp->fsbr ? "FSBR " : ""));
+- out += sprintf(out, "%s", (urbp->fsbr_timeout ? "FSBR_TO " : ""));
+-
+- if (urbp->urb->status != -EINPROGRESS)
+- out += sprintf(out, "Status=%d ", urbp->urb->status);
+- //out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime);
+-
+- count = 0;
+- list_for_each(tmp, &urbp->td_list)
+- count++;
+- out += sprintf(out, "TDs=%d ",count);
+-
+- if (urbp->queued)
+- out += sprintf(out, "queued\n");
+- else {
+- count = 0;
+- list_for_each(tmp, &urbp->queue_list)
+- count++;
+- out += sprintf(out, "queued URBs=%d\n", count);
+- }
+-
+- return out - buf;
+-}
+-
+-static int uhci_show_lists(struct uhci_hcd *uhci, char *buf, int len)
+-{
+- char *out = buf;
+- struct list_head *head, *tmp;
+- int count;
+-
+- out += sprintf(out, "Main list URBs:");
+- if (list_empty(&uhci->urb_list))
+- out += sprintf(out, " Empty\n");
+- else {
+- out += sprintf(out, "\n");
+- count = 0;
+- head = &uhci->urb_list;
+- tmp = head->next;
+- while (tmp != head) {
+- struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
+-
+- out += sprintf(out, " %d: ", ++count);
+- out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
+- tmp = tmp->next;
+- }
+- }
+-
+- out += sprintf(out, "Remove list URBs:");
+- if (list_empty(&uhci->urb_remove_list))
+- out += sprintf(out, " Empty\n");
+- else {
+- out += sprintf(out, "\n");
+- count = 0;
+- head = &uhci->urb_remove_list;
+- tmp = head->next;
+- while (tmp != head) {
+- struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
+-
+- out += sprintf(out, " %d: ", ++count);
+- out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
+- tmp = tmp->next;
+- }
+- }
+-
+- out += sprintf(out, "Complete list URBs:");
+- if (list_empty(&uhci->complete_list))
+- out += sprintf(out, " Empty\n");
+- else {
+- out += sprintf(out, "\n");
+- count = 0;
+- head = &uhci->complete_list;
+- tmp = head->next;
+- while (tmp != head) {
+- struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
+-
+- out += sprintf(out, " %d: ", ++count);
+- out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
+- tmp = tmp->next;
+- }
+- }
+-
+- return out - buf;
+-}
+-
+ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
+ {
+- unsigned long flags;
+ char *out = buf;
+ int i, j;
+ struct uhci_qh *qh;
+ struct uhci_td *td;
+ struct list_head *tmp, *head;
+
+- spin_lock_irqsave(&uhci->lock, flags);
+-
+ out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
+ out += sprintf(out, "HC status\n");
+ out += uhci_show_status(uhci, out, len - (out - buf));
++ if (debug <= 1)
++ return out - buf;
+
+ out += sprintf(out, "Frame List\n");
+ for (i = 0; i < UHCI_NUMFRAMES; ++i) {
+- int shown = 0;
+ td = uhci->frame_cpu[i];
+ if (!td)
+ continue;
+
+- if (td->dma_handle != (dma_addr_t)uhci->frame[i]) {
+- show_frame_num();
++ out += sprintf(out, "- Frame %d\n", i); \
++ if (td->dma_handle != (dma_addr_t)uhci->frame[i])
+ out += sprintf(out, " frame list does not match td->dma_handle!\n");
+- }
+- show_frame_num();
+
+ head = &td->fl_list;
+ tmp = head;
+@@ -467,14 +348,11 @@ static int uhci_sprint_schedule(struct u
+ out += sprintf(out, "Skeleton QHs\n");
+
+ for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
+- int shown = 0;
++ int cnt = 0;
+
+ qh = uhci->skelqh[i];
+-
+- if (debug > 1) {
+- show_qh_name();
+- out += uhci_show_qh(qh, out, len - (out - buf), 4);
+- }
++ out += sprintf(out, "- %s\n", qh_names[i]); \
++ out += uhci_show_qh(qh, out, len - (out - buf), 4);
+
+ /* Last QH is the Terminating QH, it's different */
+ if (i == UHCI_NUM_SKELQH - 1) {
+@@ -487,44 +365,27 @@ static int uhci_sprint_schedule(struct u
+ continue;
+ }
+
+- j = (i < 7) ? 7 : i+1; /* Next skeleton */
+- if (list_empty(&qh->list)) {
+- if (i < UHCI_NUM_SKELQH - 1) {
+- if (qh->link !=
+- (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH)) {
+- show_qh_name();
+- out += sprintf(out, " skeleton QH not linked to next skeleton QH!\n");
+- }
+- }
+-
+- continue;
+- }
+-
+- show_qh_name();
+-
+- head = &qh->list;
++ j = (i < 9) ? 9 : i+1; /* Next skeleton */
++ head = &qh->node;
+ tmp = head->next;
+
+ while (tmp != head) {
+- qh = list_entry(tmp, struct uhci_qh, list);
+-
++ qh = list_entry(tmp, struct uhci_qh, node);
+ tmp = tmp->next;
+-
+- out += uhci_show_qh(qh, out, len - (out - buf), 4);
++ if (++cnt <= 10)
++ out += uhci_show_qh(qh, out,
++ len - (out - buf), 4);
+ }
++ if ((cnt -= 10) > 0)
++ out += sprintf(out, " Skipped %d QHs\n", cnt);
+
+- if (i < UHCI_NUM_SKELQH - 1) {
++ if (i > 1 && i < UHCI_NUM_SKELQH - 1) {
+ if (qh->link !=
+ (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH))
+ out += sprintf(out, " last QH not linked to next skeleton!\n");
+ }
+ }
+
+- if (debug > 2)
+- out += uhci_show_lists(uhci, out, len - (out - buf));
+-
+- spin_unlock_irqrestore(&uhci->lock, flags);
+-
+ return out - buf;
+ }
+
+@@ -541,6 +402,7 @@ static int uhci_debug_open(struct inode
+ struct uhci_hcd *uhci = inode->u.generic_ip;
+ struct uhci_debug *up;
+ int ret = -ENOMEM;
++ unsigned long flags;
+
+ lock_kernel();
+ up = kmalloc(sizeof(*up), GFP_KERNEL);
+@@ -553,7 +415,9 @@ static int uhci_debug_open(struct inode
+ goto out;
+ }
+
++ spin_lock_irqsave(&uhci->lock, flags);
+ up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
++ spin_unlock_irqrestore(&uhci->lock, flags);
+
+ file->private_data = up;
+