# 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.457.4.1 -> 1.457.4.2
#	drivers/usb/host/ehci-q.c	1.19    -> 1.20   
#	drivers/usb/host/ehci-sched.c	1.14    -> 1.15   
#	drivers/usb/host/ehci-hcd.c	1.20    -> 1.21   
#	drivers/usb/host/ehci.h	1.4     -> 1.5    
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/08/05	david-b@pacbell.net	1.457.4.2
# [PATCH] ehci updates
# 
# This patch is the first part of fixing the EHCI driver to queue
# interrupt transactions, handle larger requests, and basically treat
# interrupt as just "bulk that lives on the periodic schedule".  One
# more patch should wrap that up.
# 
#      qh processing cleanup
# 	- split "append tds to qh" logic out of "put on async schedule",
# 	  so it can be used with "put on periodic schedule" too
#      interrupt transfer cleanup
# 	- save rest of scheduling params in the qh
# 	- calculate scheduling params only once
#      other cleanup
# 	- use new container_of()
# 	- minor code shrinkage (avoid pipe bitops, conditionals, etc)
# 	- rename variable (will track endpoints, not urbs)
# 	- free_config() logic
# --------------------------------------------
#
diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c	Tue Aug  6 22:06:54 2002
+++ b/drivers/usb/host/ehci-hcd.c	Tue Aug  6 22:06:54 2002
@@ -626,10 +626,11 @@
 
 	urb->transfer_flags &= ~EHCI_STATE_UNLINK;
 	INIT_LIST_HEAD (&qtd_list);
-	switch (usb_pipetype (urb->pipe)) {
 
-	case PIPE_CONTROL:
-	case PIPE_BULK:
+	switch (usb_pipetype (urb->pipe)) {
+	// case PIPE_CONTROL:
+	// case PIPE_BULK:
+	default:
 		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
 			return -ENOMEM;
 		return submit_async (ehci, urb, &qtd_list, mem_flags);
@@ -649,9 +650,6 @@
 		dbg ("no split iso support yet");
 		return -ENOSYS;
 #endif /* have_split_iso */
-
-	default:	/* can't happen */
-		return -ENOSYS;
 	}
 }
 
@@ -665,15 +663,16 @@
 	struct ehci_qh		*qh = (struct ehci_qh *) urb->hcpriv;
 	unsigned long		flags;
 
-	dbg ("%s urb_dequeue %p qh state %d",
-		hcd->self.bus_name, urb, qh->qh_state);
+	dbg ("%s urb_dequeue %p qh %p state %d",
+		hcd->self.bus_name, urb, qh, qh->qh_state);
 
 	switch (usb_pipetype (urb->pipe)) {
-	case PIPE_CONTROL:
-	case PIPE_BULK:
+	// case PIPE_CONTROL:
+	// case PIPE_BULK:
+	default:
 		spin_lock_irqsave (&ehci->lock, flags);
 		if (ehci->reclaim) {
-dbg ("dq: reclaim busy, %s", RUN_CONTEXT);
+			dbg ("dq: reclaim busy, %s", RUN_CONTEXT);
 			if (in_interrupt ()) {
 				spin_unlock_irqrestore (&ehci->lock, flags);
 				return -EAGAIN;
@@ -683,11 +682,8 @@
 					&& ehci->hcd.state != USB_STATE_HALT
 					) {
 				spin_unlock_irqrestore (&ehci->lock, flags);
-// yeech ... this could spin for up to two frames!
-dbg ("wait for dequeue: state %d, reclaim %p, hcd state %d",
-    qh->qh_state, ehci->reclaim, ehci->hcd.state
-);
-				udelay (100);
+				/* let pending unlinks complete */
+				wait_ms (1);
 				spin_lock_irqsave (&ehci->lock, flags);
 			}
 		}
@@ -712,9 +708,9 @@
 		// wait till next completion, do it then.
 		// completion irqs can wait up to 1024 msec,
 		urb->transfer_flags |= EHCI_STATE_UNLINK;
-		return 0;
+		break;
 	}
-	return -EINVAL;
+	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -728,6 +724,7 @@
 	int			i;
 	unsigned long		flags;
 
+	/* ASSERT:  no requests/urbs are still linked (so no TDs) */
 	/* ASSERT:  nobody can be submitting urbs for this any more */
 
 	dbg ("%s: free_config devnum %d", hcd->self.bus_name, udev->devnum);
@@ -736,34 +733,57 @@
 	for (i = 0; i < 32; i++) {
 		if (dev->ep [i]) {
 			struct ehci_qh		*qh;
+			char			*why;
 
 			/* dev->ep never has ITDs or SITDs */
 			qh = (struct ehci_qh *) dev->ep [i];
-			vdbg ("free_config, ep 0x%02x qh %p", i, qh);
-			if (!list_empty (&qh->qtd_list)) {
-				dbg ("ep 0x%02x qh %p not empty!", i, qh);
+
+			/* detect/report non-recoverable errors */
+			if (in_interrupt ()) 
+				why = "disconnect() didn't";
+			else if ((qh->hw_info2 & cpu_to_le32 (0xffff)) != 0
+					&& qh->qh_state != QH_STATE_IDLE)
+				why = "(active periodic)";
+			else
+				why = 0;
+			if (why) {
+				err ("dev %s-%s ep %d-%s error: %s",
+					hcd->self.bus_name, udev->devpath,
+					i & 0xf, (i & 0x10) ? "IN" : "OUT",
+					why);
 				BUG ();
 			}
-			dev->ep [i] = 0;
 
-			/* wait_ms() won't spin here -- we're a thread */
+			dev->ep [i] = 0;
+			if (qh->qh_state == QH_STATE_IDLE)
+				goto idle;
+			dbg ("free_config, async ep 0x%02x qh %p", i, qh);
+
+			/* scan_async() empties the ring as it does its work,
+			 * using IAA, but doesn't (yet?) turn it off.  if it
+			 * doesn't empty this qh, likely it's the last entry.
+			 */
 			while (qh->qh_state == QH_STATE_LINKED
 					&& ehci->reclaim
 					&& ehci->hcd.state != USB_STATE_HALT
 					) {
 				spin_unlock_irqrestore (&ehci->lock, flags);
+				/* wait_ms() won't spin, we're a thread;
+				 * and we know IRQ+tasklet can progress
+				 */
 				wait_ms (1);
 				spin_lock_irqsave (&ehci->lock, flags);
 			}
-			if (qh->qh_state == QH_STATE_LINKED) {
+			if (qh->qh_state == QH_STATE_LINKED)
 				start_unlink_async (ehci, qh);
-				while (qh->qh_state != QH_STATE_IDLE) {
-					spin_unlock_irqrestore (&ehci->lock,
-						flags);
-					wait_ms (1);
-					spin_lock_irqsave (&ehci->lock, flags);
-				}
+			while (qh->qh_state != QH_STATE_IDLE
+					&& ehci->hcd.state != USB_STATE_HALT) {
+				spin_unlock_irqrestore (&ehci->lock,
+					flags);
+				wait_ms (1);
+				spin_lock_irqsave (&ehci->lock, flags);
 			}
+idle:
 			qh_put (ehci, qh);
 		}
 	}
diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
--- a/drivers/usb/host/ehci-q.c	Tue Aug  6 22:06:54 2002
+++ b/drivers/usb/host/ehci-q.c	Tue Aug  6 22:06:54 2002
@@ -47,9 +47,11 @@
 qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token)
 {
 	int	i, count;
+	u64	addr = buf;
 
 	/* one buffer entry per 4K ... first might be short or unaligned */
-	qtd->hw_buf [0] = cpu_to_le32 (buf);
+	qtd->hw_buf [0] = cpu_to_le32 ((u32)addr);
+	qtd->hw_buf_hi [0] = cpu_to_le32 ((u32)(addr >> 32));
 	count = 0x1000 - (buf & 0x0fff);	/* rest of that page */
 	if (likely (len < count))		/* ... iff needed */
 		count = len;
@@ -59,7 +61,7 @@
 
 		/* per-qtd limit: from 16K to 20K (best alignment) */
 		for (i = 1; count < len && i < 5; i++) {
-			u64	addr = buf;
+			addr = buf;
 			qtd->hw_buf [i] = cpu_to_le32 ((u32)addr);
 			qtd->hw_buf_hi [i] = cpu_to_le32 ((u32)(addr >> 32));
 			buf += 0x1000;
@@ -312,7 +314,7 @@
 
 			/* unlink the rest?  once we start unlinking, after
 			 * a fault or explicit unlink, we unlink all later
-			 * urbs.  usb spec requires that.
+			 * urbs.  usb spec requires that for faults...
 			 */
 			if (unlink && urb->status == -EINPROGRESS)
 				urb->status = -ECONNRESET;
@@ -450,6 +452,7 @@
 	struct ehci_qtd		*qtd, *qtd_prev;
 	dma_addr_t		buf, map_buf;
 	int			len, maxpacket;
+	int			is_input;
 	u32			token;
 
 	/*
@@ -495,10 +498,11 @@
 	 * data transfer stage:  buffer setup
 	 */
 	len = urb->transfer_buffer_length;
+	is_input = usb_pipein (urb->pipe);
 	if (likely (len > 0)) {
 		buf = map_buf = pci_map_single (ehci->hcd.pdev,
 			urb->transfer_buffer, len,
-			usb_pipein (urb->pipe)
+			is_input
 			    ? PCI_DMA_FROMDEVICE
 			    : PCI_DMA_TODEVICE);
 		if (unlikely (!buf))
@@ -506,12 +510,11 @@
 	} else
 		buf = map_buf = 0;
 
-	if (!buf || usb_pipein (urb->pipe))
+	if (!buf || is_input)
 		token |= (1 /* "in" */ << 8);
 	/* else it's already initted to "out" pid (0 << 8) */
 
-	maxpacket = usb_maxpacket (urb->dev, urb->pipe,
-			usb_pipeout (urb->pipe));
+	maxpacket = usb_maxpacket (urb->dev, urb->pipe, !is_input) & 0x03ff;
 
 	/*
 	 * buffer gets wrapped in one or more qtds;
@@ -607,6 +610,11 @@
 // That'd mean updating how usbcore talks to HCDs. (2.5?)
 
 
+// high bandwidth multiplier, as encoded in highspeed endpoint descriptors
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+// ... and packet size, for any kind of endpoint descriptor
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x03ff)
+
 /*
  * Each QH holds a qtd list; a QH is used for everything except iso.
  *
@@ -624,6 +632,8 @@
 ) {
 	struct ehci_qh		*qh = ehci_qh_alloc (ehci, flags);
 	u32			info1 = 0, info2 = 0;
+	int			is_input, type;
+	int			maxp = 0;
 
 	if (!qh)
 		return qh;
@@ -634,6 +644,53 @@
 	info1 |= usb_pipeendpoint (urb->pipe) << 8;
 	info1 |= usb_pipedevice (urb->pipe) << 0;
 
+	is_input = usb_pipein (urb->pipe);
+	type = usb_pipetype (urb->pipe);
+	maxp = usb_maxpacket (urb->dev, urb->pipe, !is_input);
+
+	/* Compute interrupt scheduling parameters just once, and save.
+	 * - allowing for high bandwidth, how many nsec/uframe are used?
+	 * - split transactions need a second CSPLIT uframe; same question
+	 * - splits also need a schedule gap (for full/low speed I/O)
+	 * - qh has a polling interval
+	 *
+	 * For control/bulk requests, the HC or TT handles these.
+	 */
+	if (type == PIPE_INTERRUPT) {
+		qh->usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,
+				hb_mult (maxp) * max_packet (maxp));
+		qh->start = ~0;
+
+		if (urb->dev->speed == USB_SPEED_HIGH) {
+			qh->c_usecs = 0;
+			qh->gap_uf = 0;
+
+			/* FIXME handle HS periods of less than 1 frame. */
+			qh->period = urb->interval >> 3;
+			if (qh->period < 1) {
+				dbg ("intr period %d uframes, NYET!",
+						urb->interval);
+				qh = 0;
+				goto done;
+			}
+		} else {
+			/* gap is f(FS/LS transfer times) */
+			qh->gap_uf = 1 + usb_calc_bus_time (urb->dev->speed,
+					is_input, 0, maxp) / (125 * 1000);
+
+			/* FIXME this just approximates SPLIT/CSPLIT times */
+			if (is_input) {		// SPLIT, gap, CSPLIT+DATA
+				qh->c_usecs = qh->usecs + HS_USECS (0);
+				qh->usecs = HS_USECS (1);
+			} else {		// SPLIT+DATA, gap, CSPLIT
+				qh->usecs += HS_USECS (1);
+				qh->c_usecs = HS_USECS (0);
+			}
+
+			qh->period = urb->interval;
+		}
+	}
+
 	/* using TT? */
 	switch (urb->dev->speed) {
 	case USB_SPEED_LOW:
@@ -643,49 +700,42 @@
 	case USB_SPEED_FULL:
 		/* EPS 0 means "full" */
 		info1 |= (EHCI_TUNE_RL_TT << 28);
-		if (usb_pipecontrol (urb->pipe)) {
+		if (type == PIPE_CONTROL) {
 			info1 |= (1 << 27);	/* for TT */
 			info1 |= 1 << 14;	/* toggle from qtd */
 		}
-		info1 |= usb_maxpacket (urb->dev, urb->pipe,
-					usb_pipeout (urb->pipe)) << 16;
+		info1 |= maxp << 16;
 
 		info2 |= (EHCI_TUNE_MULT_TT << 30);
 		info2 |= urb->dev->ttport << 23;
 		info2 |= urb->dev->tt->hub->devnum << 16;
 
-		/* NOTE:  if (usb_pipeint (urb->pipe)) { scheduler sets c-mask }
-		 * ... and a 0.96 scheduler might use FSTN nodes too
-		 */
+		/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets c-mask } */
+
 		break;
 
 	case USB_SPEED_HIGH:		/* no TT involved */
 		info1 |= (2 << 12);	/* EPS "high" */
 		info1 |= (EHCI_TUNE_RL_HS << 28);
-		if (usb_pipecontrol (urb->pipe)) {
+		if (type == PIPE_CONTROL) {
 			info1 |= 64 << 16;	/* usb2 fixed maxpacket */
 			info1 |= 1 << 14;	/* toggle from qtd */
 			info2 |= (EHCI_TUNE_MULT_HS << 30);
-		} else if (usb_pipebulk (urb->pipe)) {
+		} else if (type == PIPE_BULK) {
 			info1 |= 512 << 16;	/* usb2 fixed maxpacket */
 			info2 |= (EHCI_TUNE_MULT_HS << 30);
-		} else {
-			u32	temp;
-			temp = usb_maxpacket (urb->dev, urb->pipe,
-						usb_pipeout (urb->pipe));
-			info1 |= (temp & 0x3ff) << 16;	/* maxpacket */
-			/* HS intr can be "high bandwidth" */
-			temp = 1 + ((temp >> 11) & 0x03);
-			info2 |= temp << 30;		/* mult */
+		} else {		/* PIPE_INTERRUPT */
+			info1 |= max_packet (maxp) << 16;
+			info2 |= hb_mult (maxp) << 30;
 		}
 		break;
-	default:
 #ifdef DEBUG
+	default:
 		BUG ();
 #endif
 	}
 
-	/* NOTE:  if (usb_pipeint (urb->pipe)) { scheduler sets s-mask } */
+	/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets s-mask } */
 
 	qh->qh_state = QH_STATE_IDLE;
 	qh->hw_info1 = cpu_to_le32 (info1);
@@ -696,14 +746,13 @@
 	qh_update (qh, list_entry (qtd_list->next, struct ehci_qtd, qtd_list));
 
 	/* initialize data toggle state */
-	if (!usb_pipecontrol (urb->pipe))
-		clear_toggle (urb->dev,
-			usb_pipeendpoint (urb->pipe),
-			usb_pipeout (urb->pipe),
-			qh);
+	clear_toggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, qh);
 
+done:
 	return qh;
 }
+#undef hb_mult
+#undef hb_packet
 
 /*-------------------------------------------------------------------------*/
 
@@ -745,35 +794,29 @@
 
 /*-------------------------------------------------------------------------*/
 
-static int
-submit_async (
+/*
+ * For control/bulk/interrupt, return QH with these TDs appended.
+ * Allocates and initializes the QH if necessary.
+ * Returns null if it can't allocate a QH it needs to.
+ * If the QH has TDs (urbs) already, that's great.
+ */
+static struct ehci_qh *qh_append_tds (
 	struct ehci_hcd		*ehci,
 	struct urb		*urb,
 	struct list_head	*qtd_list,
-	int			mem_flags
-) {
-	struct ehci_qtd		*qtd;
-	struct hcd_dev		*dev;
-	int			epnum;
-	unsigned long		flags;
+	int			epnum,
+	void			**ptr
+)
+{
 	struct ehci_qh		*qh = 0;
 
-	qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
-	dev = (struct hcd_dev *)urb->dev->hcpriv;
-	epnum = usb_pipeendpoint (urb->pipe);
-	if (usb_pipein (urb->pipe))
-		epnum |= 0x10;
-
-	vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]",
-		ehci->hcd.self.bus_name, urb, urb->transfer_buffer_length,
-		epnum & 0x0f, (epnum & 0x10) ? "in" : "out",
-		qtd, dev ? dev->ep [epnum] : (void *)~0);
-
-	spin_lock_irqsave (&ehci->lock, flags);
-
-	qh = (struct ehci_qh *) dev->ep [epnum];
+	qh = (struct ehci_qh *) *ptr;
 	if (likely (qh != 0)) {
-		u32	hw_next = QTD_NEXT (qtd->qtd_dma);
+		struct ehci_qtd	*qtd;
+		u32		hw_next;
+
+		qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
+		hw_next = QTD_NEXT (qtd->qtd_dma);
 
 		/* maybe patch the qh used for set_address */
 		if (unlikely (epnum == 0
@@ -803,6 +846,7 @@
 			 * Interrupt code must cope with case of HC having it
 			 * cached, and clobbering these updates.
 			 * ... complicates getting rid of extra interrupts!
+			 * (Or:  use dummy td, so cache always stays valid.)
 			 */
 			if (qh->hw_current == cpu_to_le32 (last_qtd->qtd_dma)) {
 				wmb ();
@@ -822,8 +866,7 @@
 			 */
 
 			/* usb_clear_halt() means qh data toggle gets reset */
-			if (usb_pipebulk (urb->pipe)
-					&& unlikely (!usb_gettoggle (urb->dev,
+			if (unlikely (!usb_gettoggle (urb->dev,
 						(epnum & 0x0f),
 						!(epnum & 0x10)))) {
 				clear_toggle (urb->dev,
@@ -836,17 +879,47 @@
 	} else {
 		/* can't sleep here, we have ehci->lock... */
 		qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC);
-		if (likely (qh != 0)) {
-			// dbg_qh ("new qh", ehci, qh);
-			dev->ep [epnum] = qh;
-		}
+		// if (qh) dbg_qh ("new qh", ehci, qh);
+		*ptr = qh;
 	}
+	if (qh)
+		urb->hcpriv = qh_get (qh);
+	return qh;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+submit_async (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	int			mem_flags
+) {
+	struct ehci_qtd		*qtd;
+	struct hcd_dev		*dev;
+	int			epnum;
+	unsigned long		flags;
+	struct ehci_qh		*qh = 0;
+
+	qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
+	dev = (struct hcd_dev *)urb->dev->hcpriv;
+	epnum = usb_pipeendpoint (urb->pipe);
+	if (usb_pipein (urb->pipe))
+		epnum |= 0x10;
+
+	vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]",
+		ehci->hcd.self.bus_name, urb, urb->transfer_buffer_length,
+		epnum & 0x0f, (epnum & 0x10) ? "in" : "out",
+		qtd, dev ? dev->ep [epnum] : (void *)~0);
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	qh = qh_append_tds (ehci, urb, qtd_list, epnum, &dev->ep [epnum]);
 
 	/* Control/bulk operations through TTs don't need scheduling,
 	 * the HC and TT handle it when the TT has a buffer ready.
 	 */
 	if (likely (qh != 0)) {
-		urb->hcpriv = qh_get (qh);
 		if (likely (qh->qh_state == QH_STATE_IDLE))
 			qh_link_async (ehci, qh_get (qh));
 	}
@@ -979,7 +1052,9 @@
 				qh_put (ehci, qh);
 			}
 
-			/* unlink idle entries (reduces PCI usage) */
+			/* unlink idle entries, reducing HC PCI usage as
+			 * well as HCD schedule-scanning costs
+			 */
 			if (list_empty (&qh->qtd_list) && !ehci->reclaim) {
 				if (qh->qh_next.qh != qh) {
 					// dbg ("irq/empty");
@@ -987,6 +1062,7 @@
 				} else {
 					// FIXME:  arrange to stop
 					// after it's been idle a while.
+					// stop/restart isn't free...
 				}
 			}
 			qh = qh->qh_next.qh;
diff -Nru a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
--- a/drivers/usb/host/ehci-sched.c	Tue Aug  6 22:06:54 2002
+++ b/drivers/usb/host/ehci-sched.c	Tue Aug  6 22:06:54 2002
@@ -241,10 +241,10 @@
 
 	qh->qh_state = QH_STATE_UNLINK;
 	qh->qh_next.ptr = 0;
-	ehci->periodic_urbs--;
+	ehci->periodic_sched--;
 
 	/* maybe turn off periodic schedule */
-	if (!ehci->periodic_urbs)
+	if (!ehci->periodic_sched)
 		status = disable_periodic (ehci);
 	else {
 		status = 0;
@@ -266,13 +266,13 @@
 
 	vdbg ("descheduled qh %p, per = %d frame = %d count = %d, urbs = %d",
 		qh, period, frame,
-		atomic_read (&qh->refcount), ehci->periodic_urbs);
+		atomic_read (&qh->refcount), ehci->periodic_sched);
 }
 
 static int check_period (
 	struct ehci_hcd *ehci, 
 	unsigned	frame,
-	int		uframe,
+	unsigned	uframe,
 	unsigned	period,
 	unsigned	usecs
 ) {
@@ -315,8 +315,7 @@
 	struct list_head	*qtd_list,
 	int			mem_flags
 ) {
-	unsigned		epnum, period;
-	unsigned short		usecs, c_usecs, gap_uf;
+	unsigned		epnum;
 	unsigned long		flags;
 	struct ehci_qh		*qh;
 	struct hcd_dev		*dev;
@@ -330,43 +329,6 @@
 		epnum |= 0x10;
 
 	/*
-	 * HS interrupt transfers are simple -- only one microframe.  FS/LS
-	 * interrupt transfers involve a SPLIT in one microframe and CSPLIT
-	 * sometime later.  We need to know how much time each will be
-	 * needed in each microframe and, for FS/LS, how many microframes
-	 * separate the two in the best case.
-	 */
-	usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,
-			urb->transfer_buffer_length);
-	if (urb->dev->speed == USB_SPEED_HIGH) {
-		gap_uf = 0;
-		c_usecs = 0;
-
-		/* FIXME handle HS periods of less than 1 frame. */
-		period = urb->interval >> 3;
-		if (period < 1) {
-			dbg ("intr period %d uframes, NYET!", urb->interval);
-			status = -EINVAL;
-			goto done;
-		}
-	} else {
-		/* gap is a function of full/low speed transfer times */
-		gap_uf = 1 + usb_calc_bus_time (urb->dev->speed, is_input, 0,
-				urb->transfer_buffer_length) / (125 * 1000);
-
-		/* FIXME this just approximates SPLIT/CSPLIT times */
-		if (is_input) {		// SPLIT, gap, CSPLIT+DATA
-			c_usecs = usecs + HS_USECS (0);
-			usecs = HS_USECS (1);
-		} else {		// SPLIT+DATA, gap, CSPLIT
-			usecs = usecs + HS_USECS (1);
-			c_usecs = HS_USECS (0);
-		}
-
-		period = urb->interval;
-	}
-
-	/*
 	 * NOTE: current completion/restart logic doesn't handle more than
 	 * one qtd in a periodic qh ... 16-20 KB/urb is pretty big for this.
 	 * such big requests need many periods to transfer.
@@ -423,19 +385,17 @@
 
 	/* Schedule this periodic QH. */
 	if (likely (status == 0)) {
-		unsigned	frame = period;
+		unsigned	frame = qh->period;
 
 		qh->hw_next = EHCI_LIST_END;
-		qh->usecs = usecs;
-		qh->c_usecs = c_usecs;
 
 		urb->hcpriv = qh_get (qh);
 		status = -ENOSPC;
 
 		/* pick a set of schedule slots, link the QH into them */
 		do {
-			int	uframe;
-			u32	c_mask = 0;
+			unsigned	uframe;
+			u32		c_mask = 0;
 
 			/* pick a set of slots such that all uframes have
 			 * enough periodic bandwidth available.
@@ -443,7 +403,7 @@
 			frame--;
 			for (uframe = 0; uframe < 8; uframe++) {
 				if (check_period (ehci, frame, uframe,
-						period, usecs) == 0)
+						qh->period, qh->usecs) == 0)
 					continue;
 
 				/* If this is a split transaction, check the
@@ -462,18 +422,18 @@
 				 *
 				 * FIXME ehci 0.96 and above can use FSTNs
 				 */
-				if (!c_usecs)
+				if (!qh->c_usecs)
 				    	break;
 				if (check_period (ehci, frame,
-						uframe + gap_uf,
-						period, c_usecs) == 0)
+						uframe + qh->gap_uf,
+						qh->period, qh->c_usecs) == 0)
 					continue;
 				if (check_period (ehci, frame,
-						uframe + gap_uf + 1,
-						period, c_usecs) == 0)
+						uframe + qh->gap_uf + 1,
+						qh->period, qh->c_usecs) == 0)
 					continue;
 
-				c_mask = 0x03 << (8 + uframe + gap_uf);
+				c_mask = 0x03 << (8 + uframe + qh->gap_uf);
 				c_mask = cpu_to_le32 (c_mask);
 				break;
 			}
@@ -481,7 +441,7 @@
 				continue;
 
 			/* QH will run once each period, starting there  */
-			urb->start_frame = frame;
+			urb->start_frame = qh->start = frame;
 			status = 0;
 
 			/* reset S-frame and (maybe) C-frame masks */
@@ -491,8 +451,10 @@
 
 			/* stuff into the periodic schedule */
 			qh->qh_state = QH_STATE_LINKED;
-			vdbg ("qh %p usecs %d period %d.0 starting %d.%d",
-				qh, qh->usecs, period, frame, uframe);
+			dbg ("qh %p usecs %d/%d period %d.0 "
+					"starting %d.%d (gap %d)",
+				qh, qh->usecs, qh->c_usecs, qh->period,
+				frame, uframe, qh->gap_uf);
 			do {
 				if (unlikely (ehci->pshadow [frame].ptr != 0)) {
 // FIXME -- just link toward the end, before any qh with a shorter period,
@@ -505,15 +467,15 @@
 						QH_NEXT (qh->qh_dma);
 				}
 				wmb ();
-				frame += period;
+				frame += qh->period;
 			} while (frame < ehci->periodic_size);
 
 			/* update bandwidth utilization records (for usbfs) */
 			usb_claim_bandwidth (urb->dev, urb,
-				(usecs + c_usecs) / period, 0);
+				(qh->usecs + qh->c_usecs) / qh->period, 0);
 
 			/* maybe enable periodic schedule processing */
-			if (!ehci->periodic_urbs++)
+			if (!ehci->periodic_sched++)
 				status = enable_periodic (ehci);
 			break;
 
@@ -806,7 +768,7 @@
 
 	/* calculate the legal range [start,max) */
 	now = readl (&ehci->regs->frame_index) + 1;	/* next uframe */
-	if (!ehci->periodic_urbs)
+	if (!ehci->periodic_sched)
 		now += 8;				/* startup delay */
 	now %= mod;
 	end = now + mod;
@@ -926,7 +888,7 @@
 		usb_claim_bandwidth (urb->dev, urb, usecs, 1);
 
 		/* maybe enable periodic schedule processing */
-		if (!ehci->periodic_urbs++) {
+		if (!ehci->periodic_sched++) {
 			if ((status =  enable_periodic (ehci)) != 0) {
 				// FIXME deschedule right away
 				err ("itd_schedule, enable = %d", status);
@@ -1009,8 +971,8 @@
 	spin_lock_irqsave (&ehci->lock, flags);
 
 	/* defer stopping schedule; completion can submit */
-	ehci->periodic_urbs--;
-	if (!ehci->periodic_urbs)
+	ehci->periodic_sched--;
+	if (!ehci->periodic_sched)
 		(void) disable_periodic (ehci);
 
 	return flags;
diff -Nru a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
--- a/drivers/usb/host/ehci.h	Tue Aug  6 22:06:54 2002
+++ b/drivers/usb/host/ehci.h	Tue Aug  6 22:06:54 2002
@@ -50,7 +50,7 @@
 
 	union ehci_shadow	*pshadow;	/* mirror hw periodic table */
 	int			next_uframe;	/* scan periodic, start here */
-	unsigned		periodic_urbs;	/* how many urbs scheduled? */
+	unsigned		periodic_sched;	/* periodic activity count */
 
 	/* deferred work from IRQ, etc */
 	struct tasklet_struct	tasklet;
@@ -72,7 +72,7 @@
 };
 
 /* unwrap an HCD pointer to get an EHCI_HCD pointer */ 
-#define hcd_to_ehci(hcd_ptr) list_entry(hcd_ptr, struct ehci_hcd, hcd)
+#define hcd_to_ehci(hcd_ptr) container_of(hcd_ptr, struct ehci_hcd, hcd)
 
 /* NOTE:  urb->transfer_flags expected to not use this bit !!! */
 #define EHCI_STATE_UNLINK	0x8000		/* urb being unlinked */
@@ -287,12 +287,19 @@
 	struct list_head	qtd_list;	/* sw qtd list */
 
 	atomic_t		refcount;
-	unsigned short		usecs;		/* intr bandwidth */
-	unsigned short		c_usecs;	/* ... split completion bw */
-	short			qh_state;
+
+	u8			qh_state;
 #define	QH_STATE_LINKED		1		/* HC sees this */
 #define	QH_STATE_UNLINK		2		/* HC may still see this */
 #define	QH_STATE_IDLE		3		/* HC doesn't see this */
+
+	/* periodic schedule info */
+	u8			usecs;		/* intr bandwidth */
+	u8			gap_uf;		/* uframes split/csplit gap */
+	u8			c_usecs;	/* ... split completion bw */
+	unsigned short		period;		/* polling interval */
+	unsigned short		start;		/* where polling starts */
+
 } __attribute__ ((aligned (32)));
 
 /*-------------------------------------------------------------------------*/
