Merge branch 'master' into gfs2
[pandora-kernel.git] / drivers / usb / host / ohci-hcd.c
index 94d8cf4..1027aa0 100644 (file)
@@ -88,7 +88,7 @@
 #include <linux/timer.h>
 #include <linux/list.h>
 #include <linux/usb.h>
-#include <linux/usb_otg.h>
+#include <linux/usb/otg.h>
 #include <linux/dma-mapping.h> 
 #include <linux/dmapool.h>
 #include <linux/reboot.h>
 
 #include "../core/hcd.h"
 
-#define DRIVER_VERSION "2005 April 22"
+#define DRIVER_VERSION "2006 August 04"
 #define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
 #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
 
 #undef OHCI_VERBOSE_DEBUG      /* not always helpful */
 
 /* For initializing controller (mask in an HCFS mode too) */
-#define        OHCI_CONTROL_INIT       OHCI_CTRL_CBSR
+#define        OHCI_CONTROL_INIT       OHCI_CTRL_CBSR
 #define        OHCI_INTR_INIT \
-       (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_WDH)
+               (OHCI_INTR_MIE | OHCI_INTR_RHSC | OHCI_INTR_UE \
+               | OHCI_INTR_RD | OHCI_INTR_WDH)
 
 #ifdef __hppa__
 /* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */
 
 static const char      hcd_name [] = "ohci_hcd";
 
+#define        STATECHANGE_DELAY       msecs_to_jiffies(300)
+
 #include "ohci.h"
 
 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);
-static int ohci_reboot (struct notifier_block *, unsigned long , void *);
 
 #include "ohci-hub.c"
 #include "ohci-dbg.c"
@@ -416,21 +418,20 @@ static void ohci_usb_reset (struct ohci_hcd *ohci)
        ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
 }
 
-/* reboot notifier forcibly disables IRQs and DMA, helping kexec and
+/* ohci_shutdown forcibly disables IRQs and DMA, helping kexec and
  * other cases where the next software may expect clean state from the
  * "firmware".  this is bus-neutral, unlike shutdown() methods.
  */
-static int
-ohci_reboot (struct notifier_block *block, unsigned long code, void *null)
+static void
+ohci_shutdown (struct usb_hcd *hcd)
 {
        struct ohci_hcd *ohci;
 
-       ohci = container_of (block, struct ohci_hcd, reboot_notifier);
+       ohci = hcd_to_ohci (hcd);
        ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
        ohci_usb_reset (ohci);
        /* flush the writes */
        (void) ohci_readl (ohci, &ohci->regs->control);
-       return 0;
 }
 
 /*-------------------------------------------------------------------------*
@@ -446,7 +447,6 @@ static int ohci_init (struct ohci_hcd *ohci)
 
        disable (ohci);
        ohci->regs = hcd->regs;
-       ohci->next_statechange = jiffies;
 
        /* REVISIT this BIOS handshake is now moved into PCI "quirks", and
         * was never needed for most non-PCI systems ... remove the code?
@@ -502,7 +502,6 @@ static int ohci_init (struct ohci_hcd *ohci)
        if ((ret = ohci_mem_init (ohci)) < 0)
                ohci_stop (hcd);
        else {
-               register_reboot_notifier (&ohci->reboot_notifier);
                create_debug_files (ohci);
        }
 
@@ -637,10 +636,14 @@ retry:
                return -EOVERFLOW;
        }
 
-       /* start controller operations */
+       /* use rhsc irqs after khubd is fully initialized */
+       hcd->poll_rh = 1;
+       hcd->uses_new_polling = 1;
+
+       /* start controller operations */
        ohci->hc_control &= OHCI_CTRL_RWC;
-       ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
-       ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+       ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
+       ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
        hcd->state = HC_STATE_RUNNING;
 
        /* wake on ConnectStatusChange, matching external hubs */
@@ -648,7 +651,7 @@ retry:
 
        /* Choose the interrupts we care about now, others later on demand */
        mask = OHCI_INTR_INIT;
-       ohci_writel (ohci, mask, &ohci->regs->intrstatus);
+       ohci_writel (ohci, ~0, &ohci->regs->intrstatus);
        ohci_writel (ohci, mask, &ohci->regs->intrenable);
 
        /* handle root hub init quirks ... */
@@ -672,6 +675,7 @@ retry:
        // flush those writes
        (void) ohci_readl (ohci, &ohci->regs->control);
 
+       ohci->next_statechange = jiffies + STATECHANGE_DELAY;
        spin_unlock_irq (&ohci->lock);
 
        // POTPGT delay is bits 24-31, in 2 ms units.
@@ -709,7 +713,23 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
        /* interrupt for some other device? */
        } else if ((ints &= ohci_readl (ohci, &regs->intrenable)) == 0) {
                return IRQ_NOTMINE;
-       } 
+       }
+
+       /* NOTE:  vendors didn't always make the same implementation
+        * choices for RHSC.  Sometimes it triggers on an edge (like
+        * setting and maybe clearing a port status change bit); and
+        * it's level-triggered on other silicon, active until khubd
+        * clears all active port status change bits.  Poll by timer
+        * til it's fully debounced and the difference won't matter.
+        */
+       if (ints & OHCI_INTR_RHSC) {
+               ohci_vdbg (ohci, "rhsc\n");
+               ohci_writel (ohci, OHCI_INTR_RHSC, &regs->intrdisable);
+               hcd->poll_rh = 1;
+               ohci->next_statechange = jiffies + STATECHANGE_DELAY;
+               ohci_writel (ohci, OHCI_INTR_RHSC, &regs->intrstatus);
+               usb_hcd_poll_rh_status(hcd);
+       }
 
        if (ints & OHCI_INTR_UE) {
                disable (ohci);
@@ -775,9 +795,10 @@ static void ohci_stop (struct usb_hcd *hcd)
 
        ohci_usb_reset (ohci);
        ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
-       
+       free_irq(hcd->irq, hcd);
+       hcd->irq = -1;
+
        remove_debug_files (ohci);
-       unregister_reboot_notifier (&ohci->reboot_notifier);
        ohci_mem_cleanup (ohci);
        if (ohci->hcca) {
                dma_free_coherent (hcd->self.controller, 
@@ -917,6 +938,10 @@ MODULE_LICENSE ("GPL");
 #include "ohci-at91.c"
 #endif
 
+#ifdef CONFIG_ARCH_PNX4008
+#include "ohci-pnx4008.c"
+#endif
+
 #if !(defined(CONFIG_PCI) \
       || defined(CONFIG_SA1111) \
       || defined(CONFIG_ARCH_S3C2410) \
@@ -928,6 +953,7 @@ MODULE_LICENSE ("GPL");
       || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
       || defined (CONFIG_ARCH_AT91RM9200) \
       || defined (CONFIG_ARCH_AT91SAM9261) \
+      || defined (CONFIG_ARCH_PNX4008) \
        )
 #error "missing bus glue for ohci-hcd"
 #endif