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

📄 isp116x-hcd.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	spin_lock_irqsave(&isp116x->lock, flags);	fmnum = isp116x_read_reg32(isp116x, HCFMNUM);	spin_unlock_irqrestore(&isp116x->lock, flags);	return (int)fmnum;}/*----------------------------------------------------------------*//*  Adapted from ohci-hub.c. Currently we don't support autosuspend.*/static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf){	struct isp116x *isp116x = hcd_to_isp116x(hcd);	int ports, i, changed = 0;	unsigned long flags;	if (!HC_IS_RUNNING(hcd->state))		return -ESHUTDOWN;	/* Report no status change now, if we are scheduled to be	   called later */	if (timer_pending(&hcd->rh_timer))		return 0;	ports = isp116x->rhdesca & RH_A_NDP;	spin_lock_irqsave(&isp116x->lock, flags);	isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS);	if (isp116x->rhstatus & (RH_HS_LPSC | RH_HS_OCIC))		buf[0] = changed = 1;	else		buf[0] = 0;	for (i = 0; i < ports; i++) {		u32 status = isp116x->rhport[i] =		    isp116x_read_reg32(isp116x, i ? HCRHPORT2 : HCRHPORT1);		if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC			      | RH_PS_OCIC | RH_PS_PRSC)) {			changed = 1;			buf[0] |= 1 << (i + 1);			continue;		}	}	spin_unlock_irqrestore(&isp116x->lock, flags);	return changed;}static void isp116x_hub_descriptor(struct isp116x *isp116x,				   struct usb_hub_descriptor *desc){	u32 reg = isp116x->rhdesca;	desc->bDescriptorType = 0x29;	desc->bDescLength = 9;	desc->bHubContrCurrent = 0;	desc->bNbrPorts = (u8) (reg & 0x3);	/* Power switching, device type, overcurrent. */	desc->wHubCharacteristics =	    (__force __u16) cpu_to_le16((u16) ((reg >> 8) & 0x1f));	desc->bPwrOn2PwrGood = (u8) ((reg >> 24) & 0xff);	/* two bitmaps:  ports removable, and legacy PortPwrCtrlMask */	desc->bitmap[0] = desc->bNbrPorts == 1 ? 1 << 1 : 3 << 1;	desc->bitmap[1] = ~0;}/* Perform reset of a given port.   It would be great to just start the reset and let the   USB core to clear the reset in due time. However,   root hub ports should be reset for at least 50 ms, while   our chip stays in reset for about 10 ms. I.e., we must   repeatedly reset it ourself here.*/static inline void root_port_reset(struct isp116x *isp116x, unsigned port){	u32 tmp;	unsigned long flags, t;	/* Root hub reset should be 50 ms, but some devices	   want it even longer. */	t = jiffies + msecs_to_jiffies(100);	while (time_before(jiffies, t)) {		spin_lock_irqsave(&isp116x->lock, flags);		/* spin until any current reset finishes */		for (;;) {			tmp = isp116x_read_reg32(isp116x, port ?						 HCRHPORT2 : HCRHPORT1);			if (!(tmp & RH_PS_PRS))				break;			udelay(500);		}		/* Don't reset a disconnected port */		if (!(tmp & RH_PS_CCS)) {			spin_unlock_irqrestore(&isp116x->lock, flags);			break;		}		/* Reset lasts 10ms (claims datasheet) */		isp116x_write_reg32(isp116x, port ? HCRHPORT2 :				    HCRHPORT1, (RH_PS_PRS));		spin_unlock_irqrestore(&isp116x->lock, flags);		msleep(10);	}}/* Adapted from ohci-hub.c */static int isp116x_hub_control(struct usb_hcd *hcd,			       u16 typeReq,			       u16 wValue, u16 wIndex, char *buf, u16 wLength){	struct isp116x *isp116x = hcd_to_isp116x(hcd);	int ret = 0;	unsigned long flags;	int ports = isp116x->rhdesca & RH_A_NDP;	u32 tmp = 0;	switch (typeReq) {	case ClearHubFeature:		DBG("ClearHubFeature: ");		switch (wValue) {		case C_HUB_OVER_CURRENT:			DBG("C_HUB_OVER_CURRENT\n");			spin_lock_irqsave(&isp116x->lock, flags);			isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_OCIC);			spin_unlock_irqrestore(&isp116x->lock, flags);		case C_HUB_LOCAL_POWER:			DBG("C_HUB_LOCAL_POWER\n");			break;		default:			goto error;		}		break;	case SetHubFeature:		DBG("SetHubFeature: ");		switch (wValue) {		case C_HUB_OVER_CURRENT:		case C_HUB_LOCAL_POWER:			DBG("C_HUB_OVER_CURRENT or C_HUB_LOCAL_POWER\n");			break;		default:			goto error;		}		break;	case GetHubDescriptor:		DBG("GetHubDescriptor\n");		isp116x_hub_descriptor(isp116x,				       (struct usb_hub_descriptor *)buf);		break;	case GetHubStatus:		DBG("GetHubStatus\n");		*(__le32 *) buf = 0;		break;	case GetPortStatus:		DBG("GetPortStatus\n");		if (!wIndex || wIndex > ports)			goto error;		tmp = isp116x->rhport[--wIndex];		*(__le32 *) buf = cpu_to_le32(tmp);		DBG("GetPortStatus: port[%d]  %08x\n", wIndex + 1, tmp);		break;	case ClearPortFeature:		DBG("ClearPortFeature: ");		if (!wIndex || wIndex > ports)			goto error;		wIndex--;		switch (wValue) {		case USB_PORT_FEAT_ENABLE:			DBG("USB_PORT_FEAT_ENABLE\n");			tmp = RH_PS_CCS;			break;		case USB_PORT_FEAT_C_ENABLE:			DBG("USB_PORT_FEAT_C_ENABLE\n");			tmp = RH_PS_PESC;			break;		case USB_PORT_FEAT_SUSPEND:			DBG("USB_PORT_FEAT_SUSPEND\n");			tmp = RH_PS_POCI;			break;		case USB_PORT_FEAT_C_SUSPEND:			DBG("USB_PORT_FEAT_C_SUSPEND\n");			tmp = RH_PS_PSSC;			break;		case USB_PORT_FEAT_POWER:			DBG("USB_PORT_FEAT_POWER\n");			tmp = RH_PS_LSDA;			break;		case USB_PORT_FEAT_C_CONNECTION:			DBG("USB_PORT_FEAT_C_CONNECTION\n");			tmp = RH_PS_CSC;			break;		case USB_PORT_FEAT_C_OVER_CURRENT:			DBG("USB_PORT_FEAT_C_OVER_CURRENT\n");			tmp = RH_PS_OCIC;			break;		case USB_PORT_FEAT_C_RESET:			DBG("USB_PORT_FEAT_C_RESET\n");			tmp = RH_PS_PRSC;			break;		default:			goto error;		}		spin_lock_irqsave(&isp116x->lock, flags);		isp116x_write_reg32(isp116x, wIndex				    ? HCRHPORT2 : HCRHPORT1, tmp);		isp116x->rhport[wIndex] =		    isp116x_read_reg32(isp116x, wIndex ? HCRHPORT2 : HCRHPORT1);		spin_unlock_irqrestore(&isp116x->lock, flags);		break;	case SetPortFeature:		DBG("SetPortFeature: ");		if (!wIndex || wIndex > ports)			goto error;		wIndex--;		switch (wValue) {		case USB_PORT_FEAT_SUSPEND:			DBG("USB_PORT_FEAT_SUSPEND\n");			spin_lock_irqsave(&isp116x->lock, flags);			isp116x_write_reg32(isp116x, wIndex					    ? HCRHPORT2 : HCRHPORT1, RH_PS_PSS);			break;		case USB_PORT_FEAT_POWER:			DBG("USB_PORT_FEAT_POWER\n");			spin_lock_irqsave(&isp116x->lock, flags);			isp116x_write_reg32(isp116x, wIndex					    ? HCRHPORT2 : HCRHPORT1, RH_PS_PPS);			break;		case USB_PORT_FEAT_RESET:			DBG("USB_PORT_FEAT_RESET\n");			root_port_reset(isp116x, wIndex);			spin_lock_irqsave(&isp116x->lock, flags);			break;		default:			goto error;		}		isp116x->rhport[wIndex] =		    isp116x_read_reg32(isp116x, wIndex ? HCRHPORT2 : HCRHPORT1);		spin_unlock_irqrestore(&isp116x->lock, flags);		break;	default:	      error:		/* "protocol stall" on error */		DBG("PROTOCOL STALL\n");		ret = -EPIPE;	}	return ret;}#ifdef	CONFIG_PMstatic int isp116x_bus_suspend(struct usb_hcd *hcd){	struct isp116x *isp116x = hcd_to_isp116x(hcd);	unsigned long flags;	u32 val;	int ret = 0;	spin_lock_irqsave(&isp116x->lock, flags);	val = isp116x_read_reg32(isp116x, HCCONTROL);	switch (val & HCCONTROL_HCFS) {	case HCCONTROL_USB_OPER:		hcd->state = HC_STATE_QUIESCING;		val &= (~HCCONTROL_HCFS & ~HCCONTROL_RWE);		val |= HCCONTROL_USB_SUSPEND;		if (hcd->remote_wakeup)			val |= HCCONTROL_RWE;		/* Wait for usb transfers to finish */		mdelay(2);		isp116x_write_reg32(isp116x, HCCONTROL, val);		hcd->state = HC_STATE_SUSPENDED;		/* Wait for devices to suspend */		mdelay(5);	case HCCONTROL_USB_SUSPEND:		break;	case HCCONTROL_USB_RESUME:		isp116x_write_reg32(isp116x, HCCONTROL,				    (val & ~HCCONTROL_HCFS) |				    HCCONTROL_USB_RESET);	case HCCONTROL_USB_RESET:		ret = -EBUSY;		break;	default:		ret = -EINVAL;	}	spin_unlock_irqrestore(&isp116x->lock, flags);	return ret;}static int isp116x_bus_resume(struct usb_hcd *hcd){	struct isp116x *isp116x = hcd_to_isp116x(hcd);	u32 val;	int ret = -EINPROGRESS;	msleep(5);	spin_lock_irq(&isp116x->lock);	val = isp116x_read_reg32(isp116x, HCCONTROL);	switch (val & HCCONTROL_HCFS) {	case HCCONTROL_USB_SUSPEND:		val &= ~HCCONTROL_HCFS;		val |= HCCONTROL_USB_RESUME;		isp116x_write_reg32(isp116x, HCCONTROL, val);	case HCCONTROL_USB_RESUME:		break;	case HCCONTROL_USB_OPER:		/* Without setting power_state here the		   SUSPENDED state won't be removed from		   sysfs/usbN/power.state as a response to remote		   wakeup. Maybe in the future. */		hcd->self.root_hub->dev.power.power_state = PMSG_ON;		ret = 0;		break;	default:		ret = -EBUSY;	}	if (ret != -EINPROGRESS) {		spin_unlock_irq(&isp116x->lock);		return ret;	}	val = isp116x->rhdesca & RH_A_NDP;	while (val--) {		u32 stat =		    isp116x_read_reg32(isp116x, val ? HCRHPORT2 : HCRHPORT1);		/* force global, not selective, resume */		if (!(stat & RH_PS_PSS))			continue;		DBG("%s: Resuming port %d\n", __func__, val);		isp116x_write_reg32(isp116x, RH_PS_POCI, val				    ? HCRHPORT2 : HCRHPORT1);	}	spin_unlock_irq(&isp116x->lock);	hcd->state = HC_STATE_RESUMING;	mdelay(20);	/* Go operational */	spin_lock_irq(&isp116x->lock);	val = isp116x_read_reg32(isp116x, HCCONTROL);	isp116x_write_reg32(isp116x, HCCONTROL,			    (val & ~HCCONTROL_HCFS) | HCCONTROL_USB_OPER);	spin_unlock_irq(&isp116x->lock);	/* see analogous comment above */	hcd->self.root_hub->dev.power.power_state = PMSG_ON;	hcd->state = HC_STATE_RUNNING;	return 0;}#else#define	isp116x_bus_suspend	NULL#define	isp116x_bus_resume	NULL#endif/*-----------------------------------------------------------------*/#ifdef STUB_DEBUG_FILEstatic inline void create_debug_file(struct isp116x *isp116x){}static inline void remove_debug_file(struct isp116x *isp116x){}#else#include <linux/proc_fs.h>#include <linux/seq_file.h>static void dump_irq(struct seq_file *s, char *label, u16 mask){	seq_printf(s, "%s %04x%s%s%s%s%s%s\n", label, mask,		   mask & HCuPINT_CLKRDY ? " clkrdy" : "",		   mask & HCuPINT_SUSP ? " susp" : "",		   mask & HCuPINT_OPR ? " opr" : "",		   mask & HCuPINT_AIIEOT ? " eot" : "",		   mask & HCuPINT_ATL ? " atl" : "",		   mask & HCuPINT_SOF ? " sof" : "");}static void dump_int(struct seq_file *s, char *label, u32 mask){	seq_printf(s, "%s %08x%s%s%s%s%s%s%s\n", label, mask,		   mask & HCINT_MIE ? " MIE" : "",		   mask & HCINT_RHSC ? " rhsc" : "",		   mask & HCINT_FNO ? " fno" : "",		   mask & HCINT_UE ? " ue" : "",		   mask & HCINT_RD ? " rd" : "",		   mask & HCINT_SF ? " sof" : "", mask & HCINT_SO ? " so" : "");}static int proc_isp116x_show(struct seq_file *s, void *unused){	struct isp116x *isp116x = s->private;	struct isp116x_ep *ep;	struct urb *urb;	unsigned i;	char *str;	seq_printf(s, "%s\n%s version %s\n",		   isp116x_to_hcd(isp116x)->product_desc, hcd_name,		   DRIVER_VERSION);	if (HC_IS_SUSPENDED(isp116x_to_hcd(isp116x)->state)) {		seq_printf(s, "HCD is suspended\n");		return 0;	}	if (!HC_IS_RUNNING(isp116x_to_hcd(isp116x)->state)) {		seq_printf(s, "HCD not running\n");		return 0;	}	spin_lock_irq(&isp116x->lock);	dump_irq(s, "hc_irq_enable", isp116x_read_reg16(isp116x, HCuPINTENB));	dump_irq(s, "hc_irq_status", isp116x_read_reg16(isp116x, HCuPINT));	dump_int(s, "hc_int_enable", isp116x_read_reg32(isp116x, HCINTENB));	dump_int(s, "hc_int_status", isp116x_read_reg32(isp116x, HCINTSTAT));	list_for_each_entry(ep, &isp116x->async, schedule) {		switch (ep->nextpid) {		case USB_PID_IN:			str = "in";			break;		case USB_PID_OUT:			str = "out";			break;		case USB_PID_SETUP:			str = "setup";			break;		case USB_PID_ACK:			str = "status";			break;		default:			str = "?";			break;		};		seq_printf(s, "%p, ep%d%s, maxpacket %d:\n", ep,			   ep->epnum, str, ep->maxpacket);		list_for_each_entry(urb, &ep->hep->urb_list, urb_list) {			seq_printf(s, "  urb%p, %d/%d\n", urb,				   urb->actual_length,				   urb->transfer_buffer_length);		}	}

⌨️ 快捷键说明

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