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

📄 pxa2xx_udc.c

📁 linux下面gadget设备驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
				handled = 1;			}			/* endpoint data transfers */			for (i = 0; i < 8; i++) {				u32	tmp = 1 << i;				if (i && (usir0 & tmp)) {					handle_ep(&dev->ep[i]);					USIR0 |= tmp;					handled = 1;				}				if (usir1 & tmp) {					handle_ep(&dev->ep[i+8]);					USIR1 |= tmp;					handled = 1;				}			}		}		/* we could also ask for 1 msec SOF (SIR) interrupts */	} while (handled);	return IRQ_HANDLED;}/*-------------------------------------------------------------------------*/static void nop_release (struct device *dev){	DMSG("%s %s\n", __FUNCTION__, dev->bus_id);}/* this uses load-time allocation and initialization (instead of * doing it at run-time) to save code, eliminate fault paths, and * be more obviously correct. */static struct pxa2xx_udc memory = {	.gadget = {		.ops		= &pxa2xx_udc_ops,		.ep0		= &memory.ep[0].ep,		.name		= driver_name,		.dev = {			.bus_id		= "gadget",			.release	= nop_release,		},	},	/* control endpoint */	.ep[0] = {		.ep = {			.name		= ep0name,			.ops		= &pxa2xx_ep_ops,			.maxpacket	= EP0_FIFO_SIZE,		},		.dev		= &memory,		.reg_udccs	= &UDCCS0,		.reg_uddr	= &UDDR0,	},	/* first group of endpoints */	.ep[1] = {		.ep = {			.name		= "ep1in-bulk",			.ops		= &pxa2xx_ep_ops,			.maxpacket	= BULK_FIFO_SIZE,		},		.dev		= &memory,		.fifo_size	= BULK_FIFO_SIZE,		.bEndpointAddress = USB_DIR_IN | 1,		.bmAttributes	= USB_ENDPOINT_XFER_BULK,		.reg_udccs	= &UDCCS1,		.reg_uddr	= &UDDR1,	},	.ep[2] = {		.ep = {			.name		= "ep2out-bulk",			.ops		= &pxa2xx_ep_ops,			.maxpacket	= BULK_FIFO_SIZE,		},		.dev		= &memory,		.fifo_size	= BULK_FIFO_SIZE,		.bEndpointAddress = 2,		.bmAttributes	= USB_ENDPOINT_XFER_BULK,		.reg_udccs	= &UDCCS2,		.reg_ubcr	= &UBCR2,		.reg_uddr	= &UDDR2,	},#ifndef CONFIG_USB_PXA2XX_SMALL	.ep[3] = {		.ep = {			.name		= "ep3in-iso",			.ops		= &pxa2xx_ep_ops,			.maxpacket	= ISO_FIFO_SIZE,		},		.dev		= &memory,		.fifo_size	= ISO_FIFO_SIZE,		.bEndpointAddress = USB_DIR_IN | 3,		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,		.reg_udccs	= &UDCCS3,		.reg_uddr	= &UDDR3,	},	.ep[4] = {		.ep = {			.name		= "ep4out-iso",			.ops		= &pxa2xx_ep_ops,			.maxpacket	= ISO_FIFO_SIZE,		},		.dev		= &memory,		.fifo_size	= ISO_FIFO_SIZE,		.bEndpointAddress = 4,		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,		.reg_udccs	= &UDCCS4,		.reg_ubcr	= &UBCR4,		.reg_uddr	= &UDDR4,	},	.ep[5] = {		.ep = {			.name		= "ep5in-int",			.ops		= &pxa2xx_ep_ops,			.maxpacket	= INT_FIFO_SIZE,		},		.dev		= &memory,		.fifo_size	= INT_FIFO_SIZE,		.bEndpointAddress = USB_DIR_IN | 5,		.bmAttributes	= USB_ENDPOINT_XFER_INT,		.reg_udccs	= &UDCCS5,		.reg_uddr	= &UDDR5,	},	/* second group of endpoints */	.ep[6] = {		.ep = {			.name		= "ep6in-bulk",			.ops		= &pxa2xx_ep_ops,			.maxpacket	= BULK_FIFO_SIZE,		},		.dev		= &memory,		.fifo_size	= BULK_FIFO_SIZE,		.bEndpointAddress = USB_DIR_IN | 6,		.bmAttributes	= USB_ENDPOINT_XFER_BULK,		.reg_udccs	= &UDCCS6,		.reg_uddr	= &UDDR6,	},	.ep[7] = {		.ep = {			.name		= "ep7out-bulk",			.ops		= &pxa2xx_ep_ops,			.maxpacket	= BULK_FIFO_SIZE,		},		.dev		= &memory,		.fifo_size	= BULK_FIFO_SIZE,		.bEndpointAddress = 7,		.bmAttributes	= USB_ENDPOINT_XFER_BULK,		.reg_udccs	= &UDCCS7,		.reg_ubcr	= &UBCR7,		.reg_uddr	= &UDDR7,	},	.ep[8] = {		.ep = {			.name		= "ep8in-iso",			.ops		= &pxa2xx_ep_ops,			.maxpacket	= ISO_FIFO_SIZE,		},		.dev		= &memory,		.fifo_size	= ISO_FIFO_SIZE,		.bEndpointAddress = USB_DIR_IN | 8,		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,		.reg_udccs	= &UDCCS8,		.reg_uddr	= &UDDR8,	},	.ep[9] = {		.ep = {			.name		= "ep9out-iso",			.ops		= &pxa2xx_ep_ops,			.maxpacket	= ISO_FIFO_SIZE,		},		.dev		= &memory,		.fifo_size	= ISO_FIFO_SIZE,		.bEndpointAddress = 9,		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,		.reg_udccs	= &UDCCS9,		.reg_ubcr	= &UBCR9,		.reg_uddr	= &UDDR9,	},	.ep[10] = {		.ep = {			.name		= "ep10in-int",			.ops		= &pxa2xx_ep_ops,			.maxpacket	= INT_FIFO_SIZE,		},		.dev		= &memory,		.fifo_size	= INT_FIFO_SIZE,		.bEndpointAddress = USB_DIR_IN | 10,		.bmAttributes	= USB_ENDPOINT_XFER_INT,		.reg_udccs	= &UDCCS10,		.reg_uddr	= &UDDR10,	},	/* third group of endpoints */	.ep[11] = {		.ep = {			.name		= "ep11in-bulk",			.ops		= &pxa2xx_ep_ops,			.maxpacket	= BULK_FIFO_SIZE,		},		.dev		= &memory,		.fifo_size	= BULK_FIFO_SIZE,		.bEndpointAddress = USB_DIR_IN | 11,		.bmAttributes	= USB_ENDPOINT_XFER_BULK,		.reg_udccs	= &UDCCS11,		.reg_uddr	= &UDDR11,	},	.ep[12] = {		.ep = {			.name		= "ep12out-bulk",			.ops		= &pxa2xx_ep_ops,			.maxpacket	= BULK_FIFO_SIZE,		},		.dev		= &memory,		.fifo_size	= BULK_FIFO_SIZE,		.bEndpointAddress = 12,		.bmAttributes	= USB_ENDPOINT_XFER_BULK,		.reg_udccs	= &UDCCS12,		.reg_ubcr	= &UBCR12,		.reg_uddr	= &UDDR12,	},	.ep[13] = {		.ep = {			.name		= "ep13in-iso",			.ops		= &pxa2xx_ep_ops,			.maxpacket	= ISO_FIFO_SIZE,		},		.dev		= &memory,		.fifo_size	= ISO_FIFO_SIZE,		.bEndpointAddress = USB_DIR_IN | 13,		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,		.reg_udccs	= &UDCCS13,		.reg_uddr	= &UDDR13,	},	.ep[14] = {		.ep = {			.name		= "ep14out-iso",			.ops		= &pxa2xx_ep_ops,			.maxpacket	= ISO_FIFO_SIZE,		},		.dev		= &memory,		.fifo_size	= ISO_FIFO_SIZE,		.bEndpointAddress = 14,		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,		.reg_udccs	= &UDCCS14,		.reg_ubcr	= &UBCR14,		.reg_uddr	= &UDDR14,	},	.ep[15] = {		.ep = {			.name		= "ep15in-int",			.ops		= &pxa2xx_ep_ops,			.maxpacket	= INT_FIFO_SIZE,		},		.dev		= &memory,		.fifo_size	= INT_FIFO_SIZE,		.bEndpointAddress = USB_DIR_IN | 15,		.bmAttributes	= USB_ENDPOINT_XFER_INT,		.reg_udccs	= &UDCCS15,		.reg_uddr	= &UDDR15,	},#endif /* !CONFIG_USB_PXA2XX_SMALL */};#define CP15R0_VENDOR_MASK	0xffffe000#if	defined(CONFIG_ARCH_PXA)#define CP15R0_XSCALE_VALUE	0x69052000	/* intel/arm/xscale */#elif	defined(CONFIG_ARCH_IXP4XX)#define CP15R0_XSCALE_VALUE	0x69054000	/* intel/arm/ixp4xx */#endif#define CP15R0_PROD_MASK	0x000003f0#define PXA25x			0x00000100	/* and PXA26x */#define PXA210			0x00000120#define CP15R0_REV_MASK		0x0000000f#define CP15R0_PRODREV_MASK	(CP15R0_PROD_MASK | CP15R0_REV_MASK)#define PXA255_A0		0x00000106	/* or PXA260_B1 */#define PXA250_C0		0x00000105	/* or PXA26x_B0 */#define PXA250_B2		0x00000104#define PXA250_B1		0x00000103	/* or PXA260_A0 */#define PXA250_B0		0x00000102#define PXA250_A1		0x00000101#define PXA250_A0		0x00000100#define PXA210_C0		0x00000125#define PXA210_B2		0x00000124#define PXA210_B1		0x00000123#define PXA210_B0		0x00000122#define IXP425_A0		0x000001c1#define IXP425_B0		0x000001f1#define IXP465_AD		0x00000200/* *	probe - binds to the platform device */static int __init pxa2xx_udc_probe(struct platform_device *pdev){	struct pxa2xx_udc *dev = &memory;	int retval, vbus_irq, irq;	u32 chiprev;	/* insist on Intel/ARM/XScale */	asm("mrc%? p15, 0, %0, c0, c0" : "=r" (chiprev));	if ((chiprev & CP15R0_VENDOR_MASK) != CP15R0_XSCALE_VALUE) {		printk(KERN_ERR "%s: not XScale!\n", driver_name);		return -ENODEV;	}	/* trigger chiprev-specific logic */	switch (chiprev & CP15R0_PRODREV_MASK) {#if	defined(CONFIG_ARCH_PXA)	case PXA255_A0:		dev->has_cfr = 1;		break;	case PXA250_A0:	case PXA250_A1:		/* A0/A1 "not released"; ep 13, 15 unusable */		/* fall through */	case PXA250_B2: case PXA210_B2:	case PXA250_B1: case PXA210_B1:	case PXA250_B0: case PXA210_B0:		/* OUT-DMA is broken ... */		/* fall through */	case PXA250_C0: case PXA210_C0:		break;#elif	defined(CONFIG_ARCH_IXP4XX)	case IXP425_A0:	case IXP425_B0:	case IXP465_AD:		dev->has_cfr = 1;		break;#endif	default:		printk(KERN_ERR "%s: unrecognized processor: %08x\n",			driver_name, chiprev);		/* iop3xx, ixp4xx, ... */		return -ENODEV;	}	irq = platform_get_irq(pdev, 0);	if (irq < 0)		return -ENODEV;#ifdef	CONFIG_ARCH_PXA	dev->clk = clk_get(&pdev->dev, "UDCCLK");	if (IS_ERR(dev->clk)) {		retval = PTR_ERR(dev->clk);		goto err_clk;	}#endif	pr_debug("%s: IRQ %d%s%s\n", driver_name, irq,		dev->has_cfr ? "" : " (!cfr)",		SIZE_STR "(pio)"		);	/* other non-static parts of init */	dev->dev = &pdev->dev;	dev->mach = pdev->dev.platform_data;	if (dev->mach->gpio_vbus) {		if ((retval = gpio_request(dev->mach->gpio_vbus,				"pxa2xx_udc GPIO VBUS"))) {			dev_dbg(&pdev->dev,				"can't get vbus gpio %d, err: %d\n",				dev->mach->gpio_vbus, retval);			goto err_gpio_vbus;		}		gpio_direction_input(dev->mach->gpio_vbus);		vbus_irq = gpio_to_irq(dev->mach->gpio_vbus);	} else		vbus_irq = 0;	if (dev->mach->gpio_pullup) {		if ((retval = gpio_request(dev->mach->gpio_pullup,				"pca2xx_udc GPIO PULLUP"))) {			dev_dbg(&pdev->dev,				"can't get pullup gpio %d, err: %d\n",				dev->mach->gpio_pullup, retval);			goto err_gpio_pullup;		}		gpio_direction_output(dev->mach->gpio_pullup, 0);	}	init_timer(&dev->timer);	dev->timer.function = udc_watchdog;	dev->timer.data = (unsigned long) dev;	device_initialize(&dev->gadget.dev);	dev->gadget.dev.parent = &pdev->dev;	dev->gadget.dev.dma_mask = pdev->dev.dma_mask;	the_controller = dev;	platform_set_drvdata(pdev, dev);	udc_disable(dev);	udc_reinit(dev);	dev->vbus = is_vbus_present();	/* irq setup after old hardware state is cleaned up */	retval = request_irq(irq, pxa2xx_udc_irq,			IRQF_DISABLED, driver_name, dev);	if (retval != 0) {		printk(KERN_ERR "%s: can't get irq %d, err %d\n",			driver_name, irq, retval);		goto err_irq1;	}	dev->got_irq = 1;#ifdef CONFIG_ARCH_LUBBOCK	if (machine_is_lubbock()) {		retval = request_irq(LUBBOCK_USB_DISC_IRQ,				lubbock_vbus_irq,				IRQF_DISABLED | IRQF_SAMPLE_RANDOM,				driver_name, dev);		if (retval != 0) {			printk(KERN_ERR "%s: can't get irq %i, err %d\n",				driver_name, LUBBOCK_USB_DISC_IRQ, retval);lubbock_fail0:			goto err_irq_lub;		}		retval = request_irq(LUBBOCK_USB_IRQ,				lubbock_vbus_irq,				IRQF_DISABLED | IRQF_SAMPLE_RANDOM,				driver_name, dev);		if (retval != 0) {			printk(KERN_ERR "%s: can't get irq %i, err %d\n",				driver_name, LUBBOCK_USB_IRQ, retval);			free_irq(LUBBOCK_USB_DISC_IRQ, dev);			goto lubbock_fail0;		}	} else#endif	if (vbus_irq) {		retval = request_irq(vbus_irq, udc_vbus_irq,				IRQF_DISABLED | IRQF_SAMPLE_RANDOM |				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,				driver_name, dev);		if (retval != 0) {			printk(KERN_ERR "%s: can't get irq %i, err %d\n",				driver_name, vbus_irq, retval);			goto err_vbus_irq;		}	}	create_proc_files();	return 0; err_vbus_irq:#ifdef	CONFIG_ARCH_LUBBOCK	free_irq(LUBBOCK_USB_DISC_IRQ, dev); err_irq_lub:#endif	free_irq(irq, dev); err_irq1:	if (dev->mach->gpio_pullup)		gpio_free(dev->mach->gpio_pullup); err_gpio_pullup:	if (dev->mach->gpio_vbus)		gpio_free(dev->mach->gpio_vbus); err_gpio_vbus:#ifdef	CONFIG_ARCH_PXA	clk_put(dev->clk); err_clk:#endif	return retval;}static void pxa2xx_udc_shutdown(struct platform_device *_dev){	pullup_off();}static int __exit pxa2xx_udc_remove(struct platform_device *pdev){	struct pxa2xx_udc *dev = platform_get_drvdata(pdev);	if (dev->driver)		return -EBUSY;	udc_disable(dev);	remove_proc_files();	if (dev->got_irq) {		free_irq(platform_get_irq(pdev, 0), dev);		dev->got_irq = 0;	}#ifdef CONFIG_ARCH_LUBBOCK	if (machine_is_lubbock()) {		free_irq(LUBBOCK_USB_DISC_IRQ, dev);		free_irq(LUBBOCK_USB_IRQ, dev);	}#endif	if (dev->mach->gpio_vbus) {		free_irq(gpio_to_irq(dev->mach->gpio_vbus), dev);		gpio_free(dev->mach->gpio_vbus);	}	if (dev->mach->gpio_pullup)		gpio_free(dev->mach->gpio_pullup);#ifdef	CONFIG_ARCH_PXA	clk_put(dev->clk);#endif	platform_set_drvdata(pdev, NULL);	the_controller = NULL;	return 0;}/*-------------------------------------------------------------------------*/#ifdef	CONFIG_PM/* USB suspend (controlled by the host) and system suspend (controlled * by the PXA) don't necessarily work well together.  If USB is active, * the 48 MHz clock is required; so the system can't enter 33 MHz idle * mode, or any deeper PM saving state. * * For now, we punt and forcibly disconnect from the USB host when PXA * enters any suspend state.  While we're disconnected, we always disable * the 48MHz USB clock ... allowing PXA sleep and/or 33 MHz idle states. * Boards without software pullup control shouldn't use those states. * VBUS IRQs should probably be ignored so that the PXA device just acts * "dead" to USB hosts until system resume. */static int pxa2xx_udc_suspend(struct platform_device *dev, pm_message_t state){	struct pxa2xx_udc	*udc = platform_get_drvdata(dev);	if (!udc->mach->gpio_pullup && !udc->mach->udc_command)		WARN("USB host won't detect disconnect!\n");	pullup(udc, 0);	return 0;}static int pxa2xx_udc_resume(struct platform_device *dev){	struct pxa2xx_udc	*udc = platform_get_drvdata(dev);	pullup(udc, 1);	return 0;}#else#define	pxa2xx_udc_suspend	NULL#define	pxa2xx_udc_resume	NULL#endif/*-------------------------------------------------------------------------*/static struct platform_driver udc_driver = {	.shutdown	= pxa2xx_udc_shutdown,	.remove		= __exit_p(pxa2xx_udc_remove),	.suspend	= pxa2xx_udc_suspend,	.resume		= pxa2xx_udc_resume,	.driver		= {		.owner	= THIS_MODULE,		.name	= "pxa2xx-udc",	},};static int __init udc_init(void){	printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);	return platform_driver_probe(&udc_driver, pxa2xx_udc_probe);}module_init(udc_init);static void __exit udc_exit(void){	platform_driver_unregister(&udc_driver);}module_exit(udc_exit);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_AUTHOR("Frank Becker, Robert Schwebel, David Brownell");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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