mfd: Rename twl5031 sih modules
[safe/jmp/linux-2.6] / drivers / usb / host / ohci-hcd.c
index 2c4a629..fc57655 100644 (file)
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/timer.h>
 #include <linux/list.h>
 #include <linux/usb.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/hcd.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
-#include <linux/reboot.h>
+#include <linux/workqueue.h>
+#include <linux/debugfs.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -43,9 +44,7 @@
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
 
-#include "../core/hcd.h"
 
-#define DRIVER_VERSION "2006 August 04"
 #define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
 #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
 
@@ -81,6 +80,30 @@ static void ohci_dump (struct ohci_hcd *ohci, int verbose);
 static int ohci_init (struct ohci_hcd *ohci);
 static void ohci_stop (struct usb_hcd *hcd);
 
+#if defined(CONFIG_PM) || defined(CONFIG_PCI)
+static int ohci_restart (struct ohci_hcd *ohci);
+#endif
+
+#ifdef CONFIG_PCI
+static void quirk_amd_pll(int state);
+static void amd_iso_dev_put(void);
+static void sb800_prefetch(struct ohci_hcd *ohci, int on);
+#else
+static inline void quirk_amd_pll(int state)
+{
+       return;
+}
+static inline void amd_iso_dev_put(void)
+{
+       return;
+}
+static inline void sb800_prefetch(struct ohci_hcd *ohci, int on)
+{
+       return;
+}
+#endif
+
+
 #include "ohci-hub.c"
 #include "ohci-dbg.c"
 #include "ohci-mem.c"
@@ -116,7 +139,6 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake");
  */
 static int ohci_urb_enqueue (
        struct usb_hcd  *hcd,
-       struct usb_host_endpoint *ep,
        struct urb      *urb,
        gfp_t           mem_flags
 ) {
@@ -129,11 +151,11 @@ static int ohci_urb_enqueue (
        int             retval = 0;
 
 #ifdef OHCI_VERBOSE_DEBUG
-       urb_print (urb, "SUB", usb_pipein (pipe));
+       urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS);
 #endif
 
        /* every endpoint has a ed, locate and maybe (re)initialize it */
-       if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval)))
+       if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval)))
                return -ENOMEM;
 
        /* for the private part of the URB we need the number of TDs (size) */
@@ -169,11 +191,10 @@ static int ohci_urb_enqueue (
        }
 
        /* allocate the private part of the URB */
-       urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),
+       urb_priv = kzalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),
                        mem_flags);
        if (!urb_priv)
                return -ENOMEM;
-       memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));
        INIT_LIST_HEAD (&urb_priv->pending);
        urb_priv->length = size;
        urb_priv->ed = ed;
@@ -199,22 +220,17 @@ static int ohci_urb_enqueue (
                retval = -ENODEV;
                goto fail;
        }
-
-       /* in case of unlink-during-submit */
-       spin_lock (&urb->lock);
-       if (urb->status != -EINPROGRESS) {
-               spin_unlock (&urb->lock);
-               urb->hcpriv = urb_priv;
-               finish_urb (ohci, urb);
-               retval = 0;
+       retval = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (retval)
                goto fail;
-       }
 
        /* schedule the ed if needed */
        if (ed->state == ED_IDLE) {
                retval = ed_schedule (ohci, ed);
-               if (retval < 0)
-                       goto fail0;
+               if (retval < 0) {
+                       usb_hcd_unlink_urb_from_ep(hcd, urb);
+                       goto fail;
+               }
                if (ed->type == PIPE_ISOCHRONOUS) {
                        u16     frame = ohci_frame_no(ohci);
 
@@ -238,8 +254,6 @@ static int ohci_urb_enqueue (
        urb->hcpriv = urb_priv;
        td_submit_urb (ohci, urb);
 
-fail0:
-       spin_unlock (&urb->lock);
 fail:
        if (retval)
                urb_free_priv (ohci, urb_priv);
@@ -248,22 +262,26 @@ fail:
 }
 
 /*
- * decouple the URB from the HC queues (TDs, urb_priv); it's
- * already marked using urb->status.  reporting is always done
+ * decouple the URB from the HC queues (TDs, urb_priv).
+ * reporting is always done
  * asynchronously, and we might be dealing with an urb that's
  * partially transferred, or an ED with other urbs being unlinked.
  */
-static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
        struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
        unsigned long           flags;
+       int                     rc;
 
 #ifdef OHCI_VERBOSE_DEBUG
-       urb_print (urb, "UNLINK", 1);
+       urb_print(urb, "UNLINK", 1, status);
 #endif
 
        spin_lock_irqsave (&ohci->lock, flags);
-       if (HC_IS_RUNNING(hcd->state)) {
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (rc) {
+               ;       /* Do nothing */
+       } else if (HC_IS_RUNNING(hcd->state)) {
                urb_priv_t  *urb_priv;
 
                /* Unless an IRQ completed the unlink while it was being
@@ -281,10 +299,10 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
                 * any more ... just clean up every urb's memory.
                 */
                if (urb->hcpriv)
-                       finish_urb (ohci, urb);
+                       finish_urb(ohci, urb, status);
        }
        spin_unlock_irqrestore (&ohci->lock, flags);
-       return 0;
+       return rc;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -313,6 +331,8 @@ rescan:
        if (!HC_IS_RUNNING (hcd->state)) {
 sanitize:
                ed->state = ED_IDLE;
+               if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+                       ohci->eds_scheduled--;
                finish_unlinks (ohci, 0);
        }
 
@@ -320,7 +340,12 @@ sanitize:
        case ED_UNLINK:         /* wait for hw to finish? */
                /* major IRQ delivery trouble loses INTR_SF too... */
                if (limit-- == 0) {
-                       ohci_warn (ohci, "IRQ INTR_SF lossage\n");
+                       ohci_warn(ohci, "ED unlink timeout\n");
+                       if (quirk_zfmicro(ohci)) {
+                               ohci_warn(ohci, "Attempting ZF TD recovery\n");
+                               ohci->ed_to_check = ed;
+                               ohci->zf_delay = 2;
+                       }
                        goto sanitize;
                }
                spin_unlock_irqrestore (&ohci->lock, flags);
@@ -378,6 +403,93 @@ ohci_shutdown (struct usb_hcd *hcd)
        (void) ohci_readl (ohci, &ohci->regs->control);
 }
 
+static int check_ed(struct ohci_hcd *ohci, struct ed *ed)
+{
+       return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0
+               && (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK)
+                       == (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK)
+               && !list_empty(&ed->td_list);
+}
+
+/* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes
+ * an interrupt TD but neglects to add it to the donelist.  On systems with
+ * this chipset, we need to periodically check the state of the queues to look
+ * for such "lost" TDs.
+ */
+static void unlink_watchdog_func(unsigned long _ohci)
+{
+       unsigned long   flags;
+       unsigned        max;
+       unsigned        seen_count = 0;
+       unsigned        i;
+       struct ed       **seen = NULL;
+       struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci;
+
+       spin_lock_irqsave(&ohci->lock, flags);
+       max = ohci->eds_scheduled;
+       if (!max)
+               goto done;
+
+       if (ohci->ed_to_check)
+               goto out;
+
+       seen = kcalloc(max, sizeof *seen, GFP_ATOMIC);
+       if (!seen)
+               goto out;
+
+       for (i = 0; i < NUM_INTS; i++) {
+               struct ed       *ed = ohci->periodic[i];
+
+               while (ed) {
+                       unsigned        temp;
+
+                       /* scan this branch of the periodic schedule tree */
+                       for (temp = 0; temp < seen_count; temp++) {
+                               if (seen[temp] == ed) {
+                                       /* we've checked it and what's after */
+                                       ed = NULL;
+                                       break;
+                               }
+                       }
+                       if (!ed)
+                               break;
+                       seen[seen_count++] = ed;
+                       if (!check_ed(ohci, ed)) {
+                               ed = ed->ed_next;
+                               continue;
+                       }
+
+                       /* HC's TD list is empty, but HCD sees at least one
+                        * TD that's not been sent through the donelist.
+                        */
+                       ohci->ed_to_check = ed;
+                       ohci->zf_delay = 2;
+
+                       /* The HC may wait until the next frame to report the
+                        * TD as done through the donelist and INTR_WDH.  (We
+                        * just *assume* it's not a multi-TD interrupt URB;
+                        * those could defer the IRQ more than one frame, using
+                        * DI...)  Check again after the next INTR_SF.
+                        */
+                       ohci_writel(ohci, OHCI_INTR_SF,
+                                       &ohci->regs->intrstatus);
+                       ohci_writel(ohci, OHCI_INTR_SF,
+                                       &ohci->regs->intrenable);
+
+                       /* flush those writes */
+                       (void) ohci_readl(ohci, &ohci->regs->control);
+
+                       goto out;
+               }
+       }
+out:
+       kfree(seen);
+       if (ohci->eds_scheduled)
+               mod_timer(&ohci->unlink_watchdog, round_jiffies(jiffies + HZ));
+done:
+       spin_unlock_irqrestore(&ohci->lock, flags);
+}
+
 /*-------------------------------------------------------------------------*
  * HC functions
  *-------------------------------------------------------------------------*/
@@ -389,6 +501,9 @@ static int ohci_init (struct ohci_hcd *ohci)
        int ret;
        struct usb_hcd *hcd = ohci_to_hcd(ohci);
 
+       if (distrust_firmware)
+               ohci->flags |= OHCI_QUIRK_HUB_POWER;
+
        disable (ohci);
        ohci->regs = hcd->regs;
 
@@ -460,7 +575,7 @@ static int ohci_init (struct ohci_hcd *ohci)
  */
 static int ohci_run (struct ohci_hcd *ohci)
 {
-       u32                     mask, temp;
+       u32                     mask, val;
        int                     first = ohci->fminterval == 0;
        struct usb_hcd          *hcd = ohci_to_hcd(ohci);
 
@@ -469,8 +584,8 @@ static int ohci_run (struct ohci_hcd *ohci)
        /* boot firmware should have set this up (5.1.1.3.1) */
        if (first) {
 
-               temp = ohci_readl (ohci, &ohci->regs->fminterval);
-               ohci->fminterval = temp & 0x3fff;
+               val = ohci_readl (ohci, &ohci->regs->fminterval);
+               ohci->fminterval = val & 0x3fff;
                if (ohci->fminterval != FI)
                        ohci_dbg (ohci, "fminterval delta %d\n",
                                ohci->fminterval - FI);
@@ -478,48 +593,37 @@ static int ohci_run (struct ohci_hcd *ohci)
                /* also: power/overcurrent flags in roothub.a */
        }
 
-       /* Reset USB nearly "by the book".  RemoteWakeupConnected was
-        * saved if boot firmware (BIOS/SMM/...) told us it's connected,
-        * or if bus glue did the same (e.g. for PCI add-in cards with
-        * PCI PM support).
+       /* Reset USB nearly "by the book".  RemoteWakeupConnected has
+        * to be checked in case boot firmware (BIOS/SMM/...) has set up
+        * wakeup in a way the bus isn't aware of (e.g., legacy PCI PM).
+        * If the bus glue detected wakeup capability then it should
+        * already be enabled; if so we'll just enable it again.
         */
-       ohci_dbg (ohci, "resetting from state '%s', control = 0x%x\n",
-                       hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
-                       ohci_readl (ohci, &ohci->regs->control));
-       if ((ohci->hc_control & OHCI_CTRL_RWC) != 0
-                       && !device_may_wakeup(hcd->self.controller))
-               device_init_wakeup(hcd->self.controller, 1);
+       if ((ohci->hc_control & OHCI_CTRL_RWC) != 0)
+               device_set_wakeup_capable(hcd->self.controller, 1);
 
        switch (ohci->hc_control & OHCI_CTRL_HCFS) {
        case OHCI_USB_OPER:
-               temp = 0;
+               val = 0;
                break;
        case OHCI_USB_SUSPEND:
        case OHCI_USB_RESUME:
                ohci->hc_control &= OHCI_CTRL_RWC;
                ohci->hc_control |= OHCI_USB_RESUME;
-               temp = 10 /* msec wait */;
+               val = 10 /* msec wait */;
                break;
        // case OHCI_USB_RESET:
        default:
                ohci->hc_control &= OHCI_CTRL_RWC;
                ohci->hc_control |= OHCI_USB_RESET;
-               temp = 50 /* msec wait */;
+               val = 50 /* msec wait */;
                break;
        }
        ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
        // flush the writes
        (void) ohci_readl (ohci, &ohci->regs->control);
-       msleep(temp);
-       temp = roothub_a (ohci);
-       if (!(temp & RH_A_NPS)) {
-               /* power down each port */
-               for (temp = 0; temp < ohci->num_ports; temp++)
-                       ohci_writel (ohci, RH_PS_LSDA,
-                               &ohci->regs->roothub.portstatus [temp]);
-       }
-       // flush those writes
-       (void) ohci_readl (ohci, &ohci->regs->control);
+       msleep(val);
+
        memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
 
        /* 2msec timelimit here means no irqs/preempt */
@@ -528,9 +632,9 @@ static int ohci_run (struct ohci_hcd *ohci)
 retry:
        /* HC Reset requires max 10 us delay */
        ohci_writel (ohci, OHCI_HCR,  &ohci->regs->cmdstatus);
-       temp = 30;      /* ... allow extra time */
+       val = 30;       /* ... allow extra time */
        while ((ohci_readl (ohci, &ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
-               if (--temp == 0) {
+               if (--val == 0) {
                        spin_unlock_irq (&ohci->lock);
                        ohci_err (ohci, "USB HC reset timed out!\n");
                        return -1;
@@ -599,22 +703,23 @@ retry:
        ohci_writel (ohci, mask, &ohci->regs->intrenable);
 
        /* handle root hub init quirks ... */
-       temp = roothub_a (ohci);
-       temp &= ~(RH_A_PSM | RH_A_OCPM);
+       val = roothub_a (ohci);
+       val &= ~(RH_A_PSM | RH_A_OCPM);
        if (ohci->flags & OHCI_QUIRK_SUPERIO) {
                /* NSC 87560 and maybe others */
-               temp |= RH_A_NOCP;
-               temp &= ~(RH_A_POTPGT | RH_A_NPS);
-               ohci_writel (ohci, temp, &ohci->regs->roothub.a);
-       } else if ((ohci->flags & OHCI_QUIRK_AMD756) || distrust_firmware) {
+               val |= RH_A_NOCP;
+               val &= ~(RH_A_POTPGT | RH_A_NPS);
+               ohci_writel (ohci, val, &ohci->regs->roothub.a);
+       } else if ((ohci->flags & OHCI_QUIRK_AMD756) ||
+                       (ohci->flags & OHCI_QUIRK_HUB_POWER)) {
                /* hub power always on; required for AMD-756 and some
                 * Mac platforms.  ganged overcurrent reporting, if any.
                 */
-               temp |= RH_A_NPS;
-               ohci_writel (ohci, temp, &ohci->regs->roothub.a);
+               val |= RH_A_NPS;
+               ohci_writel (ohci, val, &ohci->regs->roothub.a);
        }
        ohci_writel (ohci, RH_HS_LPSC, &ohci->regs->roothub.status);
-       ohci_writel (ohci, (temp & RH_A_NPS) ? 0 : RH_B_PPCM,
+       ohci_writel (ohci, (val & RH_A_NPS) ? 0 : RH_B_PPCM,
                                                &ohci->regs->roothub.b);
        // flush those writes
        (void) ohci_readl (ohci, &ohci->regs->control);
@@ -623,9 +728,18 @@ retry:
        spin_unlock_irq (&ohci->lock);
 
        // POTPGT delay is bits 24-31, in 2 ms units.
-       mdelay ((temp >> 23) & 0x1fe);
+       mdelay ((val >> 23) & 0x1fe);
        hcd->state = HC_STATE_RUNNING;
 
+       if (quirk_zfmicro(ohci)) {
+               /* Create timer to watch for bad queue state on ZF Micro */
+               setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func,
+                               (unsigned long) ohci);
+
+               ohci->eds_scheduled = 0;
+               ohci->ed_to_check = NULL;
+       }
+
        ohci_dump (ohci, 1);
 
        return 0;
@@ -639,30 +753,45 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
 {
        struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
        struct ohci_regs __iomem *regs = ohci->regs;
-       int                     ints; 
+       int                     ints;
 
-       /* we can eliminate a (slow) ohci_readl()
-          if _only_ WDH caused this irq */
-       if ((ohci->hcca->done_head != 0)
-                       && ! (hc32_to_cpup (ohci, &ohci->hcca->done_head)
-                               & 0x01)) {
-               ints =  OHCI_INTR_WDH;
+       /* Read interrupt status (and flush pending writes).  We ignore the
+        * optimization of checking the LSB of hcca->done_head; it doesn't
+        * work on all systems (edge triggering for OHCI can be a factor).
+        */
+       ints = ohci_readl(ohci, &regs->intrstatus);
 
-       /* cardbus/... hardware gone before remove() */
-       } else if ((ints = ohci_readl (ohci, &regs->intrstatus)) == ~(u32)0) {
+       /* Check for an all 1's result which is a typical consequence
+        * of dead, unclocked, or unplugged (CardBus...) devices
+        */
+       if (ints == ~(u32)0) {
                disable (ohci);
                ohci_dbg (ohci, "device removed!\n");
                return IRQ_HANDLED;
+       }
+
+       /* We only care about interrupts that are enabled */
+       ints &= ohci_readl(ohci, &regs->intrenable);
 
        /* interrupt for some other device? */
-       } else if ((ints &= ohci_readl (ohci, &regs->intrenable)) == 0) {
+       if (ints == 0)
                return IRQ_NOTMINE;
-       }
 
        if (ints & OHCI_INTR_UE) {
-               disable (ohci);
-               ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
                // e.g. due to PCI Master/Target Abort
+               if (quirk_nec(ohci)) {
+                       /* Workaround for a silicon bug in some NEC chips used
+                        * in Apple's PowerBooks. Adapted from Darwin code.
+                        */
+                       ohci_err (ohci, "OHCI Unrecoverable Error, scheduling NEC chip restart\n");
+
+                       ohci_writel (ohci, OHCI_INTR_UE, &regs->intrdisable);
+
+                       schedule_work (&ohci->nec_work);
+               } else {
+                       disable (ohci);
+                       ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
+               }
 
                ohci_dump (ohci, 1);
                ohci_usb_reset (ohci);
@@ -703,13 +832,34 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
        }
 
        if (ints & OHCI_INTR_WDH) {
-               if (HC_IS_RUNNING(hcd->state))
-                       ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrdisable);
                spin_lock (&ohci->lock);
                dl_done_list (ohci);
                spin_unlock (&ohci->lock);
-               if (HC_IS_RUNNING(hcd->state))
-                       ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrenable);
+       }
+
+       if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) {
+               spin_lock(&ohci->lock);
+               if (ohci->ed_to_check) {
+                       struct ed *ed = ohci->ed_to_check;
+
+                       if (check_ed(ohci, ed)) {
+                               /* HC thinks the TD list is empty; HCD knows
+                                * at least one TD is outstanding
+                                */
+                               if (--ohci->zf_delay == 0) {
+                                       struct td *td = list_entry(
+                                               ed->td_list.next,
+                                               struct td, td_list);
+                                       ohci_warn(ohci,
+                                                 "Reclaiming orphan TD %p\n",
+                                                 td);
+                                       takeback_td(ohci, td);
+                                       ohci->ed_to_check = NULL;
+                               }
+                       } else
+                               ohci->ed_to_check = NULL;
+               }
+               spin_unlock(&ohci->lock);
        }
 
        /* could track INTR_SO to reduce available PCI/... bandwidth */
@@ -720,7 +870,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
        spin_lock (&ohci->lock);
        if (ohci->ed_rm_list)
                finish_unlinks (ohci, ohci_frame_no(ohci));
-       if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
+       if ((ints & OHCI_INTR_SF) != 0
+                       && !ohci->ed_rm_list
+                       && !ohci->ed_to_check
                        && HC_IS_RUNNING(hcd->state))
                ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
        spin_unlock (&ohci->lock);
@@ -741,9 +893,6 @@ static void ohci_stop (struct usb_hcd *hcd)
 {
        struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
 
-       ohci_dbg (ohci, "stop %s controller (state 0x%02x)\n",
-               hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
-               hcd->state);
        ohci_dump (ohci, 1);
 
        flush_scheduled_work();
@@ -753,6 +902,11 @@ static void ohci_stop (struct usb_hcd *hcd)
        free_irq(hcd->irq, hcd);
        hcd->irq = -1;
 
+       if (quirk_zfmicro(ohci))
+               del_timer(&ohci->unlink_watchdog);
+       if (quirk_amdiso(ohci))
+               amd_iso_dev_put();
+
        remove_debug_files (ohci);
        ohci_mem_cleanup (ohci);
        if (ohci->hcca) {
@@ -766,24 +920,19 @@ static void ohci_stop (struct usb_hcd *hcd)
 
 /*-------------------------------------------------------------------------*/
 
-/* must not be called from interrupt context */
-
-#ifdef CONFIG_PM
+#if defined(CONFIG_PM) || defined(CONFIG_PCI)
 
+/* must not be called from interrupt context */
 static int ohci_restart (struct ohci_hcd *ohci)
 {
        int temp;
        int i;
        struct urb_priv *priv;
 
-       /* mark any devices gone, so they do nothing till khubd disconnects.
-        * recycle any "live" eds/tds (and urbs) right away.
-        * later, khubd disconnect processing will recycle the other state,
-        * (either as disconnect/reconnect, or maybe someday as a reset).
-        */
        spin_lock_irq(&ohci->lock);
        disable (ohci);
-       usb_root_hub_lost_power(ohci_to_hcd(ohci)->self.root_hub);
+
+       /* Recycle any "live" eds/tds (and urbs). */
        if (!list_empty (&ohci->pending))
                ohci_dbg(ohci, "abort schedule...\n");
        list_for_each_entry (priv, &ohci->pending, pending) {
@@ -807,9 +956,8 @@ static int ohci_restart (struct ohci_hcd *ohci)
                                        ed, ed->state);
                }
 
-               spin_lock (&urb->lock);
-               urb->status = -ESHUTDOWN;
-               spin_unlock (&urb->lock);
+               if (!urb->unlinked)
+                       urb->unlinked = -ESHUTDOWN;
        }
        finish_unlinks (ohci, 0);
        spin_unlock_irq(&ohci->lock);
@@ -830,27 +978,17 @@ static int ohci_restart (struct ohci_hcd *ohci)
        if ((temp = ohci_run (ohci)) < 0) {
                ohci_err (ohci, "can't restart, %d\n", temp);
                return temp;
-       } else {
-               /* here we "know" root ports should always stay powered,
-                * and that if we try to turn them back on the root hub
-                * will respond to CSC processing.
-                */
-               i = ohci->num_ports;
-               while (i--)
-                       ohci_writel (ohci, RH_PS_PSS,
-                               &ohci->regs->roothub.portstatus [i]);
-               ohci_dbg (ohci, "restart complete\n");
        }
+       ohci_dbg(ohci, "restart complete\n");
        return 0;
 }
+
 #endif
 
 /*-------------------------------------------------------------------------*/
 
-#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
-
 MODULE_AUTHOR (DRIVER_AUTHOR);
-MODULE_DESCRIPTION (DRIVER_INFO);
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE ("GPL");
 
 #ifdef CONFIG_PCI
@@ -858,19 +996,24 @@ MODULE_LICENSE ("GPL");
 #define PCI_DRIVER             ohci_pci_driver
 #endif
 
-#ifdef CONFIG_SA1111
+#if defined(CONFIG_ARCH_SA1100) && defined(CONFIG_SA1111)
 #include "ohci-sa1111.c"
 #define SA1111_DRIVER          ohci_hcd_sa1111_driver
 #endif
 
-#ifdef CONFIG_ARCH_S3C2410
+#if defined(CONFIG_ARCH_S3C2410) || defined(CONFIG_ARCH_S3C64XX)
 #include "ohci-s3c2410.c"
 #define PLATFORM_DRIVER                ohci_hcd_s3c2410_driver
 #endif
 
-#ifdef CONFIG_ARCH_OMAP
+#ifdef CONFIG_USB_OHCI_HCD_OMAP1
 #include "ohci-omap.c"
-#define PLATFORM_DRIVER                ohci_hcd_omap_driver
+#define OMAP1_PLATFORM_DRIVER  ohci_hcd_omap_driver
+#endif
+
+#ifdef CONFIG_USB_OHCI_HCD_OMAP3
+#include "ohci-omap3.c"
+#define OMAP3_PLATFORM_DRIVER  ohci_hcd_omap3_driver
 #endif
 
 #ifdef CONFIG_ARCH_LH7A404
@@ -878,7 +1021,7 @@ MODULE_LICENSE ("GPL");
 #define PLATFORM_DRIVER                ohci_hcd_lh7a404_driver
 #endif
 
-#ifdef CONFIG_PXA27x
+#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
 #include "ohci-pxa27x.c"
 #define PLATFORM_DRIVER                ohci_hcd_pxa27x_driver
 #endif
@@ -913,16 +1056,55 @@ MODULE_LICENSE ("GPL");
 #define PLATFORM_DRIVER                usb_hcd_pnx4008_driver
 #endif
 
+#ifdef CONFIG_ARCH_DAVINCI_DA8XX
+#include "ohci-da8xx.c"
+#define PLATFORM_DRIVER                ohci_hcd_da8xx_driver
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7763) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7786)
+#include "ohci-sh.c"
+#define PLATFORM_DRIVER                ohci_hcd_sh_driver
+#endif
+
 
 #ifdef CONFIG_USB_OHCI_HCD_PPC_OF
 #include "ohci-ppc-of.c"
 #define OF_PLATFORM_DRIVER     ohci_hcd_ppc_of_driver
 #endif
 
+#ifdef CONFIG_PPC_PS3
+#include "ohci-ps3.c"
+#define PS3_SYSTEM_BUS_DRIVER  ps3_ohci_driver
+#endif
+
+#ifdef CONFIG_USB_OHCI_HCD_SSB
+#include "ohci-ssb.c"
+#define SSB_OHCI_DRIVER                ssb_ohci_driver
+#endif
+
+#ifdef CONFIG_MFD_SM501
+#include "ohci-sm501.c"
+#define SM501_OHCI_DRIVER      ohci_hcd_sm501_driver
+#endif
+
+#ifdef CONFIG_MFD_TC6393XB
+#include "ohci-tmio.c"
+#define TMIO_OHCI_DRIVER       ohci_hcd_tmio_driver
+#endif
+
 #if    !defined(PCI_DRIVER) &&         \
        !defined(PLATFORM_DRIVER) &&    \
+       !defined(OMAP1_PLATFORM_DRIVER) &&      \
+       !defined(OMAP3_PLATFORM_DRIVER) &&      \
        !defined(OF_PLATFORM_DRIVER) && \
-       !defined(SA1111_DRIVER)
+       !defined(SA1111_DRIVER) &&      \
+       !defined(PS3_SYSTEM_BUS_DRIVER) && \
+       !defined(SM501_OHCI_DRIVER) && \
+       !defined(TMIO_OHCI_DRIVER) && \
+       !defined(SSB_OHCI_DRIVER)
 #error "missing bus glue for ohci-hcd"
 #endif
 
@@ -933,9 +1115,24 @@ static int __init ohci_hcd_mod_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       printk (KERN_DEBUG "%s: " DRIVER_INFO "\n", hcd_name);
+       printk(KERN_INFO "%s: " DRIVER_DESC "\n", hcd_name);
        pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
                sizeof (struct ed), sizeof (struct td));
+       set_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
+
+#ifdef DEBUG
+       ohci_debug_root = debugfs_create_dir("ohci", usb_debug_root);
+       if (!ohci_debug_root) {
+               retval = -ENOENT;
+               goto error_debug;
+       }
+#endif
+
+#ifdef PS3_SYSTEM_BUS_DRIVER
+       retval = ps3_ohci_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+       if (retval < 0)
+               goto error_ps3;
+#endif
 
 #ifdef PLATFORM_DRIVER
        retval = platform_driver_register(&PLATFORM_DRIVER);
@@ -943,6 +1140,18 @@ static int __init ohci_hcd_mod_init(void)
                goto error_platform;
 #endif
 
+#ifdef OMAP1_PLATFORM_DRIVER
+       retval = platform_driver_register(&OMAP1_PLATFORM_DRIVER);
+       if (retval < 0)
+               goto error_omap1_platform;
+#endif
+
+#ifdef OMAP3_PLATFORM_DRIVER
+       retval = platform_driver_register(&OMAP3_PLATFORM_DRIVER);
+       if (retval < 0)
+               goto error_omap3_platform;
+#endif
+
 #ifdef OF_PLATFORM_DRIVER
        retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
        if (retval < 0)
@@ -961,10 +1170,41 @@ static int __init ohci_hcd_mod_init(void)
                goto error_pci;
 #endif
 
+#ifdef SSB_OHCI_DRIVER
+       retval = ssb_driver_register(&SSB_OHCI_DRIVER);
+       if (retval)
+               goto error_ssb;
+#endif
+
+#ifdef SM501_OHCI_DRIVER
+       retval = platform_driver_register(&SM501_OHCI_DRIVER);
+       if (retval < 0)
+               goto error_sm501;
+#endif
+
+#ifdef TMIO_OHCI_DRIVER
+       retval = platform_driver_register(&TMIO_OHCI_DRIVER);
+       if (retval < 0)
+               goto error_tmio;
+#endif
+
        return retval;
 
        /* Error path */
+#ifdef TMIO_OHCI_DRIVER
+       platform_driver_unregister(&TMIO_OHCI_DRIVER);
+ error_tmio:
+#endif
+#ifdef SM501_OHCI_DRIVER
+       platform_driver_unregister(&SM501_OHCI_DRIVER);
+ error_sm501:
+#endif
+#ifdef SSB_OHCI_DRIVER
+       ssb_driver_unregister(&SSB_OHCI_DRIVER);
+ error_ssb:
+#endif
 #ifdef PCI_DRIVER
+       pci_unregister_driver(&PCI_DRIVER);
  error_pci:
 #endif
 #ifdef SA1111_DRIVER
@@ -979,12 +1219,40 @@ static int __init ohci_hcd_mod_init(void)
        platform_driver_unregister(&PLATFORM_DRIVER);
  error_platform:
 #endif
+#ifdef OMAP1_PLATFORM_DRIVER
+       platform_driver_unregister(&OMAP1_PLATFORM_DRIVER);
+ error_omap1_platform:
+#endif
+#ifdef OMAP3_PLATFORM_DRIVER
+       platform_driver_unregister(&OMAP3_PLATFORM_DRIVER);
+ error_omap3_platform:
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+       ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+ error_ps3:
+#endif
+#ifdef DEBUG
+       debugfs_remove(ohci_debug_root);
+       ohci_debug_root = NULL;
+ error_debug:
+#endif
+
+       clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
        return retval;
 }
 module_init(ohci_hcd_mod_init);
 
 static void __exit ohci_hcd_mod_exit(void)
 {
+#ifdef TMIO_OHCI_DRIVER
+       platform_driver_unregister(&TMIO_OHCI_DRIVER);
+#endif
+#ifdef SM501_OHCI_DRIVER
+       platform_driver_unregister(&SM501_OHCI_DRIVER);
+#endif
+#ifdef SSB_OHCI_DRIVER
+       ssb_driver_unregister(&SSB_OHCI_DRIVER);
+#endif
 #ifdef PCI_DRIVER
        pci_unregister_driver(&PCI_DRIVER);
 #endif
@@ -997,6 +1265,13 @@ static void __exit ohci_hcd_mod_exit(void)
 #ifdef PLATFORM_DRIVER
        platform_driver_unregister(&PLATFORM_DRIVER);
 #endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+       ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+#endif
+#ifdef DEBUG
+       debugfs_remove(ohci_debug_root);
+#endif
+       clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
 }
 module_exit(ohci_hcd_mod_exit);