]> git.hungrycats.org Git - linux/commitdiff
[PATCH] USB ohci-hcd driver update
authorGreg Kroah-Hartman <greg@kroah.com>
Tue, 5 Feb 2002 09:17:24 +0000 (01:17 -0800)
committerGreg Kroah-Hartman <greg@kroah.com>
Tue, 5 Feb 2002 09:17:24 +0000 (01:17 -0800)
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.

drivers/usb/hcd/ohci-dbg.c
drivers/usb/hcd/ohci-hcd.c
drivers/usb/hcd/ohci-hub.c
drivers/usb/hcd/ohci-mem.c
drivers/usb/hcd/ohci-q.c
drivers/usb/hcd/ohci.h

index 350ae3b6d9e02ef9466529d4959bf413f0a2c53d..7984b00ff11bbded7db444f398a5106982e061dd 100644 (file)
@@ -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 void urb_print (struct urb * urb, char * str, int small)
 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 @@ static void ohci_dump_status (struct ohci_hcd *controller)
        __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 @@ static void ohci_dump (struct ohci_hcd *controller, int verbose)
 
        // 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);
 }
index 0f14a6001ce3bd91204ceacec2256204751769dd..48576302f49ba6a52b3874ea6ea84e072e3f6015 100644 (file)
@@ -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 $
  */
  
 #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 @@ static int ohci_urb_enqueue (
        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 @@ static int ohci_get_frame (struct usb_hcd *hcd)
 {
        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 +841,10 @@ static int ohci_resume (struct usb_hcd *hcd)
                        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;
 
index f54fcd4f3eb9040ac995af9df59e0e2954b988da..879e1abc036c7695bdee913e524b80ca1fa6cbee 100644 (file)
@@ -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 $
index e41c7bdeac3b0c1cb96cdc41486d4011681c1e51..b775c71114d03ec142b17c56cf3a27995202bfb6 100644 (file)
@@ -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 @@ static void ohci_hcd_free (struct usb_hcd *hcd)
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef DEBUG
+#ifdef CONFIG_DEBUG_SLAB
 #      define OHCI_MEM_FLAGS   SLAB_POISON
 #else
 #      define OHCI_MEM_FLAGS   0
@@ -64,16 +64,17 @@ dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma)
        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 @@ td_alloc (struct ohci_hcd *hc, int mem_flags)
        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 @@ ed_alloc (struct ohci_hcd *hc, int mem_flags)
        return ed;
 }
 
-static inline void
+static void
 ed_free (struct ohci_hcd *hc, struct ed *ed)
 {
        hash_free_ed (hc, ed);
index f89cdc55455967448449ade47db556998436d1c4..642e84b7a023f38a41b17fff8e9cd1a91d7c4b30 100644 (file)
@@ -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 @@ static int return_urb (struct ohci_hcd *hc, struct urb *urb)
        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 @@ static int return_urb (struct ohci_hcd *hc, struct urb *urb)
                                        ? 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 @@ static int return_urb (struct ohci_hcd *hc, struct urb *urb)
                                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 @@ static int ep_link (struct ohci_hcd *ohci, struct ed *edi)
                        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 @@ static int ep_link (struct ohci_hcd *ohci, struct ed *edi)
                        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 @@ static int ep_unlink (struct ohci_hcd *ohci, struct ed *ed)
        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 @@ static int ep_unlink (struct ohci_hcd *ohci, struct ed *ed)
                }
                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 @@ static int ep_unlink (struct ohci_hcd *ohci, struct ed *ed)
                                }
                        }       
                }       
-#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 @@ static struct ed *ep_add_ed (
        }
 
        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 @@ static struct ed *ep_add_ed (
                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 @@ static void ed_unlink (struct usb_device *usb_dev, struct ed *ed)
                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 @@ td_fill (struct ohci_hcd *ohci, unsigned int info,
 
        /* 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 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
 
        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 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
                        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 @@ static void dl_del_list (struct ohci_hcd *ohci, unsigned int frame)
 
        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 @@ static void dl_del_list (struct ohci_hcd *ohci, unsigned int frame)
                        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 @@ static void dl_del_list (struct ohci_hcd *ohci, unsigned int frame)
                }
 
                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 @@ static void dl_done_list (struct ohci_hcd *ohci, struct td *td_list)
        int             cc = 0;
        struct urb      *urb;
        urb_priv_t      *urb_priv;
-       __u32           tdINFO, edHeadP, edTailP;
+       __u32           tdINFO;
 
        unsigned long flags;
 
@@ -968,7 +971,7 @@ static void dl_done_list (struct ohci_hcd *ohci, struct td *td_list)
                        /*
                         * 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 @@ static void dl_done_list (struct ohci_hcd *ohci, struct td *td_list)
 
                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);
index 8b2fbff24e2faec51a866778dc3c631dd5d7bbeb..0a4ae8e24b051d4ab38ef1d90a49b55beccb6844 100644 (file)
  * 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_ISO     0x00010000
-#define TD_DEL      0x00020000
-
-/* CC Codes */
+//#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];
+
+       /* rest are purely for the driver's use */
+       __u8            index;
+       struct ed       *ed;
+       struct td       *next_dl_td;
+       struct urb      *urb;
+
+       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 @@ struct ed {
 #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 @@ struct ohci_regs {
        __u32   intrenable;
        __u32   intrdisable;
 
-       /* memory pointers */
+       /* memory pointers (section 7.2) */
        __u32   hcca;
        __u32   ed_periodcurrent;
        __u32   ed_controlhead;
@@ -166,23 +175,25 @@ struct ohci_regs {
        __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 @@ struct ohci_regs {
 #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 @@ struct ohci_hcd {
        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 */