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

📄 ohci-hub.c

📁 h内核
💻 C
📖 第 1 页 / 共 2 页
字号:
		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);#ifdef CONFIG_PM	/* 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 = USB_STATE_RUNNING;		usb_unlock_device (hcd->self.root_hub);	}#endif	return changed ? length : 0;}/*-------------------------------------------------------------------------*/static voidohci_hub_descriptor (	struct ohci_hcd			*ohci,	struct usb_hub_descriptor	*desc) {	u32		rh = roothub_a (ohci);	int		ports = rh & RH_A_NDP; 	u16		temp;	desc->bDescriptorType = 0x29;	desc->bPwrOn2PwrGood = (rh & RH_A_POTPGT) >> 24;	desc->bHubContrCurrent = 0;	desc->bNbrPorts = ports;	temp = 1 + (ports / 8);	desc->bDescLength = 7 + 2 * temp;	temp = 0;	if (rh & RH_A_NPS)		/* no power switching? */	    temp |= 0x0002;	if (rh & RH_A_PSM) 		/* per-port power switching? */	    temp |= 0x0001;	if (rh & RH_A_NOCP)		/* no overcurrent reporting? */	    temp |= 0x0010;	else if (rh & RH_A_OCPM)	/* per-port overcurrent reporting? */	    temp |= 0x0008;	desc->wHubCharacteristics = (__force __u16)cpu_to_hc16(ohci, temp);	/* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */	rh = roothub_b (ohci);	desc->bitmap [0] = rh & RH_B_DR;	if (ports > 7) {		desc->bitmap [1] = (rh & RH_B_DR) >> 8;		desc->bitmap [2] = desc->bitmap [3] = 0xff;	} else		desc->bitmap [1] = 0xff;}/*-------------------------------------------------------------------------*/#ifdef	CONFIG_USB_OTGstatic int ohci_start_port_reset (struct usb_hcd *hcd, unsigned port){	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);	u32			status;	if (!port)		return -EINVAL;	port--;	/* start port reset before HNP protocol times out */	status = ohci_readl(ohci, &ohci->regs->roothub.portstatus [port]);	if (!(status & RH_PS_CCS))		return -ENODEV;	/* khubd will finish the reset later */	ohci_writel(ohci, RH_PS_PRS, &ohci->regs->roothub.portstatus [port]);	return 0;}static void start_hnp(struct ohci_hcd *ohci);#else#define	ohci_start_port_reset		NULL#endif/*-------------------------------------------------------------------------*//* See usb 7.1.7.5:  root hubs must issue at least 50 msec reset signaling, * not necessarily continuous ... to guard against resume signaling. * The short timeout is safe for non-root hubs, and is backward-compatible * with earlier Linux hosts. */#ifdef	CONFIG_USB_SUSPEND#define	PORT_RESET_MSEC		50#else#define	PORT_RESET_MSEC		10#endif/* this timer value might be vendor-specific ... */#define	PORT_RESET_HW_MSEC	10/* wrap-aware logic morphed from <linux/jiffies.h> */#define tick_before(t1,t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0)/* called from some task, normally khubd */static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port){	__hc32 __iomem *portstat = &ohci->regs->roothub.portstatus [port];	u32	temp;	u16	now = ohci_readl(ohci, &ohci->regs->fmnumber);	u16	reset_done = now + PORT_RESET_MSEC;	/* build a "continuous enough" reset signal, with up to	 * 3msec gap between pulses.  scheduler HZ==100 must work;	 * this might need to be deadline-scheduled.	 */	do {		/* spin until any current reset finishes */		for (;;) {			temp = ohci_readl (ohci, portstat);			if (!(temp & RH_PS_PRS))				break;			udelay (500);		} 		if (!(temp & RH_PS_CCS))			break;		if (temp & RH_PS_PRSC)			ohci_writel (ohci, RH_PS_PRSC, portstat);		/* start the next reset, sleep till it's probably done */		ohci_writel (ohci, RH_PS_PRS, portstat);		msleep(PORT_RESET_HW_MSEC);		now = ohci_readl(ohci, &ohci->regs->fmnumber);	} while (tick_before(now, reset_done));	/* caller synchronizes using PRSC */}static int ohci_hub_control (	struct usb_hcd	*hcd,	u16		typeReq,	u16		wValue,	u16		wIndex,	char		*buf,	u16		wLength) {	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);	int		ports = hcd_to_bus (hcd)->root_hub->maxchild;	u32		temp;	int		retval = 0;	switch (typeReq) {	case ClearHubFeature:		switch (wValue) {		case C_HUB_OVER_CURRENT:			ohci_writel (ohci, RH_HS_OCIC,					&ohci->regs->roothub.status);		case C_HUB_LOCAL_POWER:			break;		default:			goto error;		}		break;	case ClearPortFeature:		if (!wIndex || wIndex > ports)			goto error;		wIndex--;		switch (wValue) {		case USB_PORT_FEAT_ENABLE:			temp = RH_PS_CCS;			break;		case USB_PORT_FEAT_C_ENABLE:			temp = RH_PS_PESC;			break;		case USB_PORT_FEAT_SUSPEND:			temp = RH_PS_POCI;			if ((ohci->hc_control & OHCI_CTRL_HCFS)					!= OHCI_USB_OPER)				schedule_work (&ohci->rh_resume);			break;		case USB_PORT_FEAT_C_SUSPEND:			temp = RH_PS_PSSC;			break;		case USB_PORT_FEAT_POWER:			temp = RH_PS_LSDA;			break;		case USB_PORT_FEAT_C_CONNECTION:			temp = RH_PS_CSC;			break;		case USB_PORT_FEAT_C_OVER_CURRENT:			temp = RH_PS_OCIC;			break;		case USB_PORT_FEAT_C_RESET:			temp = RH_PS_PRSC;			break;		default:			goto error;		}		ohci_writel (ohci, temp,				&ohci->regs->roothub.portstatus [wIndex]);		// ohci_readl (ohci, &ohci->regs->roothub.portstatus [wIndex]);		break;	case GetHubDescriptor:		ohci_hub_descriptor (ohci, (struct usb_hub_descriptor *) buf);		break;	case GetHubStatus:		temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE);		*(__le32 *) buf = cpu_to_le32 (temp);		break;	case GetPortStatus:		if (!wIndex || wIndex > ports)			goto error;		wIndex--;		temp = roothub_portstatus (ohci, wIndex);		*(__le32 *) buf = cpu_to_le32 (temp);#ifndef	OHCI_VERBOSE_DEBUG	if (*(u16*)(buf+2))	/* only if wPortChange is interesting */#endif		dbg_port (ohci, "GetStatus", wIndex, temp);		break;	case SetHubFeature:		switch (wValue) {		case C_HUB_OVER_CURRENT:			// FIXME:  this can be cleared, yes?		case C_HUB_LOCAL_POWER:			break;		default:			goto error;		}		break;	case SetPortFeature:		if (!wIndex || wIndex > ports)			goto error;		wIndex--;		switch (wValue) {		case USB_PORT_FEAT_SUSPEND:#ifdef	CONFIG_USB_OTG			if (hcd->self.otg_port == (wIndex + 1)					&& hcd->self.b_hnp_enable)				start_hnp(ohci);			else#endif			ohci_writel (ohci, RH_PS_PSS,				&ohci->regs->roothub.portstatus [wIndex]);			break;		case USB_PORT_FEAT_POWER:			ohci_writel (ohci, RH_PS_PPS,				&ohci->regs->roothub.portstatus [wIndex]);			break;		case USB_PORT_FEAT_RESET:			root_port_reset (ohci, wIndex);			break;		default:			goto error;		}		break;	default:error:		/* "protocol stall" on error */		retval = -EPIPE;	}	return retval;}

⌨️ 快捷键说明

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