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

📄 jz4740_udc.c

📁 linux下面gadget设备驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
	DEBUG_SETUP("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->bEndpointAddress |= USB_DIR_IN;	} else {		ep->bEndpointAddress &= ~USB_DIR_IN;	}	/* Handle some SETUP packets ourselves */	switch (ctrl.bRequest) {	case USB_REQ_SET_ADDRESS:		if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE))			break;		DEBUG_SETUP("USB_REQ_SET_ADDRESS (%d)\n", ctrl.wValue);		udc_set_address(dev, ctrl.wValue);		usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));		return;	case USB_REQ_SET_CONFIGURATION:		if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE))			break;		DEBUG_SETUP("USB_REQ_SET_CONFIGURATION (%d)\n", ctrl.wValue);		usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));		/* Enable RESUME and SUSPEND interrupts */		usb_setb(USB_REG_INTRUSBE, (USB_INTR_RESUME | USB_INTR_SUSPEND));		break;	case USB_REQ_SET_INTERFACE:		if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE))			break;		DEBUG_SETUP("USB_REQ_SET_INTERFACE (%d)\n", ctrl.wValue);		usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));		break;//	case USB_REQ_GET_STATUS://		if (jz4740_handle_get_status(dev, &ctrl) == 0)//			return;	case USB_REQ_CLEAR_FEATURE:	case USB_REQ_SET_FEATURE:		if (ctrl.bRequestType == USB_RECIP_ENDPOINT) {			struct jz4740_ep *qep;			int ep_num = (ctrl.wIndex & 0x0f);			/* Support only HALT feature */			if (ctrl.wValue != 0 || ctrl.wLength != 0			    || ep_num > 3 || ep_num < 1)				break;			qep = &dev->ep[ep_num];			spin_unlock(&dev->lock);			if (ctrl.bRequest == USB_REQ_SET_FEATURE) {				DEBUG_SETUP("SET_FEATURE (%d)\n",					    ep_num);				jz4740_set_halt(&qep->ep, 1);			} else {				DEBUG_SETUP("CLR_FEATURE (%d)\n",					    ep_num);				jz4740_set_halt(&qep->ep, 0);			}			spin_lock(&dev->lock);						usb_set_index(0);			/* Reply with a ZLP on next IN token */			usb_setb(USB_REG_CSR0, 				 (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));			return;		}		break;	default:		break;	}	/* gadget drivers see class/vendor specific requests,	 * {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION}, 	 * and more.	 */	if (likely((u32)dev->driver)) {		/* device-2-host (IN) or no data setup command, process immediately */		spin_unlock(&dev->lock);		i = dev->driver->setup(&dev->gadget, &ctrl);		spin_lock(&dev->lock);		if (unlikely(i < 0)) {			/* setup processing failed, force stall */			DEBUG_SETUP			    ("  --> ERROR: gadget setup FAILED (stalling), setup returned %d\n",			     i);			usb_set_index(0);			usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL));			/* ep->stopped = 1; */			dev->ep0state = WAIT_FOR_SETUP;		}		else {			DEBUG_SETUP("gadget driver setup ok (%d)\n", ctrl.wLength);			if (!ctrl.wLength) {				usb_setb(USB_REG_CSR0, USB_CSR0_SVDOUTPKTRDY);			}		}	}}/* * DATA_STATE_NEED_ZLP */static void jz4740_ep0_in_zlp(struct jz4740_udc *dev, u32 csr){	DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);	usb_setb(USB_REG_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND));	dev->ep0state = WAIT_FOR_SETUP;}/* * handle ep0 interrupt */static void jz4740_handle_ep0(struct jz4740_udc *dev, u32 intr){	struct jz4740_ep *ep = &dev->ep[0];	u32 csr;	/* Set index 0 */	usb_set_index(0);	csr = usb_readb(USB_REG_CSR0);	DEBUG_EP0("%s: csr = %x  state = \n", __FUNCTION__, csr);//, state_names[dev->ep0state]);	/*	 * if SENT_STALL is set	 *      - clear the SENT_STALL bit	 */	if (csr & USB_CSR0_SENTSTALL) {		DEBUG_EP0("%s: USB_CSR0_SENTSTALL is set: %x\n", __FUNCTION__, csr);		usb_clearb(USB_REG_CSR0, USB_CSR0_SENDSTALL | USB_CSR0_SENTSTALL);		nuke(ep, -ECONNABORTED);		dev->ep0state = WAIT_FOR_SETUP;		return;	}	/*	 * if a transfer is in progress && INPKTRDY and OUTPKTRDY are clear	 *      - fill EP0 FIFO	 *      - if last packet	 *      -       set IN_PKT_RDY | DATA_END	 *      - else	 *              set IN_PKT_RDY	 */	if (!(csr & (USB_CSR0_INPKTRDY | USB_CSR0_OUTPKTRDY))) {		DEBUG_EP0("%s: INPKTRDY and OUTPKTRDY are clear\n",			  __FUNCTION__);		switch (dev->ep0state) {		case DATA_STATE_XMIT:			DEBUG_EP0("continue with DATA_STATE_XMIT\n");			jz4740_ep0_in(dev, csr);			return;		case DATA_STATE_NEED_ZLP:			DEBUG_EP0("continue with DATA_STATE_NEED_ZLP\n");			jz4740_ep0_in_zlp(dev, csr);			return;		default:			/* Stall? *///			DEBUG_EP0("Odd state!! state = %s\n",//				  state_names[dev->ep0state]);			dev->ep0state = WAIT_FOR_SETUP;			/* nuke(ep, 0); */			/* usb_setb(ep->csr, USB_CSR0_SENDSTALL); *///			break;			return;		}	}	/*	 * if SETUPEND is set	 *      - abort the last transfer	 *      - set SERVICED_SETUP_END_BIT	 */	if (csr & USB_CSR0_SETUPEND) {		DEBUG_EP0("%s: USB_CSR0_SETUPEND is set: %x\n", __FUNCTION__, csr);		usb_setb(USB_REG_CSR0, USB_CSR0_SVDSETUPEND);		nuke(ep, 0);		dev->ep0state = WAIT_FOR_SETUP;	}	/*	 * if USB_CSR0_OUTPKTRDY is set	 *      - read data packet from EP0 FIFO	 *      - decode command	 *      - if error	 *              set SVDOUTPKTRDY | DATAEND | SENDSTALL bits	 *      - else	 *              set SVDOUTPKTRDY | DATAEND bits	 */	if (csr & USB_CSR0_OUTPKTRDY) {		DEBUG_EP0("%s: EP0_OUT_PKT_RDY is set: %x\n", __FUNCTION__,			  csr);		switch (dev->ep0state) {		case WAIT_FOR_SETUP:			DEBUG_EP0("WAIT_FOR_SETUP\n");			jz4740_ep0_setup(dev, csr);			break;		case DATA_STATE_RECV:			DEBUG_EP0("DATA_STATE_RECV\n");			jz4740_ep0_out(dev, csr);			break;		default:			/* send stall? */			DEBUG_EP0("strange state!! 2. send stall? state = %d\n",				  dev->ep0state);			break;		}	}}static void jz4740_ep0_kick(struct jz4740_udc *dev, struct jz4740_ep *ep){	u32 csr;	usb_set_index(0);	csr = usb_readb(USB_REG_CSR0);	DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);	/* Clear "out packet ready" */	usb_setb(USB_REG_CSR0, USB_CSR0_SVDOUTPKTRDY);	if (ep_is_in(ep)) {		dev->ep0state = DATA_STATE_XMIT;		jz4740_ep0_in(dev, csr);	} else {		dev->ep0state = DATA_STATE_RECV;		jz4740_ep0_out(dev, csr);	}}/** Handle USB RESET interrupt */static void jz4740_reset_irq(struct jz4740_udc *dev){	dev->gadget.speed = (usb_readb(USB_REG_POWER) & USB_POWER_HSMODE) ? 		USB_SPEED_HIGH : USB_SPEED_FULL;	DEBUG_SETUP("%s: address = %d, speed = %s\n", __FUNCTION__, dev->usb_address,		    (dev->gadget.speed == USB_SPEED_HIGH) ? "HIGH":"FULL" );}/* *	jz4740 usb device interrupt handler. */static irqreturn_t jz4740_udc_irq(int irq, void *_dev){	struct jz4740_udc *dev = _dev;	u32 intr_usb = usb_readb(USB_REG_INTRUSB) & 0x7; /* mask SOF */	u32 intr_in  = usb_readw(USB_REG_INTRIN);	u32 intr_out = usb_readw(USB_REG_INTROUT);	u32 intr_dma = usb_readb(USB_REG_INTR);	if (!intr_usb && !intr_in && !intr_out && !intr_dma)		return IRQ_HANDLED;	DEBUG("intr_out = %x intr_in=%x intr_usb=%x\n", 	      intr_out, intr_in, intr_usb);	spin_lock(&dev->lock);	/* Check for resume from suspend mode */	if ((intr_usb & USB_INTR_RESUME) && 	    (usb_readb(USB_REG_INTRUSBE) & USB_INTR_RESUME)) {		DEBUG("USB resume\n");	}	/* Check for system interrupts */	if (intr_usb & USB_INTR_RESET) {		DEBUG("USB reset\n");#ifdef CONFIG_JZ_UDC_HOTPLUG		jz_udc_active = 1;#endif		if (udc_debug) {			/* We have tested the cable type, disable module and 			 * disconnect from host right now.			 */			udc_disable(dev);			spin_unlock(&dev->lock);			return IRQ_HANDLED;		}		jz4740_reset_irq(dev);	}	/* Check for endpoint 0 interrupt */	if (intr_in & USB_INTR_EP0) {		DEBUG("USB_INTR_EP0 (control)\n");		jz4740_handle_ep0(dev, intr_in);	}	/* Check for Bulk-IN DMA interrupt */	if (intr_dma & 0x1) {		int ep_num;		ep_num = (usb_readl(USB_REG_CNTL1) >> 4) & 0xf;		jz4740_in_epn(dev, ep_num, intr_in);	}	/* Check for Bulk-OUT DMA interrupt */	if (intr_dma & 0x2) {		int ep_num;		ep_num = (usb_readl(USB_REG_CNTL2) >> 4) & 0xf;		jz4740_out_epn(dev, ep_num, intr_out);	}	/* Check for each configured endpoint interrupt */	if (intr_in & USB_INTR_INEP1) {		DEBUG("USB_INTR_INEP1\n");		jz4740_in_epn(dev, 1, intr_in);	}	if (intr_in & USB_INTR_INEP2) {		DEBUG("USB_INTR_INEP2\n");		jz4740_in_epn(dev, 2, intr_in);	}	if (intr_out & USB_INTR_OUTEP1) {		DEBUG("USB_INTR_OUTEP1\n");		jz4740_out_epn(dev, 1, intr_out);	}	/* Check for suspend mode */	if ((intr_usb & USB_INTR_SUSPEND) && 	    (usb_readb(USB_REG_INTRUSBE) & USB_INTR_SUSPEND)) {		DEBUG("USB suspend\n");		/* Host unloaded from us, can do something, such as flushing		 the NAND block cache etc. */	}	spin_unlock(&dev->lock);	return IRQ_HANDLED;}/*-------------------------------------------------------------------------*/static int jz4740_udc_get_frame(struct usb_gadget *_gadget){	DEBUG("%s, %p\n", __FUNCTION__, _gadget);	return usb_readw(USB_REG_FRAME);}static int jz4740_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 -ENOTSUPP;}static const struct usb_gadget_ops jz4740_udc_ops = {	.get_frame = jz4740_udc_get_frame,	.wakeup = jz4740_udc_wakeup,	/* current versions must always be self-powered */};/*-------------------------------------------------------------------------*/static struct jz4740_udc udc_dev = {	.usb_address = 0,	.gadget = {		.ops = &jz4740_udc_ops,		.ep0 = &udc_dev.ep[0].ep,		.name = driver_name,		.dev = {			.bus_id = "gadget",		},	},	/* control endpoint */	.ep[0] = {		.ep = {			.name = ep0name,			.ops = &jz4740_ep_ops,			.maxpacket = EP0_MAXPACKETSIZE,		},		.dev = &udc_dev,		.bEndpointAddress = 0,		.bmAttributes = 0,		.ep_type = ep_control,		.fifo = USB_FIFO_EP0,		.csr = USB_REG_CSR0,	},	/* bulk out endpoint */	.ep[1] = {		.ep = {			.name = "ep1out-bulk",			.ops = &jz4740_ep_ops,			.maxpacket = EPBULK_MAXPACKETSIZE,		},		.dev = &udc_dev,		.bEndpointAddress = 1,		.bmAttributes = USB_ENDPOINT_XFER_BULK,		.ep_type = ep_bulk_out,		.fifo = USB_FIFO_EP1,		.csr = USB_REG_OUTCSR,	},	/* bulk in endpoint */	.ep[2] = {		.ep = {			.name = "ep1in-bulk",			.ops = &jz4740_ep_ops,			.maxpacket = EPBULK_MAXPACKETSIZE,		},		.dev = &udc_dev,		.bEndpointAddress = USB_DIR_IN | 1,		.bmAttributes = USB_ENDPOINT_XFER_BULK,		.ep_type = ep_bulk_in,		.fifo = USB_FIFO_EP1,		.csr = USB_REG_INCSR,	},	/* interrupt in endpoint */	.ep[3] = {		.ep = {			.name = "ep2in-int",			.ops = &jz4740_ep_ops,			.maxpacket = EPINTR_MAXPACKETSIZE,		},		.dev = &udc_dev,		.bEndpointAddress = USB_DIR_IN | 2,		.bmAttributes = USB_ENDPOINT_XFER_INT,		.ep_type = ep_interrupt,		.fifo = USB_FIFO_EP2,		.csr = USB_REG_INCSR,	},};static int jz4740_udc_probe(struct platform_device *pdev){	struct jz4740_udc *dev = &udc_dev;	int rc;	DEBUG("%s\n", __FUNCTION__);	spin_lock_init(&dev->lock);	the_controller = dev;	dev->dev = &pdev->dev;	device_initialize(&dev->gadget.dev);	dev->gadget.dev.parent = &pdev->dev;//	strcpy (dum->gadget.dev.bus_id, "gadget");	dev->gadget.dev.release = jz4740_udc_release;	if ((rc = device_register (&dev->gadget.dev)) < 0)		return rc;	platform_set_drvdata(pdev, dev);	udc_disable(dev);	udc_reinit(dev);	/* irq setup */	if (request_irq(IRQ_UDC, jz4740_udc_irq, IRQF_DISABLED,//SA_SHIRQ/*|SA_SAMPLE_RANDOM*/,			driver_name, dev) != 0) {		printk(KERN_INFO "request UDC interrupt %d failed\n", IRQ_UDC);		return -EBUSY;	}	printk(KERN_INFO "%s\n", driver_desc);	printk(KERN_INFO "version: " DRIVER_VERSION "\n");	return 0;}static int jz4740_udc_remove(struct platform_device *pdev){	struct jz4740_udc *dev = platform_get_drvdata(pdev);	DEBUG("%s: %p\n", __FUNCTION__, dev);	if (dev->driver)		return -EBUSY;	udc_disable(dev);#ifdef	UDC_PROC_FILE	remove_proc_entry(proc_node_name, NULL);#endif	free_irq(IRQ_UDC, dev);	platform_set_drvdata(pdev, 0);	device_unregister(&dev->gadget.dev);	the_controller = 0;	return 0;}static struct platform_driver udc_driver = {	.probe		= jz4740_udc_probe,	.remove		= jz4740_udc_remove,	.suspend	= NULL,	.resume		= NULL,	.driver		= {		.name	= (char *) driver_name,		.owner	= THIS_MODULE,	},};static struct platform_device		the_udc_pdev = {	.name		= (char *) gadget_name,	.id		= -1,	.dev		= {		.release	= jz4740_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 + -