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

📄 ohci-hub.c

📁 usb driver for 2.6.17
💻 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" : "" \		);/*-------------------------------------------------------------------------*/#ifdef	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_bus_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);	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {		spin_unlock_irqrestore (&ohci->lock, flags);		return -ESHUTDOWN;	}	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 */	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 (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev))		ohci->hc_control |= OHCI_CTRL_RWE;	else		ohci->hc_control &= ~OHCI_CTRL_RWE;	/* Suspend hub ... this is the "global (to this bus) suspend" mode,	 * which doesn't imply ports will first be individually suspended.	 */	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:	/* external suspend vs self autosuspend ... same effect */	if (status == 0)		usb_hcd_suspend_root_hub(hcd);	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_bus_resume (struct usb_hcd *hcd){	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);	u32			temp, enables;	int			status = -EINPROGRESS;	unsigned long		flags;	if (time_before (jiffies, ohci->next_statechange))		msleep(5);	spin_lock_irqsave (&ohci->lock, flags);	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {		spin_unlock_irqrestore (&ohci->lock, flags);		return -ESHUTDOWN;	}	ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);	if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {		/* this can happen after resuming a swsusp snapshot */		if (hcd->state == HC_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:		/* this can happen after resuming a swsusp snapshot */		ohci_dbg (ohci, "snapshot resume? reinit\n");		status = -EBUSY;		break;	default:		/* RESET, we lost power */		ohci_dbg (ohci, "lost power\n");		status = -EBUSY;	}	spin_unlock_irqrestore (&ohci->lock, flags);	if (status == -EBUSY) {		(void) ohci_init (ohci);		return ohci_restart (ohci);	}	if (status != -EINPROGRESS)		return status;	temp = ohci->num_ports;	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 erratum) need extra-long delays */	msleep (20 /* usb 11.5.1.10 */ + 12 /* 32 msec counter */ + 1);	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);	/* Sometimes PCI D3 suspend trashes frame timings ... */	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->hc_control;	temp &= OHCI_CTRL_RWC;	temp |= OHCI_CONTROL_INIT | OHCI_USB_OPER;	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);	}	return 0;}#endif	/* 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		i, changed = 0, length = 1;	int		can_suspend = device_may_wakeup(&hcd->self.root_hub->dev);	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",

⌨️ 快捷键说明

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