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

📄 s3c2410_udc22222222.c

📁 2.4核linux的s3c2410-udc驱动代码!经过调试了!
💻 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 0

static 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_t
s3c2410_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_AUTHOR ("Herbert P鰐zl");
MODULE_LICENSE ("GPL");


⌨️ 快捷键说明

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