/*
 * 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);
}
Beispiel #3
0
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);
}
Beispiel #5
0
/* 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;
	}
}
Beispiel #6
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;
	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;
}
Beispiel #7
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);
}
Beispiel #9
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;
	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;
}
Beispiel #10
0
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;
}
Beispiel #12
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));
}
Beispiel #14
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;
}
Beispiel #15
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;
}
Beispiel #16
0
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;
}
Beispiel #17
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;
}
Beispiel #18
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;
}
Beispiel #19
0
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;
}
Beispiel #20
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;
}
Beispiel #23
0
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;
}
Beispiel #24
0
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;
}
Beispiel #25
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;
}
Beispiel #26
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, &regs->int_status);
	if ((ints & ADMHC_INTR_INTA) == 0) {
		/* no unmasked interrupt status is set */
		return IRQ_NONE;
	}

	ints &= admhc_readl(ahcd, &regs->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;
}