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

📄 jz4730_udc.c

📁 linux下面gadget设备驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
					if (write_fifo(ep, req) == 1)						req = 0;				}			}			pio_irq_enable(ep);		} else {			/* EP5 ~ EP7 */			pio_irq_enable(ep);			if (ep->irq_pending || 			    (REG_UDC_EPIntR & UDC_EPIntR_OUTEP5)) {				u32 stats, count;				stats = REG_UDC_EP5OutSR;				if (stats & UDC_EPSR_OUT_RCVDATA) {					ep->irq_pending = 0;					REG_UDC_EP5OutSR &= ~UDC_EPSR_OUT_MASK;					if (REG_UDC_EPIntR & UDC_EPIntR_OUTEP5)						REG_UDC_EPIntR = UDC_EPIntR_OUTEP5;					count = OUT_COUNT(stats);					if (read_fifo(ep, req, count) == 1)						req = 0;				}			}		} 	}	/* pio or dma irq handler advances the queue. */	if (likely(req != 0)) {		list_add_tail(&req->queue, &ep->queue);	}	spin_unlock_irqrestore(&dev->lock, flags);	return status;}/* dequeue ALL requests */static void nuke(struct jz4730_ep *ep, int status){	struct jz4730_request *req;	if (list_empty(&ep->queue))		return;	while (!list_empty(&ep->queue)) {		req = list_entry(ep->queue.next, struct jz4730_request, queue);		done(ep, req, status);	}}/* dequeue JUST ONE request */static int jz4730_dequeue(struct usb_ep *_ep, struct usb_request *_req){	struct jz4730_request *req;	struct jz4730_ep *ep;	struct jz4730_udc *dev;	unsigned long flags;	int stopped;	ep = container_of(_ep, struct jz4730_ep, ep);	if (!_ep || !_req || (!ep->desc && ep->index != 0))		return -EINVAL;	dev = ep->dev;	if (!dev->driver)		return -ESHUTDOWN;	DEBUG("%s %s %p\n", __FUNCTION__, _ep->name,_req);	spin_lock_irqsave(&dev->lock, flags);	stopped = ep->stopped;	ep->stopped = 1;	/* 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) {		spin_unlock_irqrestore (&dev->lock, flags);		return -EINVAL;	}		/* queue head may be partially complete. */	if (ep->queue.next == &req->queue) {		done (ep, req, -ECONNRESET);		req = 0;	}	if (req)		done (ep, req, -ECONNRESET);	ep->stopped = stopped;	spin_unlock_irqrestore (&ep->dev->lock, flags);	return req ? 0 : -EOPNOTSUPP;}/*-------------------------------------------------------------------------*/static void jz4730_clear_halt(struct jz4730_ep *ep){	if (ep->stopped) {		ep->stopped = 0;	}}static int jz4730_set_halt(struct usb_ep *_ep, int value){	struct jz4730_ep *ep;	unsigned long flags;	int retval = 0;	if (!_ep)		return -ENODEV;	ep = container_of (_ep, struct jz4730_ep, ep);	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)		return -ESHUTDOWN;	if (ep->desc /* not ep0 */ && (ep->desc->bmAttributes & 0x03)						== USB_ENDPOINT_XFER_ISOC)		return -EINVAL;	if (ep->index == 0) {		if (value) {			ep->dev->ep0state = EP0_STALL;			ep->dev->ep[0].stopped = 1;		} else			return -EINVAL;	/* don't change EPxSTATUS_EP_INVALID to READY */	} else if (!ep->desc) {		DEBUG("%s %s inactive?\n", __FUNCTION__, ep->ep.name);		return -EINVAL;	}	spin_lock_irqsave(&ep->dev->lock, flags);	if (!list_empty(&ep->queue))		retval = -EAGAIN;	else if (!value)		jz4730_clear_halt(ep);	else {		ep->stopped = 1;	}	spin_unlock_irqrestore(&ep->dev->lock, flags);	return retval;}static int jz4730_fifo_status(struct usb_ep *_ep){	struct jz4730_ep *ep;	u32 size = 0;	if (!_ep)		return -ENODEV;	ep = container_of(_ep, struct jz4730_ep, ep);	/* size is only reported sanely for OUT */	if (ep->is_in)		return -EOPNOTSUPP;	return size;}static void jz4730_fifo_flush(struct usb_ep *_ep){	struct jz4730_ep *ep;	if (!_ep)		return;	ep = container_of(_ep, struct jz4730_ep, ep);	/* don't change EPxSTATUS_EP_INVALID to READY */	if (!ep->desc && ep->index != 0) {		return;	}}static struct usb_ep_ops jz4730_ep_ops = {	.enable		= jz4730_ep_enable,	.disable	= jz4730_ep_disable,	.alloc_request	= jz4730_alloc_request,	.free_request	= jz4730_free_request,#if 0	.alloc_buffer	= jz4730_alloc_buffer,	.free_buffer	= jz4730_free_buffer,#endif	.queue		= jz4730_queue,	.dequeue	= jz4730_dequeue,	.set_halt	= jz4730_set_halt,	.fifo_status	= jz4730_fifo_status,	.fifo_flush	= jz4730_fifo_flush,};/*-------------------------------------------------------------------------*/static int jz4730_get_frame(struct usb_gadget *_gadget){	return -EOPNOTSUPP;}static const struct usb_gadget_ops jz4730_ops = {	.get_frame	= jz4730_get_frame,	// no remote wakeup	// not selfpowered};/*-------------------------------------------------------------------------*/static void udc_reinit(struct jz4730_udc *dev){	static char *names [] = { "ep0", "ep1in-int", "ep2in-bulk", "ep3in-bulk",				  "ep4in-iso", "ep5out-bulk", "ep6out-bulk",				  "ep7out-iso" };	int i;	INIT_LIST_HEAD (&dev->gadget.ep_list);	dev->gadget.ep0 = &dev->ep[0].ep;	dev->gadget.speed = USB_SPEED_UNKNOWN;	dev->ep0state = EP0_DISCONNECT;	for (i = 0; i < MAX_EP_NUM; i++) {		struct jz4730_ep *ep = &dev->ep[i];		ep->index = i;		ep->ep.name = names[i];		ep->fifo = ep_fifo[i];		ep->ep.maxpacket = 64;		ep->ep.ops = &jz4730_ep_ops;		list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);		ep->dev = dev;		INIT_LIST_HEAD(&ep->queue);		ep->desc = 0;		ep->stopped = 1;		ep->irq_pending = 0;	}	dev->ep[0].ep.maxpacket = MAX_EP0_SIZE;	list_del_init(&dev->ep[0].ep.ep_list);}/* Reset udc registers */static void udc_reset(struct jz4730_udc *dev){	REG_UDC_DevIntMR = 0x32; /* Enable RESET and SC interrupts */	REG_UDC_EPIntMR  = 0x0;  /* Enable all EP interrupts */	REG_UDC_DevCFGR = 0x17;	REG_UDC_DevCR = 0x0;	REG_UDC_EP0InCR = (0 << 4) | (1 << 1);	REG_UDC_EP0InCR = (0 << 4);	REG_UDC_EP1InCR = (3 << 4) | (1 << 1);	REG_UDC_EP1InCR = (3 << 4);	REG_UDC_EP2InCR = (2 << 4) | (1 << 1);	REG_UDC_EP2InCR = (2 << 4);	REG_UDC_EP3InCR = (2 << 4) | (1 << 1);	REG_UDC_EP3InCR = (2 << 4);	REG_UDC_EP4InCR = (1 << 4) | (1 << 1);	REG_UDC_EP4InCR = (1 << 4);	REG_UDC_EP0OutCR = (0 << 4);	REG_UDC_EP5OutCR = (2 << 4);	REG_UDC_EP6OutCR = (2 << 4);	REG_UDC_EP7OutCR = (1 << 4);	REG_UDC_EP0InSR = 0;	REG_UDC_EP1InSR = 0;	REG_UDC_EP2InSR = 0;	REG_UDC_EP3InSR = 0;	REG_UDC_EP4InSR = 0;	REG_UDC_EP5OutSR = 0;	REG_UDC_EP6OutSR = 0;	REG_UDC_EP7OutSR = 0;	REG_UDC_EP0InBSR = MAX_EP0_SIZE/4;	REG_UDC_EP1InBSR = MAX_EP1_SIZE/4;	REG_UDC_EP2InBSR = MAX_EP2_SIZE/4;	REG_UDC_EP3InBSR = MAX_EP3_SIZE/4;	REG_UDC_EP4InBSR = MAX_EP4_SIZE/4;	REG_UDC_EP0InMPSR = MAX_EP0_SIZE;	REG_UDC_EP1InMPSR = MAX_EP1_SIZE;	REG_UDC_EP2InMPSR = MAX_EP2_SIZE;	REG_UDC_EP3InMPSR = MAX_EP3_SIZE;	REG_UDC_EP4InMPSR = MAX_EP4_SIZE;	REG_UDC_EP0OutMPSR = MAX_EP0_SIZE;	REG_UDC_EP5OutMPSR = MAX_EP5_SIZE;	REG_UDC_EP6OutMPSR = MAX_EP6_SIZE;	REG_UDC_EP7OutMPSR = MAX_EP7_SIZE;	REG_UDC_EP0InfR = (MAX_EP0_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (0 << 5) | (0 << 4) | (0 << 0);	REG_UDC_EP1InfR = (MAX_EP1_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (3 << 5) | (1 << 4) | (1 << 0);	REG_UDC_EP2InfR = (MAX_EP2_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (1 << 4) | (2 << 0);	REG_UDC_EP3InfR = (MAX_EP3_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (1 << 4) | (3 << 0);	REG_UDC_EP4InfR = (MAX_EP4_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (1 << 5) | (1 << 4) | (4 << 0);	REG_UDC_EP5InfR = (MAX_EP5_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (0 << 4) | (5 << 0);	REG_UDC_EP6InfR = (MAX_EP6_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (0 << 4) | (6 << 0);	REG_UDC_EP7InfR = (MAX_EP7_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (1 << 5) | (0 << 4) | (7 << 0);		REG_UDC_STCMAR = 0xffff;}static void ep0_start(struct jz4730_udc *dev){	udc_reset(dev);	udc_reinit(dev);	/* expect ep0 requests when the host drops reset */	dev->gadget.speed = USB_SPEED_FULL;	dev->ep0state = EP0_IDLE;}static void udc_enable(struct jz4730_udc *dev){	/* Enable udc and enable all interrupts */	__intc_unmask_irq(IRQ_UDC);	__harb_usb0_udc();	/* start enumeration now, or after power detect irq */	ep0_start(dev);}/*-------------------------------------------------------------------------*//* keeping it simple: * - one bus driver, initted first; * - one function driver, initted second */static struct jz4730_udc	*the_controller;/* 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 jz4730_udc	*dev = the_controller;	int			retval;		if (!driver//			|| driver->speed != USB_SPEED_FULL			|| !driver->bind			|| !driver->unbind			|| !driver->disconnect			|| !driver->setup)	{	printk("\n -EINVAL");		return -EINVAL;	}	if (!dev)		return -ENODEV;	if (dev->driver)		return -EBUSY;	/* hook up the driver */	dev->driver = driver;	retval = driver->bind(&dev->gadget);	if (retval) {		DEBUG("bind to driver %s --> error %d\n",		      driver->driver.name, retval);		dev->driver = 0;		return retval;	}	/* then enable host detection and ep0; and we're ready	 * for set_configuration as well as eventual disconnect.	 */	udc_enable(dev);	DEBUG("registered gadget driver '%s'\n", driver->driver.name);	return 0;}EXPORT_SYMBOL(usb_gadget_register_driver);static voidstop_activity(struct jz4730_udc *dev, struct usb_gadget_driver *driver){	unsigned	i;	DEBUG("%s\n", __FUNCTION__);	if (dev->gadget.speed == USB_SPEED_UNKNOWN)		driver = 0;	/* disconnect gadget driver after quiesceing hw and the driver */	udc_reset (dev);	for (i = 0; i < MAX_EP_NUM; i++)		nuke(&dev->ep [i], -ESHUTDOWN);	if (driver) {		spin_unlock(&dev->lock);		driver->disconnect(&dev->gadget);		spin_lock(&dev->lock);	}	if (dev->driver)		udc_enable(dev);}int usb_gadget_unregister_driver(struct usb_gadget_driver *driver){	struct jz4730_udc	*dev = the_controller;	unsigned long	flags;	/* disable UDC irq */	__intc_mask_irq(IRQ_UDC);	__harb_usb0_uhc();	if (!dev)		return -ENODEV;	if (!driver || driver != dev->driver)		return -EINVAL;	spin_lock_irqsave(&dev->lock, flags);	dev->driver = 0;	stop_activity(dev, driver);	spin_unlock_irqrestore(&dev->lock, flags);	driver->unbind(&dev->gadget);	DEBUG("unregistered driver '%s'\n", driver->driver.name);	return 0;}EXPORT_SYMBOL(usb_gadget_unregister_driver);static void jz4730_epn_out(struct jz4730_udc *dev, int ep_idx, u32 count){	struct jz4730_request *req;	struct jz4730_ep *ep = &dev->ep[ep_idx];	req = list_entry(ep->queue.next, struct jz4730_request, queue);	read_fifo(ep, req, count);}static void jz4730_epn_in(struct jz4730_udc *dev, int ep_idx){	struct jz4730_request *req;	struct jz4730_ep *ep = &dev->ep[ep_idx];	req = list_entry(ep->queue.next, struct jz4730_request, queue);	write_fifo(ep, req);}/****************************************************************//* End Point 0 related functions                                *//****************************************************************//* return:  0 = still running, 1 = completed, negative = errno */static int write_fifo_ep0(struct jz4730_ep *ep, struct jz4730_request *req){	u32 max, count;	int is_last;	max = ep->ep.maxpacket;	count = write_packet(ep, req, max);	/* last packet is usually short (or a zlp) */	if (unlikely(count != max))		is_last = 1;	else {

⌨️ 快捷键说明

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