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

📄 goku_udc.c

📁 LINUX2.4.18内核下的usb GADGET驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
	for (i = 0; i < 4; i++)		nuke(&dev->ep [i], -ESHUTDOWN);	if (driver) {		spin_unlock(&dev->lock);		driver->disconnect(&dev->gadget);		spin_lock(&dev->lock);	}	if (dev->driver)		udc_enable(dev);}int usb_gadget_unregister_driver(struct usb_gadget_driver *driver){	struct goku_udc	*dev = the_controller;	unsigned long	flags;	if (!dev)		return -ENODEV;	if (!driver || driver != dev->driver)		return -EINVAL;	spin_lock_irqsave(&dev->lock, flags);	dev->driver = 0;	stop_activity(dev, driver);	spin_unlock_irqrestore(&dev->lock, flags);	driver->unbind(&dev->gadget);	DBG(dev, "unregistered driver '%s'\n", driver->driver.name);	return 0;}EXPORT_SYMBOL(usb_gadget_unregister_driver);/*-------------------------------------------------------------------------*/static void ep0_setup(struct goku_udc *dev){	struct goku_udc_regs	*regs = dev->regs;	struct usb_ctrlrequest	ctrl;	int			tmp;	/* read SETUP packet and enter DATA stage */	ctrl.bRequestType = readl(&regs->bRequestType);	ctrl.bRequest = readl(&regs->bRequest);	ctrl.wValue  = (readl(&regs->wValueH)  << 8) | readl(&regs->wValueL);	ctrl.wIndex  = (readl(&regs->wIndexH)  << 8) | readl(&regs->wIndexL);	ctrl.wLength = (readl(&regs->wLengthH) << 8) | readl(&regs->wLengthL);	writel(0, &regs->SetupRecv);	nuke(&dev->ep[0], 0);	dev->ep[0].stopped = 0;	if (likely(ctrl.bRequestType & USB_DIR_IN)) {		dev->ep[0].is_in = 1;		dev->ep0state = EP0_IN;		/* detect early status stages */		writel(ICONTROL_STATUSNAK, &dev->regs->IntControl);	} else {		dev->ep[0].is_in = 0;		dev->ep0state = EP0_OUT;		/* NOTE:  CLEAR_FEATURE is done in software so that we can		 * synchronize transfer restarts after bulk IN stalls.  data		 * won't even enter the fifo until the halt is cleared.		 */		switch (ctrl.bRequest) {		case USB_REQ_CLEAR_FEATURE:			switch (ctrl.bRequestType) {			case USB_RECIP_ENDPOINT:				tmp = ctrl.wIndex & 0x0f;				/* active endpoint */				if (tmp > 3 || (!dev->ep[tmp].desc && tmp != 0))					goto stall;				if (ctrl.wIndex & USB_DIR_IN) {					if (!dev->ep[tmp].is_in)						goto stall;				} else {					if (dev->ep[tmp].is_in)						goto stall;				}				/* endpoint halt */				if (ctrl.wValue != 0)					goto stall;				if (tmp)					goku_clear_halt(&dev->ep[tmp]);succeed:				/* start ep0out status stage */				writel(~(1<<0), &regs->EOP);				dev->ep[0].stopped = 1;				dev->ep0state = EP0_STATUS;				return;			case USB_RECIP_DEVICE:				/* device remote wakeup: always clear */				if (ctrl.wValue != 1)					goto stall;				VDBG(dev, "clear dev remote wakeup\n");				goto succeed;			case USB_RECIP_INTERFACE:				goto stall;			default:		/* pass to gadget driver */				break;			}			break;		default:			break;		}	}#ifdef USB_TRACE	VDBG(dev, "SETUP %02x.%02x v%04x i%04x l%04x\n",		ctrl.bRequestType, ctrl.bRequest,		ctrl.wValue, ctrl.wIndex, ctrl.wLength);#endif	/* hw wants to know when we're configured (or not) */	dev->req_config = (ctrl.bRequest == USB_REQ_SET_CONFIGURATION				&& ctrl.bRequestType == USB_RECIP_DEVICE);	if (unlikely(dev->req_config))		dev->configured = (ctrl.wValue != 0);	/* delegate everything to the gadget driver.	 * it may respond after this irq handler returns.	 */	spin_unlock (&dev->lock);	tmp = dev->driver->setup(&dev->gadget, &ctrl);	spin_lock (&dev->lock);	if (unlikely(tmp < 0)) {stall:#ifdef USB_TRACE		VDBG(dev, "req %02x.%02x protocol STALL; err %d\n",				ctrl.bRequestType, ctrl.bRequest, tmp);#endif		command(regs, COMMAND_STALL, 0);		dev->ep[0].stopped = 1;		dev->ep0state = EP0_STALL;	}	/* expect at least one data or status stage irq */}#define ACK(irqbit) { \		stat &= ~irqbit; \		writel(~irqbit, &regs->int_status); \		handled = 1; \		}static irqreturn_t goku_irq(int irq, void *_dev, struct pt_regs *r){	struct goku_udc		*dev = _dev;	struct goku_udc_regs	*regs = dev->regs;	struct goku_ep		*ep;	u32			stat, handled = 0;	unsigned		i, rescans = 5;	spin_lock(&dev->lock);rescan:	stat = readl(&regs->int_status) & dev->int_enable;        if (!stat)		goto done;	dev->irqs++;	/* device-wide irqs */	if (unlikely(stat & INT_DEVWIDE)) {		if (stat & INT_SYSERROR) {			ERROR(dev, "system error\n");			stop_activity(dev, dev->driver);			stat = 0;			handled = 1;			// FIXME have a neater way to prevent re-enumeration			dev->driver = 0;			goto done;		}		if (stat & INT_PWRDETECT) {			writel(~stat, &regs->int_status);			if (readl(&dev->regs->power_detect) & PW_DETECT) {				VDBG(dev, "connect\n");				ep0_start(dev);			} else {				DBG(dev, "disconnect\n");				if (dev->gadget.speed == USB_SPEED_FULL)					stop_activity(dev, dev->driver);				dev->ep0state = EP0_DISCONNECT;				dev->int_enable = INT_DEVWIDE;				writel(dev->int_enable, &dev->regs->int_enable);			}			stat = 0;			handled = 1;			goto done;		}		if (stat & INT_SUSPEND) {			ACK(INT_SUSPEND);			if (readl(&regs->ep_status[0]) & EPxSTATUS_SUSPEND) {				switch (dev->ep0state) {				case EP0_DISCONNECT:				case EP0_SUSPEND:					goto pm_next;				default:					break;				}				DBG(dev, "USB suspend\n");				dev->ep0state = EP0_SUSPEND;				if (dev->gadget.speed != USB_SPEED_UNKNOWN						&& dev->driver						&& dev->driver->suspend) {					spin_unlock(&dev->lock);					dev->driver->suspend(&dev->gadget);					spin_lock(&dev->lock);				}			} else {				if (dev->ep0state != EP0_SUSPEND) {					DBG(dev, "bogus USB resume %d\n",						dev->ep0state);					goto pm_next;				}				DBG(dev, "USB resume\n");				dev->ep0state = EP0_IDLE;				if (dev->gadget.speed != USB_SPEED_UNKNOWN						&& dev->driver						&& dev->driver->resume) {					spin_unlock(&dev->lock);					dev->driver->resume(&dev->gadget);					spin_lock(&dev->lock);				}			}		}pm_next:		if (stat & INT_USBRESET) {		/* hub reset done */			ACK(INT_USBRESET);			INFO(dev, "USB reset done, gadget %s\n",				dev->driver->driver.name);		}		// and INT_ERR on some endpoint's crc/bitstuff/... problem	}	/* progress ep0 setup, data, or status stages.	 * no transition {EP0_STATUS, EP0_STALL} --> EP0_IDLE; saves irqs	 */	if (stat & INT_SETUP) {		ACK(INT_SETUP);		dev->ep[0].irqs++;		ep0_setup(dev);	}        if (stat & INT_STATUSNAK) {		ACK(INT_STATUSNAK|INT_ENDPOINT0);		if (dev->ep0state == EP0_IN) {			ep = &dev->ep[0];			ep->irqs++;			nuke(ep, 0);			writel(~(1<<0), &regs->EOP);			dev->ep0state = EP0_STATUS;		}	}        if (stat & INT_ENDPOINT0) {		ACK(INT_ENDPOINT0);		ep = &dev->ep[0];		ep->irqs++;		pio_advance(ep);        }	/* dma completion */        if (stat & INT_MSTRDEND) {	/* IN */		ACK(INT_MSTRDEND);		ep = &dev->ep[UDC_MSTRD_ENDPOINT];		ep->irqs++;		dma_advance(dev, ep);        }        if (stat & INT_MSTWREND) {	/* OUT */		ACK(INT_MSTWREND);		ep = &dev->ep[UDC_MSTWR_ENDPOINT];		ep->irqs++;		dma_advance(dev, ep);        }        if (stat & INT_MSTWRTMOUT) {	/* OUT */		ACK(INT_MSTWRTMOUT);		ep = &dev->ep[UDC_MSTWR_ENDPOINT];		ep->irqs++;		ERROR(dev, "%s write timeout ?\n", ep->ep.name);		// reset dma? then dma_advance()        }	/* pio */	for (i = 1; i < 4; i++) {		u32		tmp = INT_EPxDATASET(i);		if (!(stat & tmp))			continue;		ep = &dev->ep[i];		pio_advance(ep);		if (list_empty (&ep->queue))			pio_irq_disable(dev, regs, i);		stat &= ~tmp;		handled = 1;		ep->irqs++;	}	if (rescans--)		goto rescan;done:	(void)readl(&regs->int_enable);	spin_unlock(&dev->lock);	if (stat)		DBG(dev, "unhandled irq status: %05x (%05x, %05x)\n", stat,				readl(&regs->int_status), dev->int_enable);	return IRQ_RETVAL(handled);}#undef ACK/*-------------------------------------------------------------------------*//* tear down the binding between this driver and the pci device */static void goku_remove(struct pci_dev *pdev){	struct goku_udc		*dev = pci_get_drvdata(pdev);	DBG(dev, "%s\n", __FUNCTION__);	/* start with the driver above us */	if (dev->driver) {		/* should have been done already by driver model core */		WARN(dev, "pci remove, driver '%s' is still registered\n",				dev->driver->driver.name);		usb_gadget_unregister_driver(dev->driver);	}#ifdef	UDC_PROC_FILE	remove_proc_entry(proc_node_name, NULL);#endif	if (dev->regs)		udc_reset(dev);	if (dev->got_irq)		free_irq(pdev->irq, dev);	if (dev->regs)		iounmap(dev->regs);	if (dev->got_region)		release_mem_region(pci_resource_start (pdev, 0),				pci_resource_len (pdev, 0));	if (dev->enabled)		pci_disable_device(pdev);	pci_set_drvdata(pdev, 0);	dev->regs = 0;	the_controller = 0;	INFO(dev, "unbind\n");}/* wrap this driver around the specified pci device, but * don't respond over USB until a gadget driver binds to us. */static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id){	struct goku_udc		*dev = 0;	unsigned long		resource, len;	void			*base = 0;	int			retval;	char			buf [8], *bufp;	/* if you want to support more than one controller in a system,	 * usb_gadget_driver_{register,unregister}() must change.	 */	if (the_controller) {		WARN(dev, "ignoring %s\n", pci_name(pdev));		return -EBUSY;	}	if (!pdev->irq) {		printk(KERN_ERR "Check PCI %s IRQ setup!\n", pci_name(pdev));		retval = -ENODEV;		goto done;	}	/* alloc, and start init */	dev = kmalloc (sizeof *dev, SLAB_KERNEL);	if (dev == NULL){		pr_debug("enomem %s\n", pci_name(pdev));		retval = -ENOMEM;		goto done;	}	memset(dev, 0, sizeof *dev);	spin_lock_init(&dev->lock);	dev->pdev = pdev;	dev->gadget.ops = &goku_ops;	/* the "gadget" abstracts/virtualizes the controller */	dev->gadget.dev.bus_id = "gadget";	dev->gadget.name = driver_name;	/* now all the pci goodies ... */	retval = pci_enable_device(pdev);	if (retval < 0) {		DBG(dev, "can't enable, %d\n", retval);		goto done;	}	dev->enabled = 1;	resource = pci_resource_start(pdev, 0);	len = pci_resource_len(pdev, 0);	if (!request_mem_region(resource, len, driver_name)) {		DBG(dev, "controller already in use\n");		retval = -EBUSY;		goto done;	}	dev->got_region = 1;	base = ioremap_nocache(resource, len);	if (base == NULL) {		DBG(dev, "can't map memory\n");		retval = -EFAULT;		goto done;	}	dev->regs = (struct goku_udc_regs *) base;	pci_set_drvdata(pdev, dev);	INFO(dev, "%s\n", driver_desc);	INFO(dev, "version: " DRIVER_VERSION " %s\n", dmastr());#ifndef __sparc__	snprintf(buf, sizeof buf, "%d", pdev->irq);	bufp = buf;#else	bufp = __irq_itoa(pdev->irq);#endif	INFO(dev, "irq %s, pci mem %p\n", bufp, base);	/* init to known state, then setup irqs */	udc_reset(dev);	udc_reinit (dev);	if (request_irq(pdev->irq, goku_irq, SA_SHIRQ/*|SA_SAMPLE_RANDOM*/,			driver_name, dev) != 0) {		DBG(dev, "request interrupt %s failed\n", bufp);		retval = -EBUSY;		goto done;	}	dev->got_irq = 1;	if (use_dma)		pci_set_master(pdev);#ifdef	UDC_PROC_FILE	create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev);#endif	/* done */	the_controller = dev;	return 0;done:	if (dev)		goku_remove (pdev);	return retval;}/*-------------------------------------------------------------------------*/static struct pci_device_id pci_ids [] = { {	.class = 	((PCI_CLASS_SERIAL_USB << 8) | 0xfe),	.class_mask = 	~0,	.vendor =	0x102f,		/* Toshiba */	.device =	0x0107,		/* this UDC */	.subvendor =	PCI_ANY_ID,	.subdevice =	PCI_ANY_ID,}, { /* end: all zeroes */ }};MODULE_DEVICE_TABLE (pci, pci_ids);static struct pci_driver goku_pci_driver = {	.name =		(char *) driver_name,	.id_table =	pci_ids,	.probe =	goku_probe,	.remove =	goku_remove,	/* FIXME add power management support */};static int __init init (void){	return pci_module_init (&goku_pci_driver);}module_init (init);static void __exit cleanup (void){	pci_unregister_driver (&goku_pci_driver);}module_exit (cleanup);

⌨️ 快捷键说明

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