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

📄 s3c2410_udc.c

📁 s3c2410 usb device controller 的驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
	spin_lock_irqsave (&udc->lock, flags);	list_for_each_entry (req, &ep->queue, queue) {		if (&req->req == _req) {			list_del_init (&req->queue);			_req->status = -ECONNRESET;			retval = 0;			break;		}	}	spin_unlock_irqrestore (&udc->lock, flags);	if (retval == 0) {		dprintk( "dequeued req %p from %s, len %d buf %p\n",				req, _ep->name, _req->length, _req->buf);		_req->complete (_ep, _req);	}	return retval;}static ints3c2410_set_halt (struct usb_ep *_ep, int value){	struct s3c2410_ep	*ep;    	printk("s3c2410_set_halt(ep=%p)\n", _ep);	if (!_ep)		return -EINVAL;	if (!the_controller->driver)		return -ESHUTDOWN;	ep = container_of (_ep, struct s3c2410_ep, ep);	if (!value)		ep->halted = 0;	else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&			!list_empty (&ep->queue))		return -EAGAIN;	else		ep->halted = 1;	/* FIXME clear emulated data toggle too */	return 0;}static const struct usb_ep_ops s3c2410_ep_ops = {	.enable		= s3c2410_enable,	.disable	= s3c2410_disable,	.alloc_request	= s3c2410_alloc_request,	.free_request	= s3c2410_free_request,	.alloc_buffer	= s3c2410_alloc_buffer,	.free_buffer	= s3c2410_free_buffer,	/* map, unmap, ... eventually hook the "generic" dma calls */	.queue		= s3c2410_queue,	.dequeue	= s3c2410_dequeue,	.set_halt	= s3c2410_set_halt,};/*-------------------------------------------------------------------------*//* there are both host and device side versions of this call ... */static int s3c2410_g_get_frame (struct usb_gadget *_gadget){	struct timeval	tv;    	printk("s3c2410_g_get_frame()\n");	do_gettimeofday (&tv);	return tv.tv_usec / 1000;}static int s3c2410_wakeup (struct usb_gadget *_gadget){	struct s3c2410_udc  *udc;    	printk("s3c2410_wakeup()\n");		udc = container_of (_gadget, struct s3c2410_udc, gadget);	// udc->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND);	return 0;}static int s3c2410_set_selfpowered (struct usb_gadget *_gadget, int value){	struct s3c2410_udc  *udc;    	printk("s3c2410_set_selfpowered()\n");	udc = container_of (_gadget, struct s3c2410_udc, gadget);	if (value)		udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED);	else		udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);	return 0;}static void nop_release (struct device *dev){	dprintk("%s %s\n", __FUNCTION__, dev->bus_id);}static const struct usb_gadget_ops s3c2410_ops = {	.get_frame	    = s3c2410_g_get_frame,	.wakeup		    = s3c2410_wakeup,	.set_selfpowered    = s3c2410_set_selfpowered,};/*-------------------------------------------------------------------------*//* "function" sysfs attribute */static ssize_tshow_function (struct device *_dev, char *buf){	struct s3c2410_udc *udc = the_controller;    	printk("s3c2410_show_function(dev=%p)\n", _dev);	if (!udc->driver->function		|| strlen (udc->driver->function) > PAGE_SIZE)		return 0;	return snprintf (buf, PAGE_SIZE, "%s\n", udc->driver->function);}DEVICE_ATTR (function, S_IRUGO, show_function, NULL);/*-------------------------------------------------------------------------*//* * Driver registration/unregistration. * * This is basically hardware-specific; there's usually only one real USB * device (not host) controller since that's how USB devices are intended * to work.  So most implementations of these api calls will rely on the * fact that only one driver will ever bind to the hardware.  But curious * hardware can be built with discrete components, so the gadget API doesn't * require that assumption. *//* caller must hold lock */static voidstop_activity (struct s3c2410_udc *udc, struct usb_gadget_driver *driver){	struct s3c2410_ep *ep;    	printk("stop_activity()\n");	/* prevent any more requests */	udc->address = 0;	/* The timer is left running so that outstanding URBs can fail */	/* nuke any pending requests first, so driver i/o is quiesced */	list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list)		nuke (udc, ep);	/* driver now does any non-usb quiescing necessary */	if (driver) {		spin_unlock (&udc->lock);		driver->disconnect (&udc->gadget);		spin_lock (&udc->lock);	}}intusb_gadget_register_driver (struct usb_gadget_driver *driver){	struct s3c2410_udc *udc = the_controller;	int		retval, i;    	printk("usb_gadget_register_driver() '%s'\n",		driver->driver.name);	if (!udc)		return -EINVAL;	if (udc->driver)		return -EBUSY;	if (!driver->bind || !driver->unbind || !driver->setup			|| driver->speed == USB_SPEED_UNKNOWN)		return -EINVAL;	udc->gadget.name = gadget_name;	udc->gadget.ops = &s3c2410_ops;	udc->gadget.is_dualspeed = 1;	udc->gadget.dev.release = nop_release;	udc->devstatus = 0;	INIT_LIST_HEAD (&udc->gadget.ep_list);	for (i = 0; i < S3C2410_ENDPOINTS; i++) {		struct s3c2410_ep *ep = &udc->ep[i];		if (!ep_name[i])			break;		ep->ep.name = ep_name[i];		ep->ep.ops = &s3c2410_ep_ops;		list_add_tail (&ep->ep.ep_list, &udc->gadget.ep_list);		ep->halted = ep->already_seen = ep->setup_stage = 0;		ep->ep.maxpacket = ~0;		ep->last_io = jiffies;		ep->gadget = &udc->gadget;		ep->dev = udc;		ep->desc = 0;		INIT_LIST_HEAD (&ep->queue);	}	udc->gadget.ep0 = &udc->ep[0].ep;	udc->ep[0].ep.maxpacket = 16;	list_del_init (&udc->ep[0].ep.ep_list);	INIT_LIST_HEAD(&udc->fifo_req.queue);	udc->driver = driver;	udc->gadget.dev.driver = &driver->driver;	dprintk( "binding gadget driver '%s'\n", driver->driver.name);	if ((retval = driver->bind (&udc->gadget)) != 0) {		udc->driver = 0;		udc->gadget.dev.driver = 0;		return retval;	}        driver->driver.bus = 0;        udc->driver = driver;        udc->gadget.dev.driver = &driver->driver;/*	driver_register (&driver->driver);	device_bind_driver (&udc->gadget.dev);*/        retval = driver->bind(&udc->gadget);        if (retval) {                dprintk("bind to driver %s --> error %d\n",			driver->driver.name, retval);                udc->driver = 0;                udc->gadget.dev.driver = 0;                return retval;        }#if 0	/* khubd will enumerate this in a while */	udc->port_status |= USB_PORT_STAT_CONNECTION		| (1 << USB_PORT_FEAT_C_CONNECTION);#endif	return 0;}EXPORT_SYMBOL (usb_gadget_register_driver);intusb_gadget_unregister_driver (struct usb_gadget_driver *driver){	struct s3c2410_udc *udc = the_controller;	unsigned long	flags;	if (!udc)		return -ENODEV;	if (!driver || driver != udc->driver)		return -EINVAL;    	printk("usb_gadget_register_driver() '%s'\n",		driver->driver.name);	spin_lock_irqsave (&udc->lock, flags);	stop_activity (udc, driver);/*	udc->port_status &= ~USB_PORT_STAT_CONNECTION;	udc->port_status |= (1 << USB_PORT_FEAT_C_CONNECTION);*/	spin_unlock_irqrestore (&udc->lock, flags);	driver->unbind (&udc->gadget);	udc->driver = 0;	device_release_driver (&udc->gadget.dev);	driver_unregister (&driver->driver);	return 0;}EXPORT_SYMBOL (usb_gadget_unregister_driver);#undef is_enabledint s3c2410_set_fifo_mode (struct usb_gadget *gadget, int mode){	return -ENOSYS;}EXPORT_SYMBOL (s3c2410_set_fifo_mode);/*-------------------------------------------------------------------------*//*-------------------------------------------------------------------------*/#define EP0_FIFO_SIZE	16#define BULK_FIFO_SIZE	64static struct s3c2410_udc memory;static inline void clear_ep_state (struct s3c2410_udc *dev){	unsigned i;	/* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint	 * fifos, and pending transactions mustn't be continued in any case.	 */	for (i = 1; i < 5; i++)		nuke(dev, &dev->ep[i]);}enum ep0_state {         EP0_IDLE,        EP0_IN_DATA_PHASE,        EP0_OUT_DATA_PHASE,        EP0_END_XFER,        EP0_STALL,};static inline void ep0_idle (struct s3c2410_udc *dev){	dev->ep0state = EP0_IDLE;}static inline int windex_to_ep_num( __u16 w ) {     	return (int) ( w & 0x000F); }static inline void udc_change_index(int index, int *backup){    	if (backup)	    	*backup = __raw_readl(S3C2410_UDC_INDEX_REG);	if ((index >= 0) && (index <= 5))	    	__raw_writel(index, S3C2410_UDC_INDEX_REG);}static inline int fifo_count_out(void){	int tmp;      	tmp = __raw_readl(S3C2410_UDC_OUT_FIFO_CNT2_REG) << 8;      	tmp |= __raw_readl(S3C2410_UDC_OUT_FIFO_CNT1_REG);	return tmp & 0xffff;}static inline void out_pkt_ack(int last){      	__raw_writel(S3C2410_UDC_EP0_CSR_SOPKTRDY |	    	(last)?S3C2410_UDC_EP0_CSR_DE:0, 		S3C2410_UDC_EP0_CSR_REG);}/* * read_fifo_crq() * Read 1-8 bytes out of EP0 FIFO and put in request. * Called to do the initial read of setup requests * from the host. Return number of bytes read. * * Like write fifo above, this driver uses multiple * reads checked agains the count register with an * overall timeout. * */static intread_fifo_crq(struct usb_ctrlrequest *crq){	int bytes_read = 0;	int fifo_count = 0;	int i; // , ep;	unsigned char *pOut = (unsigned char*)crq;           	udc_change_index(0, NULL);		fifo_count = fifo_count_out();	BUG_ON( fifo_count > 8 );	dprintk("read_fifo_crq(): fifo_count=%d\n", fifo_count );	while( fifo_count-- ) {		i = 0;		do {			*pOut = (unsigned char) 				__raw_readl(S3C2410_UDC_EP0_FIFO_REG); 		  	udelay( 10 );  			i++;					} while((fifo_count_out() != fifo_count) && (i < 10));		if ( i == 10 ) {			printk("read_fifo(): read failure\n");			// usbd_info.stats.ep0_fifo_read_failures++;		}		pOut++;		bytes_read++;	}	dprintk("read_fifo_crq(): len=%d %02x:%02x {%x,%x,%x}\n", 	    	bytes_read, crq->bRequest, crq->bRequestType, 		crq->wValue, crq->wIndex, crq->wLength);	// usbd_info.stats.ep0_bytes_read++;	return bytes_read;}static void handle_ep0(struct s3c2410_udc *dev){	u32			ep0csr;	struct s3c2410_ep	*ep = &dev->ep [0];	struct s3c2410_request	*req;	struct usb_ctrlrequest	crq;	if (list_empty(&ep->queue))    		req = 0;	else		req = list_entry(ep->queue.next, struct s3c2410_request, queue);  	S3C2410_UDC_SETIX(EP0);	ep0csr = __raw_readl(S3C2410_UDC_IN_CSR1_REG);	/* clear stall status */	if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) {		nuke(dev, ep);	    	clear_ep0_sst;/*		del_timer(&dev->timer);*/		ep0_idle(dev);	}	if (ep0csr & S3C2410_UDC_EP0_CSR_SE	    	&& dev->ep0state != EP0_IDLE) {	    	clear_ep0_se;/*		del_timer(&dev->timer);*/		ep0_idle(dev);	}	switch (dev->ep0state) {	case EP0_IDLE:		/* start control request? */		if (ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) {			int len, ret, tmp;			

⌨️ 快捷键说明

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