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

📄 s3c2410_udc.c

📁 s3c2410 usb device controller 的驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
			len = read_fifo_crq(&crq);			if (len != sizeof(crq)) {			  	dprintk("setup begin: fifo READ ERROR" 				    	" wanted %d bytes got %d. Stalling out...\n", 					sizeof(crq), len); 				set_ep0_ss;				return;			}/*			nuke (ep, -EPROTO);*/			/* cope with automagic for some standard requests. */			dev->req_std = (crq.bRequestType & USB_TYPE_MASK)						== USB_TYPE_STANDARD;			dev->req_config = 0;			dev->req_pending = 1;			switch (crq.bRequest) {			/* hardware restricts gadget drivers here! */			case USB_REQ_SET_CONFIGURATION:			    	dprintk("USB_REQ_SET_CONFIGURATION ... \n");				if (crq.bRequestType == USB_RECIP_DEVICE) {					/* reflect hardware's automagic					 * up to the gadget driver.					 */config_change:					dev->req_config = 1;					clear_ep_state(dev);					/* if !has_cfr, there's no synch					 * else use AREN (later) not SA|OPR					 * USIR0_IR0 acts edge sensitive					 */				}				break;			/* ... and here, even more ... */			case USB_REQ_SET_INTERFACE:			    	dprintk("USB_REQ_SET_INTERFACE ... \n");				if (crq.bRequestType == USB_RECIP_INTERFACE) {					/* udc hardware is broken by design:					 *  - altsetting may only be zero;					 *  - hw resets all interfaces' eps;					 *  - ep reset doesn't include halt(?).					 */					goto config_change;				}				break;			/* hardware was supposed to hide this */			case USB_REQ_SET_ADDRESS:			    	dprintk("USB_REQ_SET_ADDRESS ... \n");								tmp = crq.wValue & 0x7F;				__raw_writel((tmp | 0x80), S3C2410_UDC_FUNC_ADDR_REG);								// usbd_info.address = address;				// usbctl_next_state_on_event( kEvAddress );								out_pkt_ack(1);								if (crq.bRequestType == USB_RECIP_DEVICE) {					// ep0start(dev, 0, "address");					return;				}				break;			}			if (crq.bRequestType & USB_DIR_IN)				dev->ep0state = EP0_IN_DATA_PHASE;			else				dev->ep0state = EP0_OUT_DATA_PHASE;			ret = dev->driver->setup(&dev->gadget, &crq);			if (ret < 0) {				/* hardware automagic preventing STALL... */				if (dev->req_config) {					/* hardware sometimes neglects to tell					 * tell us about config change events,					 * so later ones may fail...					 */					dprintk("config change %02x fail %d?\n",						crq.bRequest, ret);					return;					/* TODO experiment:  if has_cfr,					 * hardware didn't ACK; maybe we					 * could actually STALL!					 */				}// stall:				/* the watchdog timer helps deal with cases				 * where udc seems to clear FST wrongly, and				 * then NAKs instead of STALLing.				 */				// ep0start(dev, UDCCS0_FST|UDCCS0_FTF, "stall");				// start_watchdog(dev);				dev->ep0state = EP0_STALL;			/* deferred i/o == no response yet */			} else if (dev->req_pending) {			    	dprintk("dev->req_pending... what now?\n");#if 0				if (likely(dev->ep0state == EP0_IN_DATA_PHASE						|| dev->req_std || crq.wLength))					ep0start(dev, 0, "defer");				else					ep0start(dev, UDCCS0_IPR, "defer/IPR");#endif			}			/* expect at least one data or status stage irq */			return;		}		break;	case EP0_IN_DATA_PHASE:			/* GET_DESCRIPTOR etc */	    	dprintk("EP0_IN_DATA_PHASE ... what now?\n");#if 0		if (udccs0 & UDCCS0_OPR) {			UDCCS0 = UDCCS0_OPR|UDCCS0_FTF;			if (req)				done(ep, req, 0);			ep0_idle(dev);		} else /* irq was IPR clearing */ {			if (req) {				/* this IN packet might finish the request */				(void) write_ep0_fifo(ep, req);			} /* else IN token before response was written */		}#endif		break;	case EP0_OUT_DATA_PHASE:		/* SET_DESCRIPTOR etc */	    	dprintk("EP0_OUT_DATA_PHASE ... what now?\n");#if 0		if (udccs0 & UDCCS0_OPR) {			if (req) {				/* this OUT packet might finish the request */				if (read_ep0_fifo(ep, req))					done(ep, req, 0);				/* else more OUT packets expected */			} /* else OUT token before read was issued */		} else /* irq was IPR clearing */ {			if (req)				done(ep, req, 0);			ep0_idle(dev);		}#endif		break;	case EP0_END_XFER:	    	dprintk("EP0_END_XFER ... what now?\n");#if 0		if (req)			done(ep, req, 0);		/* ack control-IN status (maybe in-zlp was skipped)		 * also appears after some config change events.		 */		if (udccs0 & UDCCS0_OPR)			UDCCS0 = UDCCS0_OPR;		ep0_idle(dev);#endif		break;	case EP0_STALL:	    	set_ep0_ss;		break;	}//	USIR0 = USIR0_IR0;}#if 0static void handle_ep(struct s3c2410_ep *ep){	struct s3c2410_request	*req;	int			is_in = ep->bEndpointAddress & USB_DIR_IN;	int			completed;	u32			udccs, tmp;	do {		completed = 0;		if (likely (!list_empty(&ep->queue)))			req = list_entry(ep->queue.next,					struct s3c2410_request, queue);		else			req = 0;		// TODO check FST handling		udccs = *ep->reg_udccs;		if (unlikely(is_in)) {	/* irq from TPC, SST, or (ISO) TUR */			tmp = UDCCS_BI_TUR;			if (likely(ep->bmAttributes == USB_ENDPOINT_XFER_BULK))				tmp |= UDCCS_BI_SST;			tmp &= udccs;			if (likely (tmp))				*ep->reg_udccs = tmp;			if (req && likely ((udccs & UDCCS_BI_TFS) != 0))				completed = write_fifo(ep, req);		} else {	/* irq from RPC (or for ISO, ROF) */			if (likely(ep->bmAttributes == USB_ENDPOINT_XFER_BULK))				tmp = UDCCS_BO_SST | UDCCS_BO_DME;			else				tmp = UDCCS_IO_ROF | UDCCS_IO_DME;			tmp &= udccs;			if (likely(tmp))				*ep->reg_udccs = tmp;			/* fifos can hold packets, ready for reading... */			if (likely(req)) {				completed = read_fifo(ep, req);			} else				pio_irq_disable (ep->bEndpointAddress);		}		ep->pio_irqs++;	} while (completed);}#endif/* *	s3c2410_udc_irq - interrupt handler * * avoid delays in ep0 processing. the control handshaking isn't always * under software control, and delays could cause usb protocol errors. */static irqreturn_ts3c2410_udc_irq(int irq, void *_dev, struct pt_regs *r){	struct s3c2410_udc	*dev = _dev;	// static int sb_debug_cnt = 1;		int handled;		dprintk("irq: %d ...\n", irq);	do {		// int saveIdx = __raw_readl(S3C2410_UDC_INDEX_REG);		int usb_status = __raw_readl(S3C2410_UDC_USB_INT_REG);		int usbd_status = __raw_readl(S3C2410_UDC_EP_INT_REG);			handled = 0;			dprintk("check usbs=0x%02x, usbds=0x%02x\n",			usb_status, usbd_status);						/* ReSeT Interrupt Request - USB reset */		if (usb_status & S3C2410_UDC_USBINT_RESET) {			dprintk("USB reset\n");			//			if( usbctl_next_state_on_event(kEvReset) != kError )			    			/* clear interrupt */			__raw_writel(S3C2410_UDC_USBINT_RESET,				S3C2410_UDC_USB_INT_REG);			dev->gadget.speed = USB_SPEED_FULL;			// memset(&dev->stats, 0, sizeof dev->stats);			/* driver and endpoints are still reset */			// enable_disconnect_irq();			handled = 1;		}		/* RESume Interrupt Request */		if (usb_status & S3C2410_UDC_USBINT_RESUME) {			dprintk("USB resume\n");						/* clear interrupt */			__raw_writel(S3C2410_UDC_USBINT_RESUME,				S3C2410_UDC_USB_INT_REG);			if (dev->gadget.speed != USB_SPEED_UNKNOWN				&& dev->driver				&& dev->driver->resume				/* && is_usb_connected() */)				dev->driver->resume(&dev->gadget);			handled = 1;		}		/* SUSpend Interrupt Request */		if (usb_status & S3C2410_UDC_USBINT_SUSPEND) {					dprintk("USB suspend\n");			/* clear interrupt */			__raw_writel(S3C2410_UDC_USBINT_SUSPEND,				S3C2410_UDC_USB_INT_REG);							// if (!is_usb_connected())				stop_activity(dev, dev->driver);			/* else */ if (dev->gadget.speed != USB_SPEED_UNKNOWN					&& dev->driver					&& dev->driver->suspend)				dev->driver->suspend(&dev->gadget);			ep0_idle (dev);			handled = 1;		}		/* EP interrupts */    	    	if (usbd_status) {  			int	i;  			/* control traffic */  			if (usbd_status & S3C2410_UDC_INT_EP0) {  				// dev->ep[0].pio_irqs++;   			      	dprintk("USB ep0 irq\n");  				handle_ep0(dev);    	    	    	    	// ep0_int_hndlr();				  				/* Clear the interrupt bit by setting it to 1 */  				__raw_writel(S3C2410_UDC_INT_EP0,  				      S3C2410_UDC_EP_INT_REG);  				handled = 1;  			}  			/* endpoint data transfers */  			for (i = 1; i < 5; i++) {  				u32 tmp = 1 << i;  				if (usbd_status & tmp) {  			      	    	dprintk("USB ep%d irq\n", i);					  					// handle_ep(&dev->ep[i]);   					/* Clear the interrupt bit by setting it to 1 */  					__raw_writel(tmp, S3C2410_UDC_EP_INT_REG);  					handled = 1;  				}  			}		}		// UD_INDEX= saveIdx; /* restore idx */	} while (handled);	dprintk("irq: %d done.\n\n", irq);		return IRQ_HANDLED;}/* *	probe - binds to the platform device */static int __init s3c2410_udc_probe(struct device *_dev){	struct s3c2410_udc *udc = &memory;	int retval; // , out_dma = 0;	dprintk("s3c2410_udc_probe\n");	/* other non-static parts of init *///	udc->dev = _dev;//	udc->mach = _dev->platform_data;/*	init_timer(&dev->timer);	dev->timer.function = udc_watchdog;	dev->timer.data = (unsigned long) dev;*/	device_initialize(&udc->gadget.dev);	udc->gadget.dev.parent = _dev;	udc->gadget.dev.dma_mask = _dev->dma_mask;	the_controller = udc;	dev_set_drvdata(_dev, udc);	// udc_disable(udc);	// udc_reinit(udc);	/* irq setup after old hardware state is cleaned up */	retval = request_irq(IRQ_USBD, s3c2410_udc_irq,		SA_INTERRUPT, gadget_name, udc);	if (retval != 0) {		printk(KERN_ERR "%s: can't get irq %i, err %d\n",			gadget_name, IRQ_USBD, retval);		return -EBUSY;	}	dprintk("%s: got irq %i\n", gadget_name, IRQ_USBD);	udc->got_irq = 1;//	create_proc_files();	return 0;}static int __exit s3c2410_udc_remove(struct device *_dev){	struct s3c2410_udc *udc = _dev->driver_data;	dprintk("s3c2410_udc_remove\n");//	udc_disable(udc);//	remove_proc_files();	usb_gadget_unregister_driver(udc->driver);	if (udc->got_irq) {		free_irq(IRQ_USBD, udc);		udc->got_irq = 0;	}	dev_set_drvdata(_dev, 0);	the_controller = 0;	return 0;}/*-------------------------------------------------------------------------*/static struct device_driver udc_driver = {	.name		= "s3c2410-udc",	.bus		= &platform_bus_type,	.probe		= s3c2410_udc_probe,	.remove		= __exit_p(s3c2410_udc_remove),	// FIXME power management support	// .suspend = ... disable UDC	// .resume = ... re-enable UDC};static int __init udc_init(void){	int tmp;		dprintk("%s: version %s\n", gadget_name, DRIVER_VERSION);		tmp = __raw_readl(S3C2410_CLKCON);	tmp &= ~S3C2410_CLKCON_USBD;	__raw_writel(tmp, S3C2410_CLKCON);	tmp = __raw_readl(S3C2410_MISCCR);	tmp &= ~S3C2410_MISCCR_USBHOST;	__raw_writel(tmp, S3C2410_MISCCR);		/* UPLLCON */	tmp = (0x78 << S3C2410_PLLCON_MDIVSHIFT)		| (0x02 << S3C2410_PLLCON_PDIVSHIFT)		| (0x03 << S3C2410_PLLCON_SDIVSHIFT);	__raw_writel(tmp, S3C2410_UPLLCON);		tmp = __raw_readl(S3C2410_CLKCON);	tmp |= S3C2410_CLKCON_USBD;	__raw_writel(tmp, S3C2410_CLKCON);	mdelay(10);		return driver_register(&udc_driver);}module_init(udc_init);static void __exit udc_exit(void){	driver_unregister(&udc_driver);}module_exit(udc_exit);MODULE_DESCRIPTION (DRIVER_DESC);MODULE_LICENSE ("GPL");

⌨️ 快捷键说明

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