From: Greg KH <greg@kroah.com>
To: torvalds@transmeta.com
Cc: linux-usb-devel@lists.sourceforge.net
Subject: [PATCH 9 of 9] USB ohci-hcd driver update

Hi,

Here's a patch against 2.5.3 for the USB ohci-hcd driver that does the
following:
	- doesn't assume CONFIG_DEBUG_SLAB
	- unlink from interrupt completions now work
	- doesn't force debugging on
	- updated copyright / license statements
	- slightly smaller object size
	- fewer inlined magic numbers
	- removes unused fields from data structures
	- header file reorg, doc fixup
This patch was done by David Brownell.

thanks,

greg k-h



diff -Nru a/drivers/usb/hcd/ohci-dbg.c b/drivers/usb/hcd/ohci-dbg.c
--- a/drivers/usb/hcd/ohci-dbg.c	Sun Feb  3 00:53:05 2002
+++ b/drivers/usb/hcd/ohci-dbg.c	Sun Feb  3 00:53:05 2002
@@ -2,9 +2,9 @@
  * OHCI HCD (Host Controller Driver) for USB.
  * 
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
- * This file is licenced under GPL
+ * This file is licenced under the GPL.
  * $Id: ohci-dbg.c,v 1.2 2002/01/19 00:15:45 dbrownell Exp $
  */
  
@@ -74,27 +74,34 @@
 static inline struct ed *
 dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma);
 
+#ifdef OHCI_VERBOSE_DEBUG
 /* print non-empty branches of the periodic ed tree */
-void ep_print_int_eds (struct ohci_hcd *ohci, char * str)
+void ohci_dump_periodic (struct ohci_hcd *ohci, char *label)
 {
 	int i, j;
-	 __u32 * ed_p;
+	u32 *ed_p;
+	int printed = 0;
+
 	for (i= 0; i < 32; i++) {
 		j = 5;
 		ed_p = &(ohci->hcca->int_table [i]);
 		if (*ed_p == 0)
-		    continue;
-		printk (KERN_DEBUG __FILE__ ": %s branch int %2d(%2x):",
-				str, i, i);
+			continue;
+		printed = 1;
+		printk (KERN_DEBUG "%s, ohci %s frame %2d:",
+				label, ohci->hcd.bus_name, i);
 		while (*ed_p != 0 && j--) {
 			struct ed *ed = dma_to_ed (ohci, le32_to_cpup(ed_p));
-			printk (" ed: %4x;", ed->hwINFO);
+			printk (" %p/%08x;", ed, ed->hwINFO);
 			ed_p = &ed->hwNextED;
 		}
 		printk ("\n");
 	}
+	if (!printed)
+		printk (KERN_DEBUG "%s, ohci %s, empty periodic schedule\n",
+				label, ohci->hcd.bus_name);
 }
-
+#endif
 
 static void ohci_dump_intr_mask (char *label, __u32 mask)
 {
@@ -137,8 +144,9 @@
 	__u32			temp;
 
 	temp = readl (&regs->revision) & 0xff;
-	if (temp != 0x10)
-		dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+	dbg ("OHCI %d.%d, %s legacy support registers",
+		0x03 & (temp >> 4), (temp & 0x0f),
+		(temp & 0x10) ? "with" : "NO");
 
 	temp = readl (&regs->control);
 	dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
@@ -225,8 +233,10 @@
 
 	// dumps some of the state we know about
 	ohci_dump_status (controller);
+#ifdef OHCI_VERBOSE_DEBUG
 	if (verbose)
-		ep_print_int_eds (controller, "hcca");
+		ohci_dump_periodic (controller, "hcca");
+#endif
 	dbg ("hcca frame #%04x", controller->hcca->frame_no);
 	ohci_dump_roothub (controller, 1);
 }
diff -Nru a/drivers/usb/hcd/ohci-hcd.c b/drivers/usb/hcd/ohci-hcd.c
--- a/drivers/usb/hcd/ohci-hcd.c	Sun Feb  3 00:53:05 2002
+++ b/drivers/usb/hcd/ohci-hcd.c	Sun Feb  3 00:53:05 2002
@@ -2,7 +2,7 @@
  * OHCI HCD (Host Controller Driver) for USB.
  *
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
  * [ Initialisation is based on Linus'  ]
  * [ uhci code and gregs ohci fragments ]
@@ -55,7 +55,7 @@
  * v2.0 1999/05/04 
  * v1.0 1999/04/27 initial release
  *
- * This file is licenced under GPL
+ * This file is licenced under the GPL.
  * $Id: ohci-hcd.c,v 1.7 2002/01/19 00:20:56 dbrownell Exp $
  */
  
@@ -74,10 +74,6 @@
 #include <linux/list.h>
 #include <linux/interrupt.h>  /* for in_interrupt () */
 
-#ifndef CONFIG_USB_DEBUG
-	#define CONFIG_USB_DEBUG	/* this is still experimental! */
-#endif
-
 #ifdef CONFIG_USB_DEBUG
 	#define DEBUG
 #else
@@ -258,7 +254,9 @@
 	if (ed->state != ED_OPER)
 		ep_link (ohci, ed);
 
-	/* fill the TDs and link it to the ed */
+	/* fill the TDs and link them to the ed; and
+	 * enable that part of the schedule, if needed
+	 */
 	td_submit_urb (urb);
 
 	spin_unlock_irqrestore (&ohci->lock, flags);
@@ -357,7 +355,9 @@
 {
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 
+#ifdef	OHCI_VERBOSE_DEBUG
 	dbg ("%s: ohci_get_frame", hcd->bus_name);
+#endif
 	return le16_to_cpu (ohci->hcca->frame_no);
 }
 
@@ -841,9 +847,10 @@
 			dl_done_list (ohci, dl_reverse_done_list (ohci));
 		writel (OHCI_INTR_WDH, &ohci->regs->intrenable); 
 
-//		writel (OHCI_BLF, &ohci->regs->cmdstatus);
-//		writel (OHCI_CLF, &ohci->regs->cmdstatus);
-ohci_dump_status (ohci);
+		/* assume there are TDs on the bulk and control lists */
+		writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus);
+
+// ohci_dump_status (ohci);
 dbg ("sleeping = %d, disabled = %d", ohci->sleeping, ohci->disabled);
 		break;
 
diff -Nru a/drivers/usb/hcd/ohci-hub.c b/drivers/usb/hcd/ohci-hub.c
--- a/drivers/usb/hcd/ohci-hub.c	Sun Feb  3 00:53:05 2002
+++ b/drivers/usb/hcd/ohci-hub.c	Sun Feb  3 00:53:05 2002
@@ -2,7 +2,7 @@
  * OHCI HCD (Host Controller Driver) for USB.
  * 
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
  * This file is licenced under GPL
  * $Id: ohci-hub.c,v 1.2 2002/01/19 00:21:49 dbrownell Exp $
diff -Nru a/drivers/usb/hcd/ohci-mem.c b/drivers/usb/hcd/ohci-mem.c
--- a/drivers/usb/hcd/ohci-mem.c	Sun Feb  3 00:53:04 2002
+++ b/drivers/usb/hcd/ohci-mem.c	Sun Feb  3 00:53:04 2002
@@ -2,9 +2,9 @@
  * OHCI HCD (Host Controller Driver) for USB.
  * 
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
- * This file is licenced under GPL
+ * This file is licenced under the GPL.
  * $Id: ohci-mem.c,v 1.2 2002/01/19 00:22:13 dbrownell Exp $
  */
 
@@ -42,7 +42,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef DEBUG
+#ifdef	CONFIG_DEBUG_SLAB
 #	define OHCI_MEM_FLAGS	SLAB_POISON
 #else
 #	define OHCI_MEM_FLAGS	0
@@ -64,16 +64,17 @@
 	return scan->virt;
 }
 
-static inline struct ed *
+static struct ed *
 dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma)
 {
 	return (struct ed *) dma_to_ed_td(&(hc->ed_hash [ED_HASH_FUNC(ed_dma)]),
 				      ed_dma);
 }
 
-static inline struct td *
+static struct td *
 dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma)
 {
+	td_dma &= TD_MASK;
 	return (struct td *) dma_to_ed_td(&(hc->td_hash [TD_HASH_FUNC(td_dma)]),
 				      td_dma);
 }
@@ -214,7 +215,7 @@
 	return td;
 }
 
-static inline void
+static void
 td_free (struct ohci_hcd *hc, struct td *td)
 {
 	hash_free_td (hc, td);
@@ -242,7 +243,7 @@
 	return ed;
 }
 
-static inline void
+static void
 ed_free (struct ohci_hcd *hc, struct ed *ed)
 {
 	hash_free_ed (hc, ed);
diff -Nru a/drivers/usb/hcd/ohci-q.c b/drivers/usb/hcd/ohci-q.c
--- a/drivers/usb/hcd/ohci-q.c	Sun Feb  3 00:53:03 2002
+++ b/drivers/usb/hcd/ohci-q.c	Sun Feb  3 00:53:03 2002
@@ -2,9 +2,9 @@
  * OHCI HCD (Host Controller Driver) for USB.
  * 
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
- * This file is licenced under GPL
+ * This file is licenced under the GPL.
  * $Id: ohci-q.c,v 1.6 2002/01/19 00:23:15 dbrownell Exp $
  */
  
@@ -95,11 +95,11 @@
 	urb_print (urb, "RET", usb_pipeout (urb->pipe));
 #endif
 
-// FIXME:  but if urb->status says it was was unlinked ...
-
 	switch (usb_pipetype (urb->pipe)) {
   		case PIPE_INTERRUPT:
 #ifdef CONFIG_PCI
+// FIXME rewrite this resubmit path.  use pci_dma_sync_single()
+// and requeue more cheaply, and only if needed.
 			pci_unmap_single (hc->hcd.pdev,
 				urb_priv->td [0]->data_dma,
 				urb->transfer_buffer_length,
@@ -107,16 +107,22 @@
 					? PCI_DMA_TODEVICE
 					: PCI_DMA_FROMDEVICE);
 #endif
+			/* FIXME: MP race.  If another CPU partially unlinks
+			 * this URB (urb->status was updated, hasn't yet told
+			 * us to dequeue) before we call complete() here, an
+			 * extra "unlinked" completion will be reported...
+			 */
 			urb->complete (urb);
 
-			/* implicitly requeued */
+			/* always requeued, but ED_SKIP if complete() unlinks.
+			 * removed from periodic table only at SOF intr.
+			 */
   			urb->actual_length = 0;
-  			urb->status = -EINPROGRESS;
-  			if (urb_priv->state != URB_DEL) {
-				spin_lock_irqsave (&hc->lock, flags);
-  				td_submit_urb (urb);
-  				spin_unlock_irqrestore (&hc->lock, flags);
-			}
+			if (urb_priv->state != URB_DEL)
+				urb->status = -EINPROGRESS;
+			spin_lock_irqsave (&hc->lock, flags);
+			td_submit_urb (urb);
+			spin_unlock_irqrestore (&hc->lock, flags);
   			break;
 
 		case PIPE_ISOCHRONOUS:
@@ -126,7 +132,7 @@
 				continue;
 			if (urbt) { /* send the reply and requeue URB */	
 #ifdef CONFIG_PCI
-// FIXME this style unmap is only done on this route ...
+// FIXME rewrite this resubmit path too
 				pci_unmap_single (hc->hcd.pdev,
 					urb_priv->td [0]->data_dma,
 					urb->transfer_buffer_length,
@@ -290,8 +296,8 @@
 			ed->hwNextED = *ed_p; 
 			*ed_p = cpu_to_le32 (ed->dma);
 		}
-#ifdef DEBUG
-		ep_print_int_eds (ohci, "LINK_INT");
+#ifdef OHCI_VERBOSE_DEBUG
+		ohci_dump_periodic (ohci, "LINK_INT");
 #endif
 		break;
 
@@ -313,8 +319,8 @@
 			ed->ed_prev = NULL;
 		}	
 		ohci->ed_isotail = edi;  
-#ifdef DEBUG
-		ep_print_int_eds (ohci, "LINK_ISO");
+#ifdef OHCI_VERBOSE_DEBUG
+		ohci_dump_periodic (ohci, "LINK_ISO");
 #endif
 		break;
 	}	 	
@@ -336,7 +342,7 @@
 	int	interval;
 	__u32	*ed_p;
 
-	ed->hwINFO |= __constant_cpu_to_le32 (OHCI_ED_SKIP);
+	ed->hwINFO |= ED_SKIP;
 
 	switch (ed->type) {
 	case PIPE_CONTROL:
@@ -394,8 +400,8 @@
 		}
 		for (i = int_branch; i < NUM_INTS; i += interval)
 		    ohci->ohci_int_load [i] -= ed->int_load;
-#ifdef DEBUG
-		ep_print_int_eds (ohci, "UNLINK_INT");
+#ifdef OHCI_VERBOSE_DEBUG
+		ohci_dump_periodic (ohci, "UNLINK_INT");
 #endif
 		break;
 
@@ -421,11 +427,15 @@
 				}
 			}	
 		}	
-#ifdef DEBUG
-		ep_print_int_eds (ohci, "UNLINK_ISO");
+#ifdef OHCI_VERBOSE_DEBUG
+		ohci_dump_periodic (ohci, "UNLINK_ISO");
 #endif
 		break;
 	}
+
+	/* FIXME ED's "unlink" state is indeterminate;
+	 * the HC might still be caching it (till SOF).
+	 */
 	ed->state = ED_UNLINK;
 	return 0;
 }
@@ -478,7 +488,7 @@
 	}
 
 	if (ed->state == ED_NEW) {
-		ed->hwINFO = __constant_cpu_to_le32 (OHCI_ED_SKIP);
+		ed->hwINFO = ED_SKIP;
   		/* dummy td; end of td list for ed */
 		td = td_alloc (ohci, SLAB_ATOMIC);
  		if (!td) {
@@ -492,8 +502,6 @@
 		ed->type = usb_pipetype (pipe);
 	}
 
-	ohci->dev [usb_pipedevice (pipe)] = udev;
-
 // FIXME:  don't do this if it's linked to the HC,
 // we might clobber data toggle or other state ...
 
@@ -531,7 +539,7 @@
 		return;
 	ed->state |= ED_URB_DEL;
 
-	ed->hwINFO |= __constant_cpu_to_le32 (OHCI_ED_SKIP);
+	ed->hwINFO |= ED_SKIP;
 
 	switch (ed->type) {
 		case PIPE_CONTROL: /* stop control list */
@@ -582,7 +590,7 @@
 
 	/* fill the old dummy TD */
 	td = urb_priv->td [index] = dma_to_td (ohci,
-			le32_to_cpup (&urb_priv->ed->hwTailP) & ~0xf);
+			le32_to_cpup (&urb_priv->ed->hwTailP));
 
 	td->ed = urb_priv->ed;
 	td->next_dl_td = NULL;
@@ -795,7 +803,7 @@
 
   	spin_lock_irqsave (&ohci->lock, flags);
 
-	td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0;
+	td_list_hc = le32_to_cpup (&ohci->hcca->done_head);
 	ohci->hcca->done_head = 0;
 
 	while (td_list_hc) {		
@@ -806,26 +814,24 @@
 			dbg (" USB-error/status: %x : %p", 
 				TD_CC_GET (le32_to_cpup (&td_list->hwINFO)),
 				td_list);
-			if (td_list->ed->hwHeadP
-					& __constant_cpu_to_le32 (0x1)) {
+			/* typically the endpoint halted too */
+			if (td_list->ed->hwHeadP & ED_H) {
 				if (urb_priv && ((td_list->index + 1)
 						< urb_priv->length)) {
 					td_list->ed->hwHeadP = 
 			    (urb_priv->td [urb_priv->length - 1]->hwNextTD
-				    & __constant_cpu_to_le32 (0xfffffff0))
-			    | (td_list->ed->hwHeadP
-				    & __constant_cpu_to_le32 (0x2));
+				    & __constant_cpu_to_le32 (TD_MASK))
+			    | (td_list->ed->hwHeadP & ED_C);
 					urb_priv->td_cnt += urb_priv->length
 						- td_list->index - 1;
 				} else 
-					td_list->ed->hwHeadP &=
-					__constant_cpu_to_le32 (0xfffffff2);
+					td_list->ed->hwHeadP &= ~ED_H;
 			}
 		}
 
 		td_list->next_dl_td = td_rev;	
 		td_rev = td_list;
-		td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0;	
+		td_list_hc = le32_to_cpup (&td_list->hwNextTD);
 	}	
 	spin_unlock_irqrestore (&ohci->lock, flags);
 	return td_list;
@@ -851,10 +857,8 @@
 
 	for (ed = ohci->ed_rm_list [frame]; ed != NULL; ed = ed->ed_rm_list) {
 
-		tdTailP = dma_to_td (ohci,
-			le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
-		tdHeadP = dma_to_td (ohci,
-			le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
+		tdTailP = dma_to_td (ohci, le32_to_cpup (&ed->hwTailP));
+		tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP));
 		edINFO = le32_to_cpup (&ed->hwINFO);
 		td_p = &ed->hwHeadP;
 
@@ -863,7 +867,7 @@
 			urb_priv_t *urb_priv = td->urb->hcpriv;
 
 			td_next = dma_to_td (ohci,
-				le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
+				le32_to_cpup (&td->hwNextTD));
 			if ((urb_priv->state == URB_DEL)) {
 				tdINFO = le32_to_cpup (&td->hwINFO);
 				if (TD_CC_GET (tdINFO) < 0xE)
@@ -882,17 +886,16 @@
 		}
 
 		ed->state &= ~ED_URB_DEL;
-		tdHeadP = dma_to_td (ohci,
-			le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
+		tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP));
 
 		if (tdHeadP == tdTailP) {
 			if (ed->state == ED_OPER)
 				ep_unlink (ohci, ed);
 			td_free (ohci, tdTailP);
-			ed->hwINFO = __constant_cpu_to_le32 (OHCI_ED_SKIP);
+			ed->hwINFO = ED_SKIP;
 			ed->state = ED_NEW;
 		} else
-			ed->hwINFO &= ~__constant_cpu_to_le32 (OHCI_ED_SKIP);
+			ed->hwINFO &= ~ED_SKIP;
 
 		switch (ed->type) {
 			case PIPE_CONTROL:
@@ -938,7 +941,7 @@
 	int		cc = 0;
 	struct urb	*urb;
 	urb_priv_t	*urb_priv;
- 	__u32		tdINFO, edHeadP, edTailP;
+ 	__u32		tdINFO;
 
  	unsigned long flags;
 
@@ -968,7 +971,7 @@
 			/*
 			 * Except for periodic transfers, both branches do
 			 * the same thing.  Periodic urbs get reissued until
-			 * they're "deleted" with usb_unlink_urb.
+			 * they're "deleted" (in SOF intr) by usb_unlink_urb.
 			 */
 			if ((ed->state & (ED_OPER | ED_UNLINK))
 					&& (urb_priv->state != URB_DEL)) {
@@ -983,13 +986,11 @@
 
   		spin_lock_irqsave (&ohci->lock, flags);
   		if (ed->state != ED_NEW) { 
-  			edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0;
-  			edTailP = le32_to_cpup (&ed->hwTailP);
-
-// FIXME:  ED_UNLINK is very fuzzy w.r.t. what the hc knows...
+  			u32 edHeadP = ed->hwHeadP;
 
 			/* unlink eds if they are not busy */
-     			if ((edHeadP == edTailP) && (ed->state == ED_OPER)) 
+			edHeadP &= __constant_cpu_to_le32 (ED_MASK);
+     			if ((edHeadP == ed->hwTailP) && (ed->state == ED_OPER)) 
      				ep_unlink (ohci, ed);
      		}	
      		spin_unlock_irqrestore (&ohci->lock, flags);
diff -Nru a/drivers/usb/hcd/ohci.h b/drivers/usb/hcd/ohci.h
--- a/drivers/usb/hcd/ohci.h	Sun Feb  3 00:53:05 2002
+++ b/drivers/usb/hcd/ohci.h	Sun Feb  3 00:53:05 2002
@@ -2,86 +2,102 @@
  * OHCI HCD (Host Controller Driver) for USB.
  * 
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
- * This file is licenced under GPL
+ * This file is licenced under the GPL.
  * $Id: ohci.h,v 1.5 2002/01/19 00:24:01 dbrownell Exp $
  */
  
-static const int cc_to_error [16] = { 
-
-/* map OHCI status to errno values */ 
-	/* No  Error  */               0,
-	/* CRC Error  */               -EILSEQ,
-	/* Bit Stuff  */               -EPROTO,
-	/* Data Togg  */               -EILSEQ,
-	/* Stall      */               -EPIPE,
-	/* DevNotResp */               -ETIMEDOUT,
-	/* PIDCheck   */               -EPROTO,
-	/* UnExpPID   */               -EPROTO,
-	/* DataOver   */               -EOVERFLOW,
-	/* DataUnder  */               -EREMOTEIO,
-	/* (for hw)   */               -EIO,
-	/* (for hw)   */               -EIO,
-	/* BufferOver */               -ECOMM,
-	/* BuffUnder  */               -ENOSR,
-	/* (for HCD)  */               -EALREADY,
-	/* (for HCD)  */               -EALREADY 
-};
-
-
-/* ED States */
-
+/*
+ * OHCI Endpoint Descriptor (ED) ... holds TD queue
+ * See OHCI spec, section 4.2
+ */
+struct ed {
+	/* first fields are hardware-specified, le32 */
+	__u32			hwINFO;       	/* endpoint config bitmap */
+#define ED_ISO		__constant_cpu_to_le32(1 << 15)
+#define ED_SKIP		__constant_cpu_to_le32(1 << 14)
+#define ED_LOWSPEED	__constant_cpu_to_le32(1 << 13)
+#define ED_OUT		__constant_cpu_to_le32(0x01 << 11)
+#define ED_IN		__constant_cpu_to_le32(0x10 << 11)
+	__u32			hwTailP;	/* tail of TD list */
+	__u32			hwHeadP;	/* head of TD list */
+#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 */
+
+	/* rest are purely for the driver's use */
+	struct ed		*ed_prev;  
+	__u8			int_period;
+	__u8			int_branch;
+	__u8			int_load; 
+	__u8			int_interval;
+	__u8			state;			// ED_{NEW,UNLINK,OPER}
 #define ED_NEW 		0x00		/* unused, no dummy td */
 #define ED_UNLINK 	0x01		/* dummy td, maybe linked to hc */
 #define ED_OPER		0x02		/* dummy td, _is_ linked to hc */
+#define ED_URB_DEL  	0x08		/* for unlinking; masked in */
 
-#define ED_URB_DEL  	0x08		/* masked in */
+	__u8			type; 
+	__u16			last_iso;
+	struct ed		*ed_rm_list;
 
-/* usb_ohci_ed */
-struct ed {
-	/* first fields are hardware-specified */
-	__u32 hwINFO;       
-	__u32 hwTailP;
-	__u32 hwHeadP;
-	__u32 hwNextED;
-
-	struct ed * ed_prev;  
-	__u8 int_period;
-	__u8 int_branch;
-	__u8 int_load; 
-	__u8 int_interval;
-	__u8 state;			// ED_{NEW,UNLINK,OPER}
-	__u8 type; 
-	__u16 last_iso;
-	struct ed * ed_rm_list;
-
-	dma_addr_t dma;
-	__u32 unused [3];
-} __attribute((aligned(16)));
+	dma_addr_t		dma;			/* addr of ED */
+} __attribute__ ((aligned(16)));
+
+#define ED_MASK	((u32)~0x0f)		/* strip hw status in low addr bits */
 
  
-/* TD info field */
-#define TD_CC       0xf0000000
+/*
+ * OHCI Transfer Descriptor (TD) ... one per transfer segment
+ * See OHCI spec, sections 4.3.1 (general = control/bulk/interrupt)
+ * and 4.3.2 (iso)
+ */
+struct td {
+	/* first fields are hardware-specified, le32 */
+	__u32		hwINFO;		/* transfer info bitmask */
+#define TD_CC       0xf0000000			/* condition code */
 #define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
-#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
-#define TD_EC       0x0C000000
-#define TD_T        0x03000000
-#define TD_T_DATA0  0x02000000
-#define TD_T_DATA1  0x03000000
-#define TD_T_TOGGLE 0x00000000
-#define TD_R        0x00040000
-#define TD_DI       0x00E00000
-#define TD_DI_SET(X) (((X) & 0x07)<< 21)
-#define TD_DP       0x00180000
-#define TD_DP_SETUP 0x00000000
-#define TD_DP_IN    0x00100000
-#define TD_DP_OUT   0x00080000
+//#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_EC       0x0C000000			/* error count */
+#define TD_T        0x03000000			/* data toggle state */
+#define TD_T_DATA0  0x02000000				/* DATA0 */
+#define TD_T_DATA1  0x03000000				/* DATA1 */
+#define TD_T_TOGGLE 0x00000000				/* uses ED_C */
+#define TD_DI       0x00E00000			/* frames before interrupt */
+//#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP       0x00180000			/* direction/pid */
+#define TD_DP_SETUP 0x00000000			/* SETUP pid */
+#define TD_DP_IN    0x00100000				/* IN pid */
+#define TD_DP_OUT   0x00080000				/* OUT pid */
+							/* 0x00180000 rsvd */
+#define TD_R        0x00040000			/* round: short packets OK? */
+					/* bits 0x1ffff are defined by HCD */
+#define TD_ISO	    0x00010000			/* copy of ED_ISO */
+
+  	__u32		hwCBP;		/* Current Buffer Pointer (or 0) */
+  	__u32		hwNextTD;	/* Next TD Pointer */
+  	__u32		hwBE;		/* Memory Buffer End Pointer */
+
+	/* PSW is only for ISO */
+#define MAXPSW 1		/* hardware allows 8 */
+  	__u16		hwPSW [MAXPSW];
 
-#define TD_ISO	    0x00010000
-#define TD_DEL      0x00020000
+	/* rest are purely for the driver's use */
+  	__u8		index;
+  	struct ed	*ed;
+  	struct td	*next_dl_td;
+  	struct urb	*urb;
 
-/* CC Codes */
+	dma_addr_t	td_dma;		/* addr of this TD */
+	dma_addr_t	data_dma;	/* addr of data it points to */
+} __attribute__ ((aligned(32)));	/* c/b/i need 16; only iso needs 32 */
+
+#define TD_MASK	((u32)~0x1f)		/* strip hw status in low addr bits */
+
+/*
+ * Hardware transfer status codes -- CC from td->hwINFO or td->hwPSW
+ */
 #define TD_CC_NOERROR      0x00
 #define TD_CC_CRC          0x01
 #define TD_CC_BITSTUFFING  0x02
@@ -99,57 +115,50 @@
 #define TD_NOTACCESSED     0x0F
 
 
-#define MAXPSW 1
-
-struct td {
-	/* first hardware fields are in all tds */
-	__u32		hwINFO;
-  	__u32		hwCBP;		/* Current Buffer Pointer */
-  	__u32		hwNextTD;	/* Next TD Pointer */
-  	__u32		hwBE;		/* Memory Buffer End Pointer */
-
-  	__u16		hwPSW [MAXPSW];	/* PSW is only for ISO */
-
-  	__u8		unused;
-  	__u8		index;
-  	struct ed	*ed;
-  	struct td	*next_dl_td;
-  	struct urb	*urb;
-
-	dma_addr_t	td_dma;
-	dma_addr_t	data_dma;
-	__u32		unused2 [2];
-} __attribute((aligned(32)));		/* iso needs 32 */
+/* map OHCI TD status codes (CC) to errno values */ 
+static const int cc_to_error [16] = { 
+	/* No  Error  */               0,
+	/* CRC Error  */               -EILSEQ,
+	/* Bit Stuff  */               -EPROTO,
+	/* Data Togg  */               -EILSEQ,
+	/* Stall      */               -EPIPE,
+	/* DevNotResp */               -ETIMEDOUT,
+	/* PIDCheck   */               -EPROTO,
+	/* UnExpPID   */               -EPROTO,
+	/* DataOver   */               -EOVERFLOW,
+	/* DataUnder  */               -EREMOTEIO,
+	/* (for hw)   */               -EIO,
+	/* (for hw)   */               -EIO,
+	/* BufferOver */               -ECOMM,
+	/* BuffUnder  */               -ENOSR,
+	/* (for HCD)  */               -EALREADY,
+	/* (for HCD)  */               -EALREADY 
+};
 
-#define OHCI_ED_SKIP	(1 << 14)
 
 /*
  * The HCCA (Host Controller Communications Area) is a 256 byte
- * structure defined in the OHCI spec. The host controller is
+ * structure defined section 4.4.1 of the OHCI spec. The HC is
  * told the base address of it.  It must be 256-byte aligned.
  */
-#define NUM_INTS 32	/* part of the OHCI standard */
 struct ohci_hcca {
-	__u32	int_table [NUM_INTS];	/* Interrupt ED table */
+#define NUM_INTS 32
+	__u32	int_table [NUM_INTS];	/* periodic schedule */
 	__u16	frame_no;		/* current frame number */
 	__u16	pad1;			/* set to 0 on each frame_no change */
 	__u32	done_head;		/* info returned for an interrupt */
 	u8	reserved_for_hc [116];
-} __attribute((aligned(256)));
+	u8	what [4];		/* spec only identifies 252 bytes :) */
+} __attribute__ ((aligned(256)));
 
   
 /*
- * Maximum number of root hub ports.  
- */
-#define MAX_ROOT_PORTS	15	/* maximum OHCI root hub ports */
-
-/*
- * This is the structure of the OHCI controller's memory mapped I/O
- * region.  This is Memory Mapped I/O.  You must use the readl() and
- * writel() macros defined in asm/io.h to access these!!
+ * This is the structure of the OHCI controller's memory mapped I/O region.
+ * You must use readl() and writel() (in <asm/io.h>) to access these fields!!
+ * Layout is in section 7 (and appendix B) of the spec.
  */
 struct ohci_regs {
-	/* control and status registers */
+	/* control and status registers (section 7.1) */
 	__u32	revision;
 	__u32	control;
 	__u32	cmdstatus;
@@ -157,7 +166,7 @@
 	__u32	intrenable;
 	__u32	intrdisable;
 
-	/* memory pointers */
+	/* memory pointers (section 7.2) */
 	__u32	hcca;
 	__u32	ed_periodcurrent;
 	__u32	ed_controlhead;
@@ -166,23 +175,25 @@
 	__u32	ed_bulkcurrent;
 	__u32	donehead;
 
-	/* frame counters */
+	/* frame counters (section 7.3) */
 	__u32	fminterval;
 	__u32	fmremaining;
 	__u32	fmnumber;
 	__u32	periodicstart;
 	__u32	lsthresh;
 
-	/* Root hub ports */
+	/* Root hub ports (section 7.4) */
 	struct	ohci_roothub_regs {
 		__u32	a;
 		__u32	b;
 		__u32	status;
+#define MAX_ROOT_PORTS	15	/* maximum OHCI root hub ports (RH_A_NDP) */
 		__u32	portstatus [MAX_ROOT_PORTS];
 	} roothub;
 
-	/* and some optional registers for legacy compatibility */
-} __attribute((aligned(32)));
+	/* and optional "legacy support" registers (appendix B) at 0x0100 */
+
+} __attribute__ ((aligned(32)));
 
 
 /* OHCI CONTROL AND STATUS REGISTER MASKS */
@@ -270,9 +281,8 @@
 #define	RH_A_POTPGT	(0xff << 24)		/* power on to power good time */
 
 
-/* urb */
-typedef struct urb_priv
-{
+/* hcd-private per-urb state */
+typedef struct urb_priv {
 	struct ed		*ed;
 	__u16			length;		// # tds in this request
 	__u16			td_cnt;		// tds already serviced
@@ -345,7 +355,6 @@
 	int			sleeping;
 	int			ohci_int_load [NUM_INTS];
 	u32 			hc_control;	/* copy of hc control reg */
-	struct usb_device	*dev [128];
 
 	unsigned long		flags;		/* for HC bugs */
 #define	OHCI_QUIRK_AMD756	0x01			/* erratum #4 */
