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

📄 fsl_usb2_udc.c

📁 linux下面gadget设备驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
				status = -EPIPE;				/* FIXME: continue with next queued TD? */				break;			}			if (errors & DTD_STATUS_DATA_BUFF_ERR) {				VDBG("Transfer overflow");				status = -EPROTO;				break;			} else if (errors & DTD_STATUS_TRANSACTION_ERR) {				VDBG("ISO error");				status = -EILSEQ;				break;			} else				ERR("Unknown error has occured (0x%x)!\r\n",					errors);		} else if (le32_to_cpu(curr_td->size_ioc_sts)				& DTD_STATUS_ACTIVE) {			VDBG("Request not complete");			status = REQ_UNCOMPLETE;			return status;		} else if (remaining_length) {			if (direction) {				VDBG("Transmit dTD remaining length not zero");				status = -EPROTO;				break;			} else {				td_complete++;				break;			}		} else {			td_complete++;			VDBG("dTD transmitted successful ");		}		if (j != curr_req->dtd_count - 1)			curr_td = (struct ep_td_struct *)curr_td->next_td_virt;	}	if (status)		return status;	curr_req->req.actual = actual;	return 0;}/* Process a DTD completion interrupt */static void dtd_complete_irq(struct fsl_udc *udc){	u32 bit_pos;	int i, ep_num, direction, bit_mask, status;	struct fsl_ep *curr_ep;	struct fsl_req *curr_req, *temp_req;	/* Clear the bits in the register */	bit_pos = fsl_readl(&dr_regs->endptcomplete);	fsl_writel(bit_pos, &dr_regs->endptcomplete);	if (!bit_pos)		return;	for (i = 0; i < udc->max_ep * 2; i++) {		ep_num = i >> 1;		direction = i % 2;		bit_mask = 1 << (ep_num + 16 * direction);		if (!(bit_pos & bit_mask))			continue;		curr_ep = get_ep_by_pipe(udc, i);		/* If the ep is configured */		if (curr_ep->name == NULL) {			WARN("Invalid EP?");			continue;		}		/* process the req queue until an uncomplete request */		list_for_each_entry_safe(curr_req, temp_req, &curr_ep->queue,				queue) {			status = process_ep_req(udc, i, curr_req);			VDBG("status of process_ep_req= %d, ep = %d",					status, ep_num);			if (status == REQ_UNCOMPLETE)				break;			/* write back status to req */			curr_req->req.status = status;			if (ep_num == 0) {				ep0_req_complete(udc, curr_ep, curr_req);				break;			} else				done(curr_ep, curr_req, status);		}	}}/* Process a port change interrupt */static void port_change_irq(struct fsl_udc *udc){	u32 speed;	if (udc->bus_reset)		udc->bus_reset = 0;	/* Bus resetting is finished */	if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) {		/* Get the speed */		speed = (fsl_readl(&dr_regs->portsc1)				& PORTSCX_PORT_SPEED_MASK);		switch (speed) {		case PORTSCX_PORT_SPEED_HIGH:			udc->gadget.speed = USB_SPEED_HIGH;			break;		case PORTSCX_PORT_SPEED_FULL:			udc->gadget.speed = USB_SPEED_FULL;			break;		case PORTSCX_PORT_SPEED_LOW:			udc->gadget.speed = USB_SPEED_LOW;			break;		default:			udc->gadget.speed = USB_SPEED_UNKNOWN;			break;		}	}	/* Update USB state */	if (!udc->resume_state)		udc->usb_state = USB_STATE_DEFAULT;}/* Process suspend interrupt */static void suspend_irq(struct fsl_udc *udc){	udc->resume_state = udc->usb_state;	udc->usb_state = USB_STATE_SUSPENDED;	/* report suspend to the driver, serial.c does not support this */	if (udc->driver->suspend)		udc->driver->suspend(&udc->gadget);}static void bus_resume(struct fsl_udc *udc){	udc->usb_state = udc->resume_state;	udc->resume_state = 0;	/* report resume to the driver, serial.c does not support this */	if (udc->driver->resume)		udc->driver->resume(&udc->gadget);}/* Clear up all ep queues */static int reset_queues(struct fsl_udc *udc){	u8 pipe;	for (pipe = 0; pipe < udc->max_pipes; pipe++)		udc_reset_ep_queue(udc, pipe);	/* report disconnect; the driver is already quiesced */	udc->driver->disconnect(&udc->gadget);	return 0;}/* Process reset interrupt */static void reset_irq(struct fsl_udc *udc){	u32 temp;	unsigned long timeout;	/* Clear the device address */	temp = fsl_readl(&dr_regs->deviceaddr);	fsl_writel(temp & ~USB_DEVICE_ADDRESS_MASK, &dr_regs->deviceaddr);	udc->device_address = 0;	/* Clear usb state */	udc->resume_state = 0;	udc->ep0_dir = 0;	udc->ep0_state = WAIT_FOR_SETUP;	udc->remote_wakeup = 0;	/* default to 0 on reset */	udc->gadget.b_hnp_enable = 0;	udc->gadget.a_hnp_support = 0;	udc->gadget.a_alt_hnp_support = 0;	/* Clear all the setup token semaphores */	temp = fsl_readl(&dr_regs->endptsetupstat);	fsl_writel(temp, &dr_regs->endptsetupstat);	/* Clear all the endpoint complete status bits */	temp = fsl_readl(&dr_regs->endptcomplete);	fsl_writel(temp, &dr_regs->endptcomplete);	timeout = jiffies + 100;	while (fsl_readl(&dr_regs->endpointprime)) {		/* Wait until all endptprime bits cleared */		if (time_after(jiffies, timeout)) {			ERR("Timeout for reset\n");			break;		}		cpu_relax();	}	/* Write 1s to the flush register */	fsl_writel(0xffffffff, &dr_regs->endptflush);	if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) {		VDBG("Bus reset");		/* Bus is reseting */		udc->bus_reset = 1;		/* Reset all the queues, include XD, dTD, EP queue		 * head and TR Queue */		reset_queues(udc);		udc->usb_state = USB_STATE_DEFAULT;	} else {		VDBG("Controller reset");		/* initialize usb hw reg except for regs for EP, not		 * touch usbintr reg */		dr_controller_setup(udc);		/* Reset all internal used Queues */		reset_queues(udc);		ep0_setup(udc);		/* Enable DR IRQ reg, Set Run bit, change udc state */		dr_controller_run(udc);		udc->usb_state = USB_STATE_ATTACHED;	}}/* * USB device controller interrupt handler */static irqreturn_t fsl_udc_irq(int irq, void *_udc){	struct fsl_udc *udc = _udc;	u32 irq_src;	irqreturn_t status = IRQ_NONE;	unsigned long flags;	/* Disable ISR for OTG host mode */	if (udc->stopped)		return IRQ_NONE;	spin_lock_irqsave(&udc->lock, flags);	irq_src = fsl_readl(&dr_regs->usbsts) & fsl_readl(&dr_regs->usbintr);	/* Clear notification bits */	fsl_writel(irq_src, &dr_regs->usbsts);	/* VDBG("irq_src [0x%8x]", irq_src); */	/* Need to resume? */	if (udc->usb_state == USB_STATE_SUSPENDED)		if ((fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_SUSPEND) == 0)			bus_resume(udc);	/* USB Interrupt */	if (irq_src & USB_STS_INT) {		VDBG("Packet int");		/* Setup package, we only support ep0 as control ep */		if (fsl_readl(&dr_regs->endptsetupstat) & EP_SETUP_STATUS_EP0) {			tripwire_handler(udc, 0,					(u8 *) (&udc->local_setup_buff));			setup_received_irq(udc, &udc->local_setup_buff);			status = IRQ_HANDLED;		}		/* completion of dtd */		if (fsl_readl(&dr_regs->endptcomplete)) {			dtd_complete_irq(udc);			status = IRQ_HANDLED;		}	}	/* SOF (for ISO transfer) */	if (irq_src & USB_STS_SOF) {		status = IRQ_HANDLED;	}	/* Port Change */	if (irq_src & USB_STS_PORT_CHANGE) {		port_change_irq(udc);		status = IRQ_HANDLED;	}	/* Reset Received */	if (irq_src & USB_STS_RESET) {		reset_irq(udc);		status = IRQ_HANDLED;	}	/* Sleep Enable (Suspend) */	if (irq_src & USB_STS_SUSPEND) {		suspend_irq(udc);		status = IRQ_HANDLED;	}	if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) {		VDBG("Error IRQ %x ", irq_src);	}	spin_unlock_irqrestore(&udc->lock, flags);	return status;}/*----------------------------------------------------------------* * Hook to gadget drivers * Called by initialization code of gadget drivers*----------------------------------------------------------------*/int usb_gadget_register_driver(struct usb_gadget_driver *driver){	int retval = -ENODEV;	unsigned long flags = 0;	if (!udc_controller)		return -ENODEV;	if (!driver || (driver->speed != USB_SPEED_FULL				&& driver->speed != USB_SPEED_HIGH)			|| !driver->bind || !driver->disconnect			|| !driver->setup)		return -EINVAL;	if (udc_controller->driver)		return -EBUSY;	/* lock is needed but whether should use this lock or another */	spin_lock_irqsave(&udc_controller->lock, flags);	driver->driver.bus = 0;	/* hook up the driver */	udc_controller->driver = driver;	udc_controller->gadget.dev.driver = &driver->driver;	spin_unlock_irqrestore(&udc_controller->lock, flags);	/* bind udc driver to gadget driver */	retval = driver->bind(&udc_controller->gadget);	if (retval) {		VDBG("bind to %s --> %d", driver->driver.name, retval);		udc_controller->gadget.dev.driver = 0;		udc_controller->driver = 0;		goto out;	}	/* Enable DR IRQ reg and Set usbcmd reg  Run bit */	dr_controller_run(udc_controller);	udc_controller->usb_state = USB_STATE_ATTACHED;	udc_controller->ep0_state = WAIT_FOR_SETUP;	udc_controller->ep0_dir = 0;	printk(KERN_INFO "%s: bind to driver %s \n",			udc_controller->gadget.name, driver->driver.name);out:	if (retval)		printk("retval %d \n", retval);	return retval;}EXPORT_SYMBOL(usb_gadget_register_driver);/* Disconnect from gadget driver */int usb_gadget_unregister_driver(struct usb_gadget_driver *driver){	struct fsl_ep *loop_ep;	unsigned long flags;	if (!udc_controller)		return -ENODEV;	if (!driver || driver != udc_controller->driver || !driver->unbind)		return -EINVAL;	if (udc_controller->transceiver)		(void)otg_set_peripheral(udc_controller->transceiver, 0);	/* stop DR, disable intr */	dr_controller_stop(udc_controller);	/* in fact, no needed */	udc_controller->usb_state = USB_STATE_ATTACHED;	udc_controller->ep0_state = WAIT_FOR_SETUP;	udc_controller->ep0_dir = 0;	/* stand operation */	spin_lock_irqsave(&udc_controller->lock, flags);	udc_controller->gadget.speed = USB_SPEED_UNKNOWN;	nuke(&udc_controller->eps[0], -ESHUTDOWN);	list_for_each_entry(loop_ep, &udc_controller->gadget.ep_list,			ep.ep_list)		nuke(loop_ep, -ESHUTDOWN);	spin_unlock_irqrestore(&udc_controller->lock, flags);	/* unbind gadget and unhook driver. */	driver->unbind(&udc_controller->gadget);	udc_controller->gadget.dev.driver = 0;	udc_controller->driver = 0;	printk("unregistered gadget driver '%s'\r\n", driver->driver.name);	return 0;}EXPORT_SYMBOL(usb_gadget_unregister_driver);/*-------------------------------------------------------------------------		PROC File System Support-------------------------------------------------------------------------*/#ifdef CONFIG_USB_GADGET_DEBUG_FILES#include <linux/seq_file.h>static const char proc_filename[] = "driver/fsl_usb2_udc";static int fsl_proc_read(char *page, char **start, off_t off, int count,		int *eof, void *_dev){	char *buf = page;	char *next = buf;	unsigned size = count;	unsigned long flags;	int t, i;	u32 tmp_reg;	struct fsl_ep *ep = NULL;	struct fsl_req *req;	struct fsl_udc *udc = udc_controller;	if (off != 0)		return 0;	spin_lock_irqsave(&udc->lock, flags);	/* ------basic driver infomation ---- */	t = scnprintf(next, size,			DRIVER_DESC "\n"			"%s version: %s\n"			"Gadget driver: %s\n\n",			driver_name, DRIVER_VERSION,			udc->driver ? udc->driver->driver.name : "(none)");	size -= t;	next += t;	/* ------ DR Registers ----- */	tmp_reg = fsl_readl(&dr_regs->usbcmd);	t = scnprintf(next, size,			"USBCMD reg:\n"			"SetupTW: %d\n"			"Run/Stop: %s\n\n",			(tmp_reg & USB_CMD_SUTW) ? 1 : 0,			(tmp_reg & USB_CMD_RUN_STOP) ? "Run" : "Stop");	size -= t;	next += t;	tmp_reg = fsl_readl(&dr_regs->usbsts);	t = scnprintf(next, size,			"USB Status Reg:\n"			"Dr Suspend: %d" "Reset Received: %d" "System Error: %s"			"USB Error Interrupt: %s\n\n",			(tmp_reg & USB_STS_SUSPEND) ? 1 : 0,			(tmp_reg & USB_STS_RESET) ? 1 : 0,			(tmp_reg & USB_STS_SYS_ERR) ? "Err" : "Normal",			(tmp_reg & USB_STS_ERR) ? "Err detected" : "No err");	size -= t;	next += t;	tmp_reg = fsl_readl(&dr_regs->usbintr);	t = scnprintf(next, size,			"USB Intrrupt Enable Reg:\n"			"Sleep Enable: %d" "SOF Received Enable: %d"			"Reset Enable: %d\n"			"System Error Enable: %d"			"Port Change Dectected Enable: %d\n"			"USB Error Intr Enable: %d" "USB Intr Enable: %d\n\n",			(tmp_reg & USB_INTR_DEVICE_SUSPEND) ? 1 : 0,			(tmp_reg & USB_INTR_SOF_EN) ? 1 : 0,			(tmp_reg & USB_INTR_RESET_EN) ? 1 : 0,			(tmp_reg & USB_INTR_SYS_ERR_EN) ? 1 : 0,			(tmp_reg & USB_INTR_PTC_DETECT_EN) ? 1 : 0,			(tmp_reg & USB_INTR_ERR_INT_EN) ? 1 : 0,			(tmp_reg & USB_INTR_INT_EN) ? 1 : 0);	size -= t;	next += t;	tmp_reg = fsl_readl(&dr_regs->frindex);	t = scnprintf(next, size,			"USB Frame Index Reg:" "Frame Number is 0x%x\n\n",

⌨️ 快捷键说明

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