include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / usb / host / ohci-q.c
index e08d1a2..83094d0 100644 (file)
@@ -1,13 +1,14 @@
 /*
  * OHCI HCD (Host Controller Driver) for USB.
- * 
+ *
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
  * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
- * 
+ *
  * This file is licenced under the GPL.
  */
 
 #include <linux/irq.h>
+#include <linux/slab.h>
 
 static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
 {
@@ -36,33 +37,25 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
  * PRECONDITION:  ohci lock held, irqs blocked.
  */
 static void
-finish_urb (struct ohci_hcd *ohci, struct urb *urb)
+finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status)
 __releases(ohci->lock)
 __acquires(ohci->lock)
 {
        // ASSERT (urb->hcpriv != 0);
 
        urb_free_priv (ohci, urb->hcpriv);
-       urb->hcpriv = NULL;
-
-       spin_lock (&urb->lock);
-       if (likely (urb->status == -EINPROGRESS))
-               urb->status = 0;
-       /* report short control reads right even though the data TD always
-        * has TD_R set.  (much simpler, but creates the 1-td limit.)
-        */
-       if (unlikely (urb->transfer_flags & URB_SHORT_NOT_OK)
-                       && unlikely (usb_pipecontrol (urb->pipe))
-                       && urb->actual_length < urb->transfer_buffer_length
-                       && usb_pipein (urb->pipe)
-                       && urb->status == 0) {
-               urb->status = -EREMOTEIO;
-       }
-       spin_unlock (&urb->lock);
+       if (likely(status == -EINPROGRESS))
+               status = 0;
 
        switch (usb_pipetype (urb->pipe)) {
        case PIPE_ISOCHRONOUS:
                ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs--;
+               if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) {
+                       if (quirk_amdiso(ohci))
+                               quirk_amd_pll(1);
+                       if (quirk_amdprefetch(ohci))
+                               sb800_prefetch(ohci, 0);
+               }
                break;
        case PIPE_INTERRUPT:
                ohci_to_hcd(ohci)->self.bandwidth_int_reqs--;
@@ -70,12 +63,13 @@ __acquires(ohci->lock)
        }
 
 #ifdef OHCI_VERBOSE_DEBUG
-       urb_print (urb, "RET", usb_pipeout (urb->pipe));
+       urb_print(urb, "RET", usb_pipeout (urb->pipe), status);
 #endif
 
        /* urb->complete() can reenter this HCD */
+       usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb);
        spin_unlock (&ohci->lock);
-       usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb);
+       usb_hcd_giveback_urb(ohci_to_hcd(ohci), urb, status);
        spin_lock (&ohci->lock);
 
        /* stop periodic dma if it's not needed */
@@ -89,7 +83,7 @@ __acquires(ohci->lock)
 
 /*-------------------------------------------------------------------------*
  * ED handling functions
- *-------------------------------------------------------------------------*/  
+ *-------------------------------------------------------------------------*/
 
 /* search for the right schedule branch to use for a periodic ed.
  * does some load balancing; returns the branch, or negative errno.
@@ -107,7 +101,6 @@ static int balance (struct ohci_hcd *ohci, int interval, int load)
         */
        for (i = 0; i < interval ; i++) {
                if (branch < 0 || ohci->load [branch] > ohci->load [i]) {
-#if 1  /* CONFIG_USB_BANDWIDTH */
                        int     j;
 
                        /* usb 1.1 says 90% of one frame */
@@ -117,8 +110,7 @@ static int balance (struct ohci_hcd *ohci, int interval, int load)
                        }
                        if (j < NUM_INTS)
                                continue;
-#endif
-                       branch = i; 
+                       branch = i;
                }
        }
        return branch;
@@ -171,16 +163,17 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed)
 /* link an ed into one of the HC chains */
 
 static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
-{       
+{
        int     branch;
 
-       if (ohci_to_hcd(ohci)->state == HC_STATE_QUIESCING)
-               return -EAGAIN;
-
        ed->state = ED_OPER;
        ed->ed_prev = NULL;
        ed->ed_next = NULL;
        ed->hwNextED = 0;
+       if (quirk_zfmicro(ohci)
+                       && (ed->type == PIPE_INTERRUPT)
+                       && !(ohci->eds_scheduled++))
+               mod_timer(&ohci->unlink_watchdog, round_jiffies(jiffies + HZ));
        wmb ();
 
        /* we care about rm_list when setting CLE/BLE in case the HC was at
@@ -248,7 +241,7 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
                }
                ed->branch = branch;
                periodic_link (ohci, ed);
-       }               
+       }
 
        /* the HC may not see the schedule updates yet, but if it does
         * then they'll be properly ordered.
@@ -277,7 +270,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)
                        *prev = ed->ed_next;
                }
                ohci->load [i] -= ed->load;
-       }       
+       }
        ohci_to_hcd(ohci)->self.bandwidth_allocated -= ed->load / ed->interval;
 
        ohci_vdbg (ohci, "unlink %sed %p branch %d [%dus.], interval %d\n",
@@ -285,7 +278,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)
                ed, ed->branch, ed->load, ed->interval);
 }
 
-/* unlink an ed from one of the HC chains. 
+/* unlink an ed from one of the HC chains.
  * just the link to the ed is unlinked.
  * the link from the ed still points to another operational ed or 0
  * so the HC can eventually finish the processing of the unlinked ed
@@ -307,7 +300,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)
  * When finish_unlinks() runs later, after SOF interrupt, it will often
  * complete one or more URB unlinks before making that state change.
  */
-static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) 
+static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed)
 {
        ed->hwINFO |= cpu_to_hc32 (ohci, ED_SKIP);
        wmb ();
@@ -397,7 +390,7 @@ static struct ed *ed_get (
        unsigned int            pipe,
        int                     interval
 ) {
-       struct ed               *ed; 
+       struct ed               *ed;
        unsigned long           flags;
 
        spin_lock_irqsave (&ohci->lock, flags);
@@ -413,9 +406,9 @@ static struct ed *ed_get (
                        goto done;
                }
 
-               /* dummy td; end of td list for ed */
+               /* dummy td; end of td list for ed */
                td = td_alloc (ohci, GFP_ATOMIC);
-               if (!td) {
+               if (!td) {
                        /* out of memory */
                        ed_free (ohci, ed);
                        ed = NULL;
@@ -429,7 +422,7 @@ static struct ed *ed_get (
                is_out = !(ep->desc.bEndpointAddress & USB_DIR_IN);
 
                /* FIXME usbcore changes dev->devnum before SET_ADDRESS
-                * suceeds ... otherwise we wouldn't need "pipe".
+                * succeeds ... otherwise we wouldn't need "pipe".
                 */
                info = usb_pipedevice (pipe);
                ed->type = usb_pipetype(pipe);
@@ -462,7 +455,7 @@ static struct ed *ed_get (
 
 done:
        spin_unlock_irqrestore (&ohci->lock, flags);
-       return ed; 
+       return ed;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -474,7 +467,7 @@ done:
  * and that ed->state is ED_OPER
  */
 static void start_ed_unlink (struct ohci_hcd *ohci, struct ed *ed)
-{    
+{
        ed->hwINFO |= cpu_to_hc32 (ohci, ED_DEQUEUE);
        ed_deschedule (ohci, ed);
 
@@ -541,7 +534,7 @@ td_fill (struct ohci_hcd *ohci, u32 info,
        td->ed = urb_priv->ed;
        td->next_dl_td = NULL;
        td->index = index;
-       td->urb = urb; 
+       td->urb = urb;
        td->data_dma = data;
        if (!len)
                data = 0;
@@ -553,8 +546,8 @@ td_fill (struct ohci_hcd *ohci, u32 info,
                                                (data & 0x0FFF) | 0xE000);
                td->ed->last_iso = info & 0xffff;
        } else {
-               td->hwCBP = cpu_to_hc32 (ohci, data); 
-       }                       
+               td->hwCBP = cpu_to_hc32 (ohci, data);
+       }
        if (data)
                td->hwBE = cpu_to_hc32 (ohci, data + len - 1);
        else
@@ -597,7 +590,7 @@ static void td_submit_urb (
         * 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)) {
+       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 &= ~cpu_to_hc32 (ohci, ED_C);
@@ -691,6 +684,12 @@ static void td_submit_urb (
                                data + urb->iso_frame_desc [cnt].offset,
                                urb->iso_frame_desc [cnt].length, urb, cnt);
                }
+               if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) {
+                       if (quirk_amdiso(ohci))
+                               quirk_amd_pll(0);
+                       if (quirk_amdprefetch(ohci))
+                               sb800_prefetch(ohci, 1);
+               }
                periodic = ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs++ == 0
                        && ohci_to_hcd(ohci)->self.bandwidth_int_reqs == 0;
                break;
@@ -710,28 +709,27 @@ static void td_submit_urb (
  * Done List handling functions
  *-------------------------------------------------------------------------*/
 
-/* calculate transfer length/status and update the urb
- * PRECONDITION:  irqsafe (only for urb->status locking)
- */
-static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
+/* calculate transfer length/status and update the urb */
+static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td)
 {
        u32     tdINFO = hc32_to_cpup (ohci, &td->hwINFO);
        int     cc = 0;
+       int     status = -EINPROGRESS;
 
        list_del (&td->td_list);
 
        /* ISO ... drivers see per-TD length/status */
-       if (tdINFO & TD_ISO) {
-               u16     tdPSW = ohci_hwPSW (ohci, td, 0);
+       if (tdINFO & TD_ISO) {
+               u16     tdPSW = ohci_hwPSW(ohci, td, 0);
                int     dlen = 0;
 
                /* NOTE:  assumes FC in tdINFO == 0, and that
                 * only the first of 0..MAXPSW psws is used.
                 */
 
-               cc = (tdPSW >> 12) & 0xF;
-               if (tdINFO & TD_CC)     /* hc didn't touch? */
-                       return;
+               cc = (tdPSW >> 12) & 0xF;
+               if (tdINFO & TD_CC)     /* hc didn't touch? */
+                       return status;
 
                if (usb_pipeout (urb->pipe))
                        dlen = urb->iso_frame_desc [td->index].length;
@@ -758,18 +756,14 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
                int     type = usb_pipetype (urb->pipe);
                u32     tdBE = hc32_to_cpup (ohci, &td->hwBE);
 
-               cc = TD_CC_GET (tdINFO);
+               cc = TD_CC_GET (tdINFO);
 
                /* update packet status if needed (short is normally ok) */
                if (cc == TD_DATAUNDERRUN
                                && !(urb->transfer_flags & URB_SHORT_NOT_OK))
                        cc = TD_CC_NOERROR;
-               if (cc != TD_CC_NOERROR && cc < 0x0E) {
-                       spin_lock (&urb->lock);
-                       if (urb->status == -EINPROGRESS)
-                               urb->status = cc_to_error [cc];
-                       spin_unlock (&urb->lock);
-               }
+               if (cc != TD_CC_NOERROR && cc < 0x0E)
+                       status = cc_to_error[cc];
 
                /* count all non-empty packets except control SETUP packet */
                if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) {
@@ -787,15 +781,16 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
                                urb, td, 1 + td->index, cc,
                                urb->actual_length,
                                urb->transfer_buffer_length);
-       }
+       }
+       return status;
 }
 
 /*-------------------------------------------------------------------------*/
 
-static inline struct td *
-ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
+static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc)
 {
-       struct urb              *urb = td->urb;
+       struct urb              *urb = td->urb;
+       urb_priv_t              *urb_priv = urb->hcpriv;
        struct ed               *ed = td->ed;
        struct list_head        *tmp = td->td_list.next;
        __hc32                  toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C);
@@ -805,15 +800,14 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
         */
        ed->hwINFO |= cpu_to_hc32 (ohci, ED_SKIP);
        wmb ();
-       ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H); 
+       ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H);
 
-       /* put any later tds from this urb onto the donelist, after 'td',
-        * order won't matter here: no errors, and nothing was transferred.
-        * also patch the ed so it looks as if those tds completed normally.
+       /* Get rid of all later tds from this urb.  We don't have
+        * to be careful: no errors and nothing was transferred.
+        * Also patch the ed so it looks as if those tds completed normally.
         */
        while (tmp != &ed->td_list) {
                struct td       *next;
-               __hc32          info;
 
                next = list_entry (tmp, struct td, td_list);
                tmp = next->td_list.next;
@@ -828,14 +822,9 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
                 * then we need to leave the control STATUS packet queued
                 * and clear ED_SKIP.
                 */
-               info = next->hwINFO;
-               info |= cpu_to_hc32 (ohci, TD_DONE);
-               info &= ~cpu_to_hc32 (ohci, TD_CC);
-               next->hwINFO = info;
-
-               next->next_dl_td = rev; 
-               rev = next;
 
+               list_del(&next->td_list);
+               urb_priv->td_cnt++;
                ed->hwHeadP = next->hwNextTD | toggle;
        }
 
@@ -861,8 +850,6 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
                        hc32_to_cpu (ohci, td->hwINFO),
                        cc, cc_to_error [cc]);
        }
-
-       return rev;
 }
 
 /* replies to the request have to be on a FIFO basis so
@@ -881,8 +868,8 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
        /* get TD from hc's singly linked list, and
         * prepend to ours.  ed->td_list changes later.
         */
-       while (td_dma) {                
-               int             cc;
+       while (td_dma) {
+               int             cc;
 
                td = dma_to_td (ohci, td_dma);
                if (!td) {
@@ -899,12 +886,12 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
                 */
                if (cc != TD_CC_NOERROR
                                && (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H)))
-                       td_rev = ed_halted (ohci, td, cc, td_rev);
+                       ed_halted(ohci, td, cc);
 
-               td->next_dl_td = td_rev;        
+               td->next_dl_td = td_rev;
                td_rev = td;
                td_dma = hc32_to_cpup (ohci, &td->hwNextTD);
-       }       
+       }
        return td_rev;
 }
 
@@ -925,7 +912,7 @@ rescan_all:
                /* only take off EDs that the HC isn't using, accounting for
                 * frame counter wraps and EDs with partially retired TDs
                 */
-               if (likely (get_irq_regs() && HC_IS_RUNNING(ohci_to_hcd(ohci)->state))) {
+               if (likely (HC_IS_RUNNING(ohci_to_hcd(ohci)->state))) {
                        if (tick_before (tick, ed->tick)) {
 skip_ed:
                                last = &ed->ed_next;
@@ -942,8 +929,12 @@ skip_ed:
                                                                TD_MASK;
 
                                /* INTR_WDH may need to clean up first */
-                               if (td->td_dma != head)
-                                       goto skip_ed;
+                               if (td->td_dma != head) {
+                                       if (ed == ohci->ed_to_check)
+                                               ohci->ed_to_check = NULL;
+                                       else
+                                               goto skip_ed;
+                               }
                        }
                }
 
@@ -971,12 +962,13 @@ rescan_this:
                        struct urb      *urb;
                        urb_priv_t      *urb_priv;
                        __hc32          savebits;
+                       u32             tdINFO;
 
                        td = list_entry (entry, struct td, td_list);
                        urb = td->urb;
                        urb_priv = td->urb->hcpriv;
 
-                       if (urb->status == -EINPROGRESS) {
+                       if (!urb->unlinked) {
                                prev = &td->hwNextTD;
                                continue;
                        }
@@ -985,6 +977,17 @@ rescan_this:
                        savebits = *prev & ~cpu_to_hc32 (ohci, TD_MASK);
                        *prev = td->hwNextTD | savebits;
 
+                       /* If this was unlinked, the TD may not have been
+                        * retired ... so manually save the data toggle.
+                        * The controller ignores the value we save for
+                        * control and ISO endpoints.
+                        */
+                       tdINFO = hc32_to_cpup(ohci, &td->hwINFO);
+                       if ((tdINFO & TD_T) == TD_T_DATA0)
+                               ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_C);
+                       else if ((tdINFO & TD_T) == TD_T_DATA1)
+                               ed->hwHeadP |= cpu_to_hc32(ohci, ED_C);
+
                        /* HC may have partly processed this TD */
                        td_done (ohci, urb, td);
                        urb_priv->td_cnt++;
@@ -992,7 +995,7 @@ rescan_this:
                        /* if URB is done, clean up */
                        if (urb_priv->td_cnt == urb_priv->length) {
                                modified = completed = 1;
-                               finish_urb (ohci, urb);
+                               finish_urb(ohci, urb, 0);
                        }
                }
                if (completed && !list_empty (&ed->td_list))
@@ -1000,6 +1003,8 @@ rescan_this:
 
                /* ED's now officially unlinked, hc doesn't see */
                ed->state = ED_IDLE;
+               if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+                       ohci->eds_scheduled--;
                ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
                ed->hwNextED = 0;
                wmb ();
@@ -1013,9 +1018,9 @@ rescan_this:
 
                if (modified)
                        goto rescan_all;
-       }
+       }
 
-       /* maybe reenable control and bulk lists */ 
+       /* maybe reenable control and bulk lists */
        if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state)
                        && ohci_to_hcd(ohci)->state != HC_STATE_QUIESCING
                        && !ohci->ed_rm_list) {
@@ -1023,7 +1028,7 @@ rescan_this:
 
                if (ohci->ed_controltail) {
                        command |= OHCI_CLF;
-                       if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+                       if (quirk_zfmicro(ohci))
                                mdelay(1);
                        if (!(ohci->hc_control & OHCI_CTRL_CLE)) {
                                control |= OHCI_CTRL_CLE;
@@ -1033,7 +1038,7 @@ rescan_this:
                }
                if (ohci->ed_bulktail) {
                        command |= OHCI_BLF;
-                       if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+                       if (quirk_zfmicro(ohci))
                                mdelay(1);
                        if (!(ohci->hc_control & OHCI_CTRL_BLE)) {
                                control |= OHCI_CTRL_BLE;
@@ -1041,20 +1046,20 @@ rescan_this:
                                        &ohci->regs->ed_bulkcurrent);
                        }
                }
-               
+
                /* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */
                if (control) {
                        ohci->hc_control |= control;
-                       if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+                       if (quirk_zfmicro(ohci))
                                mdelay(1);
-                       ohci_writel (ohci, ohci->hc_control,
-                                       &ohci->regs->control);   
-               }
+                       ohci_writel (ohci, ohci->hc_control,
+                                       &ohci->regs->control);
+               }
                if (command) {
-                       if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+                       if (quirk_zfmicro(ohci))
                                mdelay(1);
-                       ohci_writel (ohci, command, &ohci->regs->cmdstatus);   
-               }
+                       ohci_writel (ohci, command, &ohci->regs->cmdstatus);
+               }
        }
 }
 
@@ -1063,56 +1068,69 @@ rescan_this:
 /*-------------------------------------------------------------------------*/
 
 /*
+ * Used to take back a TD from the host controller. This would normally be
+ * called from within dl_done_list, however it may be called directly if the
+ * HC no longer sees the TD and it has not appeared on the donelist (after
+ * two frames).  This bug has been observed on ZF Micro systems.
+ */
+static void takeback_td(struct ohci_hcd *ohci, struct td *td)
+{
+       struct urb      *urb = td->urb;
+       urb_priv_t      *urb_priv = urb->hcpriv;
+       struct ed       *ed = td->ed;
+       int             status;
+
+       /* update URB's length and status from TD */
+       status = td_done(ohci, urb, td);
+       urb_priv->td_cnt++;
+
+       /* If all this urb's TDs are done, call complete() */
+       if (urb_priv->td_cnt == urb_priv->length)
+               finish_urb(ohci, urb, status);
+
+       /* clean schedule:  unlink EDs that are no longer busy */
+       if (list_empty(&ed->td_list)) {
+               if (ed->state == ED_OPER)
+                       start_ed_unlink(ohci, ed);
+
+       /* ... reenabling halted EDs only after fault cleanup */
+       } else if ((ed->hwINFO & cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE))
+                       == cpu_to_hc32(ohci, ED_SKIP)) {
+               td = list_entry(ed->td_list.next, struct td, td_list);
+               if (!(td->hwINFO & cpu_to_hc32(ohci, TD_DONE))) {
+                       ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP);
+                       /* ... hc may need waking-up */
+                       switch (ed->type) {
+                       case PIPE_CONTROL:
+                               ohci_writel(ohci, OHCI_CLF,
+                                               &ohci->regs->cmdstatus);
+                               break;
+                       case PIPE_BULK:
+                               ohci_writel(ohci, OHCI_BLF,
+                                               &ohci->regs->cmdstatus);
+                               break;
+                       }
+               }
+       }
+}
+
+/*
  * Process normal completions (error or success) and clean the schedules.
  *
  * This is the main path for handing urbs back to drivers.  The only other
- * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of
- * scanning the (re-reversed) donelist as this does.
+ * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list,
+ * instead of scanning the (re-reversed) donelist as this does.  There's
+ * an abnormal path too, handling a quirk in some Compaq silicon:  URBs
+ * with TDs that appear to be orphaned are directly reclaimed.
  */
 static void
 dl_done_list (struct ohci_hcd *ohci)
 {
        struct td       *td = dl_reverse_done_list (ohci);
 
-       while (td) {
+       while (td) {
                struct td       *td_next = td->next_dl_td;
-               struct urb      *urb = td->urb;
-               urb_priv_t      *urb_priv = urb->hcpriv;
-               struct ed       *ed = td->ed;
-
-               /* update URB's length and status from TD */
-               td_done (ohci, urb, td);
-               urb_priv->td_cnt++;
-
-               /* If all this urb's TDs are done, call complete() */
-               if (urb_priv->td_cnt == urb_priv->length)
-                       finish_urb (ohci, urb);
-
-               /* clean schedule:  unlink EDs that are no longer busy */
-               if (list_empty (&ed->td_list)) {
-                       if (ed->state == ED_OPER)
-                               start_ed_unlink (ohci, ed);
-
-               /* ... reenabling halted EDs only after fault cleanup */
-               } else if ((ed->hwINFO & cpu_to_hc32 (ohci, ED_SKIP | ED_DEQUEUE))
-                                       == cpu_to_hc32 (ohci, ED_SKIP)) {
-                       td = list_entry (ed->td_list.next, struct td, td_list);
-                       if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) {
-                               ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP);
-                               /* ... hc may need waking-up */
-                               switch (ed->type) {
-                               case PIPE_CONTROL:
-                                       ohci_writel (ohci, OHCI_CLF,
-                                               &ohci->regs->cmdstatus);   
-                                       break;
-                               case PIPE_BULK:
-                                       ohci_writel (ohci, OHCI_BLF,
-                                               &ohci->regs->cmdstatus);   
-                                       break;
-                               }
-                       }
-               }
-
-               td = td_next;
-       }  
+               takeback_td(ohci, td);
+               td = td_next;
+       }
 }