Esempio n. 1
0
int ohci_power(void *ohci, int is_on)
{
	struct ohci_hcd *ohcip = (struct ohci_hcd *)ohci;
	int port;
	int temp;

	temp = roothub_a(ohcip);

	/* If NoPowerSwitching is true, just return */
	if (temp & RH_A_NPS) {
		return 0;
	}

	/* If port switched, switch each port */
	if (temp & RH_A_PSM) {
		for (port = ohcip->num_ports; port > 0; ) {
			(void) ohci_hub_control(ohci_to_hcd(ohcip),
									is_on ? SetPortFeature : ClearPortFeature,
									USB_PORT_FEAT_POWER,
									port--, NULL, 0);
		}
	}
	/* Else use Global Power */
	else {
		temp = roothub_status(ohcip);
		if (is_on) {
			temp |= RH_HS_LPSC;	 /* SetGlobalPower */
		}
		else {
			temp |= RH_HS_LPS;	 /* ClearGlobalPower */
		}
		ohci_writel(ohcip, temp, &ohcip->regs->roothub.status);
	}
	return 0;
}
Esempio n. 2
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;
}
Esempio n. 3
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;
}
Esempio n. 4
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;
}
Esempio n. 5
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 = 1;

	ports = roothub_a (ohci) & RH_A_NDP; 
	if (ports > MAX_ROOT_PORTS) {
		if (!HCD_IS_RUNNING(ohci->hcd.state))
			return -ESHUTDOWN;
		ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n",
			ports, ohci_readl (&ohci->regs->roothub.a) & RH_A_NDP);
		/* retry later; "should not happen" */
		return 0;
	}

	/* 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) && ohci->hcd.remote_wakeup)
			continue;
		can_suspend = 0;
	}

#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
			&& down_trylock (&hcd->self.root_hub->serialize) == 0
			) {
		ohci_vdbg (ohci, "autosuspend\n");
		(void) ohci_hub_suspend (&ohci->hcd);
		ohci->hcd.state = USB_STATE_RUNNING;
		up (&hcd->self.root_hub->serialize);
	}
#endif

	return changed ? length : 0;
}