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

📄 ohci-hub.c

📁 h内核
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * OHCI HCD (Host Controller Driver) for USB. *  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net> *  * This file is licenced under GPL *//*-------------------------------------------------------------------------*//* * OHCI Root Hub ... the nonsharable stuff */#define dbg_port(hc,label,num,value) \	ohci_dbg (hc, \		"%s roothub.portstatus [%d] " \		"= 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \		label, num, temp, \		(temp & RH_PS_PRSC) ? " PRSC" : "", \		(temp & RH_PS_OCIC) ? " OCIC" : "", \		(temp & RH_PS_PSSC) ? " PSSC" : "", \		(temp & RH_PS_PESC) ? " PESC" : "", \		(temp & RH_PS_CSC) ? " CSC" : "", \ 		\		(temp & RH_PS_LSDA) ? " LSDA" : "", \		(temp & RH_PS_PPS) ? " PPS" : "", \		(temp & RH_PS_PRS) ? " PRS" : "", \		(temp & RH_PS_POCI) ? " POCI" : "", \		(temp & RH_PS_PSS) ? " PSS" : "", \ 		\		(temp & RH_PS_PES) ? " PES" : "", \		(temp & RH_PS_CCS) ? " CCS" : "" \		);/*-------------------------------------------------------------------------*/#if	defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM)#define OHCI_SCHED_ENABLES \	(OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)static void dl_done_list (struct ohci_hcd *, struct pt_regs *);static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *);static int ohci_restart (struct ohci_hcd *ohci);static int ohci_hub_suspend (struct usb_hcd *hcd){	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);	int			status = 0;	unsigned long		flags;	spin_lock_irqsave (&ohci->lock, flags);	ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);	switch (ohci->hc_control & OHCI_CTRL_HCFS) {	case OHCI_USB_RESUME:		ohci_dbg (ohci, "resume/suspend?\n");		ohci->hc_control &= ~OHCI_CTRL_HCFS;		ohci->hc_control |= OHCI_USB_RESET;		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);		(void) ohci_readl (ohci, &ohci->regs->control);		/* FALL THROUGH */	case OHCI_USB_RESET:		status = -EBUSY;		ohci_dbg (ohci, "needs reinit!\n");		goto done;	case OHCI_USB_SUSPEND:		ohci_dbg (ohci, "already suspended\n");		goto done;	}	ohci_dbg (ohci, "suspend root hub\n");	/* First stop any processing */	hcd->state = USB_STATE_QUIESCING;	if (ohci->hc_control & OHCI_SCHED_ENABLES) {		int		limit;		ohci->hc_control &= ~OHCI_SCHED_ENABLES;		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);		ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);		ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrstatus);		/* sched disables take effect on the next frame,		 * then the last WDH could take 6+ msec		 */		ohci_dbg (ohci, "stopping schedules ...\n");		limit = 2000;		while (limit > 0) {			udelay (250);			limit =- 250;			if (ohci_readl (ohci, &ohci->regs->intrstatus)					& OHCI_INTR_SF)				break;		}		dl_done_list (ohci, NULL);		mdelay (7);	}	dl_done_list (ohci, NULL);	finish_unlinks (ohci, ohci_frame_no(ohci), NULL);	ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus),			&ohci->regs->intrstatus);	/* maybe resume can wake root hub */	if (hcd->remote_wakeup)		ohci->hc_control |= OHCI_CTRL_RWE;	else		ohci->hc_control &= ~OHCI_CTRL_RWE;	/* Suspend hub */	ohci->hc_control &= ~OHCI_CTRL_HCFS;	ohci->hc_control |= OHCI_USB_SUSPEND;	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);	(void) ohci_readl (ohci, &ohci->regs->control);	/* no resumes until devices finish suspending */	ohci->next_statechange = jiffies + msecs_to_jiffies (5);done:	if (status == 0)		hcd->state = HCD_STATE_SUSPENDED;	spin_unlock_irqrestore (&ohci->lock, flags);	return status;}static inline struct ed *find_head (struct ed *ed){	/* for bulk and control lists */	while (ed->ed_prev)		ed = ed->ed_prev;	return ed;}/* caller has locked the root hub */static int ohci_hub_resume (struct usb_hcd *hcd){	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);	u32			temp, enables;	int			status = -EINPROGRESS;	if (time_before (jiffies, ohci->next_statechange))		msleep(5);	spin_lock_irq (&ohci->lock);	ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);	if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {		/* this can happen after suspend-to-disk */		if (hcd->state == USB_STATE_RESUMING) {			ohci_dbg (ohci, "BIOS/SMM active, control %03x\n",					ohci->hc_control);			status = -EBUSY;		/* this happens when pmcore resumes HC then root */		} else {			ohci_dbg (ohci, "duplicate resume\n");			status = 0;		}	} else switch (ohci->hc_control & OHCI_CTRL_HCFS) {	case OHCI_USB_SUSPEND:		ohci->hc_control &= ~(OHCI_CTRL_HCFS|OHCI_SCHED_ENABLES);		ohci->hc_control |= OHCI_USB_RESUME;		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);		(void) ohci_readl (ohci, &ohci->regs->control);		ohci_dbg (ohci, "resume root hub\n");		break;	case OHCI_USB_RESUME:		/* HCFS changes sometime after INTR_RD */		ohci_info (ohci, "wakeup\n");		break;	case OHCI_USB_OPER:		ohci_dbg (ohci, "odd resume\n");		status = 0;		break;	default:		/* RESET, we lost power */		ohci_dbg (ohci, "root hub hardware reset\n");		status = -EBUSY;	}	spin_unlock_irq (&ohci->lock);	if (status == -EBUSY) {		(void) ohci_init (ohci);		return ohci_restart (ohci);	}	if (status != -EINPROGRESS)		return status;	temp = roothub_a (ohci) & RH_A_NDP;	enables = 0;	while (temp--) {		u32 stat = ohci_readl (ohci,				       &ohci->regs->roothub.portstatus [temp]);		/* force global, not selective, resume */		if (!(stat & RH_PS_PSS))			continue;		ohci_writel (ohci, RH_PS_POCI,				&ohci->regs->roothub.portstatus [temp]);	}	/* Some controllers (lucent) need extra-long delays */	hcd->state = USB_STATE_RESUMING;	mdelay (20 /* usb 11.5.1.10 */ + 15);	temp = ohci_readl (ohci, &ohci->regs->control);	temp &= OHCI_CTRL_HCFS;	if (temp != OHCI_USB_RESUME) {		ohci_err (ohci, "controller won't resume\n");		return -EBUSY;	}	/* disable old schedule state, reinit from scratch */	ohci_writel (ohci, 0, &ohci->regs->ed_controlhead);	ohci_writel (ohci, 0, &ohci->regs->ed_controlcurrent);	ohci_writel (ohci, 0, &ohci->regs->ed_bulkhead);	ohci_writel (ohci, 0, &ohci->regs->ed_bulkcurrent);	ohci_writel (ohci, 0, &ohci->regs->ed_periodcurrent);	ohci_writel (ohci, (u32) ohci->hcca_dma, &ohci->regs->hcca);	periodic_reinit (ohci);	/* interrupts might have been disabled */	ohci_writel (ohci, OHCI_INTR_INIT, &ohci->regs->intrenable);	if (ohci->ed_rm_list)		ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrenable);	ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus),			&ohci->regs->intrstatus);	/* Then re-enable operations */	ohci_writel (ohci, OHCI_USB_OPER, &ohci->regs->control);	(void) ohci_readl (ohci, &ohci->regs->control);	msleep (3);	temp = OHCI_CONTROL_INIT | OHCI_USB_OPER;	if (hcd->can_wakeup)		temp |= OHCI_CTRL_RWC;	ohci->hc_control = temp;	ohci_writel (ohci, temp, &ohci->regs->control);	(void) ohci_readl (ohci, &ohci->regs->control);	/* TRSMRCY */	msleep (10);	/* keep it alive for ~5x suspend + resume costs */	ohci->next_statechange = jiffies + msecs_to_jiffies (250);	/* maybe turn schedules back on */	enables = 0;	temp = 0;	if (!ohci->ed_rm_list) {		if (ohci->ed_controltail) {			ohci_writel (ohci,					find_head (ohci->ed_controltail)->dma,					&ohci->regs->ed_controlhead);			enables |= OHCI_CTRL_CLE;			temp |= OHCI_CLF;		}		if (ohci->ed_bulktail) {			ohci_writel (ohci, find_head (ohci->ed_bulktail)->dma,				&ohci->regs->ed_bulkhead);			enables |= OHCI_CTRL_BLE;			temp |= OHCI_BLF;		}	}	if (hcd->self.bandwidth_isoc_reqs || hcd->self.bandwidth_int_reqs)		enables |= OHCI_CTRL_PLE|OHCI_CTRL_IE;	if (enables) {		ohci_dbg (ohci, "restarting schedules ... %08x\n", enables);		ohci->hc_control |= enables;		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);		if (temp)			ohci_writel (ohci, temp, &ohci->regs->cmdstatus);		(void) ohci_readl (ohci, &ohci->regs->control);	}	hcd->state = USB_STATE_RUNNING;	return 0;}static void ohci_rh_resume (void *_hcd){	struct usb_hcd	*hcd = _hcd;	usb_lock_device (hcd->self.root_hub);	(void) ohci_hub_resume (hcd);	usb_unlock_device (hcd->self.root_hub);}#elsestatic void ohci_rh_resume (void *_hcd){	struct ohci_hcd	*ohci = hcd_to_ohci (_hcd);	ohci_dbg(ohci, "rh_resume ??\n");}#endif	/* CONFIG_USB_SUSPEND || CONFIG_PM *//*-------------------------------------------------------------------------*//* build "status change" packet (one or two bytes) from HC registers */static intohci_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);	/* 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			|| !HCD_IS_RUNNING(hcd->state)) {		can_suspend = 0;		goto done;	}	ports = roothub_a (ohci) & RH_A_NDP; 	if (ports > MAX_ROOT_PORTS) {

⌨️ 快捷键说明

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