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

📄 sl811-hcd.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
		if (retval < 0)			goto fail;		ep->branch = retval;		retval = 0;		urb->start_frame = (sl811->frame & (PERIODIC_SIZE - 1))					+ ep->branch;		/* sort each schedule branch by period (slow before fast)		 * to share the faster parts of the tree without needing		 * dummy/placeholder nodes		 */		DBG("schedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);		for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {			struct sl811h_ep	**prev = &sl811->periodic[i];			struct sl811h_ep	*here = *prev;			while (here && ep != here) {				if (ep->period > here->period)					break;				prev = &here->next;				here = *prev;			}			if (ep != here) {				ep->next = here;				*prev = ep;			}			sl811->load[i] += ep->load;		}		sl811->periodic_count++;		hcd->self.bandwidth_allocated += ep->load / ep->period;		sofirq_on(sl811);	}	/* in case of unlink-during-submit */	spin_lock(&urb->lock);	if (urb->status != -EINPROGRESS) {		spin_unlock(&urb->lock);		finish_request(sl811, ep, urb, NULL, 0);		retval = 0;		goto fail;	}	urb->hcpriv = hep;	spin_unlock(&urb->lock);	start_transfer(sl811);	sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);fail:	spin_unlock_irqrestore(&sl811->lock, flags);	return retval;}static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb){	struct sl811		*sl811 = hcd_to_sl811(hcd);	struct usb_host_endpoint *hep;	unsigned long		flags;	struct sl811h_ep	*ep;	int			retval = 0;	spin_lock_irqsave(&sl811->lock, flags);	hep = urb->hcpriv;	if (!hep)		goto fail;	ep = hep->hcpriv;	if (ep) {		/* finish right away if this urb can't be active ...		 * note that some drivers wrongly expect delays		 */		if (ep->hep->urb_list.next != &urb->urb_list) {			/* not front of queue?  never active */		/* for active transfers, we expect an IRQ */		} else if (sl811->active_a == ep) {			if (time_before_eq(sl811->jiffies_a, jiffies)) {				/* happens a lot with lowspeed?? */				DBG("giveup on DONE_A: ctrl %02x sts %02x\n",					sl811_read(sl811,						SL811_EP_A(SL11H_HOSTCTLREG)),					sl811_read(sl811,						SL811_EP_A(SL11H_PKTSTATREG)));				sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG),						0);				sl811->active_a = NULL;			} else				urb = NULL;#ifdef	USE_B		} else if (sl811->active_b == ep) {			if (time_before_eq(sl811->jiffies_a, jiffies)) {				/* happens a lot with lowspeed?? */				DBG("giveup on DONE_B: ctrl %02x sts %02x\n",					sl811_read(sl811,						SL811_EP_B(SL11H_HOSTCTLREG)),					sl811_read(sl811,						SL811_EP_B(SL11H_PKTSTATREG)));				sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG),						0);				sl811->active_b = NULL;			} else				urb = NULL;#endif		} else {			/* front of queue for inactive endpoint */		}		if (urb)			finish_request(sl811, ep, urb, NULL, 0);		else			VDBG("dequeue, urb %p active %s; wait4irq\n", urb,				(sl811->active_a == ep) ? "A" : "B");	} elsefail:		retval = -EINVAL;	spin_unlock_irqrestore(&sl811->lock, flags);	return retval;}static voidsl811h_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep){	struct sl811h_ep	*ep = hep->hcpriv;	if (!ep)		return;	/* assume we'd just wait for the irq */	if (!list_empty(&hep->urb_list))		msleep(3);	if (!list_empty(&hep->urb_list))		WARN("ep %p not empty?\n", ep);	usb_put_dev(ep->udev);	kfree(ep);	hep->hcpriv = NULL;}static intsl811h_get_frame(struct usb_hcd *hcd){	struct sl811 *sl811 = hcd_to_sl811(hcd);	/* wrong except while periodic transfers are scheduled;	 * never matches the on-the-wire frame;	 * subject to overruns.	 */	return sl811->frame;}/*-------------------------------------------------------------------------*//* the virtual root hub timer IRQ checks for hub status */static intsl811h_hub_status_data(struct usb_hcd *hcd, char *buf){	struct sl811 *sl811 = hcd_to_sl811(hcd);#ifdef	QUIRK3	unsigned long flags;	/* non-SMP HACK: use root hub timer as i/o watchdog	 * this seems essential when SOF IRQs aren't in use...	 */	local_irq_save(flags);	if (!timer_pending(&sl811->timer)) {		if (sl811h_irq( /* ~0, */ hcd, NULL) != IRQ_NONE)			sl811->stat_lost++;	}	local_irq_restore(flags);#endif	if (!(sl811->port1 & (0xffff << 16)))		return 0;	/* tell khubd port 1 changed */	*buf = (1 << 1);	return 1;}static voidsl811h_hub_descriptor (	struct sl811			*sl811,	struct usb_hub_descriptor	*desc) {	u16		temp = 0;	desc->bDescriptorType = 0x29;	desc->bHubContrCurrent = 0;	desc->bNbrPorts = 1;	desc->bDescLength = 9;	/* per-port power switching (gang of one!), or none */	desc->bPwrOn2PwrGood = 0;	if (sl811->board && sl811->board->port_power) {		desc->bPwrOn2PwrGood = sl811->board->potpg;		if (!desc->bPwrOn2PwrGood)			desc->bPwrOn2PwrGood = 10;		temp = 0x0001;	} else		temp = 0x0002;	/* no overcurrent errors detection/handling */	temp |= 0x0010;	desc->wHubCharacteristics = (__force __u16)cpu_to_le16(temp);	/* two bitmaps:  ports removable, and legacy PortPwrCtrlMask */	desc->bitmap[0] = 0 << 1;	desc->bitmap[1] = ~0;}static voidsl811h_timer(unsigned long _sl811){	struct sl811 	*sl811 = (void *) _sl811;	unsigned long	flags;	u8		irqstat;	u8		signaling = sl811->ctrl1 & SL11H_CTL1MASK_FORCE;	const u32	mask = (1 << USB_PORT_FEAT_CONNECTION)				| (1 << USB_PORT_FEAT_ENABLE)				| (1 << USB_PORT_FEAT_LOWSPEED);	spin_lock_irqsave(&sl811->lock, flags);	/* stop special signaling */	sl811->ctrl1 &= ~SL11H_CTL1MASK_FORCE;	sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);	udelay(3);	irqstat = sl811_read(sl811, SL11H_IRQ_STATUS);	switch (signaling) {	case SL11H_CTL1MASK_SE0:		DBG("end reset\n");		sl811->port1 = (1 << USB_PORT_FEAT_C_RESET)				| (1 << USB_PORT_FEAT_POWER);		sl811->ctrl1 = 0;		/* don't wrongly ack RD */		if (irqstat & SL11H_INTMASK_INSRMV)			irqstat &= ~SL11H_INTMASK_RD;		break;	case SL11H_CTL1MASK_K:		DBG("end resume\n");		sl811->port1 &= ~(1 << USB_PORT_FEAT_SUSPEND);		break;	default:		DBG("odd timer signaling: %02x\n", signaling);		break;	}	sl811_write(sl811, SL11H_IRQ_STATUS, irqstat);	if (irqstat & SL11H_INTMASK_RD) {		/* usbcore nukes all pending transactions on disconnect */		if (sl811->port1 & (1 << USB_PORT_FEAT_CONNECTION))			sl811->port1 |= (1 << USB_PORT_FEAT_C_CONNECTION)					| (1 << USB_PORT_FEAT_C_ENABLE);		sl811->port1 &= ~mask;		sl811->irq_enable = SL11H_INTMASK_INSRMV;	} else {		sl811->port1 |= mask;		if (irqstat & SL11H_INTMASK_DP)			sl811->port1 &= ~(1 << USB_PORT_FEAT_LOWSPEED);		sl811->irq_enable = SL11H_INTMASK_INSRMV | SL11H_INTMASK_RD;	}	if (sl811->port1 & (1 << USB_PORT_FEAT_CONNECTION)) {		u8	ctrl2 = SL811HS_CTL2_INIT;		sl811->irq_enable |= SL11H_INTMASK_DONE_A;#ifdef USE_B		sl811->irq_enable |= SL11H_INTMASK_DONE_B;#endif		if (sl811->port1 & (1 << USB_PORT_FEAT_LOWSPEED)) {			sl811->ctrl1 |= SL11H_CTL1MASK_LSPD;			ctrl2 |= SL811HS_CTL2MASK_DSWAP;		}		/* start SOFs flowing, kickstarting with A registers */		sl811->ctrl1 |= SL11H_CTL1MASK_SOF_ENA;		sl811_write(sl811, SL11H_SOFLOWREG, 0xe0);		sl811_write(sl811, SL811HS_CTLREG2, ctrl2);		/* autoincrementing */		sl811_write(sl811, SL811_EP_A(SL11H_BUFLNTHREG), 0);		writeb(SL_SOF, sl811->data_reg);		writeb(0, sl811->data_reg);		sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG),				SL11H_HCTLMASK_ARM);		/* khubd provides debounce delay */	} else {		sl811->ctrl1 = 0;	}	sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);	/* reenable irqs */	sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);	spin_unlock_irqrestore(&sl811->lock, flags);}static intsl811h_hub_control(	struct usb_hcd	*hcd,	u16		typeReq,	u16		wValue,	u16		wIndex,	char		*buf,	u16		wLength) {	struct sl811	*sl811 = hcd_to_sl811(hcd);	int		retval = 0;	unsigned long	flags;	spin_lock_irqsave(&sl811->lock, flags);	switch (typeReq) {	case ClearHubFeature:	case SetHubFeature:		switch (wValue) {		case C_HUB_OVER_CURRENT:		case C_HUB_LOCAL_POWER:			break;		default:			goto error;		}		break;	case ClearPortFeature:		if (wIndex != 1 || wLength != 0)			goto error;		switch (wValue) {		case USB_PORT_FEAT_ENABLE:			sl811->port1 &= (1 << USB_PORT_FEAT_POWER);			sl811->ctrl1 = 0;			sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);			sl811->irq_enable = SL11H_INTMASK_INSRMV;			sl811_write(sl811, SL11H_IRQ_ENABLE,						sl811->irq_enable);			break;		case USB_PORT_FEAT_SUSPEND:			if (!(sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND)))				break;			/* 20 msec of resume/K signaling, other irqs blocked */			DBG("start resume...\n");			sl811->irq_enable = 0;			sl811_write(sl811, SL11H_IRQ_ENABLE,						sl811->irq_enable);			sl811->ctrl1 |= SL11H_CTL1MASK_K;			sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);			mod_timer(&sl811->timer, jiffies					+ msecs_to_jiffies(20));			break;		case USB_PORT_FEAT_POWER:			port_power(sl811, 0);			break;		case USB_PORT_FEAT_C_ENABLE:		case USB_PORT_FEAT_C_SUSPEND:		case USB_PORT_FEAT_C_CONNECTION:		case USB_PORT_FEAT_C_OVER_CURRENT:		case USB_PORT_FEAT_C_RESET:			break;		default:			goto error;		}		sl811->port1 &= ~(1 << wValue);		break;	case GetHubDescriptor:		sl811h_hub_descriptor(sl811, (struct usb_hub_descriptor *) buf);		break;	case GetHubStatus:		*(__le32 *) buf = cpu_to_le32(0);		break;	case GetPortStatus:		if (wIndex != 1)			goto error;		*(__le32 *) buf = cpu_to_le32(sl811->port1);#ifndef	VERBOSE	if (*(u16*)(buf+2))	/* only if wPortChange is interesting */#endif		DBG("GetPortStatus %08x\n", sl811->port1);		break;	case SetPortFeature:		if (wIndex != 1 || wLength != 0)			goto error;		switch (wValue) {		case USB_PORT_FEAT_SUSPEND:			if (sl811->port1 & (1 << USB_PORT_FEAT_RESET))				goto error;			if (!(sl811->port1 & (1 << USB_PORT_FEAT_ENABLE)))				goto error;			DBG("suspend...\n");			sl811->ctrl1 &= ~SL11H_CTL1MASK_SOF_ENA;			sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);			break;		case USB_PORT_FEAT_POWER:			port_power(sl811, 1);			break;		case USB_PORT_FEAT_RESET:			if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND))				goto error;			if (!(sl811->port1 & (1 << USB_PORT_FEAT_POWER)))				break;			/* 50 msec of reset/SE0 signaling, irqs blocked */			sl811->irq_enable = 0;			sl811_write(sl811, SL11H_IRQ_ENABLE,						sl811->irq_enable);			sl811->ctrl1 = SL11H_CTL1MASK_SE0;			sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);			sl811->port1 |= (1 << USB_PORT_FEAT_RESET);			mod_timer(&sl811->timer, jiffies					+ msecs_to_jiffies(50));			break;		default:			goto error;		}		sl811->port1 |= 1 << wValue;		break;	default:error:		/* "protocol stall" on error */		retval = -EPIPE;	}	spin_unlock_irqrestore(&sl811->lock, flags);	return retval;}#ifdef	CONFIG_PMstatic intsl811h_bus_suspend(struct usb_hcd *hcd){	// SOFs off	DBG("%s\n", __FUNCTION__);	return 0;}static intsl811h_bus_resume(struct usb_hcd *hcd){	// SOFs on	DBG("%s\n", __FUNCTION__);	return 0;}#else#define	sl811h_bus_suspend	NULL#define	sl811h_bus_resume	NULL#endif/*-------------------------------------------------------------------------*/#ifdef STUB_DEBUG_FILEstatic inline void create_debug_file(struct sl811 *sl811) { }static inline void remove_debug_file(struct sl811 *sl811) { }

⌨️ 快捷键说明

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