/* * ehci_work is called from some interrupts, timers, and so on. * it calls driver completion functions, after dropping ehci->lock. */ static void ehci_work (struct ehci_hcd *ehci) { timer_action_done (ehci, TIMER_IO_WATCHDOG); /* another CPU may drop ehci->lock during a schedule scan while * it reports urb completions. this flag guards against bogus * attempts at re-entrant schedule scanning. */ if (ehci->scanning) return; ehci->scanning = 1; scan_async (ehci); if (ehci->next_uframe != -1) scan_periodic (ehci); ehci->scanning = 0; /* the IO watchdog guards against hardware or driver bugs that * misplace IRQs, and should let us run completely without IRQs. * such lossage has been observed on both VT6202 and VT8235. */ if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && (ehci->async->qh_next.ptr != NULL || ehci->periodic_sched != 0)) timer_action (ehci, TIMER_IO_WATCHDOG); }
/** * usb_remove_hcd - shutdown processing for generic HCDs * @hcd: the usb_hcd structure to remove * Context: !in_interrupt() * * Disconnects the root hub, then reverses the effects of usb_add_hcd(), * invoking the HCD's stop() method. */ void mtk_usb_remove_hcd(struct usb_hcd *hcd) { dev_info(hcd->self.controller, "remove, state %x\n", hcd->state); if (HC_IS_RUNNING (hcd->state)) hcd->state = HC_STATE_QUIESCING; dev_dbg(hcd->self.controller, "roothub graceful disconnect\n"); #if 0 spin_lock_irq (&hcd_root_hub_lock); hcd->rh_registered = 0; spin_unlock_irq (&hcd_root_hub_lock); #endif #if 0 //#ifdef CONFIG_USB_SUSPEND cancel_work_sync(&hcd->wakeup_work); #endif #if 0 sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group); mutex_lock(&usb_bus_list_lock); usb_disconnect(&hcd->self.root_hub); mutex_unlock(&usb_bus_list_lock); #endif hcd->driver->stop(hcd); hcd->state = HC_STATE_HALT; #if 0 hcd->poll_rh = 0; del_timer_sync(&hcd->rh_timer); #endif if (hcd->irq >= 0) free_irq(hcd->irq, hcd); #if 0 usb_deregister_bus(&hcd->self); #endif hcd_buffer_destroy(hcd); }
void xhci_stop(struct usb_hcd *hcd) { u32 temp; struct xhci_hcd *xhci = hcd_to_xhci(hcd); spin_lock_irq(&xhci->lock); if (HC_IS_RUNNING(hcd->state)) xhci_quiesce(xhci); xhci_halt(xhci); xhci_reset(xhci); spin_unlock_irq(&xhci->lock); #if 0 xhci_cleanup_msix(xhci); #endif #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING xhci->zombie = 1; del_timer_sync(&xhci->event_ring_timer); #endif xhci_dbg(xhci, "// Disabling event ring interrupts\n"); temp = xhci_readl(xhci, &xhci->op_regs->status); xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status); temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); xhci_writel(xhci, ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending); xhci_print_ir_set(xhci, xhci->ir_set, 0); xhci_dbg(xhci, "cleaning up memory\n"); xhci_mem_cleanup(xhci); xhci_dbg(xhci, "xhci_stop completed - status = %x\n", xhci_readl(xhci, &xhci->op_regs->status)); }
static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) { /* failfast */ if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state) && ehci->reclaim) end_unlink_async(ehci); /* if it's not linked then there's nothing to do */ if (qh->qh_state != QH_STATE_LINKED) ; /* defer till later if busy */ else if (ehci->reclaim) { struct ehci_qh *last; for (last = ehci->reclaim; last->reclaim; last = last->reclaim) continue; qh->qh_state = QH_STATE_UNLINK_WAIT; last->reclaim = qh; /* start IAA cycle */ } else start_unlink_async (ehci, qh); }
/* idle the controller (from running) */ static void ehci_quiesce (struct ehci_hcd *ehci) { u32 temp; #ifdef DEBUG if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) BUG (); #endif /* wait for any schedule enables/disables to take effect */ temp = readl (&ehci->regs->command) << 10; temp &= STS_ASS | STS_PSS; if (handshake (&ehci->regs->status, STS_ASS | STS_PSS, temp, 16 * 125) != 0) { ehci_to_hcd(ehci)->state = HC_STATE_HALT; return; } /* then disable anything that's still active */ temp = readl (&ehci->regs->command); temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE); writel (temp, &ehci->regs->command); /* hardware can take 16 microframes to turn off ... */ if (handshake (&ehci->regs->status, STS_ASS | STS_PSS, 0, 16 * 125) != 0) { ehci_to_hcd(ehci)->state = HC_STATE_HALT; return; } }
static int ehci_hub_status_data (struct usb_hcd *hcd, char *buf) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 temp, status = 0; int ports, i, retval = 1; unsigned long flags; /* if !USB_SUSPEND, root hub timers won't get shut down ... */ if (!HC_IS_RUNNING(hcd->state)) return 0; /* init status to no-changes */ buf [0] = 0; ports = HCS_N_PORTS (ehci->hcs_params); if (ports > 7) { buf [1] = 0; retval++; } /* no hub change reports (bit 0) for now (power, ...) */ /* port N changes (bit N)? */ spin_lock_irqsave (&ehci->lock, flags); for (i = 0; i < ports; i++) { temp = readl (&ehci->regs->port_status [i]); if (temp & PORT_OWNER) { /* don't report this in GetPortStatus */ if (temp & PORT_CSC) { temp &= ~PORT_RWC_BITS; temp |= PORT_CSC; writel (temp, &ehci->regs->port_status [i]); } continue; } if (!(temp & PORT_CONNECT)) ehci->reset_done [i] = 0; if ((temp & (PORT_CSC | PORT_PEC | PORT_OCC)) != 0 // PORT_STAT_C_SUSPEND? || ((temp & PORT_RESUME) != 0 && time_after (jiffies, ehci->reset_done [i]))) { if (i < 7) buf [0] |= 1 << (i + 1); else buf [1] |= 1 << (i - 7); status = STS_PCD; } } /* FIXME autosuspend idle root hubs */ spin_unlock_irqrestore (&ehci->lock, flags); return status ? retval : 0; }
static int ehci_bus_suspend (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); int port; if (time_before (jiffies, ehci->next_statechange)) msleep(5); del_timer_sync(&ehci->watchdog); del_timer_sync(&ehci->iaa_watchdog); port = HCS_N_PORTS (ehci->hcs_params); spin_lock_irq (&ehci->lock); /* stop schedules, clean any completed work */ if (HC_IS_RUNNING(hcd->state)) { ehci_quiesce (ehci); hcd->state = HC_STATE_QUIESCING; } ehci->command = readl (&ehci->regs->command); if (ehci->reclaim) end_unlink_async(ehci, NULL); ehci_work(ehci, NULL); /* suspend any active/unsuspended ports, maybe allow wakeup */ while (port--) { u32 __iomem *reg = &ehci->regs->port_status [port]; u32 t1 = readl (reg) & ~PORT_RWC_BITS; u32 t2 = t1; if ((t1 & PORT_PE) && !(t1 & PORT_OWNER)) t2 |= PORT_SUSPEND; if (device_may_wakeup(&hcd->self.root_hub->dev)) { t2 &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E); t2 |= PORT_WKOC_E; } else { t2 &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E); } if (t1 != t2) { ehci_vdbg (ehci, "port %d, %08x -> %08x\n", port + 1, t1, t2); writel (t2, reg); } } /* turn off now-idle HC */ ehci_halt (ehci); hcd->state = HC_STATE_SUSPENDED; ehci->next_statechange = jiffies + msecs_to_jiffies(10); spin_unlock_irq (&ehci->lock); return 0; }
static void ehci_iaa_watchdog(unsigned long param) { struct ehci_hcd *ehci = (struct ehci_hcd *) param; unsigned long flags; spin_lock_irqsave (&ehci->lock, flags); /* Lost IAA irqs wedge things badly; seen first with a vt8235. * So we need this watchdog, but must protect it against both * (a) SMP races against real IAA firing and retriggering, and * (b) clean HC shutdown, when IAA watchdog was pending. */ if (ehci->reclaim && !timer_pending(&ehci->iaa_watchdog) && HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) { u32 cmd, status; /* If we get here, IAA is *REALLY* late. It's barely * conceivable that the system is so busy that CMD_IAAD * is still legitimately set, so let's be sure it's * clear before we read STS_IAA. (The HC should clear * CMD_IAAD when it sets STS_IAA.) */ cmd = ehci_readl(ehci, &ehci->regs->command); if (cmd & CMD_IAAD) ehci_writel(ehci, cmd & ~CMD_IAAD, &ehci->regs->command); /* If IAA is set here it either legitimately triggered * before we cleared IAAD above (but _way_ late, so we'll * still count it as lost) ... or a silicon erratum: * - VIA seems to set IAA without triggering the IRQ; * - IAAD potentially cleared without setting IAA. */ status = ehci_readl(ehci, &ehci->regs->status); if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { COUNT (ehci->stats.lost_iaa); ehci_writel(ehci, STS_IAA, &ehci->regs->status); } ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd); end_unlink_async(ehci); } spin_unlock_irqrestore(&ehci->lock, flags); }
/** * usb_hcd_pci_resume - power management resume of a PCI-based HCD * @dev: USB Host Controller being resumed * * Store this function in the HCD's struct pci_driver as resume(). */ int usb_hcd_pci_resume (struct pci_dev *dev) { struct usb_hcd *hcd; int retval; int has_pci_pm; hcd = pci_get_drvdata(dev); if (hcd->state != HC_STATE_SUSPENDED) { dev_dbg (hcd->self.controller, "can't resume, not suspended!\n"); return 0; } has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM); /* D3cold resume isn't usually reported this way... */ dev_dbg(hcd->self.controller, "resume from PCI %s%s\n", pci_state(dev->current_state), has_pci_pm ? "" : " (legacy)"); hcd->state = HC_STATE_RESUMING; if (has_pci_pm) pci_set_power_state (dev, 0); dev->dev.power.power_state = 0; retval = request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ, hcd->driver->description, hcd); if (retval < 0) { dev_err (hcd->self.controller, "can't restore IRQ after resume!\n"); return retval; } hcd->saw_irq = 0; pci_restore_state (dev); #ifdef CONFIG_USB_SUSPEND pci_enable_wake (dev, dev->current_state, 0); pci_enable_wake (dev, 4, 0); #endif retval = hcd->driver->resume (hcd); if (!HC_IS_RUNNING (hcd->state)) { dev_dbg (hcd->self.controller, "resume fail, retval %d\n", retval); usb_hc_died (hcd); } return retval; }
static int usb_lpm_enter(struct usb_hcd *hcd) { unsigned long flags; struct device *dev = container_of((void *)hcd, struct device, driver_data); struct msmusb_hcd *mhcd = hcd_to_mhcd(hcd); spin_lock_irqsave(&mhcd->lock, flags); if (mhcd->in_lpm) { pr_info("%s: already in lpm. nothing to do\n", __func__); spin_unlock_irqrestore(&mhcd->lock, flags); return 0; } if (HC_IS_RUNNING(hcd->state)) { pr_info("%s: can't enter into lpm. controller is runnning\n", __func__); spin_unlock_irqrestore(&mhcd->lock, flags); return -1; } pr_info("%s: lpm enter procedure started\n", __func__); mhcd->in_lpm = 1; disable_irq(hcd->irq); spin_unlock_irqrestore(&mhcd->lock, flags); if (usb_suspend_phy(hcd)) { mhcd->in_lpm = 0; enable_irq(hcd->irq); pr_info("phy suspend failed\n"); pr_info("%s: lpm enter procedure end\n", __func__); return -1; } msm_xusb_disable_clks(mhcd); if (mhcd->xceiv && mhcd->xceiv->set_suspend) mhcd->xceiv->set_suspend(1); if (device_may_wakeup(dev)) enable_irq_wake(hcd->irq); enable_irq(hcd->irq); pr_info("%s: lpm enter procedure end\n", __func__); return 0; }
static int pxau2h_ehci_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); if (HC_IS_RUNNING(hcd->state)) hcd->state = HC_STATE_QUIESCING; usb_disconnect(&hcd->self.root_hub); hcd->driver->stop(hcd); usb_remove_hcd(hcd); iounmap(hcd->regs); iounmap((void *)info->phybase); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); return 0; }
/* * 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 admhc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct admhcd *ahcd = hcd_to_admhcd(hcd); unsigned long flags; int ret; spin_lock_irqsave(&ahcd->lock, flags); #ifdef ADMHC_VERBOSE_DEBUG urb_print(ahcd, urb, "DEQUEUE", 1, status); #endif ret = usb_hcd_check_unlink_urb(hcd, urb, status); if (ret) { /* Do nothing */ ; } else if (HC_IS_RUNNING(hcd->state)) { struct urb_priv *urb_priv; /* Unless an IRQ completed the unlink while it was being * handed to us, flag it for unlink and giveback, and force * some upcoming INTR_SF to call finish_unlinks() */ urb_priv = urb->hcpriv; if (urb_priv) { if (urb_priv->ed->state == ED_OPER) start_ed_unlink(ahcd, urb_priv->ed); } } else { /* * with HC dead, we won't respect hc queue pointers * any more ... just clean up every urb's memory. */ if (urb->hcpriv) finish_urb(ahcd, urb, status); } spin_unlock_irqrestore(&ahcd->lock, flags); return ret; }
/* * Called when the ehci_hcd module is removed. */ static void ehci_stop (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); ehci_dbg (ehci, "stop\n"); /* no more interrupts ... */ del_timer_sync (&ehci->watchdog); del_timer_sync(&ehci->iaa_watchdog); spin_lock_irq(&ehci->lock); if (HC_IS_RUNNING (hcd->state)) ehci_quiesce (ehci); ehci_silence_controller(ehci); ehci_reset (ehci); spin_unlock_irq(&ehci->lock); remove_companion_file(ehci); remove_debug_files (ehci); /* root hub is shut down separately (first, when possible) */ spin_lock_irq (&ehci->lock); if (ehci->async) ehci_work (ehci); spin_unlock_irq (&ehci->lock); ehci_mem_cleanup (ehci); #ifdef EHCI_STATS ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n", ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim, ehci->stats.lost_iaa); ehci_dbg (ehci, "complete %ld unlink %ld\n", ehci->stats.complete, ehci->stats.unlink); #endif dbg_status (ehci, "ehci_stop completed", ehci_readl(ehci, &ehci->regs->status)); }
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; }
/** * usb_hcd_pci_resume - power management resume of a PCI-based HCD * @dev: USB Host Controller being resumed * * Store this function in the HCD's struct pci_driver as resume(). */ int usb_hcd_pci_resume (struct pci_dev *dev) { struct usb_hcd *hcd; int retval; hcd = pci_get_drvdata(dev); if (hcd->state != HC_STATE_SUSPENDED) { dev_dbg (hcd->self.controller, "can't resume, not suspended!\n"); return 0; } /* NOTE: chip docs cover clean "real suspend" cases (what Linux * calls "standby", "suspend to RAM", and so on). There are also * dirty cases when swsusp fakes a suspend in "shutdown" mode. */ if (dev->current_state != PCI_D0) { #ifdef DEBUG int pci_pm; u16 pmcr; pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM); pci_read_config_word(dev, pci_pm + PCI_PM_CTRL, &pmcr); pmcr &= PCI_PM_CTRL_STATE_MASK; if (pmcr) { /* Clean case: power to USB and to HC registers was * maintained; remote wakeup is easy. */ dev_dbg(hcd->self.controller, "resume from PCI D%d\n", pmcr); } else { /* Clean: HC lost Vcc power, D0 uninitialized * + Vaux may have preserved port and transceiver * state ... for remote wakeup from D3cold * + or not; HCD must reinit + re-enumerate * * Dirty: D0 semi-initialized cases with swsusp * + after BIOS init * + after Linux init (HCD statically linked) */ dev_dbg(hcd->self.controller, "PCI D0, from previous PCI D%d\n", dev->current_state); } #endif pci_enable_wake (dev, dev->current_state, 0); pci_enable_wake (dev, PCI_D3cold, 0); } else { /* Same basic cases: clean (powered/not), dirty */ dev_dbg(hcd->self.controller, "PCI legacy resume\n"); } /* NOTE: the PCI API itself is asymmetric here. We don't need to * pci_set_power_state(PCI_D0) since that's part of re-enabling; * but that won't re-enable bus mastering. Yet pci_disable_device() * explicitly disables bus mastering... */ retval = pci_enable_device (dev); if (retval < 0) { dev_err (hcd->self.controller, "can't re-enable after resume, %d!\n", retval); return retval; } pci_set_master (dev); pci_restore_state (dev); dev->dev.power.power_state = PMSG_ON; hcd->state = HC_STATE_RESUMING; hcd->saw_irq = 0; retval = request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ, hcd->irq_descr, hcd); if (retval < 0) { dev_err (hcd->self.controller, "can't restore IRQ after resume!\n"); usb_hc_died (hcd); return retval; } retval = hcd->driver->resume (hcd); if (!HC_IS_RUNNING (hcd->state)) { dev_dbg (hcd->self.controller, "resume fail, retval %d\n", retval); usb_hc_died (hcd); } pci_enable_device(dev); return retval; }
static int ehci_bus_suspend (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); int port; int mask; if (time_before (jiffies, ehci->next_statechange)) msleep(5); port = HCS_N_PORTS (ehci->hcs_params); spin_lock_irq (&ehci->lock); /* stop schedules, clean any completed work */ if (HC_IS_RUNNING(hcd->state)) { ehci_quiesce (ehci); hcd->state = HC_STATE_QUIESCING; } ehci->command = ehci_readl(ehci, &ehci->regs->command); if (ehci->reclaim) ehci->reclaim_ready = 1; ehci_work(ehci, NULL); /* Unlike other USB host controller types, EHCI doesn't have * any notion of "global" or bus-wide suspend. The driver has * to manually suspend all the active unsuspended ports, and * then manually resume them in the bus_resume() routine. */ ehci->bus_suspended = 0; while (port--) { u32 __iomem *reg = &ehci->regs->port_status [port]; u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; u32 t2 = t1; /* keep track of which ports we suspend */ if ((t1 & PORT_PE) && !(t1 & PORT_OWNER) && !(t1 & PORT_SUSPEND)) { t2 |= PORT_SUSPEND; set_bit(port, &ehci->bus_suspended); } /* enable remote wakeup on all ports */ if (device_may_wakeup(&hcd->self.root_hub->dev)) t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E; else t2 &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E); if (t1 != t2) { ehci_vdbg (ehci, "port %d, %08x -> %08x\n", port + 1, t1, t2); ehci_writel(ehci, t2, reg); } } /* turn off now-idle HC */ del_timer_sync (&ehci->watchdog); ehci_halt (ehci); hcd->state = HC_STATE_SUSPENDED; /* allow remote wakeup */ mask = INTR_MASK; if (!device_may_wakeup(&hcd->self.root_hub->dev)) mask &= ~STS_PCD; ehci_writel(ehci, mask, &ehci->regs->intr_enable); ehci_readl(ehci, &ehci->regs->intr_enable); ehci->next_statechange = jiffies + msecs_to_jiffies(10); spin_unlock_irq (&ehci->lock); return 0; }
static int ehci_hub_status_data (struct usb_hcd *hcd, char *buf) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 temp, status = 0; u32 mask; int ports, i, retval = 1; unsigned long flags; /* if !USB_SUSPEND, root hub timers won't get shut down ... */ if (!HC_IS_RUNNING(hcd->state)) return 0; /* init status to no-changes */ buf [0] = 0; ports = HCS_N_PORTS (ehci->hcs_params); if (ports > 7) { buf [1] = 0; retval++; } /* Some boards (mostly VIA?) report bogus overcurrent indications, * causing massive log spam unless we completely ignore them. It * may be relevant that VIA VT8235 controlers, where PORT_POWER is * always set, seem to clear PORT_OCC and PORT_CSC when writing to * PORT_POWER; that's surprising, but maybe within-spec. */ if (!ignore_oc) mask = PORT_CSC | PORT_PEC | PORT_OCC; else mask = PORT_CSC | PORT_PEC; // PORT_RESUME from hardware ~= PORT_STAT_C_SUSPEND /* no hub change reports (bit 0) for now (power, ...) */ /* port N changes (bit N)? */ spin_lock_irqsave (&ehci->lock, flags); for (i = 0; i < ports; i++) { temp = ehci_readl(ehci, &ehci->regs->port_status [i]); if (temp & PORT_OWNER) { /* don't report this in GetPortStatus */ if (temp & PORT_CSC) { temp &= ~PORT_RWC_BITS; temp |= PORT_CSC; ehci_writel(ehci, temp, &ehci->regs->port_status [i]); } continue; } if (!(temp & PORT_CONNECT)) ehci->reset_done [i] = 0; if ((temp & mask) != 0 || ((temp & PORT_RESUME) != 0 && time_after (jiffies, ehci->reset_done [i]))) { if (i < 7) buf [0] |= 1 << (i + 1); else buf [1] |= 1 << (i - 7); status = STS_PCD; } } /* FIXME autosuspend idle root hubs */ spin_unlock_irqrestore (&ehci->lock, flags); return status ? retval : 0; }
/* * queue up an urb for anything except the root hub */ static int admhc_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) { struct admhcd *ahcd = hcd_to_admhcd(hcd); struct ed *ed; struct urb_priv *urb_priv; unsigned int pipe = urb->pipe; int td_cnt = 0; unsigned long flags; int ret = 0; #ifdef ADMHC_VERBOSE_DEBUG spin_lock_irqsave(&ahcd->lock, flags); urb_print(ahcd, urb, "ENQEUE", usb_pipein(pipe), -EINPROGRESS); spin_unlock_irqrestore(&ahcd->lock, flags); #endif /* every endpoint has an ed, locate and maybe (re)initialize it */ ed = ed_get(ahcd, urb->ep, urb->dev, pipe, urb->interval); if (!ed) return -ENOMEM; /* for the private part of the URB we need the number of TDs */ switch (ed->type) { case PIPE_CONTROL: if (urb->transfer_buffer_length > TD_DATALEN_MAX) /* td_submit_urb() doesn't yet handle these */ return -EMSGSIZE; /* 1 TD for setup, 1 for ACK, plus ... */ td_cnt = 2; /* FALLTHROUGH */ case PIPE_BULK: /* one TD for every 4096 Bytes (can be upto 8K) */ td_cnt += urb->transfer_buffer_length / TD_DATALEN_MAX; /* ... and for any remaining bytes ... */ if ((urb->transfer_buffer_length % TD_DATALEN_MAX) != 0) td_cnt++; /* ... and maybe a zero length packet to wrap it up */ if (td_cnt == 0) td_cnt++; else if ((urb->transfer_flags & URB_ZERO_PACKET) != 0 && (urb->transfer_buffer_length % usb_maxpacket(urb->dev, pipe, usb_pipeout (pipe))) == 0) td_cnt++; break; case PIPE_INTERRUPT: /* * for Interrupt IN/OUT transactions, each ED contains * only 1 TD. * TODO: check transfer_buffer_length? */ td_cnt = 1; break; case PIPE_ISOCHRONOUS: /* number of packets from URB */ td_cnt = urb->number_of_packets; break; } urb_priv = urb_priv_alloc(ahcd, td_cnt, mem_flags); if (!urb_priv) return -ENOMEM; urb_priv->ed = ed; spin_lock_irqsave(&ahcd->lock, flags); /* don't submit to a dead HC */ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { ret = -ENODEV; goto fail; } if (!HC_IS_RUNNING(hcd->state)) { ret = -ENODEV; goto fail; } ret = usb_hcd_link_urb_to_ep(hcd, urb); if (ret) goto fail; /* schedule the ed if needed */ if (ed->state == ED_IDLE) { ret = ed_schedule(ahcd, ed); if (ret < 0) { usb_hcd_unlink_urb_from_ep(hcd, urb); goto fail; } if (ed->type == PIPE_ISOCHRONOUS) { u16 frame = admhc_frame_no(ahcd); /* delay a few frames before the first TD */ frame += max_t (u16, 8, ed->interval); frame &= ~(ed->interval - 1); frame |= ed->branch; urb->start_frame = frame; /* yes, only URB_ISO_ASAP is supported, and * urb->start_frame is never used as input. */ } } else if (ed->type == PIPE_ISOCHRONOUS) urb->start_frame = ed->last_iso + ed->interval; /* fill the TDs and link them to the ed; and * enable that part of the schedule, if needed * and update count of queued periodic urbs */ urb->hcpriv = urb_priv; td_submit_urb(ahcd, urb); #ifdef ADMHC_VERBOSE_DEBUG admhc_dump_ed(ahcd, "admhc_urb_enqueue", urb_priv->ed, 1); #endif fail: if (ret) urb_priv_free(ahcd, urb_priv); spin_unlock_irqrestore(&ahcd->lock, flags); return ret; }
static int ohci_hub_status_data (struct usb_hcd *hcd, char *buf) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); int ports, i, changed = 0, length = 1; int can_suspend = hcd->can_wakeup; unsigned long flags; spin_lock_irqsave (&ohci->lock, flags); // hack by cfyeh for usb suspend/resume if(usb_ehci_suspend_flag == 1) { can_suspend = 0; goto done; } /* handle autosuspended root: finish resuming before * letting khubd or root hub timer see state changes. */ if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER || !HC_IS_RUNNING(hcd->state)) { can_suspend = 0; goto done; } ports = roothub_a (ohci) & RH_A_NDP; if (ports > MAX_ROOT_PORTS) { ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n", ports, 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 (ports > 7) { buf [1] = 0; length++; } /* look at each port */ for (i = 0; i < 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); #if defined(CONFIG_PM) || defined(CONFIG_REALTEK_VENUS_USB) //cfyeh+ 2005/11/07 /* save power by suspending idle root hubs; * INTR_RD wakes us when there's work * NOTE: if we can do this, we don't need a root hub timer! */ 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) ) { ohci_vdbg (ohci, "autosuspend\n"); (void) ohci_hub_suspend (hcd); hcd->state = HC_STATE_RUNNING; usb_unlock_device (hcd->self.root_hub); } #endif return changed ? length : 0; }
static void xhci_quiesce(struct xhci_hcd *xhci) { BUG_ON(!HC_IS_RUNNING(xhci_to_hcd(xhci)->state)); xhci_dbg(xhci, "Finished quiescing -- code not written yet\n"); }
static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_qh *qh; unsigned long flags; int rc; spin_lock_irqsave (&ehci->lock, flags); rc = usb_hcd_check_unlink_urb(hcd, urb, status); if (rc) goto done; switch (usb_pipetype (urb->pipe)) { // case PIPE_CONTROL: // case PIPE_BULK: default: qh = (struct ehci_qh *) urb->hcpriv; if (!qh) break; switch (qh->qh_state) { case QH_STATE_LINKED: case QH_STATE_COMPLETING: unlink_async(ehci, qh); break; case QH_STATE_UNLINK: case QH_STATE_UNLINK_WAIT: /* already started */ break; case QH_STATE_IDLE: WARN_ON(1); break; } break; case PIPE_INTERRUPT: qh = (struct ehci_qh *) urb->hcpriv; if (!qh) break; switch (qh->qh_state) { case QH_STATE_LINKED: intr_deschedule (ehci, qh); /* FALL THROUGH */ case QH_STATE_IDLE: qh_completions (ehci, qh); break; default: ehci_dbg (ehci, "bogus qh %p state %d\n", qh, qh->qh_state); goto done; } /* reschedule QH iff another request is queued */ if (!list_empty (&qh->qtd_list) && HC_IS_RUNNING (hcd->state)) { rc = qh_schedule(ehci, qh); /* An error here likely indicates handshake failure * or no space left in the schedule. Neither fault * should happen often ... * * FIXME kill the now-dysfunctional queued urbs */ if (rc != 0) ehci_err(ehci, "can't reschedule qh %p, err %d", qh, rc); } break; case PIPE_ISOCHRONOUS: // itd or sitd ... // wait till next completion, do it then. // completion irqs can wait up to 1024 msec, break; } done: spin_unlock_irqrestore (&ehci->lock, flags); return rc; }
static void ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); unsigned long flags; struct ehci_qh *qh, *tmp; /* ASSERT: any requests/urbs are being unlinked */ /* ASSERT: nobody can be submitting urbs for this any more */ rescan: spin_lock_irqsave (&ehci->lock, flags); qh = ep->hcpriv; if (!qh) goto done; /* endpoints can be iso streams. for now, we don't * accelerate iso completions ... so spin a while. */ if (qh->hw_info1 == 0) { ehci_vdbg (ehci, "iso delay\n"); goto idle_timeout; } if (!HC_IS_RUNNING (hcd->state)) qh->qh_state = QH_STATE_IDLE; switch (qh->qh_state) { case QH_STATE_LINKED: for (tmp = ehci->async->qh_next.qh; tmp && tmp != qh; tmp = tmp->qh_next.qh) continue; /* periodic qh self-unlinks on empty */ if (!tmp) goto nogood; unlink_async (ehci, qh); /* FALL THROUGH */ case QH_STATE_UNLINK: /* wait for hw to finish? */ case QH_STATE_UNLINK_WAIT: idle_timeout: spin_unlock_irqrestore (&ehci->lock, flags); schedule_timeout_uninterruptible(1); goto rescan; case QH_STATE_IDLE: /* fully unlinked */ if (list_empty (&qh->qtd_list)) { qh_put (qh); break; } /* else FALL THROUGH */ default: nogood: /* caller was supposed to have unlinked any requests; * that's not our job. just leak this memory. */ ehci_err (ehci, "qh %p (#%02x) state %d%s\n", qh, ep->desc.bEndpointAddress, qh->qh_state, list_empty (&qh->qtd_list) ? "" : "(has tds)"); break; } ep->hcpriv = NULL; done: spin_unlock_irqrestore (&ehci->lock, flags); return; }
static void admhc_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep) { struct admhcd *ahcd = hcd_to_admhcd(hcd); unsigned long flags; struct ed *ed = ep->hcpriv; unsigned limit = 1000; /* ASSERT: any requests/urbs are being unlinked */ /* ASSERT: nobody can be submitting urbs for this any more */ if (!ed) return; #ifdef ADMHC_VERBOSE_DEBUG spin_lock_irqsave(&ahcd->lock, flags); admhc_dump_ed(ahcd, "EP-DISABLE", ed, 1); spin_unlock_irqrestore(&ahcd->lock, flags); #endif rescan: spin_lock_irqsave(&ahcd->lock, flags); if (!HC_IS_RUNNING(hcd->state)) { sanitize: ed->state = ED_IDLE; finish_unlinks(ahcd, 0); } switch (ed->state) { case ED_UNLINK: /* wait for hw to finish? */ /* major IRQ delivery trouble loses INTR_SOFI too... */ if (limit-- == 0) { admhc_warn(ahcd, "IRQ INTR_SOFI lossage\n"); goto sanitize; } spin_unlock_irqrestore(&ahcd->lock, flags); schedule_timeout_uninterruptible(1); goto rescan; case ED_IDLE: /* fully unlinked */ if (list_empty(&ed->td_list)) { td_free (ahcd, ed->dummy); ed_free (ahcd, ed); break; } /* else FALL THROUGH */ default: /* caller was supposed to have unlinked any requests; * that's not our job. can't recover; must leak ed. */ admhc_err(ahcd, "leak ed %p (#%02x) state %d%s\n", ed, ep->desc.bEndpointAddress, ed->state, list_empty(&ed->td_list) ? "" : " (has tds)"); td_free(ahcd, ed->dummy); break; } ep->hcpriv = NULL; spin_unlock_irqrestore(&ahcd->lock, flags); return; }
static int vhcd_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags) { int ret = 0; unsigned int transfer_flags = 0 ; struct usb_device * udev = urb->dev; /* FIXME Check for non existent device */ if (!HC_IS_RUNNING(hcd->state)) { LOG("HC is not running\n"); return -ENODEV; } /* we have to trap some control messages, i.e. USB_REQ_SET_ADDRESS... */ /* TODO we don't have to do it here, but in the server */ if (usb_pipedevice(urb->pipe) == 0) { __u8 type = usb_pipetype(urb->pipe); struct usb_ctrlrequest *ctrlreq = (struct usb_ctrlrequest *) urb->setup_packet; if (type != PIPE_CONTROL || !ctrlreq ) { LOG("invalid request to devnum 0\n"); ret = -EINVAL; goto no_need_xmit; } switch (ctrlreq->bRequest) { case USB_REQ_SET_ADDRESS: LOG("SetAddress Request (%d) to port %d\n", ctrlreq->wValue, urb->dev->portnum); spin_lock (&urb->lock); if (urb->status == -EINPROGRESS) { /* This request is successfully completed. */ /* If not -EINPROGRESS, possibly unlinked. */ urb->status = 0; } spin_unlock (&urb->lock); goto no_need_xmit; case USB_REQ_GET_DESCRIPTOR: if (ctrlreq->wValue == (USB_DT_DEVICE << 8)) LOG("Get_Descriptor to device 0 (get max pipe size)\n"); goto out; default: /* NOT REACHED */ LOG("invalid request to devnum 0 bRequest %u, wValue %u\n", ctrlreq->bRequest, ctrlreq->wValue); ret = -EINVAL; goto no_need_xmit; } } out: if (urb->status != -EINPROGRESS) { LOG("URB already unlinked!, status %d\n", urb->status); return urb->status; } if (usb_pipeisoc(urb->pipe)) { LOG("ISO URBs not supported"); ret = -EINVAL; goto no_need_xmit; } urb->hcpriv = (void *) hcd_to_vhcd(hcd); LOG("hcpriv %p", urb->hcpriv); transfer_flags = urb->transfer_flags; usb_get_urb(urb); #if 0 d_urb->type = usb_pipetype(urb->pipe); d_urb->dev_id = data->gadget[urb->dev->portnum-1].id; d_urb->endpoint = usb_pipeendpoint(urb->pipe); d_urb->direction = 0 || usb_pipein(urb->pipe); d_urb->interval = urb->interval; d_urb->transfer_flags = urb->transfer_flags; d_urb->number_of_packets = urb->number_of_packets; d_urb->priv = priv; d_urb->size = urb->transfer_buffer_length; d_urb->data = urb->transfer_buffer; d_urb->phys_addr = d_urb->data?virt_to_phys(d_urb->data):0; if (urb->setup_packet) { memcpy(d_urb->setup_packet, urb->setup_packet, 8); } /* XXX ISO ? */ // if (urb->number_of_packets) // memcpy(d_urb->iso_desc, urb->iso_frame_desc, urb->number_of_packets*sizeof(struct usb_iso_packet_descriptor)); ret = libddeusb_submit_d_urb(d_urb); #else unsigned port_num = urb->dev->portnum; switch (usb_pipetype(urb->pipe)) { case PIPE_CONTROL: { struct usb_ctrlrequest *req = (struct usb_ctrlrequest *) urb->setup_packet; dde_linux26_usb_vhcd_submit_control_urb_cb(port_num, usb_pipeendpoint(urb->pipe), usb_pipein(urb->pipe), urb, /* handle */ sizeof(*req), req); } break; case PIPE_INTERRUPT: printk(" int\n"); // dde_linux26_usb_vhcd_submit_urb(urb->transfer_buffer, // urb->transfer_buffer_length); return -EINVAL; break; /* unsupported transfer types */ case PIPE_BULK: printk(" bulk\n"); return -EINVAL; case PIPE_ISOCHRONOUS: printk(" isoc\n"); return -EINVAL; } #endif // if (ret) { // LOG("URB SUBMIT FAILED (%d).",ret); // /* s.t. went wrong. */ // spin_lock_irqsave(&data->lock, flags); // data->rcv_buf[i]=NULL; // spin_unlock_irqrestore(&data->lock, flags); // down(&data->rcv_buf_free); // kmem_cache_free(priv_cache, urb->hcpriv); // usb_put_urb(urb); // urb->status = ret; // urb->hcpriv = NULL; // libddeusb_free_d_urb(d_urb); // return ret; // } LOG("URB %p submitted", urb); return 0; no_need_xmit: usb_hcd_giveback_urb(hcd, urb); return 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 = 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 irqreturn_t admhc_irq(struct usb_hcd *hcd) { struct admhcd *ahcd = hcd_to_admhcd(hcd); struct admhcd_regs __iomem *regs = ahcd->regs; u32 ints; ints = admhc_readl(ahcd, ®s->int_status); if ((ints & ADMHC_INTR_INTA) == 0) { /* no unmasked interrupt status is set */ return IRQ_NONE; } ints &= admhc_readl(ahcd, ®s->int_enable); if (ints & ADMHC_INTR_FATI) { /* e.g. due to PCI Master/Target Abort */ admhc_disable(ahcd); admhc_err(ahcd, "Fatal Error, controller disabled\n"); admhc_dump(ahcd, 1); admhc_usb_reset(ahcd); } if (ints & ADMHC_INTR_BABI) { admhc_intr_disable(ahcd, ADMHC_INTR_BABI); admhc_intr_ack(ahcd, ADMHC_INTR_BABI); admhc_err(ahcd, "Babble Detected\n"); } if (ints & ADMHC_INTR_INSM) { admhc_vdbg(ahcd, "Root Hub Status Change\n"); ahcd->next_statechange = jiffies + STATECHANGE_DELAY; admhc_intr_ack(ahcd, ADMHC_INTR_RESI | ADMHC_INTR_INSM); /* NOTE: Vendors didn't always make the same implementation * choices for RHSC. Many followed the spec; RHSC triggers * on an edge, like setting and maybe clearing a port status * change bit. With others it's level-triggered, active * until khubd clears all the port status change bits. We'll * always disable it here and rely on polling until khubd * re-enables it. */ admhc_intr_disable(ahcd, ADMHC_INTR_INSM); usb_hcd_poll_rh_status(hcd); } else if (ints & ADMHC_INTR_RESI) { /* For connect and disconnect events, we expect the controller * to turn on RHSC along with RD. But for remote wakeup events * this might not happen. */ admhc_vdbg(ahcd, "Resume Detect\n"); admhc_intr_ack(ahcd, ADMHC_INTR_RESI); hcd->poll_rh = 1; if (ahcd->autostop) { spin_lock(&ahcd->lock); admhc_rh_resume(ahcd); spin_unlock(&ahcd->lock); } else usb_hcd_resume_root_hub(hcd); } if (ints & ADMHC_INTR_TDC) { admhc_vdbg(ahcd, "Transfer Descriptor Complete\n"); admhc_intr_ack(ahcd, ADMHC_INTR_TDC); if (HC_IS_RUNNING(hcd->state)) admhc_intr_disable(ahcd, ADMHC_INTR_TDC); spin_lock(&ahcd->lock); admhc_td_complete(ahcd); spin_unlock(&ahcd->lock); if (HC_IS_RUNNING(hcd->state)) admhc_intr_enable(ahcd, ADMHC_INTR_TDC); } if (ints & ADMHC_INTR_SO) { /* could track INTR_SO to reduce available PCI/... bandwidth */ admhc_vdbg(ahcd, "Schedule Overrun\n"); } #if 1 spin_lock(&ahcd->lock); if (ahcd->ed_rm_list) finish_unlinks(ahcd, admhc_frame_no(ahcd)); if ((ints & ADMHC_INTR_SOFI) != 0 && !ahcd->ed_rm_list && HC_IS_RUNNING(hcd->state)) admhc_intr_disable(ahcd, ADMHC_INTR_SOFI); spin_unlock(&ahcd->lock); #else if (ints & ADMHC_INTR_SOFI) { admhc_vdbg(ahcd, "Start Of Frame\n"); spin_lock(&ahcd->lock); /* handle any pending ED removes */ finish_unlinks(ahcd, admhc_frameno(ahcd)); /* leaving INTR_SOFI enabled when there's still unlinking * to be done in the (next frame). */ if ((ahcd->ed_rm_list == NULL) || HC_IS_RUNNING(hcd->state) == 0) /* * disable INTR_SOFI if there are no unlinking to be * done (in the next frame) */ admhc_intr_disable(ahcd, ADMHC_INTR_SOFI); spin_unlock(&ahcd->lock); } #endif if (HC_IS_RUNNING(hcd->state)) { admhc_intr_ack(ahcd, ints); admhc_intr_enable(ahcd, ADMHC_INTR_MIE); admhc_writel_flush(ahcd); } return IRQ_HANDLED; }