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

📄 omap_udc.c

📁 h内核
💻 C
📖 第 1 页 / 共 5 页
字号:
				goto delegate;			if (u.r.wLength != 0)				goto do_stall;			udc->ep0_set_config = 1;			udc->ep0_reset_config = (u.r.wValue == 0);			VDBG("set config %d\n", u.r.wValue);			/* update udc NOW since gadget driver may start			 * queueing requests immediately; clear config			 * later if it fails the request.			 */			if (udc->ep0_reset_config)				UDC_SYSCON2_REG = UDC_CLR_CFG;			else				UDC_SYSCON2_REG = UDC_DEV_CFG;			update_otg(udc);			goto delegate;		case USB_REQ_CLEAR_FEATURE:			/* clear endpoint halt */			if (u.r.bRequestType != USB_RECIP_ENDPOINT)				goto delegate;			if (u.r.wValue != USB_ENDPOINT_HALT					|| u.r.wLength != 0)				goto do_stall;			ep = &udc->ep[u.r.wIndex & 0xf];			if (ep != ep0) {				if (u.r.wIndex & USB_DIR_IN)					ep += 16;				if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC						|| !ep->desc)					goto do_stall;				use_ep(ep, 0);				UDC_CTRL_REG = UDC_RESET_EP;				ep->ackwait = 0;				if (!(ep->bEndpointAddress & USB_DIR_IN)) {					UDC_CTRL_REG = UDC_SET_FIFO_EN;					ep->ackwait = 1 + ep->double_buf;				}			}			VDBG("%s halt cleared by host\n", ep->name);			goto ep0out_status_stage;		case USB_REQ_SET_FEATURE:			/* set endpoint halt */			if (u.r.bRequestType != USB_RECIP_ENDPOINT)				goto delegate;			if (u.r.wValue != USB_ENDPOINT_HALT					|| u.r.wLength != 0)				goto do_stall;			ep = &udc->ep[u.r.wIndex & 0xf];			if (u.r.wIndex & USB_DIR_IN)				ep += 16;			if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC					|| ep == ep0 || !ep->desc)				goto do_stall;			if (use_dma && ep->has_dma) {				/* this has rude side-effects (aborts) and				 * can't really work if DMA-IN is active				 */				DBG("%s host set_halt, NYET \n", ep->name);				goto do_stall;			}			use_ep(ep, 0);			/* can't halt if fifo isn't empty... */			UDC_CTRL_REG = UDC_CLR_EP;			UDC_CTRL_REG = UDC_SET_HALT;			VDBG("%s halted by host\n", ep->name);ep0out_status_stage:			status = 0;			UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR;			UDC_CTRL_REG = UDC_CLR_EP;			UDC_CTRL_REG = UDC_SET_FIFO_EN;			UDC_EP_NUM_REG = UDC_EP_DIR;			udc->ep0_pending = 0;			break;		case USB_REQ_GET_STATUS:			/* return interface status.  if we were pedantic,			 * we'd detect non-existent interfaces, and stall.			 */			if (u.r.bRequestType					!= (USB_DIR_IN|USB_RECIP_INTERFACE))				goto delegate;			/* return two zero bytes */			UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR;			UDC_DATA_REG = 0;			UDC_CTRL_REG = UDC_SET_FIFO_EN;			UDC_EP_NUM_REG = UDC_EP_DIR;			status = 0;			VDBG("GET_STATUS, interface %d\n", u.r.wIndex);			/* next, status stage */			break;		default:delegate:			/* activate the ep0out fifo right away */			if (!udc->ep0_in && u.r.wLength) {				UDC_EP_NUM_REG = 0;				UDC_CTRL_REG = UDC_SET_FIFO_EN;			}			/* gadget drivers see class/vendor specific requests,			 * {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION},			 * and more			 */			VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n",				u.r.bRequestType, u.r.bRequest,				u.r.wValue, u.r.wIndex, u.r.wLength);			/* The gadget driver may return an error here,			 * causing an immediate protocol stall.			 *			 * Else it must issue a response, either queueing a			 * response buffer for the DATA stage, or halting ep0			 * (causing a protocol stall, not a real halt).  A			 * zero length buffer means no DATA stage.			 *			 * It's fine to issue that response after the setup()			 * call returns, and this IRQ was handled.			 */			udc->ep0_setup = 1;			spin_unlock(&udc->lock);			status = udc->driver->setup (&udc->gadget, &u.r);			spin_lock(&udc->lock);			udc->ep0_setup = 0;		}		if (status < 0) {do_stall:			VDBG("req %02x.%02x protocol STALL; stat %d\n",					u.r.bRequestType, u.r.bRequest, status);			if (udc->ep0_set_config) {				if (udc->ep0_reset_config)					WARN("error resetting config?\n");				else					UDC_SYSCON2_REG = UDC_CLR_CFG;			}			UDC_SYSCON2_REG = UDC_STALL_CMD;			udc->ep0_pending = 0;		}	}}/*-------------------------------------------------------------------------*/#define OTG_FLAGS (UDC_B_HNP_ENABLE|UDC_A_HNP_SUPPORT|UDC_A_ALT_HNP_SUPPORT)static void devstate_irq(struct omap_udc *udc, u16 irq_src){	u16	devstat, change;	devstat = UDC_DEVSTAT_REG;	change = devstat ^ udc->devstat;	udc->devstat = devstat;	if (change & (UDC_USB_RESET|UDC_ATT)) {		udc_quiesce(udc);		if (change & UDC_ATT) {			/* driver for any external transceiver will			 * have called omap_vbus_session() already			 */			if (devstat & UDC_ATT) {				udc->gadget.speed = USB_SPEED_FULL;				VDBG("connect\n");				if (!udc->transceiver)					pullup_enable(udc);				// if (driver->connect) call it			} else if (udc->gadget.speed != USB_SPEED_UNKNOWN) {				udc->gadget.speed = USB_SPEED_UNKNOWN;				if (!udc->transceiver)					pullup_disable(udc);				DBG("disconnect, gadget %s\n",					udc->driver->driver.name);				if (udc->driver->disconnect) {					spin_unlock(&udc->lock);					udc->driver->disconnect(&udc->gadget);					spin_lock(&udc->lock);				}			}			change &= ~UDC_ATT;		}		if (change & UDC_USB_RESET) {			if (devstat & UDC_USB_RESET) {				VDBG("RESET=1\n");			} else {				udc->gadget.speed = USB_SPEED_FULL;				INFO("USB reset done, gadget %s\n",					udc->driver->driver.name);				/* ep0 traffic is legal from now on */				UDC_IRQ_EN_REG = UDC_DS_CHG_IE | UDC_EP0_IE;			}			change &= ~UDC_USB_RESET;		}	}	if (change & UDC_SUS) {		if (udc->gadget.speed != USB_SPEED_UNKNOWN) {			// FIXME tell isp1301 to suspend/resume (?)			if (devstat & UDC_SUS) {				VDBG("suspend\n");				update_otg(udc);				/* HNP could be under way already */				if (udc->gadget.speed == USB_SPEED_FULL						&& udc->driver->suspend) {					spin_unlock(&udc->lock);					udc->driver->suspend(&udc->gadget);					spin_lock(&udc->lock);				}			} else {				VDBG("resume\n");				if (udc->gadget.speed == USB_SPEED_FULL						&& udc->driver->resume) {					spin_unlock(&udc->lock);					udc->driver->resume(&udc->gadget);					spin_lock(&udc->lock);				}			}		}		change &= ~UDC_SUS;	}	if (!cpu_is_omap15xx() && (change & OTG_FLAGS)) {		update_otg(udc);		change &= ~OTG_FLAGS;	}	change &= ~(UDC_CFG|UDC_DEF|UDC_ADD);	if (change)		VDBG("devstat %03x, ignore change %03x\n",			devstat,  change);	UDC_IRQ_SRC_REG = UDC_DS_CHG;}static irqreturn_tomap_udc_irq(int irq, void *_udc, struct pt_regs *r){	struct omap_udc	*udc = _udc;	u16		irq_src;	irqreturn_t	status = IRQ_NONE;	unsigned long	flags;	spin_lock_irqsave(&udc->lock, flags);	irq_src = UDC_IRQ_SRC_REG;	/* Device state change (usb ch9 stuff) */	if (irq_src & UDC_DS_CHG) {		devstate_irq(_udc, irq_src);		status = IRQ_HANDLED;		irq_src &= ~UDC_DS_CHG;	}	/* EP0 control transfers */	if (irq_src & (UDC_EP0_RX|UDC_SETUP|UDC_EP0_TX)) {		ep0_irq(_udc, irq_src);		status = IRQ_HANDLED;		irq_src &= ~(UDC_EP0_RX|UDC_SETUP|UDC_EP0_TX);	}	/* DMA transfer completion */	if (use_dma && (irq_src & (UDC_TXN_DONE|UDC_RXN_CNT|UDC_RXN_EOT))) {		dma_irq(_udc, irq_src);		status = IRQ_HANDLED;		irq_src &= ~(UDC_TXN_DONE|UDC_RXN_CNT|UDC_RXN_EOT);	}	irq_src &= ~(UDC_SOF|UDC_EPN_TX|UDC_EPN_RX);	if (irq_src)		DBG("udc_irq, unhandled %03x\n", irq_src);	spin_unlock_irqrestore(&udc->lock, flags);	return status;}/* workaround for seemingly-lost IRQs for RX ACKs... */#define PIO_OUT_TIMEOUT	(jiffies + HZ/3)#define HALF_FULL(f)	(!((f)&(UDC_NON_ISO_FIFO_FULL|UDC_NON_ISO_FIFO_EMPTY)))static void pio_out_timer(unsigned long _ep){	struct omap_ep	*ep = (void *) _ep;	unsigned long	flags;	u16		stat_flg;	spin_lock_irqsave(&ep->udc->lock, flags);	if (!list_empty(&ep->queue) && ep->ackwait) {		use_ep(ep, 0);		stat_flg = UDC_STAT_FLG_REG;		if ((stat_flg & UDC_ACK) && (!(stat_flg & UDC_FIFO_EN)				|| (ep->double_buf && HALF_FULL(stat_flg)))) {			struct omap_req	*req;			VDBG("%s: lose, %04x\n", ep->ep.name, stat_flg);			req = container_of(ep->queue.next,					struct omap_req, queue);			UDC_EP_NUM_REG = ep->bEndpointAddress | UDC_EP_SEL;			(void) read_fifo(ep, req);			UDC_EP_NUM_REG = ep->bEndpointAddress;			UDC_CTRL_REG = UDC_SET_FIFO_EN;			ep->ackwait = 1 + ep->double_buf;		}	}	mod_timer(&ep->timer, PIO_OUT_TIMEOUT);	spin_unlock_irqrestore(&ep->udc->lock, flags);}static irqreturn_tomap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r){	u16		epn_stat, irq_src;	irqreturn_t	status = IRQ_NONE;	struct omap_ep	*ep;	int		epnum;	struct omap_udc	*udc = _dev;	struct omap_req	*req;	unsigned long	flags;	spin_lock_irqsave(&udc->lock, flags);	epn_stat = UDC_EPN_STAT_REG;	irq_src = UDC_IRQ_SRC_REG;	/* handle OUT first, to avoid some wasteful NAKs */	if (irq_src & UDC_EPN_RX) {		epnum = (epn_stat >> 8) & 0x0f;		UDC_IRQ_SRC_REG = UDC_EPN_RX;		status = IRQ_HANDLED;		ep = &udc->ep[epnum];		ep->irqs++;		UDC_EP_NUM_REG = epnum | UDC_EP_SEL;		ep->fnf = 0;		if ((UDC_STAT_FLG_REG & UDC_ACK)) {			ep->ackwait--;			if (!list_empty(&ep->queue)) {				int stat;				req = container_of(ep->queue.next,						struct omap_req, queue);				stat = read_fifo(ep, req);				if (!ep->double_buf)					ep->fnf = 1;			}		}		/* min 6 clock delay before clearing EP_SEL ... */		epn_stat = UDC_EPN_STAT_REG;		epn_stat = UDC_EPN_STAT_REG;		UDC_EP_NUM_REG = epnum;		/* enabling fifo _after_ clearing ACK, contrary to docs,		 * reduces lossage; timer still needed though (sigh).		 */		if (ep->fnf) {			UDC_CTRL_REG = UDC_SET_FIFO_EN;			ep->ackwait = 1 + ep->double_buf;		}		mod_timer(&ep->timer, PIO_OUT_TIMEOUT);	}	/* then IN transfers */	else if (irq_src & UDC_EPN_TX) {		epnum = epn_stat & 0x0f;		UDC_IRQ_SRC_REG = UDC_EPN_TX;		status = IRQ_HANDLED;		ep = &udc->ep[16 + epnum];		ep->irqs++;		UDC_EP_NUM_REG = epnum | UDC_EP_DIR | UDC_EP_SEL;		if ((UDC_STAT_FLG_REG & UDC_ACK)) {			ep->ackwait = 0;			if (!list_empty(&ep->queue)) {				req = container_of(ep->queue.next,						struct omap_req, queue);				(void) write_fifo(ep, req);			}		}		/* min 6 clock delay before clearing EP_SEL ... */		epn_stat = UDC_EPN_STAT_REG;		epn_stat = UDC_EPN_STAT_REG;		UDC_EP_NUM_REG = epnum | UDC_EP_DIR;		/* then 6 clocks before it'd tx */	}	spin_unlock_irqrestore(&udc->lock, flags);	return status;}#ifdef	USE_ISOstatic irqreturn_tomap_udc_iso_irq(int irq, void *_dev, struct pt_regs *r){	struct omap_udc	*udc = _dev;	struct omap_ep	*ep;	int		pending = 0;	unsigned long	flags;	spin_lock_irqsave(&udc->lock, flags);	/* handle all non-DMA ISO transfers */	list_for_each_entry (ep, &udc->iso, iso) {		u16		stat;		struct omap_req	*req;		if (ep->has_dma || list_empty(&ep->queue))			continue;		req = list_entry(ep->queue.next, struct omap_req, queue);		use_ep(ep, UDC_EP_SEL);		stat = UDC_STAT_FLG_REG;		/* NOTE: like the other controller drivers, this isn't		 * currently reporting lost or damaged frames.		 */		if (ep->bEndpointAddress & USB_DIR_IN) {			if (stat & UDC_MISS_IN)				/* done(ep, req, -EPROTO) */;			else				write_fifo(ep, req);		} else {			int	status = 0;			if (stat & UDC_NO_RXPACKET)				status = -EREMOTEIO;			else if (stat & UDC_ISO_ERR)				status = -EILSEQ;			else if (stat & UDC_DATA_FLUSH)				status = -ENOSR;			if (status)				/* done(ep, req, status) */;			else				read_fifo(ep, req);		}		deselect_ep();		/* 6 wait states before next EP */		ep->irqs++;		if (!list_empty(&ep->queue))			pending = 1;	}	if (!pending)		UDC_IRQ_EN_REG &= ~UDC_SOF_IE;	UDC_IRQ_SRC_REG = UDC_SOF;	spin_unlock_irqrestore(&udc->lock, flags);	return IRQ_HANDLED;}#endif/*-------------------------------------------------------------------------*/static struct omap_udc *udc;int usb_gadget_register_driver (struct usb_gadget_driver *driver){	int		status = -ENODEV;	struct omap_ep	*ep;	unsigned long	flags;	/* basic sanity tests */	if (!udc)		return -ENODEV;	if (!driver			// FIXME if otg, check:  driver->is_otg			|| driver->speed < USB_SPEED_FULL			|| !driver->bind			|| !driver->unbind			|| !driver->setup)		return -EINVAL;	spin_lock_irqsave(&udc->lock, flags);	if (udc->driver) {		spin_unlock_irqrestore(&udc->lock, flags);		return -EBUSY;	}	/* reset state */	list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {		ep->irqs = 0;		if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC)			continue;		use_ep(ep, 0);		UDC_CTRL_REG = UDC_SET_HALT;	}	udc->ep0_pending = 0;	udc->ep[0].irqs = 0;	udc->softconnect = 1;	/* hook up the driver */	driver->driver.bus = 0;	udc->driver = driver;	udc->gadget.dev.driver = &driver->driver;	spin_unlock_irqrestore(&udc->lock, flags);	status = driver->bind (&udc->gadget);	if (status) {		DBG("bind to %s --> %d\n", driver->driver.name, status);		udc->gadget.dev.driver = 0;		udc->driver = 0;		goto done;	}	DBG("bound to driver %s\n", driver->driver.name);	UDC_IRQ_SRC_REG = UDC_IRQ_SRC_MASK;	/* connect to bus through transceiver */	if (udc->transceiver) {		status = otg_set_peripheral(udc->transceiver, &udc->gadget);		if (status < 0) {			ERR("can't bind to transceiver\n");			driver->unbind (&udc->gadget);			udc->gadget.dev.driver = 0;			udc->driver = 0;			goto done;

⌨️ 快捷键说明

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