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

📄 goku_udc.c

📁 LINUX2.4.18内核下的usb GADGET驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
			&& (ep->dev->regs->DataSet & DATASET_AB(ep->num)))		retval = -EAGAIN;	else if (!value)		goku_clear_halt(ep);	else {		ep->stopped = 1;		VDBG(ep->dev, "%s set halt\n", ep->ep.name);		command(ep->dev->regs, COMMAND_STALL, ep->num);		readl(ep->reg_status);	}	spin_unlock_irqrestore(&ep->dev->lock, flags);	return retval;}static int goku_fifo_status(struct usb_ep *_ep){	struct goku_ep		*ep;	struct goku_udc_regs	*regs;	u32			size;	if (!_ep)		return -ENODEV;	ep = container_of(_ep, struct goku_ep, ep);	/* size is only reported sanely for OUT */	if (ep->is_in)		return -EOPNOTSUPP;	/* ignores 16-byte dma buffer; SizeH == 0 */	regs = ep->dev->regs;	size = readl(&regs->EPxSizeLA[ep->num]) & DATASIZE;	size += readl(&regs->EPxSizeLB[ep->num]) & DATASIZE;	VDBG(ep->dev, "%s %s %u\n", __FUNCTION__, ep->ep.name, size);	return size;}static void goku_fifo_flush(struct usb_ep *_ep){	struct goku_ep		*ep;	struct goku_udc_regs	*regs;	u32			size;	if (!_ep)		return;	ep = container_of(_ep, struct goku_ep, ep);	VDBG(ep->dev, "%s %s\n", __FUNCTION__, ep->ep.name);	/* don't change EPxSTATUS_EP_INVALID to READY */	if (!ep->desc && ep->num != 0) {		DBG(ep->dev, "%s %s inactive?\n", __FUNCTION__, ep->ep.name);		return;	}	regs = ep->dev->regs;	size = readl(&regs->EPxSizeLA[ep->num]);	size &= DATASIZE;	/* Non-desirable behavior:  FIFO_CLEAR also clears the	 * endpoint halt feature.  For OUT, we _could_ just read	 * the bytes out (PIO, if !ep->dma); for in, no choice.	 */	if (size)		command(regs, COMMAND_FIFO_CLEAR, ep->num);}static struct usb_ep_ops goku_ep_ops = {	.enable		= goku_ep_enable,	.disable	= goku_ep_disable,	.alloc_request	= goku_alloc_request,	.free_request	= goku_free_request,	.alloc_buffer	= goku_alloc_buffer,	.free_buffer	= goku_free_buffer,	.queue		= goku_queue,	.dequeue	= goku_dequeue,	.set_halt	= goku_set_halt,	.fifo_status	= goku_fifo_status,	.fifo_flush	= goku_fifo_flush,};/*-------------------------------------------------------------------------*/static int goku_get_frame(struct usb_gadget *_gadget){	return -EOPNOTSUPP;}static const struct usb_gadget_ops goku_ops = {	.get_frame	= goku_get_frame,	// no remote wakeup	// not selfpowered};/*-------------------------------------------------------------------------*/static inline char *dmastr(void){	if (use_dma == 0)		return "(dma disabled)";	else if (use_dma == 2)		return "(dma IN and OUT)";	else		return "(dma IN)";}/* if we're trying to save space, don't bother with this proc file */#if defined(CONFIG_PROC_FS) && !defined(CONFIG_EMBEDDED)#  define	UDC_PROC_FILE#endif#ifdef UDC_PROC_FILEstatic const char proc_node_name [] = "driver/udc";#define FOURBITS "%s%s%s%s"#define EIGHTBITS FOURBITS FOURBITSstatic voiddump_intmask(const char *label, u32 mask, char **next, unsigned *size){	int t;	/* int_status is the same format ... */	t = snprintf(*next, *size,		"%s %05X =" FOURBITS EIGHTBITS EIGHTBITS "\n",		label, mask,		(mask & INT_PWRDETECT) ? " power" : "",		(mask & INT_SYSERROR) ? " sys" : "",		(mask & INT_MSTRDEND) ? " in-dma" : "",		(mask & INT_MSTWRTMOUT) ? " wrtmo" : "",		(mask & INT_MSTWREND) ? " out-dma" : "",		(mask & INT_MSTWRSET) ? " wrset" : "",		(mask & INT_ERR) ? " err" : "",		(mask & INT_SOF) ? " sof" : "",		(mask & INT_EP3NAK) ? " ep3nak" : "",		(mask & INT_EP2NAK) ? " ep2nak" : "",		(mask & INT_EP1NAK) ? " ep1nak" : "",		(mask & INT_EP3DATASET) ? " ep3" : "",		(mask & INT_EP2DATASET) ? " ep2" : "",		(mask & INT_EP1DATASET) ? " ep1" : "",		(mask & INT_STATUSNAK) ? " ep0snak" : "",		(mask & INT_STATUS) ? " ep0status" : "",		(mask & INT_SETUP) ? " setup" : "",		(mask & INT_ENDPOINT0) ? " ep0" : "",		(mask & INT_USBRESET) ? " reset" : "",		(mask & INT_SUSPEND) ? " suspend" : "");	*size -= t;	*next += t;}static intudc_proc_read(char *buffer, char **start, off_t off, int count,		int *eof, void *_dev){	char			*buf = buffer;	struct goku_udc		*dev = _dev;	struct goku_udc_regs	*regs = dev->regs;	char			*next = buf;	unsigned		size = count;	unsigned long		flags;	int			i, t, is_usb_connected;	u32			tmp;	if (off != 0)		return 0;	local_irq_save(flags);	/* basic device status */	tmp = readl(&regs->power_detect);	is_usb_connected = tmp & PW_DETECT;	t = snprintf(next, size,		"%s - %s\n"		"%s version: %s %s\n"		"Gadget driver: %s\n"		"Host %s, %s\n"		"\n",		pci_name(dev->pdev), driver_desc,		driver_name, DRIVER_VERSION, dmastr(),		dev->driver ? dev->driver->driver.name : "(none)",		is_usb_connected			? ((tmp & PW_PULLUP) ? "full speed" : "powered")			: "disconnected",		({char *tmp;		switch(dev->ep0state){		case EP0_DISCONNECT:	tmp = "ep0_disconnect"; break;		case EP0_IDLE:		tmp = "ep0_idle"; break;		case EP0_IN:		tmp = "ep0_in"; break;		case EP0_OUT:		tmp = "ep0_out"; break;		case EP0_STATUS:	tmp = "ep0_status"; break;		case EP0_STALL:		tmp = "ep0_stall"; break;		case EP0_SUSPEND:	tmp = "ep0_suspend"; break;		default:		tmp = "ep0_?"; break;		} tmp; })		);	size -= t;	next += t;	dump_intmask("int_status", readl(&regs->int_status), &next, &size);	dump_intmask("int_enable", readl(&regs->int_enable), &next, &size);	if (!is_usb_connected || !dev->driver || (tmp & PW_PULLUP) == 0)		goto done;	/* registers for (active) device and ep0 */	t = snprintf(next, size, "\nirqs %lu\ndataset %02x "			"single.bcs %02x.%02x state %x addr %u\n",			dev->irqs, readl(&regs->DataSet),			readl(&regs->EPxSingle), readl(&regs->EPxBCS),			readl(&regs->UsbState),			readl(&regs->address));	size -= t;	next += t;	tmp = readl(&regs->dma_master);	t = snprintf(next, size,		"dma %03X =" EIGHTBITS "%s %s\n", tmp,		(tmp & MST_EOPB_DIS) ? " eopb-" : "",		(tmp & MST_EOPB_ENA) ? " eopb+" : "",		(tmp & MST_TIMEOUT_DIS) ? " tmo-" : "",		(tmp & MST_TIMEOUT_ENA) ? " tmo+" : "",		(tmp & MST_RD_EOPB) ? " eopb" : "",		(tmp & MST_RD_RESET) ? " in_reset" : "",		(tmp & MST_WR_RESET) ? " out_reset" : "",		(tmp & MST_RD_ENA) ? " IN" : "",		(tmp & MST_WR_ENA) ? " OUT" : "",		(tmp & MST_CONNECTION)			? "ep1in/ep2out"			: "ep1out/ep2in");	size -= t;	next += t;	/* dump endpoint queues */	for (i = 0; i < 4; i++) {		struct goku_ep		*ep = &dev->ep [i];		struct goku_request	*req;		int			t;		if (i && !ep->desc)			continue;		tmp = readl(ep->reg_status);		t = snprintf(next, size,			"%s %s max %u %s, irqs %lu, "			"status %02x (%s) " FOURBITS "\n",			ep->ep.name,			ep->is_in ? "in" : "out",			ep->ep.maxpacket,			ep->dma ? "dma" : "pio",			ep->irqs,			tmp, ({ char *s;			switch (tmp & EPxSTATUS_EP_MASK) {			case EPxSTATUS_EP_READY:				s = "ready"; break;			case EPxSTATUS_EP_DATAIN:				s = "packet"; break;			case EPxSTATUS_EP_FULL:				s = "full"; break;			case EPxSTATUS_EP_TX_ERR:	// host will retry				s = "tx_err"; break;			case EPxSTATUS_EP_RX_ERR:				s = "rx_err"; break;			case EPxSTATUS_EP_BUSY:		/* ep0 only */				s = "busy"; break;			case EPxSTATUS_EP_STALL:				s = "stall"; break;			case EPxSTATUS_EP_INVALID:	// these "can't happen"				s = "invalid"; break;			default:				s = "?"; break;			}; s; }),			(tmp & EPxSTATUS_TOGGLE) ? "data1" : "data0",			(tmp & EPxSTATUS_SUSPEND) ? " suspend" : "",			(tmp & EPxSTATUS_FIFO_DISABLE) ? " disable" : "",			(tmp & EPxSTATUS_STAGE_ERROR) ? " ep0stat" : ""			);		if (t <= 0 || t > size)			goto done;		size -= t;		next += t;		if (list_empty(&ep->queue)) {			t = snprintf(next, size, "\t(nothing queued)\n");			if (t <= 0 || t > size)				goto done;			size -= t;			next += t;			continue;		}		list_for_each_entry(req, &ep->queue, queue) {			if (ep->dma && req->queue.prev == &ep->queue) {				if (i == UDC_MSTRD_ENDPOINT)					tmp = readl(&regs->in_dma_current);				else					tmp = readl(&regs->out_dma_current);				tmp -= req->req.dma;				tmp++;			} else				tmp = req->req.actual;			t = snprintf(next, size,				"\treq %p len %u/%u buf %p\n",				&req->req, tmp, req->req.length,				req->req.buf);			if (t <= 0 || t > size)				goto done;			size -= t;			next += t;		}	}done:	local_irq_restore(flags);	*eof = 1;	return count - size;}#endif	/* UDC_PROC_FILE *//*-------------------------------------------------------------------------*/static void udc_reinit (struct goku_udc *dev){	static char *names [] = { "ep0", "ep1-bulk", "ep2-bulk", "ep3-bulk" };		unsigned i;	INIT_LIST_HEAD (&dev->gadget.ep_list);	dev->gadget.ep0 = &dev->ep [0].ep;	dev->gadget.speed = USB_SPEED_UNKNOWN;	dev->ep0state = EP0_DISCONNECT;	dev->irqs = 0;	for (i = 0; i < 4; i++) {		struct goku_ep	*ep = &dev->ep[i];		ep->num = i;		ep->ep.name = names[i];		ep->reg_fifo = &dev->regs->ep_fifo [i];		ep->reg_status = &dev->regs->ep_status [i];		ep->reg_mode = &dev->regs->ep_mode[i];		ep->ep.ops = &goku_ep_ops;		list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);		ep->dev = dev;		INIT_LIST_HEAD (&ep->queue);		ep_reset(0, ep);	}	dev->ep[0].reg_mode = 0;	dev->ep[0].ep.maxpacket = MAX_EP0_SIZE;	list_del_init (&dev->ep[0].ep.ep_list);}static void udc_reset(struct goku_udc *dev){	struct goku_udc_regs	*regs = dev->regs;	writel(0, &regs->power_detect);	writel(0, &regs->int_enable);	readl(&regs->int_enable);	dev->int_enable = 0;	/* deassert reset, leave USB D+ at hi-Z (no pullup)	 * don't let INT_PWRDETECT sequence begin	 */	udelay(250);	writel(PW_RESETB, &regs->power_detect);	readl(&regs->int_enable);}static void ep0_start(struct goku_udc *dev){	struct goku_udc_regs	*regs = dev->regs;	unsigned		i;	VDBG(dev, "%s\n", __FUNCTION__);	udc_reset(dev);	udc_reinit (dev);	//writel(MST_EOPB_ENA | MST_TIMEOUT_ENA, &regs->dma_master);	/* hw handles set_address, set_feature, get_status; maybe more */	writel(   G_REQMODE_SET_INTF | G_REQMODE_GET_INTF		| G_REQMODE_SET_CONF | G_REQMODE_GET_CONF		| G_REQMODE_GET_DESC		| G_REQMODE_CLEAR_FEAT		, &regs->reqmode);	for (i = 0; i < 4; i++)		dev->ep[i].irqs = 0;	/* can't modify descriptors after writing UsbReady */	for (i = 0; i < DESC_LEN; i++)		writel(0, &regs->descriptors[i]);	writel(0, &regs->UsbReady);	/* expect ep0 requests when the host drops reset */	writel(PW_RESETB | PW_PULLUP, &regs->power_detect);	dev->int_enable = INT_DEVWIDE | INT_EP0;	writel(dev->int_enable, &dev->regs->int_enable);	readl(&regs->int_enable);	dev->gadget.speed = USB_SPEED_FULL;	dev->ep0state = EP0_IDLE;}static void udc_enable(struct goku_udc *dev){	/* start enumeration now, or after power detect irq */	if (readl(&dev->regs->power_detect) & PW_DETECT)		ep0_start(dev);	else {		DBG(dev, "%s\n", __FUNCTION__);		dev->int_enable = INT_PWRDETECT;		writel(dev->int_enable, &dev->regs->int_enable);	}}/*-------------------------------------------------------------------------*//* keeping it simple: * - one bus driver, initted first; * - one function driver, initted second */static struct goku_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 goku_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) {		DBG(dev, "bind to driver %s --> error %d\n",				driver->driver.name, 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);	DBG(dev, "registered gadget driver '%s'\n", driver->driver.name);	return 0;}EXPORT_SYMBOL(usb_gadget_register_driver);static voidstop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver){	unsigned	i;	DBG (dev, "%s\n", __FUNCTION__);	if (dev->gadget.speed == USB_SPEED_UNKNOWN)		driver = 0;	/* disconnect gadget driver after quiesceing hw and the driver */	udc_reset (dev);

⌨️ 快捷键说明

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