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

📄 jz4730_udc.c

📁 linux下面gadget设备驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
		if (likely(req->req.length != req->req.actual) || req->req.zero)			is_last = 0;		else			is_last = 1;	}	DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __FUNCTION__,		  ep->ep.name, count,		  is_last ? "/L" : "", req->req.length - req->req.actual, req);	/* requests complete when all IN data is in the FIFO */	if (is_last) {		done(ep, req, 0);		return 1;	}	return 0;}/* * Simulate a USB_REQ_SET_CONFIGURATION to the function driver, * this is required to enable the endpoints of the function driver. * UDC should let software have the chance to handle this standard  * request, unfortunately UDC can't do that. */static void psudo_set_config(void){	struct jz4730_udc *dev = (struct jz4730_udc *) the_controller;	struct usb_ctrlrequest ctrl;	int tmp;	/* SETUP packet */	ctrl.bRequestType = 0x00;	ctrl.bRequest = USB_REQ_SET_CONFIGURATION;	ctrl.wValue = 1;	ctrl.wIndex = 0;	ctrl.wLength = 0;	nuke(&dev->ep[0], 0);	dev->ep[0].stopped = 0;	if (likely(ctrl.bRequestType & USB_DIR_IN)) {		dev->ep[0].is_in = 1;		dev->ep0state = EP0_IN;	} else {		dev->ep[0].is_in = 0;		dev->ep0state = EP0_OUT;	}	/* delegate everything to the gadget driver.	 * it may respond after this irq handler returns.	 */	spin_unlock (&dev->lock);	tmp = dev->driver->setup(&dev->gadget, &ctrl);	spin_lock (&dev->lock);	if (unlikely(tmp < 0)) {		DEBUG_EP0("req %02x.%02x protocol STALL; err %d\n",			  ctrl.bRequestType, ctrl.bRequest, tmp);		dev->ep[0].stopped = 1;		dev->ep0state = EP0_STALL;	}}/*  * Read 8 bytes setup packet from EP0 RX buffer */static void read_setup_packet(u8 *buf){	u32 *tmp = (u32 *)buf;	*tmp++ = readl((unsigned int *)RXFIFO);	*tmp++ = readl((unsigned int *)RXFIFO);	REG32(UDC_RXCONFIRM);}static void jz4730_ep0_setup(struct jz4730_udc *dev){	struct jz4730_ep *ep = &dev->ep[0];	struct usb_ctrlrequest ctrl;	int tmp;	/* read control req from fifo (8 bytes) */	read_setup_packet((unsigned char *) &ctrl);	DEBUG_EP0("SETUP %02x.%02x v%04x i%04x l%04x\n",		  ctrl.bRequestType, ctrl.bRequest,		  ctrl.wValue, ctrl.wIndex, ctrl.wLength);	/* Set direction of EP0 */	if (likely(ctrl.bRequestType & USB_DIR_IN)) {		ep->is_in = 1;		dev->ep0state = EP0_IN;	} else {		ep->is_in = 0;		dev->ep0state = EP0_OUT;	}	/* Nuke all previous transfers */	nuke(ep, 0);	ep->stopped = 0;	/* delegate everything to the gadget driver.	 * it may respond after this irq handler returns.	 */	if (likely((u32)dev->driver)) {		/* device-2-host (IN) or no data setup command, process immediately */		spin_unlock(&dev->lock);		tmp = dev->driver->setup(&dev->gadget, &ctrl);		spin_lock(&dev->lock);		if (unlikely(tmp < 0)) {			/* setup processing failed, force stall */			DEBUG_EP0("req %02x.%02x protocol STALL; err %d\n",				  ctrl.bRequestType, ctrl.bRequest, tmp);			dev->ep0state = EP0_STALL;		}	}}static int jz4730_ep0_in(struct jz4730_udc *dev){	struct jz4730_request *req;	struct jz4730_ep *ep = &dev->ep[0];	int ret;	if (list_empty(&ep->queue))		req = 0;	else		req = list_entry(ep->queue.next, struct jz4730_request, queue);	if (!req) {		DEBUG_EP0("%s: NULL REQ\n", __FUNCTION__);		return 0;	}	ret = write_fifo_ep0(ep, req);	return ret;}static void jz4730_ep0_out(struct jz4730_udc *dev){	u32 epsr;  	struct jz4730_ep *ep = &dev->ep[0];	epsr = REG_UDC_EP0OutSR;	REG_UDC_EP0OutSR &= ~UDC_EPSR_OUT_MASK;	if (epsr & UDC_EPSR_OUT_RCVSETUP) {		jz4730_ep0_setup(dev);	}	else if (epsr & UDC_EPSR_OUT_RCVDATA) {		u32 count = __udc_ep0out_packet_size();		if (count == 0) {			readl((unsigned int *)UDC_RXCONFIRM); // ack zero packet		}		else {			/* EP0 OUT Data */  			if (list_empty(&ep->queue)) {  				ep->irq_pending = 1;  				pio_irq_disable(ep);  			}  			else  				jz4730_epn_out(dev, 0, count);		}	}}static void handle_reset_irq(struct jz4730_udc *dev){	int i;	/* clear any status */	REG_UDC_EPIntR = 0xffffffff;	REG_UDC_DevIntR = 0xffffffff;	/* reset udc */	udc_reset(dev);	/* reset driver status */	for (i = 0; i < MAX_EP_NUM; i++) {		struct jz4730_ep *ep = &dev->ep[i];		ep->irq_pending = 0;//		nuke(ep, 0);  		nuke(ep, -ESHUTDOWN);	}}static irqreturn_t jz4730_udc_irq(int irq, void *_dev){	struct jz4730_udc *dev = _dev;	struct jz4730_ep *ep;	u32 intr_dev, intr_ep, stats, count;	spin_lock(&dev->lock);	intr_dev = REG_UDC_DevIntR;	intr_ep = REG_UDC_EPIntR;	DEBUG("*** udc irq intr_dev=0x%x intr_ep=0x%x\n", intr_dev, intr_ep);	if (!intr_dev && !intr_ep) {		spin_unlock(&dev->lock);		return IRQ_HANDLED;	}	if (udc_debug) {#ifdef CONFIG_JZ_UDC_HOTPLUG		jz_udc_active = 1;#endif		REG_UDC_DevIntR = intr_dev;		REG_UDC_EPIntR = intr_ep;		__harb_usb0_uhc();		__intc_mask_irq(IRQ_UDC);		spin_unlock(&dev->lock);		return IRQ_HANDLED;	}	if (intr_dev) {		if (intr_dev & UDC_DevIntR_SC) {			psudo_set_config();			udelay(100);		}		if (intr_dev & UDC_DevIntR_UR) {#ifdef CONFIG_JZ_UDC_HOTPLUG			jz_udc_active = 1;#endif			handle_reset_irq(dev);		}		REG_UDC_DevIntR = intr_dev;	}	if (intr_ep & UDC_EPIntR_OUTEP0) {		REG_UDC_EPIntR = UDC_EPIntR_OUTEP0;		jz4730_ep0_out(dev);	}	if (intr_ep & UDC_EPIntR_INEP0) {		ep = &dev->ep[0];		if (list_empty(&ep->queue)) {			pio_irq_disable(ep);		}		else {			stats = REG_UDC_EP0InSR;			if (stats & UDC_EPSR_IN) {				REG_UDC_EPIntR = UDC_EPIntR_INEP0;				REG_UDC_EP0InSR &= ~UDC_EPSR_IN;				jz4730_ep0_in(dev);			}		}	}	if (intr_ep & UDC_EPIntR_OUTEP5) {		REG_UDC_EPIntR = UDC_EPIntR_OUTEP5;		ep = &dev->ep[5];		if (list_empty(&ep->queue)) {			ep->irq_pending = 1;			pio_irq_disable(ep);		}		else {			stats = REG_UDC_EP5OutSR;			if (stats & UDC_EPSR_OUT_RCVDATA) {				REG_UDC_EP5OutSR &= ~UDC_EPSR_OUT_MASK;				count = OUT_COUNT(stats);				jz4730_epn_out(dev, 5, count);			}		}	}	if (intr_ep & UDC_EPIntR_INEP2) {		ep = &dev->ep[2];		if (list_empty(&ep->queue)) {			ep->irq_pending = 1;			pio_irq_disable(ep);		}		else {			stats = REG_UDC_EP2InSR;			if (stats & UDC_EPSR_IN) {				REG_UDC_EP2InSR &= ~UDC_EPSR_IN;				jz4730_epn_in(dev, 2);			}		}		REG_UDC_EPIntR = UDC_EPIntR_INEP2;	}  	if (intr_ep & UDC_EPIntR_INEP1) {  		ep = &dev->ep[1];  		if (list_empty(&ep->queue)) {  			ep->irq_pending = 1;  			pio_irq_disable(ep);  		}  		else {  			stats = REG_UDC_EP1InSR;  			if (stats & UDC_EPSR_IN) {  				REG_UDC_EP1InSR &= ~UDC_EPSR_IN;  				jz4730_epn_in(dev, 1);  			}  		}    		REG_UDC_EPIntR = UDC_EPIntR_INEP1;  	}	spin_unlock(&dev->lock);	return IRQ_HANDLED;}/*-------------------------------------------------------------------------*/static struct jz4730_udc udc_dev = {	.usb_address = 0,	.gadget = {		.ops = &jz4730_ops,		.ep0 = &udc_dev.ep[0].ep,		.name = driver_name,		.dev = {			.bus_id = "gadget",		},	},	/* control endpoint  no need to init here!*/ 	/* control endpoint */};/* tear down the binding between this driver and the pci device */static int jz4730_udc_remove(struct platform_device *pdev){	struct jz4730_udc *dev = platform_get_drvdata(pdev);	if (dev->driver)		return -EBUSY;	/* USB port0 as UHC */	__harb_usb0_uhc();	/* reset udc */	udc_reset(dev);	/* clear any status */	REG_UDC_EPIntR = 0xffffffff;	REG_UDC_DevIntR = 0xffffffff;	/* disable all UDC interrupts */	REG_UDC_DevIntMR = 0xffffffff;	REG_UDC_EPIntMR  = 0xffffffff;	free_irq(IRQ_UDC, dev);	platform_set_drvdata(pdev, 0);	device_unregister(&dev->gadget.dev);	the_controller = 0;	return 0;}static int jz4730_udc_probe(struct platform_device *pdev){	struct jz4730_udc *dev = &udc_dev;	int retval,rc;	/* if you want to support more than one controller in a system,	 * usb_gadget_driver_{register,unregister}() must change.	 */	if (the_controller) {		printk("Check the_controller: %s\n", driver_name);		return -EBUSY;	}	spin_lock_init(&dev->lock);	device_initialize(&dev->gadget.dev);	dev->gadget.dev.parent = &pdev->dev;      //if no,can only insmod once!!	dev->gadget.dev.release = jz4730_udc_release;	rc = device_register (&dev->gadget.dev);	if (rc < 0)		return rc;	platform_set_drvdata(pdev, dev);	/*	 * Note: we just mask INTC irq but allow UDC irq.	 * This avoid that we miss any UDC irqs.	 */	/* To avoid any UDC irqs here, we call cli() first *///	cli();	/* disable INTC irq */	__intc_mask_irq(IRQ_UDC);	/* init to known state, then setup irqs */	udc_reset(dev);	udc_reinit(dev);	/* request UDC irq */	if (request_irq(IRQ_UDC, jz4730_udc_irq, IRQF_DISABLED, // SA_INTERRUPT,			driver_name, dev) != 0) {		printk(KERN_INFO "request UDC interrupt %d failed\n", IRQ_UDC);		retval = -EBUSY;		goto done;	}	/* disable INTC irq again since request_irq has enabled it */	__intc_mask_irq(IRQ_UDC);	__intc_ack_irq(IRQ_UDC);	/* Re-enable irqs *///	sti();	printk(KERN_INFO "%s\n", driver_desc);	printk(KERN_INFO "version: " DRIVER_VERSION "\n");	/* done */	the_controller = dev;	return 0;done:	if (dev)		jz4730_udc_remove (pdev);	return retval;}static struct platform_driver udc_driver = {	.probe		= jz4730_udc_probe,	.remove		= jz4730_udc_remove,	.suspend	= NULL,	.resume		= NULL,	.driver		= {		.name	= (char *) driver_name,		.owner	= THIS_MODULE,	},};static struct platform_device		the_udc_pdev = {	.name		= (char *) driver_name,	.id		= -1,	.dev		= {		.release	= jz4730_udc_release,	},};/*-------------------------------------------------------------------------*/static int __init udc_init (void){        platform_driver_register(&udc_driver);	return platform_device_register (&the_udc_pdev);}static void __exit udc_exit (void){	platform_driver_unregister(&udc_driver);	platform_device_unregister(&the_udc_pdev);}module_init(udc_init);module_exit(udc_exit);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_AUTHOR("Wei Jianli <jlwei@ingenic.cn>");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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