Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
[deliverable/linux.git] / drivers / usb / host / ohci-pci.c
index b331ac4d0d62e619865d21bc102aa7767ad33970..d0360f65ebd99951243d8d7cbd1cfe1683419c8a 100644 (file)
 
 /*-------------------------------------------------------------------------*/
 
+static int broken_suspend(struct usb_hcd *hcd)
+{
+       device_init_wakeup(&hcd->self.root_hub->dev, 0);
+       return 0;
+}
+
 /* AMD 756, for most chips (early revs), corrupts register
  * values on read ... so enable the vendor workaround.
  */
-static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd)
+static int ohci_quirk_amd756(struct usb_hcd *hcd)
 {
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
 
@@ -31,16 +37,14 @@ static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd)
        ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
 
        /* also erratum 10 (suspend/resume issues) */
-       device_init_wakeup(&hcd->self.root_hub->dev, 0);
-
-       return 0;
+       return broken_suspend(hcd);
 }
 
 /* Apple's OHCI driver has a lot of bizarre workarounds
  * for this chip.  Evidently control and bulk lists
  * can get confused.  (B&W G3 models, and ...)
  */
-static int __devinit ohci_quirk_opti(struct usb_hcd *hcd)
+static int ohci_quirk_opti(struct usb_hcd *hcd)
 {
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
 
@@ -53,7 +57,7 @@ static int __devinit ohci_quirk_opti(struct usb_hcd *hcd)
  * identify the USB (fn2). This quirk might apply to more or
  * even all NSC stuff.
  */
-static int __devinit ohci_quirk_ns(struct usb_hcd *hcd)
+static int ohci_quirk_ns(struct usb_hcd *hcd)
 {
        struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
        struct pci_dev  *b;
@@ -75,12 +79,12 @@ static int __devinit ohci_quirk_ns(struct usb_hcd *hcd)
  * delays before control or bulk queues get re-activated
  * in finish_unlinks()
  */
-static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd)
+static int ohci_quirk_zfmicro(struct usb_hcd *hcd)
 {
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
 
        ohci->flags |= OHCI_QUIRK_ZFMICRO;
-       ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
+       ohci_dbg(ohci, "enabled Compaq ZFMicro chipset quirks\n");
 
        return 0;
 }
@@ -88,7 +92,7 @@ static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd)
 /* Check for Toshiba SCC OHCI which has big endian registers
  * and little endian in memory data structures
  */
-static int __devinit ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
+static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
 {
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
 
@@ -107,6 +111,38 @@ static int __devinit ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
 #endif
 }
 
+/* Check for NEC chip and apply quirk for allegedly lost interrupts.
+ */
+
+static void ohci_quirk_nec_worker(struct work_struct *work)
+{
+       struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
+       int status;
+
+       status = ohci_init(ohci);
+       if (status != 0) {
+               ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
+                        "ohci_init", status);
+               return;
+       }
+
+       status = ohci_restart(ohci);
+       if (status != 0)
+               ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
+                        "ohci_restart", status);
+}
+
+static int ohci_quirk_nec(struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+       ohci->flags |= OHCI_QUIRK_NEC;
+       INIT_WORK(&ohci->nec_work, ohci_quirk_nec_worker);
+       ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n");
+
+       return 0;
+}
+
 /* List of quirks for OHCI */
 static const struct pci_device_id ohci_pci_quirks[] = {
        {
@@ -129,6 +165,22 @@ static const struct pci_device_id ohci_pci_quirks[] = {
                PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6),
                .driver_data = (unsigned long)ohci_quirk_toshiba_scc,
        },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB),
+               .driver_data = (unsigned long)ohci_quirk_nec,
+       },
+       {
+               /* Toshiba portege 4000 */
+               .vendor         = PCI_VENDOR_ID_AL,
+               .device         = 0x5237,
+               .subvendor      = PCI_VENDOR_ID_TOSHIBA,
+               .subdevice      = 0x0004,
+               .driver_data    = (unsigned long) broken_suspend,
+       },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_ITE, 0x8152),
+               .driver_data = (unsigned long) broken_suspend,
+       },
        /* FIXME for some of the early AMD 760 southbridges, OHCI
         * won't work at all.  blacklist them.
         */
@@ -186,6 +238,42 @@ static int __devinit ohci_pci_start (struct usb_hcd *hcd)
        return ret;
 }
 
+#if    defined(CONFIG_USB_PERSIST) && (defined(CONFIG_USB_EHCI_HCD) || \
+               defined(CONFIG_USB_EHCI_HCD_MODULE))
+
+/* Following a power loss, we must prepare to regain control of the ports
+ * we used to own.  This means turning on the port power before ehci-hcd
+ * tries to switch ownership.
+ *
+ * This isn't a 100% perfect solution.  On most systems the OHCI controllers
+ * lie at lower PCI addresses than the EHCI controller, so they will be
+ * discovered (and hence resumed) first.  But there is no guarantee things
+ * will always work this way.  If the EHCI controller is resumed first and
+ * the OHCI ports are unpowered, then the handover will fail.
+ */
+static void prepare_for_handover(struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+       int             port;
+
+       /* Here we "know" root ports should always stay powered */
+       ohci_dbg(ohci, "powerup ports\n");
+       for (port = 0; port < ohci->num_ports; port++)
+               ohci_writel(ohci, RH_PS_PPS,
+                               &ohci->regs->roothub.portstatus[port]);
+
+       /* Flush those writes */
+       ohci_readl(ohci, &ohci->regs->control);
+       msleep(20);
+}
+
+#else
+
+static inline void prepare_for_handover(struct usb_hcd *hcd)
+{ }
+
+#endif /* CONFIG_USB_PERSIST etc. */
+
 #ifdef CONFIG_PM
 
 static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
@@ -225,7 +313,10 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
 static int ohci_pci_resume (struct usb_hcd *hcd)
 {
        set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-       usb_hcd_resume_root_hub(hcd);
+
+       /* FIXME: we should try to detect loss of VBUS power here */
+       prepare_for_handover(hcd);
+
        return 0;
 }
 
This page took 0.028261 seconds and 5 git commands to generate.