⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ehci-hub.c

📁 usb driver for 2.6.17
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 2001-2004 by David Brownell *  * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* this file is part of ehci-hcd.c *//*-------------------------------------------------------------------------*//* * EHCI Root Hub ... the nonsharable stuff * * Registers don't need cpu_to_le32, that happens transparently *//*-------------------------------------------------------------------------*/#ifdef	CONFIG_PMstatic 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);	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)		ehci->reclaim_ready = 1;	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;		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 */	del_timer_sync (&ehci->watchdog);	ehci_halt (ehci);	hcd->state = HC_STATE_SUSPENDED;	ehci->next_statechange = jiffies + msecs_to_jiffies(10);	spin_unlock_irq (&ehci->lock);	return 0;}/* caller has locked the root hub, and should reset/reinit on error */static int ehci_bus_resume (struct usb_hcd *hcd){	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);	u32			temp;	int			i;	int			intr_enable;	if (time_before (jiffies, ehci->next_statechange))		msleep(5);	spin_lock_irq (&ehci->lock);	/* Ideally and we've got a real resume here, and no port's power	 * was lost.  (For PCI, that means Vaux was maintained.)  But we	 * could instead be restoring a swsusp snapshot -- so that BIOS was	 * the last user of the controller, not reset/pm hardware keeping	 * state we gave to it.	 */	/* re-init operational registers in case we lost power */	if (readl (&ehci->regs->intr_enable) == 0) { 		/* at least some APM implementations will try to deliver		 * IRQs right away, so delay them until we're ready. 		 */ 		intr_enable = 1;		writel (0, &ehci->regs->segment);		writel (ehci->periodic_dma, &ehci->regs->frame_list);		writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);	} else		intr_enable = 0;	ehci_dbg(ehci, "resume root hub%s\n",			intr_enable ? " after power loss" : "");	/* restore CMD_RUN, framelist size, and irq threshold */	writel (ehci->command, &ehci->regs->command);	/* take ports out of suspend */	i = HCS_N_PORTS (ehci->hcs_params);	while (i--) {		temp = readl (&ehci->regs->port_status [i]);		temp &= ~(PORT_RWC_BITS			| PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);		if (temp & PORT_SUSPEND) {			ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);			temp |= PORT_RESUME;		}		writel (temp, &ehci->regs->port_status [i]);	}	i = HCS_N_PORTS (ehci->hcs_params);	mdelay (20);	while (i--) {		temp = readl (&ehci->regs->port_status [i]);		if ((temp & PORT_SUSPEND) == 0)			continue;		temp &= ~(PORT_RWC_BITS | PORT_RESUME);		writel (temp, &ehci->regs->port_status [i]);		ehci_vdbg (ehci, "resumed port %d\n", i + 1);	}	(void) readl (&ehci->regs->command);	/* maybe re-activate the schedule(s) */	temp = 0;	if (ehci->async->qh_next.qh)		temp |= CMD_ASE;	if (ehci->periodic_sched)		temp |= CMD_PSE;	if (temp) {		ehci->command |= temp;		writel (ehci->command, &ehci->regs->command);	}	ehci->next_statechange = jiffies + msecs_to_jiffies(5);	hcd->state = HC_STATE_RUNNING;	/* Now we can safely re-enable irqs */	if (intr_enable)		writel (INTR_MASK, &ehci->regs->intr_enable);	spin_unlock_irq (&ehci->lock);	return 0;}#else#define ehci_bus_suspend	NULL#define ehci_bus_resume		NULL#endif	/* CONFIG_PM *//*-------------------------------------------------------------------------*/static int check_reset_complete (	struct ehci_hcd	*ehci,	int		index,	int		port_status) {	if (!(port_status & PORT_CONNECT)) {		ehci->reset_done [index] = 0;		return port_status;	}	/* if reset finished and it's still not enabled -- handoff */	if (!(port_status & PORT_PE)) {		/* with integrated TT, there's nobody to hand it to! */		if (ehci_is_TDI(ehci)) {			ehci_dbg (ehci,				"Failed to enable port %d on root hub TT\n",				index+1);			return port_status;		}		ehci_dbg (ehci, "port %d full speed --> companion\n",			index + 1);		// what happens if HCS_N_CC(params) == 0 ?		port_status |= PORT_OWNER;		port_status &= ~PORT_RWC_BITS;		writel (port_status, &ehci->regs->port_status [index]);	} else		ehci_dbg (ehci, "port %d high speed\n", index + 1);	return port_status;}/*-------------------------------------------------------------------------*//* build "status change" packet (one or two bytes) from HC registers */static intehci_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 voidehci_hub_descriptor (	struct ehci_hcd			*ehci,	struct usb_hub_descriptor	*desc) {	int		ports = HCS_N_PORTS (ehci->hcs_params);	u16		temp;	desc->bDescriptorType = 0x29;	desc->bPwrOn2PwrGood = 10;	/* ehci 1.0, 2.3.9 says 20ms max */	desc->bHubContrCurrent = 0;	desc->bNbrPorts = ports;	temp = 1 + (ports / 8);	desc->bDescLength = 7 + 2 * temp;	/* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -