]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/usb/host/ohci-hub.c
Remove executable permission for dma.c
[linux-2.6-omap-h63xx.git] / drivers / usb / host / ohci-hub.c
index 7ea9a7b311554199f4e5f97ba060cc853786f2f0..32bbce9718f0626b98cc37e09b14faa51a5cc16f 100644 (file)
@@ -359,21 +359,24 @@ static void ohci_finish_controller_resume(struct usb_hcd *hcd)
 
 /* Carry out polling-, autostop-, and autoresume-related state changes */
 static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
-               int any_connected)
+               int any_connected, int rhsc_status)
 {
        int     poll_rh = 1;
-       int     rhsc;
+       int     rhsc_enable;
 
-       rhsc = ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC;
-       switch (ohci->hc_control & OHCI_CTRL_HCFS) {
+       /* Some broken controllers never turn off RHCS in the interrupt
+        * status register.  For their sake we won't re-enable RHSC
+        * interrupts if the interrupt bit is already active.
+        */
+       rhsc_enable = ohci_readl(ohci, &ohci->regs->intrenable) &
+                       OHCI_INTR_RHSC;
 
+       switch (ohci->hc_control & OHCI_CTRL_HCFS) {
        case OHCI_USB_OPER:
-               /* If no status changes are pending, enable status-change
-                * interrupts.
-                */
-               if (!rhsc && !changed) {
-                       rhsc = OHCI_INTR_RHSC;
-                       ohci_writel(ohci, rhsc, &ohci->regs->intrenable);
+               /* If no status changes are pending, enable RHSC interrupts. */
+               if (!rhsc_enable && !rhsc_status && !changed) {
+                       rhsc_enable = OHCI_INTR_RHSC;
+                       ohci_writel(ohci, rhsc_enable, &ohci->regs->intrenable);
                }
 
                /* Keep on polling until we know a device is connected
@@ -383,7 +386,7 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
                        if (any_connected ||
                                        !device_may_wakeup(&ohci_to_hcd(ohci)
                                                ->self.root_hub->dev)) {
-                               if (rhsc)
+                               if (rhsc_enable)
                                        poll_rh = 0;
                        } else {
                                ohci->autostop = 1;
@@ -396,34 +399,45 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
                                ohci->autostop = 0;
                                ohci->next_statechange = jiffies +
                                                STATECHANGE_DELAY;
-                       } else if (rhsc && time_after_eq(jiffies,
+                       } else if (time_after_eq(jiffies,
                                                ohci->next_statechange)
                                        && !ohci->ed_rm_list
                                        && !(ohci->hc_control &
                                                OHCI_SCHED_ENABLES)) {
                                ohci_rh_suspend(ohci, 1);
-                               poll_rh = 0;
+                               if (rhsc_enable)
+                                       poll_rh = 0;
                        }
                }
                break;
 
-       /* if there is a port change, autostart or ask to be resumed */
        case OHCI_USB_SUSPEND:
        case OHCI_USB_RESUME:
+               /* if there is a port change, autostart or ask to be resumed */
                if (changed) {
                        if (ohci->autostop)
                                ohci_rh_resume(ohci);
                        else
                                usb_hcd_resume_root_hub(ohci_to_hcd(ohci));
-               } else {
-                       if (!rhsc && (ohci->autostop ||
-                                       ohci_to_hcd(ohci)->self.root_hub->
-                                               do_remote_wakeup))
-                               ohci_writel(ohci, OHCI_INTR_RHSC,
-                                               &ohci->regs->intrenable);
 
-                       /* everything is idle, no need for polling */
+               /* If remote wakeup is disabled, stop polling */
+               } else if (!ohci->autostop &&
+                               !ohci_to_hcd(ohci)->self.root_hub->
+                                       do_remote_wakeup) {
                        poll_rh = 0;
+
+               } else {
+                       /* If no status changes are pending,
+                        * enable RHSC interrupts
+                        */
+                       if (!rhsc_enable && !rhsc_status) {
+                               rhsc_enable = OHCI_INTR_RHSC;
+                               ohci_writel(ohci, rhsc_enable,
+                                               &ohci->regs->intrenable);
+                       }
+                       /* Keep polling until RHSC is enabled */
+                       if (rhsc_enable)
+                               poll_rh = 0;
                }
                break;
        }
@@ -441,18 +455,22 @@ static inline int ohci_rh_resume(struct ohci_hcd *ohci)
  * autostop isn't used when CONFIG_PM is turned off.
  */
 static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
-               int any_connected)
+               int any_connected, int rhsc_status)
 {
        /* If RHSC is enabled, don't poll */
        if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
                return 0;
 
-       /* If no status changes are pending, enable status-change interrupts */
-       if (!changed) {
-               ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
-               return 0;
-       }
-       return 1;
+       /* If status changes are pending, continue polling.
+        * Conversely, if no status changes are pending but the RHSC
+        * status bit was set, then RHSC may be broken so continue polling.
+        */
+       if (changed || rhsc_status)
+               return 1;
+
+       /* It's safe to re-enable RHSC interrupts */
+       ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
+       return 0;
 }
 
 #endif /* CONFIG_PM */
@@ -467,6 +485,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
        int             i, changed = 0, length = 1;
        int             any_connected = 0;
+       int             rhsc_status;
        unsigned long   flags;
 
        spin_lock_irqsave (&ohci->lock, flags);
@@ -492,12 +511,10 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
                length++;
        }
 
-       /* Some broken controllers never turn off RHCS in the interrupt
-        * status register.  For their sake we won't re-enable RHSC
-        * interrupts if the flag is already set.
-        */
-       if (ohci_readl(ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC)
-               changed = 1;
+       /* Clear the RHSC status flag before reading the port statuses */
+       ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrstatus);
+       rhsc_status = ohci_readl(ohci, &ohci->regs->intrstatus) &
+                       OHCI_INTR_RHSC;
 
        /* look at each port */
        for (i = 0; i < ohci->num_ports; i++) {
@@ -517,7 +534,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
        }
 
        hcd->poll_rh = ohci_root_hub_state_changes(ohci, changed,
-                       any_connected);
+                       any_connected, rhsc_status);
 
 done:
        spin_unlock_irqrestore (&ohci->lock, flags);