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

📄 pxa2xx_udc.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	local_irq_save(flags);	/* make sure it's actually queued on this endpoint */	list_for_each_entry (req, &ep->queue, queue) {		if (&req->req == _req)			break;	}	if (&req->req != _req) {		local_irq_restore(flags);		return -EINVAL;	}#ifdef	USE_DMA	if (ep->dma >= 0 && ep->queue.next == &req->queue && !ep->stopped) {		cancel_dma(ep);		done(ep, req, -ECONNRESET);		/* restart i/o */		if (!list_empty(&ep->queue)) {			req = list_entry(ep->queue.next,					struct pxa2xx_request, queue);			kick_dma(ep, req);		}	} else#endif		done(ep, req, -ECONNRESET);	local_irq_restore(flags);	return 0;}/*-------------------------------------------------------------------------*/static int pxa2xx_ep_set_halt(struct usb_ep *_ep, int value){	struct pxa2xx_ep	*ep;	unsigned long		flags;	ep = container_of(_ep, struct pxa2xx_ep, ep);	if (unlikely (!_ep			|| (!ep->desc && ep->ep.name != ep0name))			|| ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) {		DMSG("%s, bad ep\n", __FUNCTION__);		return -EINVAL;	}	if (value == 0) {		/* this path (reset toggle+halt) is needed to implement		 * SET_INTERFACE on normal hardware.  but it can't be		 * done from software on the PXA UDC, and the hardware		 * forgets to do it as part of SET_INTERFACE automagic.		 */		DMSG("only host can clear %s halt\n", _ep->name);		return -EROFS;	}	local_irq_save(flags);	if ((ep->bEndpointAddress & USB_DIR_IN) != 0			&& ((*ep->reg_udccs & UDCCS_BI_TFS) == 0			   || !list_empty(&ep->queue))) {		local_irq_restore(flags);		return -EAGAIN;	}	/* FST bit is the same for control, bulk in, bulk out, interrupt in */	*ep->reg_udccs = UDCCS_BI_FST|UDCCS_BI_FTF;	/* ep0 needs special care */	if (!ep->desc) {		start_watchdog(ep->dev);		ep->dev->req_pending = 0;		ep->dev->ep0state = EP0_STALL;		LED_EP0_OFF; 	/* and bulk/intr endpoints like dropping stalls too */ 	} else { 		unsigned i; 		for (i = 0; i < 1000; i += 20) { 			if (*ep->reg_udccs & UDCCS_BI_SST) 				break; 			udelay(20); 		}  	} 	local_irq_restore(flags);	DBG(DBG_VERBOSE, "%s halt\n", _ep->name);	return 0;}static int pxa2xx_ep_fifo_status(struct usb_ep *_ep){	struct pxa2xx_ep        *ep;	ep = container_of(_ep, struct pxa2xx_ep, ep);	if (!_ep) {		DMSG("%s, bad ep\n", __FUNCTION__);		return -ENODEV;	}	/* pxa can't report unclaimed bytes from IN fifos */	if ((ep->bEndpointAddress & USB_DIR_IN) != 0)		return -EOPNOTSUPP;	if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN			|| (*ep->reg_udccs & UDCCS_BO_RFS) == 0)		return 0;	else		return (*ep->reg_ubcr & 0xfff) + 1;}static void pxa2xx_ep_fifo_flush(struct usb_ep *_ep){	struct pxa2xx_ep        *ep;	ep = container_of(_ep, struct pxa2xx_ep, ep);	if (!_ep || ep->ep.name == ep0name || !list_empty(&ep->queue)) {		DMSG("%s, bad ep\n", __FUNCTION__);		return;	}	/* toggle and halt bits stay unchanged */	/* for OUT, just read and discard the FIFO contents. */	if ((ep->bEndpointAddress & USB_DIR_IN) == 0) {		while (((*ep->reg_udccs) & UDCCS_BO_RNE) != 0)			(void) *ep->reg_uddr;		return;	}	/* most IN status is the same, but ISO can't stall */	*ep->reg_udccs = UDCCS_BI_TPC|UDCCS_BI_FTF|UDCCS_BI_TUR		| (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC)			? 0 : UDCCS_BI_SST;}static struct usb_ep_ops pxa2xx_ep_ops = {	.enable		= pxa2xx_ep_enable,	.disable	= pxa2xx_ep_disable,	.alloc_request	= pxa2xx_ep_alloc_request,	.free_request	= pxa2xx_ep_free_request,	.alloc_buffer	= pxa2xx_ep_alloc_buffer,	.free_buffer	= pxa2xx_ep_free_buffer,	.queue		= pxa2xx_ep_queue,	.dequeue	= pxa2xx_ep_dequeue,	.set_halt	= pxa2xx_ep_set_halt,	.fifo_status	= pxa2xx_ep_fifo_status,	.fifo_flush	= pxa2xx_ep_fifo_flush,};/* --------------------------------------------------------------------------- * 	device-scoped parts of the api to the usb controller hardware * --------------------------------------------------------------------------- */static int pxa2xx_udc_get_frame(struct usb_gadget *_gadget){	return ((UFNRH & 0x07) << 8) | (UFNRL & 0xff);}static int pxa2xx_udc_wakeup(struct usb_gadget *_gadget){	/* host may not have enabled remote wakeup */	if ((UDCCS0 & UDCCS0_DRWF) == 0)		return -EHOSTUNREACH;	udc_set_mask_UDCCR(UDCCR_RSM);	return 0;}static const struct usb_gadget_ops pxa2xx_udc_ops = {	.get_frame	 = pxa2xx_udc_get_frame,	.wakeup		 = pxa2xx_udc_wakeup,	// current versions must always be self-powered};/*-------------------------------------------------------------------------*/#ifdef UDC_PROC_FILEstatic const char proc_node_name [] = "driver/udc";static intudc_proc_read(char *page, char **start, off_t off, int count,		int *eof, void *_dev){	char			*buf = page;	struct pxa2xx_udc	*dev = _dev;	char			*next = buf;	unsigned		size = count;	unsigned long		flags;	int			i, t;	u32			tmp;	if (off != 0)		return 0;	local_irq_save(flags);	/* basic device status */	t = scnprintf(next, size, DRIVER_DESC "\n"		"%s version: %s\nGadget driver: %s\nHost %s\n\n",		driver_name, DRIVER_VERSION SIZE_STR DMASTR,		dev->driver ? dev->driver->driver.name : "(none)",		is_usb_connected() ? "full speed" : "disconnected");	size -= t;	next += t;	/* registers for device and ep0 */	t = scnprintf(next, size,		"uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n",		UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL);	size -= t;	next += t;	tmp = UDCCR;	t = scnprintf(next, size,		"udccr %02X =%s%s%s%s%s%s%s%s\n", tmp,		(tmp & UDCCR_REM) ? " rem" : "",		(tmp & UDCCR_RSTIR) ? " rstir" : "",		(tmp & UDCCR_SRM) ? " srm" : "",		(tmp & UDCCR_SUSIR) ? " susir" : "",		(tmp & UDCCR_RESIR) ? " resir" : "",		(tmp & UDCCR_RSM) ? " rsm" : "",		(tmp & UDCCR_UDA) ? " uda" : "",		(tmp & UDCCR_UDE) ? " ude" : "");	size -= t;	next += t;	tmp = UDCCS0;	t = scnprintf(next, size,		"udccs0 %02X =%s%s%s%s%s%s%s%s\n", tmp,		(tmp & UDCCS0_SA) ? " sa" : "",		(tmp & UDCCS0_RNE) ? " rne" : "",		(tmp & UDCCS0_FST) ? " fst" : "",		(tmp & UDCCS0_SST) ? " sst" : "",		(tmp & UDCCS0_DRWF) ? " dwrf" : "",		(tmp & UDCCS0_FTF) ? " ftf" : "",		(tmp & UDCCS0_IPR) ? " ipr" : "",		(tmp & UDCCS0_OPR) ? " opr" : "");	size -= t;	next += t;	if (dev->has_cfr) {		tmp = UDCCFR;		t = scnprintf(next, size,			"udccfr %02X =%s%s\n", tmp,			(tmp & UDCCFR_AREN) ? " aren" : "",			(tmp & UDCCFR_ACM) ? " acm" : "");		size -= t;		next += t;	}	if (!is_usb_connected() || !dev->driver)		goto done;	t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n",		dev->stats.write.bytes, dev->stats.write.ops,		dev->stats.read.bytes, dev->stats.read.ops,		dev->stats.irqs);	size -= t;	next += t;	/* dump endpoint queues */	for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {		struct pxa2xx_ep	*ep = &dev->ep [i];		struct pxa2xx_request	*req;		int			t;		if (i != 0) {			const struct usb_endpoint_descriptor	*d;			d = ep->desc;			if (!d)				continue;			tmp = *dev->ep [i].reg_udccs;			t = scnprintf(next, size,				"%s max %d %s udccs %02x irqs %lu/%lu\n",				ep->ep.name, le16_to_cpu (d->wMaxPacketSize),				(ep->dma >= 0) ? "dma" : "pio", tmp,				ep->pio_irqs, ep->dma_irqs);			/* TODO translate all five groups of udccs bits! */		} else /* ep0 should only have one transfer queued */			t = scnprintf(next, size, "ep0 max 16 pio irqs %lu\n",				ep->pio_irqs);		if (t <= 0 || t > size)			goto done;		size -= t;		next += t;		if (list_empty(&ep->queue)) {			t = scnprintf(next, size, "\t(nothing queued)\n");			if (t <= 0 || t > size)				goto done;			size -= t;			next += t;			continue;		}		list_for_each_entry(req, &ep->queue, queue) {#ifdef	USE_DMA			if (ep->dma >= 0 && req->queue.prev == &ep->queue)				t = scnprintf(next, size,					"\treq %p len %d/%d "					"buf %p (dma%d dcmd %08x)\n",					&req->req, req->req.actual,					req->req.length, req->req.buf,					ep->dma, DCMD(ep->dma)					// low 13 bits == bytes-to-go					);			else#endif				t = scnprintf(next, size,					"\treq %p len %d/%d buf %p\n",					&req->req, req->req.actual,					req->req.length, req->req.buf);			if (t <= 0 || t > size)				goto done;			size -= t;			next += t;		}	}done:	local_irq_restore(flags);	*eof = 1;	return count - size;}#define create_proc_files() \	create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev)#define remove_proc_files() \	remove_proc_entry(proc_node_name, NULL)#else	/* !UDC_PROC_FILE */#define create_proc_files() do {} while (0)#define remove_proc_files() do {} while (0)#endif	/* UDC_PROC_FILE *//* "function" sysfs attribute */static ssize_tshow_function (struct device *_dev, char *buf){	struct pxa2xx_udc	*dev = dev_get_drvdata (_dev);	if (!dev->driver			|| !dev->driver->function			|| strlen (dev->driver->function) > PAGE_SIZE)		return 0;	return scnprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function);}static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);/*-------------------------------------------------------------------------*//* * 	udc_disable - disable USB device controller */static void udc_disable(struct pxa2xx_udc *dev){	/* block all irqs */	udc_set_mask_UDCCR(UDCCR_SRM|UDCCR_REM);	UICR0 = UICR1 = 0xff;	UFNRH = UFNRH_SIM;	/* if hardware supports it, disconnect from usb */	make_usb_disappear();	udc_clear_mask_UDCCR(UDCCR_UDE);#ifdef	CONFIG_ARCH_PXA        /* Disable clock for USB device */        CKEN &= ~CKEN11_USB;#endif	ep0_idle (dev);	dev->gadget.speed = USB_SPEED_UNKNOWN;	LED_CONNECTED_OFF;}/* * 	udc_reinit - initialize software state */static void udc_reinit(struct pxa2xx_udc *dev){	u32	i;	/* device/ep0 records init */	INIT_LIST_HEAD (&dev->gadget.ep_list);	INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);	dev->ep0state = EP0_IDLE;	/* basic endpoint records init */	for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {		struct pxa2xx_ep *ep = &dev->ep[i];		if (i != 0)			list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);		ep->desc = 0;		ep->stopped = 0;		INIT_LIST_HEAD (&ep->queue);		ep->pio_irqs = ep->dma_irqs = 0;	}	/* the rest was statically initialized, and is read-only */}/* until it's enabled, this UDC should be completely invisible * to any USB host. */static void udc_enable (struct pxa2xx_udc *dev){	udc_clear_mask_UDCCR(UDCCR_UDE);#ifdef	CONFIG_ARCH_PXA        /* Enable clock for USB device */        CKEN |= CKEN11_USB;#endif	/* try to clear these bits before we enable the udc */	udc_ack_int_UDCCR(UDCCR_SUSIR|/*UDCCR_RSTIR|*/UDCCR_RESIR);	ep0_idle(dev);	dev->gadget.speed = USB_SPEED_UNKNOWN;	dev->stats.irqs = 0;	/*	 * sequence taken from chapter 12.5.10, PXA250 AppProcDevManual:	 * - enable UDC	 * - if RESET is already in progress, ack interrupt	 * - unmask reset interrupt	 */	udc_set_mask_UDCCR(UDCCR_UDE);	if (!(UDCCR & UDCCR_UDA))		udc_ack_int_UDCCR(UDCCR_RSTIR);	if (dev->has_cfr /* UDC_RES2 is defined */) {		/* pxa255 (a0+) can avoid a set_config race that could		 * prevent gadget drivers from configuring correctly		 */		UDCCFR = UDCCFR_ACM;	} else {		/* "USB test mode" for pxa250 errata 40-42 (stepping a0, a1)		 * which could result in missing packets and interrupts.		 * supposedly one bit per endpoint, controlling whether it		 * double buffers or not; ACM/AREN bits fit into the holes.		 * zero bits (like USIR0_IRx) disable double buffering.		 */		UDC_RES1 = 0x00;		UDC_RES2 = 0x00;	}#ifdef	DISABLE_TEST_MODE	/* "test mode" seems to have become the default in later chip	 * revs, preventing double buffering (and invalidating docs).	 * this EXPERIMENT enables it for bulk endpoints by tweaking	 * undefined/reserved register bits (that other drivers clear).	 * Belcarra code comments noted this usage.	 */	if (fifo_mode & 1) {	/* IN endpoints */		UDC_RES1 |= USIR0_IR1|USIR0_IR6;		UDC_RES2 |= USIR1_IR11;	}	if (fifo_mode & 2) {	/* OUT endpoints */		UDC_RES1 |= USIR0_IR2|USIR0_IR7;		UDC_RES2 |= USIR1_IR12;	}#endif	/* caller must be able to sleep in order to cope	 * with startup transients.	 */	schedule_timeout(HZ/10);	/* enable suspend/resume and reset irqs */	udc_clear_mask_UDCCR(UDCCR_SRM | UDCCR_REM);	/* enable ep0 irqs */	UICR0 &= ~UICR0_IM0;	/* if hardware supports it, connect to usb and wait for host */	let_usb_appear();}/* when a driver is successfully registered, it will receive * control requests including set_configuration(), which enables * non-control requests.  then usb traffic follows until a * disconnect is reported.  then a host may connect again, or * the driver might get unbound. */int usb_gadget_register_driver(struct usb_gadget_driver *driver){	struct pxa2xx_udc	*dev = the_controller;	int			retval;	if (!driver			|| driver->speed != USB_SPEED_FULL			|| !driver->bind			|| !driver->unbind			|| !driver->disconnect			|| !driver->setup)		return -EINVAL;	if (!dev)		return -ENODEV;	if (dev->driver)		return -EBUSY;	/* first hook up the driver ... */	dev->driver = driver;

⌨️ 快捷键说明

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