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

📄 n9604.c

📁 LINUX2.4.18内核下的usb GADGET驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
		if (&req->req == _req)			break;	}	if (&req->req != _req) {		spin_unlock_irqrestore (&dev->lock, flags);		return -EINVAL;	}	spin_unlock_irqrestore(&dev->lock, flags);	return req ? 0 : -EOPNOTSUPP;}static int n9604_clear_halt(struct usb_ep *_ep) {	struct n9604_ep *ep;	ep = container_of (_ep, struct n9604_ep, ep);	write_9604(read_9604(ep->control) & ~EPC_STALL, ep->control);	pio_advance(ep);	return 0;}static int n9604_set_halt(struct usb_ep *_ep, int value) {	struct n9604_ep *ep;	unsigned long   flags;	int             retval = 0;	if (!_ep) {		retval = -ENODEV; goto exit;	}	ep = container_of (_ep, struct n9604_ep, ep);	if (ep->num == 0) {//is this valid?		if (!value) {			 retval = -EINVAL; goto exit; }	/* don't change EPxSTATUS_EP_INVALID to READY */	} else if (!ep->desc) {		retval = -EINVAL; goto exit;	}	spin_lock_irqsave(&ep->dev->lock, flags);	if (!list_empty(&ep->queue))		retval = -EAGAIN;	else if (!value)		n9604_clear_halt(_ep);	else {		write_9604(read_9604(ep->control) | EPC_STALL, ep->control);	}	spin_unlock_irqrestore(&ep->dev->lock, flags);exit:	return retval;}static int n9604_fifo_status(struct usb_ep *_ep) {//not implemented	return -1;}static void n9604_fifo_flush(struct usb_ep *_ep) {//not implemented	struct n9604_ep *ep;	ep = container_of (_ep, struct n9604_ep, ep);}/*-------------------------------------------------------------------------*/static struct usb_ep_ops n9604_ep_ops = {	.enable         = n9604_ep_enable,	.disable        = n9604_ep_disable,	.alloc_request  = n9604_alloc_request,//io request objects called struct usb_request	.free_request   = n9604_free_request,	.alloc_buffer   = n9604_alloc_buffer,	.free_buffer    = n9604_free_buffer,	.queue          = n9604_queue,//submit a struct usb_request object to an endpoint	.dequeue        = n9604_dequeue,	.set_halt       = n9604_set_halt,//halts an endpoint	.fifo_status    = n9604_fifo_status,//bytes in FIFO + data ready to go in FIFO	.fifo_flush     = n9604_fifo_flush,//flush all the data, endpoint is probably been reconfigured};/*-------------------------------------------------------------------------*/static int n9604_get_frame(struct usb_gadget *_gadget){	return -EOPNOTSUPP;}static const struct usb_gadget_ops n9604_ops = {	.get_frame	= n9604_get_frame,};/*-------------------------------------------------------------------------*/static void udc_reinit (struct n9604_udc *dev){	static char *names [] = { "ep0", "ep1in", "ep2out", "ep3in", "ep4out", "ep5in", "ep6out" };	unsigned i;	INIT_LIST_HEAD (&dev->gadget.ep_list);	dev->gadget.ep0 = &dev->ep [0].ep;	dev->gadget.speed = USB_SPEED_UNKNOWN;	dev->irqs = 0;	dev->configured = 0;	//for (i = 0; i < 7; i++) {	for (i = 0; i < ARRAY_SIZE(names); i++) {		struct n9604_ep	*ep = &dev->ep[i];		ep->num = i;		ep->numActual = i; 		ep->ep.name = names[i];		ep->irqs = 0;		if (i) {			ep->fifo = (i * 4) + RXD0;	//each FIFO address is 4 bytes away.  TXD0 is the first			ep->control = ep->fifo - 1;			ep->status = ep->fifo + 1;			ep->command = ep->fifo + 2;			Flush(ep->command);//flush any data in the fifo//we don't care about the previous state			read_9604(ep->status);			ep->ep.maxpacket = MAX_FIFO_SIZE;		} else {//were are endpoint 0			ep->fifo = ep->control = ep->status = ep->command = 0xff;//this should force an error										//we need to do this since we don't know if 										//this is tx or rx			read_9604(TXS0);			Flush(TXC0);			Flush(RXC0);//we could potentially (probably) overwriting a pending setup packet			if (ep->stage)//if we get a setup packet before we have a chance to finish the reset we have a problem				read_9604(RXS0);//fix this by sending stalls or something			ep->stage = 0;			ep->ep.maxpacket = MAX_EP0_SIZE;		}		ep->is_in = i % 2;		ep->fifoNum = (i + ep->is_in) / 2;//ignored for endpoint 0		ep->ep.ops = &n9604_ep_ops;		list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);		ep->dev = dev;		INIT_LIST_HEAD (&ep->queue);		ep->nuking=0;		ep->queue_reqs = 0;		ep->queue_active = 0;		ep->packets = 0;		ep->desc = 0;		ep->irqs = 0;	}	list_del_init (&dev->ep[0].ep.ep_list);	write_9604(~WKUP_PNDUSB & ~WKUP_PNDUC & read_9604(WKUP), WKUP);//clear the bits, we've done a reset	write_9604(FAR_AD_EN, FAR);//enable the chip to answer requests//address 0	dev->address = 0;	write_9604(0, EPC0);//clear the control register	write_9604(NFSR_NodeOperational, NFSR);//we're going for gold}static void udc_reset(struct n9604_udc *dev){	//USBD_DISABLE_IRQ; This disables all interrupts sharing that line	write_9604(MCNTRL_SRST,MCNTRL);//software reset -- this also prevents pullup	write_9604(0x00, MAMSK); //disable interrupts}static void udc_enable(struct n9604_udc *dev){	udc_reset(dev); //this is to prevent a pullup resistor	udc_reinit (dev);	dev->gadget.speed = USB_SPEED_FULL;	// enable ep0 interrupts	dev->ep[0].is_in = 0;		write_9604(MAMSK_WARN | MAMSK_ALT | MAMSK_TX_EV | MAMSK_RX_EV | MAMSK_INTR, MAMSK);//for now we turn it all on, except frames & ULD & NAK	write_9604(ALTMSK_RESET, ALTMSK);//just turn on reset	write_9604(0x11, TXMSK);	write_9604(0x11, RXMSK);	write_9604(0x0, NAKMSK);	write_9604(0x0, FWMSK);	write_9604(MCNTRL_NAT | MCNTRL_INTOC_ActHigh, MCNTRL);//this activates the pull-up and turns on interrupts	USBD_ENABLE_IRQ;}/*-------------------------------------------------------------------------*//* keeping it simple: * - one bus driver, initted first; * - one function driver, initted second */static struct n9604_udc        *the_controller;/* when a driver is successfully registered, it will receive * control requests including set_configuration(), which enables * non-control requests.  then usb traffic follows until a * disconnect is reported.  then a host may connect again, or * the driver might get unbound. */int usb_gadget_register_driver(struct usb_gadget_driver *driver){	struct n9604_udc	*dev = the_controller;	int			retval;	if (!driver			|| driver->speed != USB_SPEED_FULL			|| !driver->bind			|| !driver->unbind			|| !driver->disconnect			|| !driver->setup)		return -EINVAL;	if (!dev)		return -ENODEV;	if (dev->driver)		return -EBUSY;	/* hook up the driver */	dev->driver = driver;	retval = driver->bind(&dev->gadget);	if (retval) {		dev->driver = 0;		return retval;	}	/* then enable host detection and ep0; and we're ready	 * for set_configuration as well as eventual disconnect.	 */	udc_enable(dev);	return 0;}EXPORT_SYMBOL(usb_gadget_register_driver);int usb_gadget_unregister_driver(struct usb_gadget_driver *driver){	struct n9604_udc	*dev = the_controller;	unsigned long	flags;	int i;	if (!dev)		return -ENODEV;	if (!driver || driver != dev->driver)		return -EINVAL;	spin_lock_irqsave(&dev->lock, flags);	dev->driver = 0;		udc_reset(dev);//reset & diable irqs	for (i = 0; i < ARRAY_SIZE(dev->ep); i++)		nuke(&dev->ep [i], -ESHUTDOWN);	spin_unlock_irqrestore(&dev->lock, flags);	if (dev->gadget.speed != USB_SPEED_UNKNOWN)		driver->disconnect(&dev->gadget);	driver->unbind(&dev->gadget);	return 0;}EXPORT_SYMBOL(usb_gadget_unregister_driver);/*-------------------------------------------------------------------------*/inline u8 tx_ev_irq(struct n9604_udc *dev) {	u8      mask;	mask = read_9604(TXEV) & read_9604(TXMSK);	if (mask & TXEV_FIFO0) {		write_9604(0, EPC0);//make sure we are not stalled, & not using the default address		read_9604(TXS0);//should really check for error conditions		dev->ep[0].irqs++;		pio_advance(&dev->ep[0]);	}	if (mask & TXEV_FIFO1) {		read_9604(TXS1);		dev->ep[1].irqs++;		pio_advance(&dev->ep[1]);	}	if (mask & TXEV_FIFO2) {		read_9604(TXS2);		dev->ep[3].irqs++;		pio_advance(&dev->ep[3]);	}	if (mask & TXEV_FIFO3) {		read_9604(TXS3);		dev->ep[5].irqs++;		pio_advance(&dev->ep[5]);	}	return mask;}static void my_req_complete(struct usb_ep *_ep, struct usb_request *req) {//this was for the setup packet, but I guess I could use it for anything	n9604_free_buffer(_ep, req->buf, req->dma, req->length);	n9604_free_request(_ep, req);}inline void send_dummy_packet(int endpoint, struct n9604_udc *dev, int length) {	struct usb_request *my_req;	my_req = n9604_alloc_request(&dev->ep[endpoint].ep, GFP_ATOMIC);	my_req->length = length;	my_req->buf = n9604_alloc_buffer(&dev->ep[endpoint].ep, length, &my_req->dma, GFP_ATOMIC);	my_req->complete = my_req_complete;	n9604_queue(&dev->ep[endpoint].ep, my_req, GFP_ATOMIC);}inline void send_zero_length(int endpoint, struct n9604_udc *dev) {	send_dummy_packet(endpoint, dev, 0);}inline void rx_ev_irq(struct n9604_udc *dev) {	u8	mask;	struct n9604_ep *ep;	mask = read_9604(RXEV) & read_9604(RXMSK);	if (mask & RXEV_FIFO0) {		static int read_mode = 0;		u8 rxs_mask = read_9604(RXS0);		ep = &dev->ep[0];		ep->irqs++;		if (rxs_mask & RXS_SETUP) {			struct usb_ctrlrequest ctrl;			ep->packets++;			write_9604(0x40, ALTMSK);//someone is talking to us.  Make sure we can be reset if we lose this communication			ep->stage = 1;			rxs_mask = read_9604(RXS0);//2nd read (1st one is for zero length packet)			ctrl.bRequestType = read_9604(RXD0);			ctrl.bRequest = read_9604(RXD0);			ctrl.wValue = read_9604(RXD0) + (read_9604(RXD0) << 8);			ctrl.wIndex = read_9604(RXD0) + (read_9604(RXD0) << 8);			ctrl.wLength = read_9604(RXD0) + (read_9604(RXD0) << 8);			ep->toggle = 1;			request_voodoo = ctrl.wLength;			if (ctrl.bRequestType & 0x80) {//This is an IN transaction				ep->is_in = 1;//David: is this correct for both cases//check with n9604_queue				read_mode = 0;				if (ctrl.wLength) {//should be followed by ZLP out packet				} else {//host expects ZLP out packet					ep->stage = 2;				}			} else {//This is an out transaction				if (ctrl.wLength) {					ep->is_in = 0;					read_mode = 1;				} else {//host expects ZLP in packet					read_mode = 0;					ep->stage = 2;					ep->is_in = 1;				}			}			switch (ctrl.bRequest) {				case USB_REQ_SET_ADDRESS:					write_9604(EPC_DEF, EPC0);//we still want to respond to the default address					write_9604(((dev->address = (ctrl.wValue & FAR_AD_MASK))) | FAR_AD_EN, FAR);					send_zero_length(0, dev);					dev->configured = 1;//we can send longer packets now :)					read_9604(ALTEV);					write_9604(ALTMSK_RESET, ALTMSK);//we also listen to reset requests too					break;				case USB_REQ_CLEAR_FEATURE:					if (ctrl.wValue == 0 && ctrl.bRequestType == 2) {//endpoint halt						int i;						for (i = 0; i < ARRAY_SIZE(dev->ep); i++) 							if ((ctrl.wIndex & 0xF) == dev->ep[i].numActual)								n9604_clear_halt(&dev->ep[i].ep);						send_zero_length(0, dev);						break;					}				case USB_REQ_SET_DESCRIPTOR:				case USB_REQ_SYNCH_FRAME:				case USB_REQ_GET_STATUS:				case USB_REQ_SET_FEATURE:				case USB_REQ_SET_CONFIGURATION:				case USB_REQ_GET_DESCRIPTOR:				case USB_REQ_GET_CONFIGURATION:				case USB_REQ_SET_INTERFACE:				case USB_REQ_GET_INTERFACE:				default:					if (dev->driver->setup(&dev->gadget, &ctrl) < 0)//there was an error						if (((ctrl.bRequestType & 0x80) && ctrl.wLength) || (!(ctrl.bRequestType & 0x80) && !ctrl.wLength))							send_zero_length(0, dev);			}//crtl.bRequest		}//setup		else if (read_mode)			pio_advance(ep);		else {			ep->stage = 0;			ep->packets++;		}	}//fifo 0	if (mask & RXEV_FIFO1) {		ep = &dev->ep[2];		pio_advance(ep);		ep->irqs++;	}	if (mask & RXEV_FIFO2) {		ep = &dev->ep[4];		pio_advance(ep);		ep->irqs++;	}	if (mask & RXEV_FIFO3) {		ep = &dev->ep[6];		pio_advance(ep);		ep->irqs++;	}}inline void alt_ev_irq(struct n9604_udc *dev) {	u8      mask;	mask = read_9604(ALTEV) & read_9604(ALTMSK);	if (mask & ALTEV_EOP);	if (mask & ALTEV_SD3);	if (mask & ALTEV_SD5);	if (mask & ALTEV_RESET) {		int i;		udelay(1200);//no idea why this is needed, but it makes things work		write_9604(0x0, FAR);//lets not respond to any packets until we are ready		write_9604(NFSR_NodeReset, NFSR);		dev->driver->disconnect(&dev->gadget);		for (i = 0; i < ARRAY_SIZE(dev->ep); i++)			nuke(&dev->ep [i], -ESHUTDOWN);//this should be handled above by disconnect		write_9604(0x00, ALTMSK);//make sure reset is turned off, or we will constantly be interrupted		write_9604(0x11, TXMSK);		write_9604(0x11, RXMSK);		udc_reinit(dev);		dev->gadget.speed = USB_SPEED_FULL;		dev->ep[0].is_in = 0;	}	if (mask & ALTEV_RESUME); //write_9604(NFSR_NodeOperational, NFSR);	if (mask & ALTEV_WKUP);//we don't really sleep	if (mask & ALTEV_DMA);}static void n9604_irq(int irq, void *_dev, struct pt_regs *r) {	struct n9604_udc         *dev = _dev;	u8			mask;	mask = read_9604(MAEV) & read_9604(MAMSK);	if (!mask)		return;	if (mask & MAEV_ALT) {		alt_ev_irq(dev);		mask = read_9604(MAEV) & read_9604(MAMSK);//force a re-read of the current pending interrupts	}	if (mask & MAEV_TX_EV)		tx_ev_irq(dev);	if (mask & MAEV_RX_EV)		rx_ev_irq(dev);	dev->irqs++;	return;}/*-------------------------------------------------------------------------*/static int __init init (void){	struct n9604_udc	*dev;	int ret;	u8 * addr;	if (the_controller) 		return -EBUSY;	addr = ioremap(USBN9604_PHYS, 0x2);//ioremap will bump this to 1 page size	if (!addr) {		ERROR(dev, KERN_ERR "Unable to remap address\n");		return -EINVAL;	}	USBN9604_Offset = addr;		if ((read_9604(RID) & 0xF) != 0x2) { //0x2 is the identifier for 9603/4		iounmap(addr);		return -ENODEV;	}		/* alloc, and start init */	dev = kmalloc(sizeof *dev, SLAB_KERNEL);	if (dev == NULL){		WARN(dev, "No memory");		iounmap(addr);		return -ENOMEM;	}	memset(dev, 0, sizeof *dev);	spin_lock_init(&dev->lock);	dev->gadget.ops = &n9604_ops;	dev->gadget.is_dualspeed = 0;	/* the "gadget" abstracts/virtualizes the controller */	dev->gadget.dev.bus_id = "gadget";	dev->gadget.name = driver_name;	/* initialize the hardware */	udc_reset(dev);	write_9604(CCONF_CODIS | 11, CCONF);	udc_reinit(dev);//this is necessary as it sets up the epx functions		the_controller = dev;	if ((ret=request_irq(IRQ_GPIOC, n9604_irq, SA_SHIRQ, driver_name,dev))) {		WARN(dev, "Can't get IRQ\n");		iounmap(addr);		return ret;	}	return 0;}module_init (init);static void __exit cleanup (void){	struct n9604_udc	*dev = the_controller;	//first kill the interrupts	udc_reset(dev);	free_irq(IRQ_GPIOC, dev);		/* start with the driver above us */	if (dev->driver) {		/* should have been done already by driver model core */		WARN(dev, "Warning: Driver '%s' is still registered\n",				dev->driver->driver.name);		usb_gadget_unregister_driver(dev->driver);	}	kfree(dev);	iounmap(USBN9604_Offset);	the_controller = 0;}module_exit (cleanup);MODULE_PARM_DESC (delayTime, "Delays after reads and writes to the USB chip");MODULE_PARM (delayTime, "i");

⌨️ 快捷键说明

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