static int 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 can_suspend = hcd->can_wakeup; unsigned long flags; spin_lock_irqsave (&ohci->lock, flags); /* handle autosuspended root: finish resuming before * letting khubd or root hub timer see state changes. */ if (unlikely((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER || !HC_IS_RUNNING(hcd->state))) { can_suspend = 0; goto done; } /* undocumented erratum seen on at least rev D */ if ((ohci->flags & OHCI_QUIRK_AMD756) && (roothub_a (ohci) & RH_A_NDP) > MAX_ROOT_PORTS) { ohci_warn (ohci, "bogus NDP, rereads as NDP=%d\n", ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP); /* retry later; "should not happen" */ goto done; } /* init status */ if (roothub_status (ohci) & (RH_HS_LPSC | RH_HS_OCIC)) buf [0] = changed = 1; else buf [0] = 0; if (ohci->num_ports > 7) { buf [1] = 0; length++; } /* look at each port */ for (i = 0; i < ohci->num_ports; i++) { u32 status = roothub_portstatus (ohci, i); if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC)) { changed = 1; if (i < 7) buf [0] |= 1 << (i + 1); else buf [1] |= 1 << (i - 7); continue; } /* can suspend if no ports are enabled; or if all all * enabled ports are suspended AND remote wakeup is on. */ if (!(status & RH_PS_CCS)) continue; if ((status & RH_PS_PSS) && hcd->remote_wakeup) continue; can_suspend = 0; } done: spin_unlock_irqrestore (&ohci->lock, flags); #ifdef CONFIG_PM /* save power by suspending idle root hubs; * INTR_RD wakes us when there's work */ if (can_suspend && !changed && !ohci->ed_rm_list && ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES) & ohci->hc_control) == OHCI_USB_OPER && time_after (jiffies, ohci->next_statechange) && usb_trylock_device (hcd->self.root_hub) == 0 ) { ohci_vdbg (ohci, "autosuspend\n"); (void) ohci_bus_suspend (hcd); usb_unlock_device (hcd->self.root_hub); } #endif return changed ? length : 0; }
static int 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 can_suspend; unsigned long flags; can_suspend = device_may_wakeup(&hcd->self.root_hub->dev); spin_lock_irqsave (&ohci->lock, flags); /* handle autosuspended root: finish resuming before * letting khubd or root hub timer see state changes. */ if (unlikely((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER || !HC_IS_RUNNING(hcd->state))) { can_suspend = 0; goto done; } /* undocumented erratum seen on at least rev D */ if ((ohci->flags & OHCI_QUIRK_AMD756) && (roothub_a (ohci) & RH_A_NDP) > MAX_ROOT_PORTS) { ohci_warn (ohci, "bogus NDP, rereads as NDP=%d\n", ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP); /* retry later; "should not happen" */ goto done; } /* init status */ if (roothub_status (ohci) & (RH_HS_LPSC | RH_HS_OCIC)) buf [0] = changed = 1; else buf [0] = 0; if (ohci->num_ports > 7) { buf [1] = 0; length++; } /* look at each port */ for (i = 0; i < ohci->num_ports; i++) { u32 status = roothub_portstatus (ohci, i); /* can't autosuspend with active ports */ if ((status & RH_PS_PES) && !(status & RH_PS_PSS)) can_suspend = 0; if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC)) { changed = 1; if (i < 7) buf [0] |= 1 << (i + 1); else buf [1] |= 1 << (i - 7); continue; } } /* after root hub changes, stop polling after debouncing * for a while and maybe kicking in autosuspend */ if (changed) { ohci->next_statechange = jiffies + STATECHANGE_DELAY; can_suspend = 0; } else if (time_before (jiffies, ohci->next_statechange)) { can_suspend = 0; } else { #ifdef CONFIG_PM can_suspend = can_suspend && !ohci->ed_rm_list && ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES) & ohci->hc_control) == OHCI_USB_OPER; #endif if (hcd->uses_new_polling) { hcd->poll_rh = 0; /* use INTR_RHSC iff INTR_RD won't apply */ if (!can_suspend) ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); } } done: spin_unlock_irqrestore (&ohci->lock, flags); #ifdef CONFIG_PM /* save power by autosuspending idle root hubs; * INTR_RD wakes us when there's work */ if (can_suspend && usb_trylock_device (hcd->self.root_hub) == 0) { ohci_vdbg (ohci, "autosuspend\n"); (void) ohci_bus_suspend (hcd); usb_unlock_device (hcd->self.root_hub); } #endif return changed ? length : 0; }
static int ohci_pci_resume (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); int temp; int retval = 0; #ifdef CONFIG_PMAC_PBOOK { struct device_node *of_node; /* Re-enable USB PAD & cell clock */ of_node = pci_device_to_OF_node (hcd->pdev); if (of_node) pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1); } #endif /* did we suspend, or were we powered off? */ ohci->hc_control = readl (&ohci->regs->control); temp = ohci->hc_control & OHCI_CTRL_HCFS; #ifdef DEBUG /* the registers may look crazy here */ ohci_dump_status (ohci, 0, 0); #endif /* Re-enable bus mastering */ pci_set_master (ohci->hcd.pdev); switch (temp) { case OHCI_USB_RESET: // lost power restart: ohci_info (ohci, "USB restart\n"); retval = hc_restart (ohci); break; case OHCI_USB_SUSPEND: // host wakeup case OHCI_USB_RESUME: // remote wakeup ohci_info (ohci, "USB continue from %s wakeup\n", (temp == OHCI_USB_SUSPEND) ? "host" : "remote"); /* we "should" only need RESUME if we're SUSPENDed ... */ ohci->hc_control = OHCI_USB_RESUME; writel (ohci->hc_control, &ohci->regs->control); (void) readl (&ohci->regs->control); /* Some controllers (lucent) need extra-long delays */ mdelay (35); /* no schedule here ! */ temp = readl (&ohci->regs->control); temp = ohci->hc_control & OHCI_CTRL_HCFS; if (temp != OHCI_USB_RESUME) { ohci_err (ohci, "controller won't resume\n"); /* maybe we can reset */ goto restart; } /* Then re-enable operations */ writel (OHCI_USB_OPER, &ohci->regs->control); (void) readl (&ohci->regs->control); mdelay (3); spin_lock_irq (&ohci->lock); ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; if (!ohci->ed_rm_list) { if (ohci->ed_controltail) ohci->hc_control |= OHCI_CTRL_CLE; if (ohci->ed_bulktail) ohci->hc_control |= OHCI_CTRL_BLE; } hcd->state = USB_STATE_RUNNING; writel (ohci->hc_control, &ohci->regs->control); /* trigger a start-frame interrupt (why?) */ writel (OHCI_INTR_SF, &ohci->regs->intrstatus); writel (OHCI_INTR_SF, &ohci->regs->intrenable); writel (OHCI_INTR_WDH, &ohci->regs->intrdisable); (void) readl (&ohci->regs->intrdisable); spin_unlock_irq (&ohci->lock); #ifdef CONFIG_PMAC_PBOOK if (_machine == _MACH_Pmac) enable_irq (hcd->pdev->irq); #endif /* Check for a pending done list */ if (ohci->hcca->done_head) dl_done_list (ohci, dl_reverse_done_list (ohci), NULL); writel (OHCI_INTR_WDH, &ohci->regs->intrenable); /* assume there are TDs on the bulk and control lists */ writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus); break; default: ohci_warn (ohci, "odd PCI resume\n"); } return retval; }