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

📄 at91_udc.c

📁 linux下面gadget设备驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * at91_udc -- driver for at91-series USB peripheral controller * * Copyright (C) 2004 by Thomas Rathbone * Copyright (C) 2005 by HP Labs * Copyright (C) 2005 by David Brownell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA  02111-1307, USA. */#undef	DEBUG#undef	VERBOSE#undef	PACKET_TRACE#include <linux/kernel.h>#include <linux/module.h>#include <linux/platform_device.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/list.h>#include <linux/interrupt.h>#include <linux/proc_fs.h>#include <linux/clk.h>#include <linux/usb/ch9.h>#include <linux/usb/gadget.h>#include <asm/byteorder.h>#include <asm/hardware.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/mach-types.h>#include <asm/arch/gpio.h>#include <asm/arch/board.h>#include <asm/arch/cpu.h>#include <asm/arch/at91sam9261_matrix.h>#include "at91_udc.h"/* * This controller is simple and PIO-only.  It's used in many AT91-series * full speed USB controllers, including the at91rm9200 (arm920T, with MMU), * at91sam926x (arm926ejs, with MMU), and several no-mmu versions. * * This driver expects the board has been wired with two GPIOs suppporting * a VBUS sensing IRQ, and a D+ pullup.  (They may be omitted, but the * testing hasn't covered such cases.) * * The pullup is most important (so it's integrated on sam926x parts).  It * provides software control over whether the host enumerates the device. * * The VBUS sensing helps during enumeration, and allows both USB clocks * (and the transceiver) to stay gated off until they're necessary, saving * power.  During USB suspend, the 48 MHz clock is gated off in hardware; * it may also be gated off by software during some Linux sleep states. */#define	DRIVER_VERSION	"3 May 2006"static const char driver_name [] = "at91_udc";static const char ep0name[] = "ep0";#define at91_udp_read(dev, reg) \	__raw_readl((dev)->udp_baseaddr + (reg))#define at91_udp_write(dev, reg, val) \	__raw_writel((val), (dev)->udp_baseaddr + (reg))/*-------------------------------------------------------------------------*/#ifdef CONFIG_USB_GADGET_DEBUG_FILES#include <linux/seq_file.h>static const char debug_filename[] = "driver/udc";#define FOURBITS "%s%s%s%s"#define EIGHTBITS FOURBITS FOURBITSstatic void proc_ep_show(struct seq_file *s, struct at91_ep *ep){	static char		*types[] = {		"control", "out-iso", "out-bulk", "out-int",		"BOGUS",   "in-iso",  "in-bulk",  "in-int"};	u32			csr;	struct at91_request	*req;	unsigned long	flags;	local_irq_save(flags);	csr = __raw_readl(ep->creg);	/* NOTE:  not collecting per-endpoint irq statistics... */	seq_printf(s, "\n");	seq_printf(s, "%s, maxpacket %d %s%s %s%s\n",			ep->ep.name, ep->ep.maxpacket,			ep->is_in ? "in" : "out",			ep->is_iso ? " iso" : "",			ep->is_pingpong				? (ep->fifo_bank ? "pong" : "ping")				: "",			ep->stopped ? " stopped" : "");	seq_printf(s, "csr %08x rxbytes=%d %s %s %s" EIGHTBITS "\n",		csr,		(csr & 0x07ff0000) >> 16,		(csr & (1 << 15)) ? "enabled" : "disabled",		(csr & (1 << 11)) ? "DATA1" : "DATA0",		types[(csr & 0x700) >> 8],		/* iff type is control then print current direction */		(!(csr & 0x700))			? ((csr & (1 << 7)) ? " IN" : " OUT")			: "",		(csr & (1 << 6)) ? " rxdatabk1" : "",		(csr & (1 << 5)) ? " forcestall" : "",		(csr & (1 << 4)) ? " txpktrdy" : "",		(csr & (1 << 3)) ? " stallsent" : "",		(csr & (1 << 2)) ? " rxsetup" : "",		(csr & (1 << 1)) ? " rxdatabk0" : "",		(csr & (1 << 0)) ? " txcomp" : "");	if (list_empty (&ep->queue))		seq_printf(s, "\t(queue empty)\n");	else list_for_each_entry (req, &ep->queue, queue) {		unsigned	length = req->req.actual;		seq_printf(s, "\treq %p len %d/%d buf %p\n",				&req->req, length,				req->req.length, req->req.buf);	}	local_irq_restore(flags);}static void proc_irq_show(struct seq_file *s, const char *label, u32 mask){	int i;	seq_printf(s, "%s %04x:%s%s" FOURBITS, label, mask,		(mask & (1 << 13)) ? " wakeup" : "",		(mask & (1 << 12)) ? " endbusres" : "",		(mask & (1 << 11)) ? " sofint" : "",		(mask & (1 << 10)) ? " extrsm" : "",		(mask & (1 << 9)) ? " rxrsm" : "",		(mask & (1 << 8)) ? " rxsusp" : "");	for (i = 0; i < 8; i++) {		if (mask & (1 << i))			seq_printf(s, " ep%d", i);	}	seq_printf(s, "\n");}static int proc_udc_show(struct seq_file *s, void *unused){	struct at91_udc	*udc = s->private;	struct at91_ep	*ep;	u32		tmp;	seq_printf(s, "%s: version %s\n", driver_name, DRIVER_VERSION);	seq_printf(s, "vbus %s, pullup %s, %s powered%s, gadget %s\n\n",		udc->vbus ? "present" : "off",		udc->enabled			? (udc->vbus ? "active" : "enabled")			: "disabled",		udc->selfpowered ? "self" : "VBUS",		udc->suspended ? ", suspended" : "",		udc->driver ? udc->driver->driver.name : "(none)");	/* don't access registers when interface isn't clocked */	if (!udc->clocked) {		seq_printf(s, "(not clocked)\n");		return 0;	}	tmp = at91_udp_read(udc, AT91_UDP_FRM_NUM);	seq_printf(s, "frame %05x:%s%s frame=%d\n", tmp,		(tmp & AT91_UDP_FRM_OK) ? " ok" : "",		(tmp & AT91_UDP_FRM_ERR) ? " err" : "",		(tmp & AT91_UDP_NUM));	tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);	seq_printf(s, "glbstate %02x:%s" FOURBITS "\n", tmp,		(tmp & AT91_UDP_RMWUPE) ? " rmwupe" : "",		(tmp & AT91_UDP_RSMINPR) ? " rsminpr" : "",		(tmp & AT91_UDP_ESR) ? " esr" : "",		(tmp & AT91_UDP_CONFG) ? " confg" : "",		(tmp & AT91_UDP_FADDEN) ? " fadden" : "");	tmp = at91_udp_read(udc, AT91_UDP_FADDR);	seq_printf(s, "faddr   %03x:%s fadd=%d\n", tmp,		(tmp & AT91_UDP_FEN) ? " fen" : "",		(tmp & AT91_UDP_FADD));	proc_irq_show(s, "imr   ", at91_udp_read(udc, AT91_UDP_IMR));	proc_irq_show(s, "isr   ", at91_udp_read(udc, AT91_UDP_ISR));	if (udc->enabled && udc->vbus) {		proc_ep_show(s, &udc->ep[0]);		list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {			if (ep->desc)				proc_ep_show(s, ep);		}	}	return 0;}static int proc_udc_open(struct inode *inode, struct file *file){	return single_open(file, proc_udc_show, PDE(inode)->data);}static const struct file_operations proc_ops = {	.open		= proc_udc_open,	.read		= seq_read,	.llseek		= seq_lseek,	.release	= single_release,};static void create_debug_file(struct at91_udc *udc){	struct proc_dir_entry *pde;	pde = create_proc_entry (debug_filename, 0, NULL);	udc->pde = pde;	if (pde == NULL)		return;	pde->proc_fops = &proc_ops;	pde->data = udc;}static void remove_debug_file(struct at91_udc *udc){	if (udc->pde)		remove_proc_entry(debug_filename, NULL);}#elsestatic inline void create_debug_file(struct at91_udc *udc) {}static inline void remove_debug_file(struct at91_udc *udc) {}#endif/*-------------------------------------------------------------------------*/static void done(struct at91_ep *ep, struct at91_request *req, int status){	unsigned	stopped = ep->stopped;	struct at91_udc	*udc = ep->udc;	list_del_init(&req->queue);	if (req->req.status == -EINPROGRESS)		req->req.status = status;	else		status = req->req.status;	if (status && status != -ESHUTDOWN)		VDBG("%s done %p, status %d\n", ep->ep.name, req, status);	ep->stopped = 1;	req->req.complete(&ep->ep, &req->req);	ep->stopped = stopped;	/* ep0 is always ready; other endpoints need a non-empty queue */	if (list_empty(&ep->queue) && ep->int_mask != (1 << 0))		at91_udp_write(udc, AT91_UDP_IDR, ep->int_mask);}/*-------------------------------------------------------------------------*//* bits indicating OUT fifo has data ready */#define	RX_DATA_READY	(AT91_UDP_RX_DATA_BK0 | AT91_UDP_RX_DATA_BK1)/* * Endpoint FIFO CSR bits have a mix of bits, making it unsafe to just write * back most of the value you just read (because of side effects, including * bits that may change after reading and before writing). * * Except when changing a specific bit, always write values which: *  - clear SET_FX bits (setting them could change something) *  - set CLR_FX bits (clearing them could change something) * * There are also state bits like FORCESTALL, EPEDS, DIR, and EPTYPE * that shouldn't normally be changed. * * NOTE at91sam9260 docs mention synch between UDPCK and MCK clock domains, * implying a need to wait for one write to complete (test relevant bits) * before starting the next write.  This shouldn't be an issue given how * infrequently we write, except maybe for write-then-read idioms. */#define	SET_FX	(AT91_UDP_TXPKTRDY)#define	CLR_FX	(RX_DATA_READY | AT91_UDP_RXSETUP \		| AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)/* pull OUT packet data from the endpoint's fifo */static int read_fifo (struct at91_ep *ep, struct at91_request *req){	u32 __iomem	*creg = ep->creg;	u8 __iomem	*dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));	u32		csr;	u8		*buf;	unsigned int	count, bufferspace, is_done;	buf = req->req.buf + req->req.actual;	bufferspace = req->req.length - req->req.actual;	/*	 * there might be nothing to read if ep_queue() calls us,	 * or if we already emptied both pingpong buffers	 */rescan:	csr = __raw_readl(creg);	if ((csr & RX_DATA_READY) == 0)		return 0;	count = (csr & AT91_UDP_RXBYTECNT) >> 16;	if (count > ep->ep.maxpacket)		count = ep->ep.maxpacket;	if (count > bufferspace) {		DBG("%s buffer overflow\n", ep->ep.name);		req->req.status = -EOVERFLOW;		count = bufferspace;	}	__raw_readsb(dreg, buf, count);	/* release and swap pingpong mem bank */	csr |= CLR_FX;	if (ep->is_pingpong) {		if (ep->fifo_bank == 0) {			csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);			ep->fifo_bank = 1;		} else {			csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK1);			ep->fifo_bank = 0;		}	} else		csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);	__raw_writel(csr, creg);	req->req.actual += count;	is_done = (count < ep->ep.maxpacket);	if (count == bufferspace)		is_done = 1;	PACKET("%s %p out/%d%s\n", ep->ep.name, &req->req, count,			is_done ? " (done)" : "");	/*	 * avoid extra trips through IRQ logic for packets already in	 * the fifo ... maybe preventing an extra (expensive) OUT-NAK	 */	if (is_done)		done(ep, req, 0);	else if (ep->is_pingpong) {		bufferspace -= count;		buf += count;		goto rescan;	}	return is_done;}/* load fifo for an IN packet */static int write_fifo(struct at91_ep *ep, struct at91_request *req){	u32 __iomem	*creg = ep->creg;	u32		csr = __raw_readl(creg);	u8 __iomem	*dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));	unsigned	total, count, is_last;	/*	 * TODO: allow for writing two packets to the fifo ... that'll	 * reduce the amount of IN-NAKing, but probably won't affect	 * throughput much.  (Unlike preventing OUT-NAKing!)	 */	/*	 * If ep_queue() calls us, the queue is empty and possibly in	 * odd states like TXCOMP not yet cleared (we do it, saving at	 * least one IRQ) or the fifo not yet being free.  Those aren't	 * issues normally (IRQ handler fast path).	 */	if (unlikely(csr & (AT91_UDP_TXCOMP | AT91_UDP_TXPKTRDY))) {		if (csr & AT91_UDP_TXCOMP) {			csr |= CLR_FX;			csr &= ~(SET_FX | AT91_UDP_TXCOMP);			__raw_writel(csr, creg);			csr = __raw_readl(creg);		}		if (csr & AT91_UDP_TXPKTRDY)			return 0;	}	total = req->req.length - req->req.actual;	if (ep->ep.maxpacket < total) {		count = ep->ep.maxpacket;		is_last = 0;	} else {		count = total;		is_last = (count < ep->ep.maxpacket) || !req->req.zero;	}	/*	 * Write the packet, maybe it's a ZLP.	 *	 * NOTE:  incrementing req->actual before we receive the ACK means	 * gadget driver IN bytecounts can be wrong in fault cases.  That's	 * fixable with PIO drivers like this one (save "count" here, and	 * do the increment later on TX irq), but not for most DMA hardware.	 *	 * So all gadget drivers must accept that potential error.  Some	 * hardware supports precise fifo status reporting, letting them	 * recover when the actual bytecount matters (e.g. for USB Test	 * and Measurement Class devices).	 */	__raw_writesb(dreg, req->req.buf + req->req.actual, count);	csr &= ~SET_FX;	csr |= CLR_FX | AT91_UDP_TXPKTRDY;	__raw_writel(csr, creg);	req->req.actual += count;	PACKET("%s %p in/%d%s\n", ep->ep.name, &req->req, count,			is_last ? " (done)" : "");	if (is_last)		done(ep, req, 0);	return is_last;}static void nuke(struct at91_ep *ep, int status){	struct at91_request *req;	// terminer chaque requete dans la queue	ep->stopped = 1;	if (list_empty(&ep->queue))		return;	VDBG("%s %s\n", __FUNCTION__, ep->ep.name);

⌨️ 快捷键说明

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