# 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.484   -> 1.485  
#	drivers/usb/host/ohci-hcd.c	1.21    -> 1.22   
#	drivers/usb/host/ohci-hub.c	1.7     -> 1.8    
#	drivers/usb/host/ohci-dbg.c	1.8     -> 1.9    
#	drivers/usb/host/ohci-q.c	1.15    -> 1.16   
#	drivers/usb/host/ohci.h	1.10    -> 1.11   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/07/26	david-b@pacbell.net	1.485
# [PATCH] ohci-hcd cardbus unplug, remove interrupt length limit,
# 
# * handle another cardbus unplug misbehavior
#      - root hub kept polling, never stopped
#      - starts to update hcd->state to match internal state
# * code to count/queue TDs for interrupt/bulk is now shared
#      - removes (low level) interrupt transfer size limitation
#      - both types already handled urb queueing
#      - re-indents some TD queuing code (most of patch, by volume)
# * cleanup
#      - use new container_of() macro, not list_entry()
#      - report a previously unreported error (control data >4K)
#      - simplify intr/bulk toggle reset
#      - tweak TD debug dump
#      - more object code shrinkage (often fits in 3 pages)
# 
# Note that the control data size error is just a long-standing
# limitation of this driver, not a USB limitation!  It could be
# fixed, if anyone starts to run into it.
# --------------------------------------------
#
diff -Nru a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
--- a/drivers/usb/host/ohci-dbg.c	Fri Jul 26 13:47:24 2002
+++ b/drivers/usb/host/ohci-dbg.c	Fri Jul 26 13:47:24 2002
@@ -281,16 +281,21 @@
 			cbp ? (be + 1 - cbp) : 0);
 	} else {
 		unsigned	i;
-		dbg ("     info %08x CC=%x DI=%d START=%04x", tmp,
-			TD_CC_GET(tmp), /* FC, */
+		dbg ("     info %08x CC=%x FC=%d DI=%d SF=%04x", tmp,
+			TD_CC_GET(tmp),
+			(tmp >> 24) & 0x07,
 			(tmp & TD_DI) >> 21,
 			tmp & 0x0000ffff);
 		dbg ("     bp0 %08x be %08x",
 			le32_to_cpup (&td->hwCBP) & ~0x0fff,
 			le32_to_cpup (&td->hwBE));
 		for (i = 0; i < MAXPSW; i++) {
-			dbg ("       psw [%d] = %2x", i,
-				le16_to_cpu (td->hwPSW [i]));
+			u16	psw = le16_to_cpup (&td->hwPSW [i]);
+			int	cc = (psw >> 12) & 0x0f;
+			dbg ("       psw [%d] = %2x, CC=%x %s=%d", i,
+				psw, cc,
+				(cc >= 0x0e) ? "OFFSET" : "SIZE",
+				psw & 0x0fff);
 		}
 	}
 }
diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
--- a/drivers/usb/host/ohci-hcd.c	Fri Jul 26 13:47:24 2002
+++ b/drivers/usb/host/ohci-hcd.c	Fri Jul 26 13:47:24 2002
@@ -125,6 +125,12 @@
 
 #include "ohci.h"
 
+static inline void disable (struct ohci_hcd *ohci)
+{
+	ohci->disabled = 1;
+	ohci->hcd.state = USB_STATE_HALT;
+}
+
 #include "ohci-hub.c"
 #include "ohci-dbg.c"
 #include "ohci-mem.c"
@@ -158,12 +164,18 @@
 		return -ENOMEM;
 
 	/* for the private part of the URB we need the number of TDs (size) */
-	switch (usb_pipetype (pipe)) {
+	switch (ed->type) {
 		case PIPE_CONTROL:
+			/* td_submit_urb() doesn't yet handle these */
+			if (urb->transfer_buffer_length > 4096)
+				return -EMSGSIZE;
+
 			/* 1 TD for setup, 1 for ACK, plus ... */
 			size = 2;
 			/* FALLTHROUGH */
-		case PIPE_BULK:
+		// case PIPE_INTERRUPT:
+		// case PIPE_BULK:
+		default:
 			/* one TD for every 4096 Bytes (can be upto 8K) */
 			size += urb->transfer_buffer_length / 4096;
 			/* ... and for any remaining bytes ... */
@@ -187,9 +199,6 @@
   				urb->iso_frame_desc [i].status = -EXDEV;
   			}
 			break;
-		case PIPE_INTERRUPT: /* one TD */
-			size = 1;
-			break;
 	}
 
 	/* allocate the private part of the URB */
@@ -242,9 +251,8 @@
 				bustime = usb_check_bandwidth (urb->dev, urb);
 			}
 			if (bustime < 0) {
-				urb_free_priv (ohci, urb_priv);
-				spin_unlock_irqrestore (&ohci->lock, flags);
-				return bustime;
+				retval = bustime;
+				goto fail;
 			}
 			usb_claim_bandwidth (urb->dev, urb,
 				bustime, usb_pipeisoc (urb->pipe));
@@ -259,7 +267,7 @@
 	/* fill the TDs and link them to the ed; and
 	 * enable that part of the schedule, if needed
 	 */
-	td_submit_urb (urb);
+	td_submit_urb (ohci, urb);
 
 fail:
 	if (retval)
@@ -513,7 +521,7 @@
 	ohci->hcd.self.root_hub = udev = usb_alloc_dev (NULL, &ohci->hcd.self);
 	ohci->hcd.state = USB_STATE_READY;
 	if (!udev) {
-		ohci->disabled = 1;
+		disable (ohci);
 		ohci->hc_control &= ~OHCI_CTRL_HCFS;
 		writel (ohci->hc_control, &ohci->regs->control);
 		return -ENOMEM;
@@ -523,7 +531,7 @@
 	udev->speed = USB_SPEED_FULL;
 	if (usb_register_root_hub (udev, ohci->parent_dev) != 0) {
 		usb_free_dev (udev); 
-		ohci->disabled = 1;
+		disable (ohci);
 		ohci->hc_control &= ~OHCI_CTRL_HCFS;
 		writel (ohci->hc_control, &ohci->regs->control);
 		return -ENODEV;
@@ -549,8 +557,8 @@
 
 	/* cardbus/... hardware gone before remove() */
 	} else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
-		ohci->disabled++;
-		err ("%s device removed!", hcd->self.bus_name);
+		disable (ohci);
+		dbg ("%s device removed!", hcd->self.bus_name);
 		return;
 
 	/* interrupt for some other device? */
@@ -562,7 +570,7 @@
 	// dbg ("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no));
 
 	if (ints & OHCI_INTR_UE) {
-		ohci->disabled++;
+		disable (ohci);
 		err ("OHCI Unrecoverable Error, %s disabled", hcd->self.bus_name);
 		// e.g. due to PCI Master/Target Abort
 
diff -Nru a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
--- a/drivers/usb/host/ohci-hub.c	Fri Jul 26 13:47:24 2002
+++ b/drivers/usb/host/ohci-hub.c	Fri Jul 26 13:47:24 2002
@@ -22,7 +22,9 @@
  */
 #define read_roothub(hc, register, mask) ({ \
 	u32 temp = readl (&hc->regs->roothub.register); \
-	if (hc->flags & OHCI_QUIRK_AMD756) \
+	if (temp == -1) \
+		disable (hc); \
+	else if (hc->flags & OHCI_QUIRK_AMD756) \
 		while (temp & mask) \
 			temp = readl (&hc->regs->roothub.register); \
 	temp; })
@@ -71,8 +73,10 @@
 
 	ports = roothub_a (ohci) & RH_A_NDP; 
 	if (ports > MAX_ROOT_PORTS) {
-		err ("%s: bogus NDP=%d", hcd->self.bus_name, ports);
-		err ("rereads as NDP=%d",
+		if (ohci->disabled)
+			return -ESHUTDOWN;
+		err ("%s bogus NDP=%d, rereads as NDP=%d",
+			hcd->self.bus_name, ports,
 			readl (&ohci->regs->roothub.a) & RH_A_NDP);
 		/* retry later; "should not happen" */
 		return 0;
diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
--- a/drivers/usb/host/ohci-q.c	Fri Jul 26 13:47:24 2002
+++ b/drivers/usb/host/ohci-q.c	Fri Jul 26 13:47:24 2002
@@ -77,12 +77,12 @@
 	usb_hcd_giveback_urb (&ohci->hcd, urb);
 }
 
-static void td_submit_urb (struct urb *urb);
+static void td_submit_urb (struct ohci_hcd *ohci, struct urb *urb);
 
 /* Report interrupt transfer completion, maybe reissue */
-static void intr_resub (struct ohci_hcd *hc, struct urb *urb)
+static inline void intr_resub (struct ohci_hcd *hc, struct urb *urb)
 {
-	urb_priv_t	*urb_priv = urb->hcpriv;
+	struct urb_priv	*urb_priv = urb->hcpriv;
 	unsigned long	flags;
 
 // FIXME rewrite this resubmit path.  use pci_dma_sync_single()
@@ -120,7 +120,7 @@
 	spin_unlock (&urb->lock);
 
 	spin_lock (&hc->lock);
-	td_submit_urb (urb);
+	td_submit_urb (hc, urb);
 	spin_unlock_irqrestore (&hc->lock, flags);
 }
 
@@ -518,12 +518,12 @@
 /* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
 
 static void
-td_fill (struct ohci_hcd *ohci, unsigned int info,
+td_fill (unsigned int info,
 	dma_addr_t data, int len,
 	struct urb *urb, int index)
 {
 	struct td		*td, *td_pt;
-	urb_priv_t		*urb_priv = urb->hcpriv;
+	struct urb_priv		*urb_priv = urb->hcpriv;
 	int			is_iso = info & TD_ISO;
 
 	if (index >= urb_priv->length) {
@@ -582,28 +582,30 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* prepare all TDs of a transfer */
-
-static void td_submit_urb (struct urb *urb)
-{ 
-	urb_priv_t	*urb_priv = urb->hcpriv;
-	struct ohci_hcd *ohci = hcd_to_ohci (urb->dev->bus->hcpriv);
+/* Prepare all TDs of a transfer, and queue them onto the ED.
+ * Caller guarantees HC is active.
+ * Usually the ED is already on the schedule, so TDs might be
+ * processed as soon as they're queued.
+ */
+static void td_submit_urb (
+	struct ohci_hcd	*ohci,
+	struct urb	*urb
+) {
+	struct urb_priv	*urb_priv = urb->hcpriv;
 	dma_addr_t	data;
 	int		data_len = urb->transfer_buffer_length;
-	int		cnt = 0; 
-	__u32		info = 0;
-  	unsigned int	toggle = 0;
+	int		cnt = 0;
+	u32		info = 0;
 	int		is_out = usb_pipeout (urb->pipe);
 
-	/* OHCI handles the DATA-toggles itself, we just use the
-	 * USB-toggle bits for resetting
+	/* OHCI handles the bulk/interrupt data toggles itself.  We just
+	 * use the device toggle bits for resetting, and rely on the fact
+	 * that resetting toggle is meaningless if the endpoint is active.
 	 */
-  	if (usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) {
-  		toggle = TD_T_TOGGLE;
-	} else {
-  		toggle = TD_T_DATA0;
+  	if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) {
 		usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe),
 			is_out, 1);
+		urb_priv->ed->hwHeadP &= ~ED_C;
 	}
 
 	urb_priv->td_cnt = 0;
@@ -619,91 +621,88 @@
 
 	/* NOTE:  TD_CC is set so we can tell which TDs the HC processed by
 	 * using TD_CC_GET, as well as by seeing them on the done list.
+	 * (CC = NotAccessed ... 0x0F, or 0x0E in PSWs for ISO.)
 	 */
-	switch (usb_pipetype (urb->pipe)) {
-		case PIPE_BULK:
-			info = is_out
-				? TD_CC | TD_DP_OUT
-				: TD_CC | TD_DP_IN ;
-			/* TDs _could_ transfer up to 8K each */
-			while (data_len > 4096) {		
-				td_fill (ohci,
-					info | (cnt? TD_T_TOGGLE:toggle),
-					data, 4096, urb, cnt);
-				data += 4096; data_len -= 4096; cnt++;
-			}
-			/* maybe avoid ED halt on final TD short read */
-			if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
-				info |= TD_R;
-			td_fill (ohci, info | (cnt ? TD_T_TOGGLE : toggle),
-				data, data_len, urb, cnt);
+	switch (urb_priv->ed->type) {
+
+	/* Bulk and interrupt are identical except for where in the schedule
+	 * their EDs live.
+	 */
+	// case PIPE_BULK:
+	// case PIPE_INTERRUPT:
+	default:
+		info = is_out
+			? TD_T_TOGGLE | TD_CC | TD_DP_OUT
+			: TD_T_TOGGLE | TD_CC | TD_DP_IN;
+		/* TDs _could_ transfer up to 8K each */
+		while (data_len > 4096) {
+			td_fill (info, data, 4096, urb, cnt);
+			data += 4096;
+			data_len -= 4096;
 			cnt++;
-			if ((urb->transfer_flags & USB_ZERO_PACKET)
-					&& cnt < urb_priv->length) {
-				td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle),
-					0, 0, urb, cnt);
-				cnt++;
-			}
-			/* start bulk list */
-			if (!ohci->sleeping) {
-				wmb ();
-				writel (OHCI_BLF, &ohci->regs->cmdstatus);
-			}
-			break;
+		}
+		/* maybe avoid ED halt on final TD short read */
+		if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
+			info |= TD_R;
+		td_fill (info, data, data_len, urb, cnt);
+		cnt++;
+		if ((urb->transfer_flags & USB_ZERO_PACKET)
+				&& cnt < urb_priv->length) {
+			td_fill (info, 0, 0, urb, cnt);
+			cnt++;
+		}
+		/* maybe kickstart bulk list */
+		if (urb_priv->ed->type == PIPE_BULK) {
+			wmb ();
+			writel (OHCI_BLF, &ohci->regs->cmdstatus);
+		}
+		break;
 
-		case PIPE_INTERRUPT:
-			/* current policy:  only one TD per request.
-			 * otherwise identical to bulk, except for BLF
-			 */
-			info = TD_CC | toggle;
-			info |= is_out
-				?  TD_DP_OUT
-				:  TD_R | TD_DP_IN;
-			td_fill (ohci, info, data, data_len, urb, cnt++);
-			break;
-
-		case PIPE_CONTROL:
-			/* control requests don't use toggle state  */
-			info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
-			td_fill (ohci, info,
-				pci_map_single (ohci->hcd.pdev,
-						urb->setup_packet, 8,
-						PCI_DMA_TODEVICE),
-				 8, urb, cnt++); 
-			if (data_len > 0) {  
-				info = TD_CC | TD_R | TD_T_DATA1;
-				info |= is_out ? TD_DP_OUT : TD_DP_IN;
-				/* NOTE:  mishandles transfers >8K, some >4K */
-				td_fill (ohci, info, data, data_len,
-						urb, cnt++);  
-			} 
-			info = is_out
-				? TD_CC | TD_DP_IN | TD_T_DATA1
-				: TD_CC | TD_DP_OUT | TD_T_DATA1;
-			td_fill (ohci, info, data, 0, urb, cnt++);
-			/* start control list */
-			if (!ohci->sleeping) {
-				wmb ();
-				writel (OHCI_CLF, &ohci->regs->cmdstatus);
-			}
-			break;
+	/* control manages DATA0/DATA1 toggle per-request; SETUP resets it,
+	 * any DATA phase works normally, and the STATUS ack is special.
+	 */
+	case PIPE_CONTROL:
+		info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+		td_fill (info,
+			pci_map_single (ohci->hcd.pdev,
+					urb->setup_packet, 8,
+					PCI_DMA_TODEVICE),
+			 8, urb, cnt++);
+		if (data_len > 0) {
+			info = TD_CC | TD_R | TD_T_DATA1;
+			info |= is_out ? TD_DP_OUT : TD_DP_IN;
+			/* NOTE:  mishandles transfers >8K, some >4K */
+			td_fill (info, data, data_len, urb, cnt++);
+		}
+		info = is_out
+			? TD_CC | TD_DP_IN | TD_T_DATA1
+			: TD_CC | TD_DP_OUT | TD_T_DATA1;
+		td_fill (info, data, 0, urb, cnt++);
+		/* maybe kickstart control list */
+		wmb ();
+		writel (OHCI_CLF, &ohci->regs->cmdstatus);
+		break;
 
-		case PIPE_ISOCHRONOUS:
-			for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
-				int	frame = urb->start_frame;
-
-				// FIXME scheduling should handle frame counter
-				// roll-around ... exotic case (and OHCI has
-				// a 2^16 iso range, vs other HCs max of 2^10)
-				frame += cnt * urb->interval;
-				frame &= 0xffff;
-				td_fill (ohci, TD_CC | TD_ISO | frame,
-				    data + urb->iso_frame_desc [cnt].offset, 
-				    urb->iso_frame_desc [cnt].length, urb, cnt); 
-			}
-			break;
-	} 
-	if (urb_priv->length != cnt) 
+	/* ISO has no retransmit, so no toggle; and it uses special TDs.
+	 * Each TD could handle multiple consecutive frames (interval 1);
+	 * we could often reduce the number of TDs here.
+	 */
+	case PIPE_ISOCHRONOUS:
+		for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
+			int	frame = urb->start_frame;
+
+			// FIXME scheduling should handle frame counter
+			// roll-around ... exotic case (and OHCI has
+			// a 2^16 iso range, vs other HCs max of 2^10)
+			frame += cnt * urb->interval;
+			frame &= 0xffff;
+			td_fill (TD_CC | TD_ISO | frame,
+				data + urb->iso_frame_desc [cnt].offset,
+				urb->iso_frame_desc [cnt].length, urb, cnt);
+		}
+		break;
+	}
+	if (urb_priv->length != cnt)
 		dbg ("TD LENGTH %d != CNT %d", urb_priv->length, cnt);
 }
 
@@ -724,8 +723,10 @@
  		u16	tdPSW = le16_to_cpu (td->hwPSW [0]);
 		int	dlen = 0;
 
+		/* NOTE:  assumes FC in tdINFO == 0 (and MAXPSW == 1) */
+
  		cc = (tdPSW >> 12) & 0xF;
-		if (cc >= 0x0E)			/* hc didn't touch? */
+  		if (tdINFO & TD_CC)	/* hc didn't touch? */
 			return;
 
 		if (usb_pipeout (urb->pipe))
diff -Nru a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
--- a/drivers/usb/host/ohci.h	Fri Jul 26 13:47:24 2002
+++ b/drivers/usb/host/ohci.h	Fri Jul 26 13:47:24 2002
@@ -401,5 +401,5 @@
 	struct usb_hcd		hcd;
 };
 
-#define hcd_to_ohci(hcd_ptr) list_entry(hcd_ptr, struct ohci_hcd, hcd)
+#define hcd_to_ohci(hcd_ptr) container_of(hcd_ptr, struct ohci_hcd, hcd)
 
