<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;"># This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.600.1.7 -&gt; 1.600.1.8
#	drivers/usb/host/ohci-hcd.c	1.23    -&gt; 1.24   
#	drivers/usb/host/ohci-mem.c	1.7     -&gt; 1.8    
#	drivers/usb/host/ohci-dbg.c	1.9     -&gt; 1.10   
#	drivers/usb/host/ohci-q.c	1.20    -&gt; 1.21   
#	drivers/usb/host/ohci.h	1.11    -&gt; 1.12   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/09/04	david-b@pacbell.net	1.600.1.8
# [PATCH] ohci-hcd endpoint scheduling, driverfs
# 
# This patch cleans up some messy parts of this driver, and
# was pleasantly painless.
# 
#       - gets rid of ED dma hashtables
#          * less memory needed
#          * also less (+faster) code
#          * ... rewrites all ED scheduling ops, they now use
#            cpu addresses, like EHCI and UHCI do already
# 
#       - simplifies ED scheduling (no dma hashtables)
#          * control and bulk lists are now doubly linked
#          * periodic tree still singly linked; driver uses a
#            new CPU view "shadow" of the hardware framelist
#          * previous periodic code was cryptic, almost read-only
#          * simpler tree code for EDs with {branch,period}
# 
#       - bugfixes periodic scheduling
#          * when CONFIG_USB_BANDWIDTH, checks per-frame load
#            against the limit; no more dodgey accounting
#          * handles iso period != 1; interrupt and iso schedule
#            EDs with the same routine (HW sees special TDs)
#          * credit usbfs with bandwidth for endpoints, not URBs
# 
#       - adds driverfs output (when CONFIG_USB_DEBUG)
#          * resembles EHCI:  'async' (control+bulk) and
#            'periodic' (interrupt+iso) files show schedules
#          * shows only queue heads (EDs) just now (*)
# 
#       - has minor text and code cleanups, etc
# 
# Now that this logic has morphed into more comprehensible
# form, I know what to borrow into the EHCI code!
# 
# 
#      (*) It shows TDs on the td_list, but this patch won't
#          put them there.  A queue fault handling update will.
# --------------------------------------------
#
diff -Nru a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
--- a/drivers/usb/host/ohci-dbg.c	Thu Sep  5 08:51:20 2002
+++ b/drivers/usb/host/ohci-dbg.c	Thu Sep  5 08:51:20 2002
@@ -72,37 +72,6 @@
 #endif
 }
 
-static inline struct ed *
-dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma);
-
-/* print non-empty branches of the periodic ed tree */
-static void __attribute__ ((unused))
-ohci_dump_periodic (struct ohci_hcd *ohci, char *label)
-{
-	int i, j;
-	u32 *ed_p;
-	int printed = 0;
-
-	for (i= 0; i &lt; 32; i++) {
-		j = 5;
-		ed_p = &amp;(ohci-&gt;hcca-&gt;int_table [i]);
-		if (*ed_p == 0)
-			continue;
-		printed = 1;
-		printk (KERN_DEBUG "%s, ohci %s frame %2d:",
-				label, ohci-&gt;hcd.self.bus_name, i);
-		while (*ed_p != 0 &amp;&amp; j--) {
-			struct ed *ed = dma_to_ed (ohci, le32_to_cpup(ed_p));
-			printk (" %p/%08x;", ed, ed-&gt;hwINFO);
-			ed_p = &amp;ed-&gt;hwNextED;
-		}
-		printk ("\n");
-	}
-	if (!printed)
-		printk (KERN_DEBUG "%s, ohci %s, empty periodic schedule\n",
-				label, ohci-&gt;hcd.self.bus_name);
-}
-
 static void ohci_dump_intr_mask (char *label, __u32 mask)
 {
 	dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
@@ -316,8 +285,9 @@
 	case ED_IN: type = "-IN"; break;
 	/* else from TDs ... control */
 	}
-	dbg ("  info %08x MAX=%d%s%s%s EP=%d%s DEV=%d", le32_to_cpu (tmp),
-		0x0fff &amp; (le32_to_cpu (tmp) &gt;&gt; 16),
+	dbg ("  info %08x MAX=%d%s%s%s%s EP=%d%s DEV=%d", le32_to_cpu (tmp),
+		0x03ff &amp; (le32_to_cpu (tmp) &gt;&gt; 16),
+		(tmp &amp; ED_DEQUEUE) ? " DQ" : "",
 		(tmp &amp; ED_ISO) ? " ISO" : "",
 		(tmp &amp; ED_SKIP) ? " SKIP" : "",
 		(tmp &amp; ED_LOWSPEED) ? " LOW" : "",
@@ -344,5 +314,222 @@
 	}
 }
 
+#if LINUX_VERSION_CODE &gt; KERNEL_VERSION(2,5,32)
+#	define DRIVERFS_DEBUG_FILES
 #endif
+
+#endif /* DEBUG */
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DRIVERFS_DEBUG_FILES
+
+static ssize_t
+show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed)
+{
+	unsigned		temp, size = count;
+
+	if (!ed)
+		return 0;
+
+	/* print first --&gt; last */
+	while (ed-&gt;ed_prev)
+		ed = ed-&gt;ed_prev;
+
+	/* dump a snapshot of the bulk or control schedule */
+	while (ed) {
+		u32			info = ed-&gt;hwINFO;
+		u32			scratch = cpu_to_le32p (&amp;ed-&gt;hwINFO);
+		struct list_head	*entry;
+		struct td		*td;
+
+		temp = snprintf (buf, size,
+			"ed/%p %cs dev%d ep%d-%s max %d %08x%s%s %s",
+			ed,
+			(info &amp; ED_LOWSPEED) ? 'l' : 'f',
+			scratch &amp; 0x7f,
+			(scratch &gt;&gt; 7) &amp; 0xf,
+			(info &amp; ED_IN) ? "in" : "out",
+			0x03ff &amp; (scratch &gt;&gt; 16),
+			scratch,
+			(info &amp; ED_SKIP) ? " s" : "",
+			(ed-&gt;hwHeadP &amp; ED_H) ? " H" : "",
+			(ed-&gt;hwHeadP &amp; ED_C) ? data1 : data0);
+		size -= temp;
+		buf += temp;
+
+		list_for_each (entry, &amp;ed-&gt;td_list) {
+			u32		cbp, be;
+
+			td = list_entry (entry, struct td, td_list);
+			scratch = cpu_to_le32p (&amp;td-&gt;hwINFO);
+			cbp = le32_to_cpup (&amp;td-&gt;hwCBP);
+			be = le32_to_cpup (&amp;td-&gt;hwBE);
+			temp = snprintf (buf, size,
+					"\n\ttd %p %s %d cc=%x urb %p (%08x)",
+					td,
+					({ char *pid;
+					switch (scratch &amp; TD_DP) {
+					case TD_DP_SETUP: pid = "setup"; break;
+					case TD_DP_IN: pid = "in"; break;
+					case TD_DP_OUT: pid = "out"; break;
+					default: pid = "(?)"; break;
+					 } pid;}),
+					cbp ? (be + 1 - cbp) : 0,
+					TD_CC_GET (scratch), td-&gt;urb, scratch);
+			size -= temp;
+			buf += temp;
+		}
+
+		temp = snprintf (buf, size, "\n");
+		size -= temp;
+		buf += temp;
+
+		ed = ed-&gt;ed_next;
+	}
+	return count - size;
+}
+
+static ssize_t
+show_async (struct device *dev, char *buf, size_t count, loff_t off)
+{
+	struct pci_dev		*pdev;
+	struct ohci_hcd		*ohci;
+	size_t			temp;
+	unsigned long		flags;
+
+	if (off != 0)
+		return 0;
+	pdev = container_of (dev, struct pci_dev, dev);
+	ohci = container_of (pci_get_drvdata (pdev), struct ohci_hcd, hcd);
+
+	/* display control and bulk lists together, for simplicity */
+	spin_lock_irqsave (&amp;ohci-&gt;lock, flags);
+	temp = show_list (ohci, buf, count, ohci-&gt;ed_controltail);
+	count = show_list (ohci, buf + temp, count - temp, ohci-&gt;ed_bulktail);
+	spin_unlock_irqrestore (&amp;ohci-&gt;lock, flags);
+
+	return temp + count;
+}
+static DEVICE_ATTR (async, S_IRUGO, show_async, NULL);
+
+
+#define DBG_SCHED_LIMIT 64
+
+static ssize_t
+show_periodic (struct device *dev, char *buf, size_t count, loff_t off)
+{
+	struct pci_dev		*pdev;
+	struct ohci_hcd		*ohci;
+	struct ed		**seen, *ed;
+	unsigned long		flags;
+	unsigned		temp, size, seen_count;
+	char			*next;
+	unsigned		i;
+
+	if (off != 0)
+		return 0;
+	if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, SLAB_ATOMIC)))
+		return 0;
+	seen_count = 0;
+
+	pdev = container_of (dev, struct pci_dev, dev);
+	ohci = container_of (pci_get_drvdata (pdev), struct ohci_hcd, hcd);
+	next = buf;
+	size = count;
+
+	temp = snprintf (next, size, "size = %d\n", NUM_INTS);
+	size -= temp;
+	next += temp;
+
+	/* dump a snapshot of the periodic schedule (and load) */
+	spin_lock_irqsave (&amp;ohci-&gt;lock, flags);
+	for (i = 0; i &lt; NUM_INTS; i++) {
+		if (!(ed = ohci-&gt;periodic [i]))
+			continue;
+
+		temp = snprintf (next, size, "%2d [%3d]:", i, ohci-&gt;load [i]);
+		size -= temp;
+		next += temp;
+
+		do {
+			temp = snprintf (next, size, " ed%d/%p",
+				ed-&gt;interval, ed);
+			size -= temp;
+			next += temp;
+			for (temp = 0; temp &lt; seen_count; temp++) {
+				if (seen [temp] == ed)
+					break;
+			}
+
+			/* show more info the first time around */
+			if (temp == seen_count) {
+				u32	info = ed-&gt;hwINFO;
+				u32	scratch = cpu_to_le32p (&amp;ed-&gt;hwINFO);
+
+				temp = snprintf (next, size,
+					" (%cs dev%d%s ep%d-%s"
+					" max %d %08x%s%s)",
+					(info &amp; ED_LOWSPEED) ? 'l' : 'f',
+					scratch &amp; 0x7f,
+					(info &amp; ED_ISO) ? " iso" : "",
+					(scratch &gt;&gt; 7) &amp; 0xf,
+					(info &amp; ED_IN) ? "in" : "out",
+					0x03ff &amp; (scratch &gt;&gt; 16),
+					scratch,
+					(info &amp; ED_SKIP) ? " s" : "",
+					(ed-&gt;hwHeadP &amp; ED_H) ? " H" : "");
+				size -= temp;
+				next += temp;
+
+				// FIXME some TD info too
+
+				if (seen_count &lt; DBG_SCHED_LIMIT)
+					seen [seen_count++] = ed;
+
+				ed = ed-&gt;ed_next;
+
+			} else {
+				/* we've seen it and what's after */
+				temp = 0;
+				ed = 0;
+			}
+
+		} while (ed);
+
+		temp = snprintf (next, size, "\n");
+		size -= temp;
+		next += temp;
+	}
+	spin_unlock_irqrestore (&amp;ohci-&gt;lock, flags);
+	kfree (seen);
+
+	return count - size;
+}
+static DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);
+
+#undef DBG_SCHED_LIMIT
+
+static inline void create_debug_files (struct ohci_hcd *bus)
+{
+	device_create_file (&amp;bus-&gt;hcd.pdev-&gt;dev, &amp;dev_attr_async);
+	device_create_file (&amp;bus-&gt;hcd.pdev-&gt;dev, &amp;dev_attr_periodic);
+	// registers
+	dbg ("%s: created debug files", bus-&gt;hcd.self.bus_name);
+}
+
+static inline void remove_debug_files (struct ohci_hcd *bus)
+{
+	device_remove_file (&amp;bus-&gt;hcd.pdev-&gt;dev, &amp;dev_attr_async);
+	device_remove_file (&amp;bus-&gt;hcd.pdev-&gt;dev, &amp;dev_attr_periodic);
+}
+
+#else /* empty stubs for creating those files */
+
+static inline void create_debug_files (struct ohci_hcd *bus) { }
+static inline void remove_debug_files (struct ohci_hcd *bus) { }
+
+#endif /* DRIVERFS_DEBUG_FILES */
+
+/*-------------------------------------------------------------------------*/
 
diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
--- a/drivers/usb/host/ohci-hcd.c	Thu Sep  5 08:51:20 2002
+++ b/drivers/usb/host/ohci-hcd.c	Thu Sep  5 08:51:20 2002
@@ -17,6 +17,8 @@
  *
  * History:
  * 
+ * 2002/09/03 get rid of ed hashtables, rework periodic scheduling and
+ * 	bandwidth accounting; if debugging, show schedules in driverfs
  * 2002/07/19 fixes to management of ED and schedule state.
  * 2002/06/09 SA-1111 support (Christopher Hoover)
  * 2002/06/01 remember frame when HC won't see EDs any more; use that info
@@ -66,7 +68,6 @@
  * v1.0 1999/04/27 initial release
  *
  * This file is licenced under the GPL.
- * $Id: ohci-hcd.c,v 1.9 2002/03/27 20:41:57 dbrownell Exp $
  */
  
 #include &lt;linux/config.h&gt;
@@ -107,8 +108,8 @@
  *	- lots more testing!!
  */
 
-#define DRIVER_VERSION "2002-Jul-19"
-#define DRIVER_AUTHOR "Roman Weissgaerber &lt;weissg@vienna.at&gt;, David Brownell"
+#define DRIVER_VERSION "2002-Sep-03"
+#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
 #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
 
 /*-------------------------------------------------------------------------*/
@@ -152,7 +153,6 @@
 	unsigned int	pipe = urb-&gt;pipe;
 	int		i, size = 0;
 	unsigned long	flags;
-	int		bustime = 0;
 	int		retval = 0;
 	
 #ifdef OHCI_VERBOSE_DEBUG
@@ -230,43 +230,32 @@
 		}
 	}	
 
-// FIXME:  much of this switch should be generic, move to hcd code ...
-// ... and what's not generic can't really be handled this way.
-// need to consider periodicity for both types!
-
-	/* allocate and claim bandwidth if needed; ISO
-	 * needs start frame index if it was't provided.
-	 */
-	switch (usb_pipetype (pipe)) {
-		case PIPE_ISOCHRONOUS:
-			if (urb-&gt;transfer_flags &amp; USB_ISO_ASAP) { 
-				urb-&gt;start_frame = ((ed-&gt;state != ED_IDLE)
-					? (ed-&gt;intriso.last_iso + 1)
-					: (le16_to_cpu (ohci-&gt;hcca-&gt;frame_no)
-						+ 10)) &amp; 0xffff;
-			}
-			/* FALLTHROUGH */
-		case PIPE_INTERRUPT:
-			if (urb-&gt;bandwidth == 0) {
-				bustime = usb_check_bandwidth (urb-&gt;dev, urb);
-			}
-			if (bustime &lt; 0) {
-				retval = bustime;
-				goto fail;
-			}
-			usb_claim_bandwidth (urb-&gt;dev, urb,
-				bustime, usb_pipeisoc (urb-&gt;pipe));
-	}
+	/* schedule the ed if needed */
+	if (ed-&gt;state == ED_IDLE) {
+		retval = ed_schedule (ohci, ed);
+		if (retval &lt; 0)
+			goto fail;
+		if (ed-&gt;type == PIPE_ISOCHRONOUS) {
+			u16	frame = le16_to_cpu (ohci-&gt;hcca-&gt;frame_no);
 
-	urb-&gt;hcpriv = urb_priv;
+			/* delay a few frames before the first TD */
+			frame += max_t (u16, 8, ed-&gt;interval);
+			frame &amp;= ~(ed-&gt;interval - 1);
+			frame |= ed-&gt;branch;
+			urb-&gt;start_frame = frame;
 
-	/* schedule the ed if needed */
-	if (ed-&gt;state == ED_IDLE)
-		ed_schedule (ohci, ed);
+			/* yes, only USB_ISO_ASAP is supported, and
+			 * urb-&gt;start_frame is never used as input.
+			 */
+		}
+	} else if (ed-&gt;type == PIPE_ISOCHRONOUS)
+		urb-&gt;start_frame = ed-&gt;last_iso + ed-&gt;interval;
 
 	/* fill the TDs and link them to the ed; and
 	 * enable that part of the schedule, if needed
+	 * and update count of queued periodic urbs
 	 */
+	urb-&gt;hcpriv = urb_priv;
 	td_submit_urb (ohci, urb);
 
 fail:
@@ -537,6 +526,7 @@
 		return -ENODEV;
 	}
 
+	create_debug_files (ohci);
 	return 0;
 }
 
@@ -571,7 +561,8 @@
 
 	if (ints &amp; OHCI_INTR_UE) {
 		disable (ohci);
-		err ("OHCI Unrecoverable Error, %s disabled", hcd-&gt;self.bus_name);
+		err ("OHCI Unrecoverable Error, %s disabled",
+				hcd-&gt;self.bus_name);
 		// e.g. due to PCI Master/Target Abort
 
 #ifdef	DEBUG
@@ -620,6 +611,7 @@
 	if (!ohci-&gt;disabled)
 		hc_reset (ohci);
 	
+	remove_debug_files (ohci);
 	ohci_mem_cleanup (ohci);
 	if (ohci-&gt;hcca) {
 		pci_free_consistent (ohci-&gt;hcd.pdev, sizeof *ohci-&gt;hcca,
@@ -649,14 +641,13 @@
 		usb_disconnect (&amp;ohci-&gt;hcd.self.root_hub);
 	
 	/* empty the interrupt branches */
-	for (i = 0; i &lt; NUM_INTS; i++) ohci-&gt;ohci_int_load [i] = 0;
+	for (i = 0; i &lt; NUM_INTS; i++) ohci-&gt;load [i] = 0;
 	for (i = 0; i &lt; NUM_INTS; i++) ohci-&gt;hcca-&gt;int_table [i] = 0;
 	
 	/* no EDs to remove */
 	ohci-&gt;ed_rm_list = NULL;
 
 	/* empty control and bulk lists */	 
-	ohci-&gt;ed_isotail     = NULL;
 	ohci-&gt;ed_controltail = NULL;
 	ohci-&gt;ed_bulktail    = NULL;
 
diff -Nru a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
--- a/drivers/usb/host/ohci-mem.c	Thu Sep  5 08:51:20 2002
+++ b/drivers/usb/host/ohci-mem.c	Thu Sep  5 08:51:20 2002
@@ -5,7 +5,6 @@
  * (C) Copyright 2000-2002 David Brownell &lt;dbrownell@users.sourceforge.net&gt;
  * 
  * This file is licenced under the GPL.
- * $Id: ohci-mem.c,v 1.3 2002/03/22 16:04:54 dbrownell Exp $
  */
 
 /*-------------------------------------------------------------------------*/
@@ -52,13 +51,6 @@
 	return scan-&gt;virt;
 }
 
-static struct ed *
-dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma)
-{
-	return (struct ed *) dma_to_ed_td(&amp;(hc-&gt;ed_hash [ED_HASH_FUNC(ed_dma)]),
-				      ed_dma);
-}
-
 static struct td *
 dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma)
 {
@@ -98,13 +90,6 @@
 }
 
 static inline int
-hash_add_ed (struct ohci_hcd *hc, struct ed *ed, int mem_flags)
-{
-	return hash_add_ed_td (&amp;(hc-&gt;ed_hash [ED_HASH_FUNC (ed-&gt;dma)]),
-			ed, ed-&gt;dma, mem_flags);
-}
-
-static inline int
 hash_add_td (struct ohci_hcd *hc, struct td *td, int mem_flags)
 {
 	return hash_add_ed_td (&amp;(hc-&gt;td_hash [TD_HASH_FUNC (td-&gt;td_dma)]),
@@ -139,12 +124,6 @@
 }
 
 static inline void
-hash_free_ed (struct ohci_hcd *hc, struct ed * ed)
-{
-	hash_free_ed_td (&amp;(hc-&gt;ed_hash[ED_HASH_FUNC(ed-&gt;dma)]), ed);
-}
-
-static inline void
 hash_free_td (struct ohci_hcd *hc, struct td * td)
 {
 	hash_free_ed_td (&amp;(hc-&gt;td_hash[TD_HASH_FUNC(td-&gt;td_dma)]), td);
@@ -223,11 +202,6 @@
 		memset (ed, 0, sizeof (*ed));
 		INIT_LIST_HEAD (&amp;ed-&gt;td_list);
 		ed-&gt;dma = dma;
-		/* hash it for later reverse mapping */
-		if (!hash_add_ed (hc, ed, mem_flags)) {
-			pci_pool_free (hc-&gt;ed_cache, ed, dma);
-			return NULL;
-		}
 	}
 	return ed;
 }
@@ -235,7 +209,6 @@
 static void
 ed_free (struct ohci_hcd *hc, struct ed *ed)
 {
-	hash_free_ed (hc, ed);
 	pci_pool_free (hc-&gt;ed_cache, ed, ed-&gt;dma);
 }
 
diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
--- a/drivers/usb/host/ohci-q.c	Thu Sep  5 08:51:20 2002
+++ b/drivers/usb/host/ohci-q.c	Thu Sep  5 08:51:20 2002
@@ -5,7 +5,6 @@
  * (C) Copyright 2000-2002 David Brownell &lt;dbrownell@users.sourceforge.net&gt;
  * 
  * This file is licenced under the GPL.
- * $Id: ohci-q.c,v 1.8 2002/03/27 20:57:01 dbrownell Exp $
  */
 
 static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
@@ -52,6 +51,15 @@
 		urb-&gt;status = 0;
 	spin_unlock_irqrestore (&amp;urb-&gt;lock, flags);
 
+	switch (usb_pipetype (urb-&gt;pipe)) {
+	case PIPE_ISOCHRONOUS:
+		ohci-&gt;hcd.self.bandwidth_isoc_reqs--;
+		break;
+	case PIPE_INTERRUPT:
+		ohci-&gt;hcd.self.bandwidth_int_reqs--;
+		break;
+	}
+
 #ifdef OHCI_VERBOSE_DEBUG
 	urb_print (urb, "RET", usb_pipeout (urb-&gt;pipe));
 #endif
@@ -111,67 +119,111 @@
  * ED handling functions
  *-------------------------------------------------------------------------*/  
 
-/* search for the right branch to insert an interrupt ed into the int tree 
- * do some load balancing;
- * returns the branch
- * FIXME allow for failure, when there's no bandwidth left;
- * and consider iso loads too
+/* search for the right schedule branch to use for a periodic ed.
+ * does some load balancing; returns the branch, or negative errno.
  */
-static int ep_int_balance (struct ohci_hcd *ohci, int interval, int load)
+static int balance (struct ohci_hcd *ohci, int interval, int load)
 {
-	int	i, branch = 0;
+	int	i, branch = -ENOSPC;
 
-	/* search for the least loaded interrupt endpoint branch */
-	for (i = 0; i &lt; NUM_INTS ; i++) 
-		if (ohci-&gt;ohci_int_load [branch] &gt; ohci-&gt;ohci_int_load [i])
+	/* iso periods can be huge; iso tds specify frame numbers */
+	if (interval &gt; NUM_INTS)
+		interval = NUM_INTS;
+
+	/* search for the least loaded schedule branch of that period
+	 * that has enough bandwidth left unreserved.
+	 */
+	for (i = 0; i &lt; interval ; i++) {
+		if (branch &lt; 0 || ohci-&gt;load [branch] &gt; ohci-&gt;load [i]) {
+#ifdef CONFIG_USB_BANDWIDTH
+			int	j;
+
+			/* usb 1.1 says 90% of one frame */
+			for (j = i; j &lt; NUM_INTS; j += interval) {
+				if ((ohci-&gt;load [j] + load) &gt; 900)
+					break;
+			}
+			if (j &lt; NUM_INTS)
+				continue;
+#endif
 			branch = i; 
-
-	branch = branch % interval;
-	for (i = branch; i &lt; NUM_INTS; i += interval)
-		ohci-&gt;ohci_int_load [i] += load;
-
+		}
+	}
 	return branch;
 }
 
 /*-------------------------------------------------------------------------*/
 
-/* the int tree is a binary tree 
- * in order to process it sequentially the indexes of the branches have
- * to be mapped the mapping reverses the bits of a word of num_bits length
+/* both iso and interrupt requests have periods; this routine puts them
+ * into the schedule tree in the apppropriate place.  most iso devices use
+ * 1msec periods, but that's not required.
  */
-static int ep_rev (int num_bits, int word)
+static void periodic_link (struct ohci_hcd *ohci, struct ed *ed)
 {
-	int			i, wout = 0;
+	unsigned	i;
 
-	for (i = 0; i &lt; num_bits; i++)
-		wout |= (( (word &gt;&gt; i) &amp; 1) &lt;&lt; (num_bits - i - 1));
-	return wout;
+	dbg ("%s: link %sed %p branch %d [%dus.], interval %d",
+		ohci-&gt;hcd.self.bus_name,
+		(ed-&gt;hwINFO &amp; ED_ISO) ? "iso " : "",
+		ed, ed-&gt;branch, ed-&gt;load, ed-&gt;interval);
+
+	for (i = ed-&gt;branch; i &lt; NUM_INTS; i += ed-&gt;interval) {
+		struct ed	**prev = &amp;ohci-&gt;periodic [i];
+		u32		*prev_p = &amp;ohci-&gt;hcca-&gt;int_table [i];
+		struct ed	*here = *prev;
+
+		/* sorting each branch by period (slow before fast)
+		 * lets us share the faster parts of the tree.
+		 * (plus maybe: put interrupt eds before iso)
+		 */
+		while (here &amp;&amp; ed != here) {
+			if (ed-&gt;interval &gt; here-&gt;interval)
+				break;
+			prev = &amp;here-&gt;ed_next;
+			prev_p = &amp;here-&gt;hwNextED;
+			here = *prev;
+		}
+		if (ed != here) {
+			ed-&gt;ed_next = here;
+			if (here)
+				ed-&gt;hwNextED = *prev_p;
+			wmb ();
+			*prev = ed;
+			*prev_p = cpu_to_le32p (&amp;ed-&gt;dma);
+		}
+		ohci-&gt;load [i] += ed-&gt;load;
+	}
+	ohci-&gt;hcd.self.bandwidth_allocated += ed-&gt;load / ed-&gt;interval;
 }
 
-/*-------------------------------------------------------------------------*/
-
 /* link an ed into one of the HC chains */
 
-static void ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
+static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
 {	 
-	int			int_branch, i;
-	int			inter, interval, load;
-	__u32			*ed_p;
+	int	branch;
 
 	ed-&gt;state = ED_OPER;
+	ed-&gt;ed_prev = 0;
+	ed-&gt;ed_next = 0;
 	ed-&gt;hwNextED = 0;
 	wmb ();
 
 	/* we care about rm_list when setting CLE/BLE in case the HC was at
 	 * work on some TD when CLE/BLE was turned off, and isn't quiesced
 	 * yet.  finish_unlinks() restarts as needed, some upcoming INTR_SF.
+	 *
+	 * control and bulk EDs are doubly linked (ed_next, ed_prev), but
+	 * periodic ones are singly linked (ed_next). that's because the
+	 * periodic schedule encodes a tree like figure 3-5 in the ohci
+	 * spec:  each qh can have several "previous" nodes, and the tree
+	 * doesn't have unused/idle descriptors.
 	 */
-
 	switch (ed-&gt;type) {
 	case PIPE_CONTROL:
 		if (ohci-&gt;ed_controltail == NULL) {
 			writel (ed-&gt;dma, &amp;ohci-&gt;regs-&gt;ed_controlhead);
 		} else {
+			ohci-&gt;ed_controltail-&gt;ed_next = ed;
 			ohci-&gt;ed_controltail-&gt;hwNextED = cpu_to_le32 (ed-&gt;dma);
 		}
 		ed-&gt;ed_prev = ohci-&gt;ed_controltail;
@@ -187,6 +239,7 @@
 		if (ohci-&gt;ed_bulktail == NULL) {
 			writel (ed-&gt;dma, &amp;ohci-&gt;regs-&gt;ed_bulkhead);
 		} else {
+			ohci-&gt;ed_bulktail-&gt;ed_next = ed;
 			ohci-&gt;ed_bulktail-&gt;hwNextED = cpu_to_le32 (ed-&gt;dma);
 		}
 		ed-&gt;ed_prev = ohci-&gt;ed_bulktail;
@@ -198,74 +251,55 @@
 		ohci-&gt;ed_bulktail = ed;
 		break;
 
-	case PIPE_INTERRUPT:
-		load = ed-&gt;intriso.intr_info.int_load;
-		interval = ed-&gt;interval;
-		int_branch = ep_int_balance (ohci, interval, load);
-		ed-&gt;intriso.intr_info.int_branch = int_branch;
-
-		for (i = 0; i &lt; ep_rev (6, interval); i += inter) {
-			inter = 1;
-			for (ed_p = &amp; (ohci-&gt;hcca-&gt;int_table [ep_rev (5, i) + int_branch]); 
-				 (*ed_p != 0) &amp;&amp; ((dma_to_ed (ohci, le32_to_cpup (ed_p)))-&gt;interval &gt;= interval); 
-				ed_p = &amp; ((dma_to_ed (ohci, le32_to_cpup (ed_p)))-&gt;hwNextED)) 
-					inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))-&gt;interval);
-			ed-&gt;hwNextED = *ed_p; 
-			*ed_p = cpu_to_le32 (ed-&gt;dma);
+	// case PIPE_INTERRUPT:
+	// case PIPE_ISOCHRONOUS:
+	default:
+		branch = balance (ohci, ed-&gt;interval, ed-&gt;load);
+		if (branch &lt; 0) {
+			dbg ("%s: ERR %d, interval %d msecs, load %d",
+				ohci-&gt;hcd.self.bus_name,
+				branch, ed-&gt;interval, ed-&gt;load);
+			// FIXME if there are TDs queued, fail them!
+			return branch;
 		}
-		wmb ();
-#ifdef OHCI_VERBOSE_DEBUG
-		ohci_dump_periodic (ohci, "LINK_INT");
-#endif
-		break;
-
-	case PIPE_ISOCHRONOUS:
-		ed-&gt;ed_prev = ohci-&gt;ed_isotail;
-		if (ohci-&gt;ed_isotail != NULL) {
-			ohci-&gt;ed_isotail-&gt;hwNextED = cpu_to_le32 (ed-&gt;dma);
-		} else {
-			for ( i = 0; i &lt; NUM_INTS; i += inter) {
-				inter = 1;
-				for (ed_p = &amp; (ohci-&gt;hcca-&gt;int_table [ep_rev (5, i)]); 
-					*ed_p != 0; 
-					ed_p = &amp; ((dma_to_ed (ohci, le32_to_cpup (ed_p)))-&gt;hwNextED)) 
-						inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))-&gt;interval);
-				*ed_p = cpu_to_le32 (ed-&gt;dma);	
-			}	
-		}	
-		wmb ();
-		ohci-&gt;ed_isotail = ed;
-#ifdef OHCI_VERBOSE_DEBUG
-		ohci_dump_periodic (ohci, "LINK_ISO");
-#endif
-		break;
+		ed-&gt;branch = branch;
+		periodic_link (ohci, ed);
 	}	 	
 
 	/* the HC may not see the schedule updates yet, but if it does
 	 * then they'll be properly ordered.
 	 */
+	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
 
 /* scan the periodic table to find and unlink this ED */
-static void periodic_unlink (
-	struct ohci_hcd	*ohci,
-	struct ed	*ed,
-	unsigned	index,
-	unsigned	period
-) {
-	for (; index &lt; NUM_INTS; index += period) {
-		__u32	*ed_p = &amp;ohci-&gt;hcca-&gt;int_table [index];
+static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)
+{
+	int	i;
 
-		while (*ed_p != 0) {
-			if ((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
-				*ed_p = ed-&gt;hwNextED;		
-				break;
-			}
-			ed_p = &amp; ((dma_to_ed (ohci, le32_to_cpup (ed_p)))-&gt;hwNextED);
+	for (i = ed-&gt;branch; i &lt; NUM_INTS; i += ed-&gt;interval) {
+		struct ed	*temp;
+		struct ed	**prev = &amp;ohci-&gt;periodic [i];
+		u32		*prev_p = &amp;ohci-&gt;hcca-&gt;int_table [i];
+
+		while (*prev &amp;&amp; (temp = *prev) != ed) {
+			prev_p = &amp;temp-&gt;hwNextED;
+			prev = &amp;temp-&gt;ed_next;
+		}
+		if (*prev) {
+			*prev_p = ed-&gt;hwNextED;
+			*prev = ed-&gt;ed_next;
 		}
+		ohci-&gt;load [i] -= ed-&gt;load;
 	}	
+	ohci-&gt;hcd.self.bandwidth_allocated -= ed-&gt;load / ed-&gt;interval;
+
+	dbg ("%s: unlink %sed %p branch %d [%dus.], interval %d",
+		ohci-&gt;hcd.self.bus_name,
+		(ed-&gt;hwINFO &amp; ED_ISO) ? "iso " : "",
+		ed, ed-&gt;branch, ed-&gt;load, ed-&gt;interval);
 }
 
 /* unlink an ed from one of the HC chains. 
@@ -275,8 +309,6 @@
  */
 static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) 
 {
-	int	i;
-
 	ed-&gt;hwINFO |= ED_SKIP;
 
 	switch (ed-&gt;type) {
@@ -289,13 +321,15 @@
 			writel (le32_to_cpup (&amp;ed-&gt;hwNextED),
 				&amp;ohci-&gt;regs-&gt;ed_controlhead);
 		} else {
+			ed-&gt;ed_prev-&gt;ed_next = ed-&gt;ed_next;
 			ed-&gt;ed_prev-&gt;hwNextED = ed-&gt;hwNextED;
 		}
 		if (ohci-&gt;ed_controltail == ed) {
 			ohci-&gt;ed_controltail = ed-&gt;ed_prev;
+			if (ohci-&gt;ed_controltail)
+				ohci-&gt;ed_controltail-&gt;ed_next = 0;
 		} else {
-			 (dma_to_ed (ohci, le32_to_cpup (&amp;ed-&gt;hwNextED)))
-			 	-&gt;ed_prev = ed-&gt;ed_prev;
+			ed-&gt;ed_next-&gt;ed_prev = ed-&gt;ed_prev;
 		}
 		break;
 
@@ -308,50 +342,33 @@
 			writel (le32_to_cpup (&amp;ed-&gt;hwNextED),
 				&amp;ohci-&gt;regs-&gt;ed_bulkhead);
 		} else {
+			ed-&gt;ed_prev-&gt;ed_next = ed-&gt;ed_next;
 			ed-&gt;ed_prev-&gt;hwNextED = ed-&gt;hwNextED;
 		}
 		if (ohci-&gt;ed_bulktail == ed) {
 			ohci-&gt;ed_bulktail = ed-&gt;ed_prev;
+			if (ohci-&gt;ed_bulktail)
+				ohci-&gt;ed_bulktail-&gt;ed_next = 0;
 		} else {
-			 (dma_to_ed (ohci, le32_to_cpup (&amp;ed-&gt;hwNextED)))
-			 	-&gt;ed_prev = ed-&gt;ed_prev;
+			ed-&gt;ed_next-&gt;ed_prev = ed-&gt;ed_prev;
 		}
 		break;
 
-	case PIPE_INTERRUPT:
-		periodic_unlink (ohci, ed, ed-&gt;intriso.intr_info.int_branch, ed-&gt;interval);
-		for (i = ed-&gt;intriso.intr_info.int_branch; i &lt; NUM_INTS; i += ed-&gt;interval)
-			ohci-&gt;ohci_int_load [i] -= ed-&gt;intriso.intr_info.int_load;
-#ifdef OHCI_VERBOSE_DEBUG
-		ohci_dump_periodic (ohci, "UNLINK_INT");
-#endif
-		break;
-
-	case PIPE_ISOCHRONOUS:
-		if (ohci-&gt;ed_isotail == ed)
-			ohci-&gt;ed_isotail = ed-&gt;ed_prev;
-		if (ed-&gt;hwNextED != 0) 
-			(dma_to_ed (ohci, le32_to_cpup (&amp;ed-&gt;hwNextED)))
-		    		-&gt;ed_prev = ed-&gt;ed_prev;
-
-		if (ed-&gt;ed_prev != NULL)
-			ed-&gt;ed_prev-&gt;hwNextED = ed-&gt;hwNextED;
-		else
-			periodic_unlink (ohci, ed, 0, 1);
-#ifdef OHCI_VERBOSE_DEBUG
-		ohci_dump_periodic (ohci, "UNLINK_ISO");
-#endif
+	// case PIPE_INTERRUPT:
+	// case PIPE_ISOCHRONOUS:
+	default:
+		periodic_unlink (ohci, ed);
 		break;
 	}
 
-	/* FIXME Except for a couple of exceptionally clean unlink cases
+	/* NOTE: Except for a couple of exceptionally clean unlink cases
 	 * (like unlinking the only c/b ED, with no TDs) HCs may still be
-	 * caching this (till SOF).
-	 *
-	 * To avoid racing with the hardware, this needs to use ED_UNLINK
-	 * and delay til next INTR_SF.  Merge with start_urb_unlink().
+	 * caching this operational ED (or its address).  Safe unlinking
+	 * involves not marking it ED_IDLE till INTR_SF; we always do that
+	 * if td_list isn't empty.  Otherwise the race is small; but ...
 	 */
-	ed-&gt;state = ED_IDLE;
+	if (ed-&gt;state == ED_OPER)
+		ed-&gt;state = ED_IDLE;
 }
 
 
@@ -369,7 +386,6 @@
 ) {
 	int			is_out = !usb_pipein (pipe);
 	int			type = usb_pipetype (pipe);
-	int			bus_msecs = 0;
 	struct hcd_dev		*dev = (struct hcd_dev *) udev-&gt;hcpriv;
 	struct ed		*ed; 
 	unsigned		ep;
@@ -378,9 +394,6 @@
 	ep = usb_pipeendpoint (pipe) &lt;&lt; 1;
 	if (type != PIPE_CONTROL &amp;&amp; is_out)
 		ep |= 1;
-	if (type == PIPE_INTERRUPT)
-		bus_msecs = usb_calc_bus_time (udev-&gt;speed, !is_out, 0,
-			usb_maxpacket (udev, pipe, is_out)) / 1000;
 
 	spin_lock_irqsave (&amp;ohci-&gt;lock, flags);
 
@@ -422,23 +435,25 @@
 		info = cpu_to_le32 (info);
 		if (udev-&gt;speed == USB_SPEED_LOW)
 			info |= ED_LOWSPEED;
-		/* control transfers store pids in tds */
+		/* only control transfers store pids in tds */
 		if (type != PIPE_CONTROL) {
 			info |= is_out ? ED_OUT : ED_IN;
-			if (type == PIPE_ISOCHRONOUS)
-				info |= ED_ISO;
-			if (type == PIPE_INTERRUPT) {
-				ed-&gt;intriso.intr_info.int_load = bus_msecs;
-				if (interval &gt; 32)
+			if (type != PIPE_BULK) {
+				/* periodic transfers... */
+				if (type == PIPE_ISOCHRONOUS)
+					info |= ED_ISO;
+				else if (interval &gt; 32)	/* iso can be bigger */
 					interval = 32;
+				ed-&gt;interval = interval;
+				ed-&gt;load = usb_calc_bus_time (
+					udev-&gt;speed, !is_out,
+					type == PIPE_ISOCHRONOUS,
+					usb_maxpacket (udev, pipe, is_out))
+						/ 1000;
 			}
 		}
 		ed-&gt;hwINFO = info;
 
-		/* value ignored except on periodic EDs, where
-		 * we know it's already a power of 2
-		 */
-		ed-&gt;interval = interval;
 #ifdef DEBUG
 	/*
 	 * There are two other cases we ought to change hwINFO, both during
@@ -473,8 +488,9 @@
  */
 static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed)
 {    
-	ed_deschedule (ohci, ed);
+	ed-&gt;hwINFO |= ED_DEQUEUE;
 	ed-&gt;state = ED_UNLINK;
+	ed_deschedule (ohci, ed);
 
 	/* SF interrupt might get delayed; record the frame counter value that
 	 * indicates when the HC isn't looking at it, so concurrent unlinks
@@ -483,7 +499,9 @@
 	 */
 	ed-&gt;tick = le16_to_cpu (ohci-&gt;hcca-&gt;frame_no) + 1;
 
+	/* rm_list is just singly linked, for simplicity */
 	ed-&gt;ed_next = ohci-&gt;ed_rm_list;
+	ed-&gt;ed_prev = 0;
 	ohci-&gt;ed_rm_list = ed;
 
 	/* enable SOF interrupt */
@@ -529,7 +547,6 @@
 
 	/* use this td as the next dummy */
 	td_pt = urb_priv-&gt;td [index];
-	td_pt-&gt;hwNextTD = 0;
 
 	/* fill the old dummy TD */
 	td = urb_priv-&gt;td [index] = urb_priv-&gt;ed-&gt;dummy;
@@ -547,7 +564,7 @@
 	if (is_iso) {
 		td-&gt;hwCBP = cpu_to_le32 (data &amp; 0xFFFFF000);
 		td-&gt;hwPSW [0] = cpu_to_le16 ((data &amp; 0x0FFF) | 0xE000);
-		td-&gt;ed-&gt;intriso.last_iso = info &amp; 0xffff;
+		td-&gt;ed-&gt;last_iso = info &amp; 0xffff;
 	} else {
 		td-&gt;hwCBP = cpu_to_le32 (data); 
 	}			
@@ -608,9 +625,11 @@
 	/* Bulk and interrupt are identical except for where in the schedule
 	 * their EDs live.
 	 */
-	// case PIPE_BULK:
-	// case PIPE_INTERRUPT:
-	default:
+	case PIPE_INTERRUPT:
+		/* ... and periodic urbs have extra accounting */
+		ohci-&gt;hcd.self.bandwidth_int_reqs++;
+		/* FALLTHROUGH */
+	case PIPE_BULK:
 		info = is_out
 			? TD_T_TOGGLE | TD_CC | TD_DP_OUT
 			: TD_T_TOGGLE | TD_CC | TD_DP_IN;
@@ -676,6 +695,7 @@
 				data + urb-&gt;iso_frame_desc [cnt].offset,
 				urb-&gt;iso_frame_desc [cnt].length, urb, cnt);
 		}
+		ohci-&gt;hcd.self.bandwidth_isoc_reqs++;
 		break;
 	}
 	if (urb_priv-&gt;length != cnt)
@@ -802,6 +822,7 @@
 			if (td_list-&gt;ed-&gt;hwHeadP &amp; ED_H) {
 				if (urb_priv &amp;&amp; ((td_list-&gt;index + 1)
 						&lt; urb_priv-&gt;length)) {
+#ifdef DEBUG
 					struct urb *urb = td_list-&gt;urb;
 
 					/* help for troubleshooting: */
@@ -817,6 +838,7 @@
 						1 + td_list-&gt;index,
 						urb_priv-&gt;length,
 						cc, cc_to_error [cc]);
+#endif
 					td_list-&gt;ed-&gt;hwHeadP = 
 			    (urb_priv-&gt;td [urb_priv-&gt;length - 1]-&gt;hwNextTD
 				    &amp; __constant_cpu_to_le32 (TD_MASK))
@@ -872,8 +894,7 @@
 		 * we call a completion since it might have unlinked
 		 * another (earlier) urb
 		 *
-		 * FIXME use td_list to scan, not ed hashtables.
-		 * completely abolish ed hashtables!
+		 * FIXME use td_list to scan, not td hashtables.
 		 */
 rescan_this:
 		completed = 0;
@@ -894,8 +915,7 @@
 				td_done (urb, td);
 				urb_priv-&gt;td_cnt++;
 
-				*td_p = td-&gt;hwNextTD | (*td_p
-					&amp; __constant_cpu_to_le32 (0x3));
+				*td_p = td-&gt;hwNextTD | (*td_p &amp; ~TD_MASK);
 
 				/* URB is done; clean up */
 				if (urb_priv-&gt;td_cnt == urb_priv-&gt;length) {
diff -Nru a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
--- a/drivers/usb/host/ohci.h	Thu Sep  5 08:51:20 2002
+++ b/drivers/usb/host/ohci.h	Thu Sep  5 08:51:20 2002
@@ -5,7 +5,6 @@
  * (C) Copyright 2000-2002 David Brownell &lt;dbrownell@users.sourceforge.net&gt;
  * 
  * This file is licenced under the GPL.
- * $Id: ohci.h,v 1.6 2002/03/22 16:04:54 dbrownell Exp $
  */
  
 /*
@@ -18,13 +17,16 @@
 struct ed {
 	/* first fields are hardware-specified, le32 */
 	__u32			hwINFO;       	/* endpoint config bitmap */
+	/* info bits defined by hcd */
+#define ED_DEQUEUE	__constant_cpu_to_le32(1 &lt;&lt; 27)
+	/* info bits defined by the hardware */
 #define ED_ISO		__constant_cpu_to_le32(1 &lt;&lt; 15)
 #define ED_SKIP		__constant_cpu_to_le32(1 &lt;&lt; 14)
 #define ED_LOWSPEED	__constant_cpu_to_le32(1 &lt;&lt; 13)
 #define ED_OUT		__constant_cpu_to_le32(0x01 &lt;&lt; 11)
 #define ED_IN		__constant_cpu_to_le32(0x02 &lt;&lt; 11)
 	__u32			hwTailP;	/* tail of TD list */
-	__u32			hwHeadP;	/* head of TD list */
+	__u32			hwHeadP;	/* head of TD list (hc r/w) */
 #define ED_C		__constant_cpu_to_le32(0x02)	/* toggle carry */
 #define ED_H		__constant_cpu_to_le32(0x01)	/* halted */
 	__u32			hwNextED;	/* next ED in list */
@@ -48,14 +50,12 @@
 #define ED_OPER		0x02		/* IS linked to hc */
 
 	u8			type; 		/* PIPE_{BULK,...} */
-	u16			interval;	/* interrupt, isochronous */
-	union {
-		struct intr_info {		/* interrupt */
-			u8	int_branch;
-			u8	int_load; 
-		} intr_info;
-		u16		last_iso;	/* isochronous */
-	} intriso;
+
+	/* periodic scheduling params (for intr and iso) */
+	u8			branch;
+	u16			interval;
+	u16			load;
+	u16			last_iso;	/* iso only */
 
 	/* HC may see EDs on rm_list until next frame (frame_no == tick) */
 	u16			tick;
@@ -335,10 +335,8 @@
 };
 
 #define TD_HASH_SIZE    64    /* power'o'two */
-#define ED_HASH_SIZE    64    /* power'o'two */
 
 #define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma &gt;&gt; 5)) % TD_HASH_SIZE)
-#define ED_HASH_FUNC(ed_dma) ((ed_dma ^ (ed_dma &gt;&gt; 5)) % ED_HASH_SIZE)
 
 
 /*
@@ -373,7 +371,7 @@
 
 	struct ed		*ed_bulktail;		/* last in bulk list */
 	struct ed		*ed_controltail;	/* last in ctrl list */
- 	struct ed		*ed_isotail;		/* last in iso list */
+ 	struct ed		*periodic [NUM_INTS];	/* shadow int_table */
 
 	/*
 	 * memory management for queue data structures
@@ -381,14 +379,13 @@
 	struct pci_pool		*td_cache;
 	struct pci_pool		*ed_cache;
 	struct hash_list_t	td_hash [TD_HASH_SIZE];
-	struct hash_list_t	ed_hash [ED_HASH_SIZE];
 
 	/*
 	 * driver state
 	 */
 	int			disabled;	/* e.g. got a UE, we're hung */
 	int			sleeping;
-	int			ohci_int_load [NUM_INTS];
+	int			load [NUM_INTS];
 	u32 			hc_control;	/* copy of hc control reg */
 
 	unsigned long		flags;		/* for HC bugs */
</pre></body></html>