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

📄 s3c2410_udc.c

📁 2.4核linux的s3c2410-udc驱动代码!经过调试了!
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * linux/drivers/usb/gadget/s3c2410_udc.c * Samsung on-chip full speed USB device controllers * * Copyright (C) 2004 Herbert Pötzl - Arnaud Patard * * 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 * */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/timer.h>#include <linux/list.h>#include <linux/interrupt.h>#include <linux/version.h>#include <linux/usb.h>#include <linux/usb_gadget.h>#include <asm/byteorder.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/unaligned.h>#include <asm/arch/irqs.h>#include <asm/arch/hardware.h>#include <asm/arch/regs-clock.h>#include <asm/arch/regs-gpio.h>#include <asm/arch/regs-udc.h>#include <asm/arch/s3c2410_udc.h>#include <asm/hardware/clock.h>#include "s3c2410_udc.h"#define ENABLE_SYSFS#define DRIVER_DESC     "S3C2410 USB Device Controller Gadget"#define DRIVER_VERSION  "14 Mar 2005"#define DRIVER_AUTHOR	"Herbert Pötzl <herbert@13thfloor.at>, Arnaud Patard <arnaud.patard@rtp-net.org>"static const char       gadget_name [] = "s3c2410_udc";static const char	driver_desc [] = DRIVER_DESC;static struct s3c2410_udc	*the_controller;static struct clk      		*udc_clock;static struct s3c2410_udc_mach_info *udc_info;#define CONFIG_USB_S3C2410_DEBUG/*************************** DEBUG FUNCTION ***************************/#define DEBUG_NORMAL	1#define DEBUG_VERBOSE	2#ifdef CONFIG_USB_S3C2410_DEBUG#define USB_S3C2410_DEBUG_LEVEL 1uint32_t s3c2410_ticks=0;static int dprintk(int level, const char *fmt, ...){	static char printk_buf[1024];	static long prevticks;	static int invocation;	va_list args;	int len;		if (level > USB_S3C2410_DEBUG_LEVEL)		return 0;		if (s3c2410_ticks != prevticks) {		prevticks = s3c2410_ticks;		invocation = 0;	}		len = scnprintf(printk_buf, \			sizeof(printk_buf), "%1lu.%02d USB: ", \			prevticks, invocation++);	va_start(args, fmt);	len = vscnprintf(printk_buf+len, \			sizeof(printk_buf)-len, fmt, args);	va_end(args);		return printk("%s", printk_buf);}#elsestatic int dprintk(int level, const char *fmt, ...)  { return 0; }#endif#ifdef ENABLE_SYSFSstatic ssize_t s3c2410udc_regs_show(struct device *dev, char *buf){	u32 addr_reg,pwr_reg,ep_int_reg,usb_int_reg;	u32 ep_int_en_reg, usb_int_en_reg, ep0_csr;	u32 ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2;	u32 ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2;		addr_reg       = __raw_readl(S3C2410_UDC_FUNC_ADDR_REG);	pwr_reg        = __raw_readl(S3C2410_UDC_PWR_REG);	ep_int_reg     = __raw_readl(S3C2410_UDC_EP_INT_REG);	usb_int_reg    = __raw_readl(S3C2410_UDC_USB_INT_REG);	ep_int_en_reg  = __raw_readl(S3C2410_UDC_EP_INT_EN_REG);	usb_int_en_reg = __raw_readl(S3C2410_UDC_USB_INT_EN_REG);	__raw_writel(0, S3C2410_UDC_INDEX_REG);	ep0_csr        = __raw_readl(S3C2410_UDC_IN_CSR1_REG);	__raw_writel(1, S3C2410_UDC_INDEX_REG);	ep1_i_csr1     = __raw_readl(S3C2410_UDC_IN_CSR1_REG);	ep1_i_csr2     = __raw_readl(S3C2410_UDC_IN_CSR2_REG);	ep1_o_csr1     = __raw_readl(S3C2410_UDC_IN_CSR1_REG);	ep1_o_csr2     = __raw_readl(S3C2410_UDC_IN_CSR2_REG);	__raw_writel(2, S3C2410_UDC_INDEX_REG);	ep2_i_csr1     = __raw_readl(S3C2410_UDC_IN_CSR1_REG);	ep2_i_csr2     = __raw_readl(S3C2410_UDC_IN_CSR2_REG);	ep2_o_csr1     = __raw_readl(S3C2410_UDC_IN_CSR1_REG);	ep2_o_csr2     = __raw_readl(S3C2410_UDC_IN_CSR2_REG);		return snprintf(buf, PAGE_SIZE,        \		 "FUNC_ADDR_REG  : 0x%04X\n"   \		 "PWR_REG        : 0x%04X\n"   \		 "EP_INT_REG     : 0x%04X\n"   \		 "USB_INT_REG    : 0x%04X\n"   \		 "EP_INT_EN_REG  : 0x%04X\n"   \		 "USB_INT_EN_REG : 0x%04X\n"   \		 "EP0_CSR        : 0x%04X\n"   \		 "EP1_I_CSR1     : 0x%04X\n"   \		 "EP1_I_CSR2     : 0x%04X\n"   \		 "EP1_O_CSR1     : 0x%04X\n"   \		 "EP1_O_CSR2     : 0x%04X\n"   \		 "EP2_I_CSR1     : 0x%04X\n"   \		 "EP2_I_CSR2     : 0x%04X\n"   \		 "EP2_O_CSR1     : 0x%04X\n"   \		 "EP2_O_CSR2     : 0x%04X\n",  \		 addr_reg,pwr_reg,ep_int_reg,usb_int_reg,     \		 ep_int_en_reg, usb_int_en_reg, ep0_csr,      \		 ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2, \		 ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2  \		 );}static DEVICE_ATTR(regs, 0444,		   s3c2410udc_regs_show,		   NULL);#endif/*------------------------- I/O ----------------------------------*/static void nuke (struct s3c2410_udc *udc, struct s3c2410_ep *ep){	/* Sanity check */	if (&ep->queue != NULL)		while (!list_empty (&ep->queue)) {			struct s3c2410_request  *req;			req = list_entry (ep->queue.next, struct s3c2410_request, queue);			list_del_init (&req->queue);			req->req.status = -ESHUTDOWN;			spin_unlock (&udc->lock);			req->req.complete (&ep->ep, &req->req);			spin_lock (&udc->lock);		}}/* * 	done */static void done(struct s3c2410_ep *ep, struct s3c2410_request *req, int status){	list_del_init(&req->queue);	if (likely (req->req.status == -EINPROGRESS))		req->req.status = status;	else		status = req->req.status;	req->req.complete(&ep->ep, &req->req);}static inline void clear_ep_state (struct s3c2410_udc *dev){	        unsigned i;				/* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint		 * fifos, and pending transactions mustn't be continued in any case.		 */		 for (i = 1; i < S3C2410_ENDPOINTS; i++)			 nuke(dev, &dev->ep[i]);}static inline int fifo_count_out(void){	int tmp;		tmp = __raw_readl(S3C2410_UDC_OUT_FIFO_CNT2_REG) << 8;	tmp |= __raw_readl(S3C2410_UDC_OUT_FIFO_CNT1_REG);		return tmp & 0xffff;}/* * 	write_packet */static inline int write_packet(u32 fifo, struct s3c2410_request *req, unsigned max){	unsigned	len;	u8		*buf;	buf = req->req.buf + req->req.actual;	len = min(req->req.length - req->req.actual, max);	dprintk(DEBUG_VERBOSE, "write_packet %d %d %d ",req->req.actual,req->req.length,len);	req->req.actual += len;	dprintk(DEBUG_VERBOSE, "%d\n",req->req.actual);	max = len;	while (max--)		 __raw_writel(*buf++,fifo);	return len;}/* * 	write_fifo */// return:  0 = still running, 1 = completed, negative = errnostatic int write_fifo(struct s3c2410_ep *ep, struct s3c2410_request *req){	u8		*buf;	unsigned	count;	int		is_last;	u32		idx,fifo_reg;	u32		ep_csr;	switch(ep->bEndpointAddress&0x7F)	{		default:		case 0: idx = 0;			fifo_reg = S3C2410_UDC_EP0_FIFO_REG;			break;		case 1:			idx = 1;			fifo_reg = S3C2410_UDC_EP1_FIFO_REG;			break;		case 2:			idx = 2;			fifo_reg = S3C2410_UDC_EP2_FIFO_REG;			break;		case 3:			idx = 3;			fifo_reg = S3C2410_UDC_EP3_FIFO_REG;			break;		case 4:			idx = 4;			fifo_reg = S3C2410_UDC_EP4_FIFO_REG;			break;	}		buf = req->req.buf + req->req.actual;	prefetch(buf);	count = ep->ep.maxpacket;	count = write_packet(fifo_reg, req, count);	/* last packet is often short (sometimes a zlp) */	if (count < ep->ep.maxpacket)		is_last = 1;	else if (req->req.length == req->req.actual			&& !req->req.zero)		is_last = 2;	else		is_last = 0;	dprintk(DEBUG_VERBOSE, "Written ep%d %d. %d of %d b [last %d]\n",idx,count,req->req.actual,req->req.length,is_last);	if (is_last)	{		/* The order is important. It prevents to send 2 packet at the same time		 **/		if (!idx)		{			set_ep0_de_in();			ep->dev->ep0state=EP0_IDLE;		}		else		{			 __raw_writel(idx, S3C2410_UDC_INDEX_REG);			 ep_csr=__raw_readl(S3C2410_UDC_IN_CSR1_REG);			 __raw_writel(idx, S3C2410_UDC_INDEX_REG);			 __raw_writel(ep_csr|S3C2410_UDC_ICSR1_PKTRDY,S3C2410_UDC_IN_CSR1_REG);		}		done(ep, req, 0);	}	else	{		if (!idx)		{			set_ep0_ipr();		}		else		{			__raw_writel(idx, S3C2410_UDC_INDEX_REG);			ep_csr=__raw_readl(S3C2410_UDC_IN_CSR1_REG);			__raw_writel(idx, S3C2410_UDC_INDEX_REG);			__raw_writel(ep_csr|S3C2410_UDC_ICSR1_PKTRDY,S3C2410_UDC_IN_CSR1_REG);		}	}	return is_last;}static inline int read_packet(u32 fifo, u8 *buf, struct s3c2410_request *req, unsigned avail){	unsigned	len;	len = min(req->req.length - req->req.actual, avail);	req->req.actual += len;	avail = len;	while (avail--)		*buf++ = (unsigned char)__raw_readl(fifo);	return len;}// return:  0 = still running, 1 = queue empty, negative = errnostatic int read_fifo(struct s3c2410_ep *ep, struct s3c2410_request *req){	u8		*buf;	u32		ep_csr;	unsigned	bufferspace;	int is_last=1;	unsigned avail;	int fifo_count = 0;	u32		idx,fifo_reg;	switch(ep->bEndpointAddress&0x7F)	{		default:		case 0: idx = 0;			fifo_reg = S3C2410_UDC_EP0_FIFO_REG;			break;		case 1:			idx = 1;			fifo_reg = S3C2410_UDC_EP1_FIFO_REG;			break;		case 2:			idx = 2;			fifo_reg = S3C2410_UDC_EP2_FIFO_REG;			break;		case 3:			idx = 3;			fifo_reg = S3C2410_UDC_EP3_FIFO_REG;			break;		case 4:			idx = 4;			fifo_reg = S3C2410_UDC_EP4_FIFO_REG;			break;	}	buf = req->req.buf + req->req.actual;	bufferspace = req->req.length - req->req.actual;	if (!bufferspace)	{		dprintk(DEBUG_NORMAL, "read_fifo: Buffer full !!\n");		return -1;	}	__raw_writel(idx, S3C2410_UDC_INDEX_REG);		        fifo_count = fifo_count_out();	dprintk(DEBUG_VERBOSE, "fifo_read fifo count : %d\n",fifo_count);	if (fifo_count > ep->ep.maxpacket)		avail = ep->ep.maxpacket;	else		avail = fifo_count;	fifo_count=read_packet(fifo_reg,buf,req,avail);	if (fifo_count < ep->ep.maxpacket) {		is_last = 1;		/* overflowed this request?  flush extra data */		if (fifo_count != avail) {			req->req.status = -EOVERFLOW;		}	} else {		if (req->req.length == req->req.actual) 			is_last = 1;		else			is_last = 0;	}	__raw_writel(idx, S3C2410_UDC_INDEX_REG);	fifo_count = fifo_count_out();			dprintk(DEBUG_VERBOSE, "fifo_read fifo count : %d [last %d]\n",fifo_count,is_last);		if (is_last) {		if (!idx)		{			set_ep0_de_out();			ep->dev->ep0state=EP0_IDLE;		}		else		{			__raw_writel(idx, S3C2410_UDC_INDEX_REG);			ep_csr=__raw_readl(S3C2410_UDC_OUT_CSR1_REG);			__raw_writel(idx, S3C2410_UDC_INDEX_REG);			__raw_writel(ep_csr&~S3C2410_UDC_OCSR1_PKTRDY,S3C2410_UDC_OUT_CSR1_REG);		}		done(ep, req, 0);		if (!list_empty(&ep->queue))		{			is_last=0;			req = container_of(ep->queue.next,				struct s3c2410_request, queue);		}		else			is_last=1;//		is_last = 0;	}	else	{		if (!idx)		{			clear_ep0_opr();		}		else		{				__raw_writel(idx, S3C2410_UDC_INDEX_REG);			ep_csr=__raw_readl(S3C2410_UDC_OUT_CSR1_REG);			__raw_writel(idx, S3C2410_UDC_INDEX_REG);			__raw_writel(ep_csr&~S3C2410_UDC_OCSR1_PKTRDY,S3C2410_UDC_OUT_CSR1_REG);		}	}		return is_last;}static intread_fifo_crq(struct usb_ctrlrequest *crq){	int bytes_read = 0;	int fifo_count = 0;	int i;			unsigned char *pOut = (unsigned char*)crq;		__raw_writel(0, S3C2410_UDC_INDEX_REG);		fifo_count = fifo_count_out();		BUG_ON( fifo_count > 8 );		dprintk(DEBUG_VERBOSE, "read_fifo_crq(): fifo_count=%d\n", fifo_count );	while( fifo_count-- ) {		i = 0;				do {			*pOut = (unsigned char)__raw_readl(S3C2410_UDC_EP0_FIFO_REG);			udelay( 10 );			i++;		} while((fifo_count_out() != fifo_count) && (i < 10));				if ( i == 10 ) {			dprintk(DEBUG_NORMAL, "read_fifo(): read failure\n");		}				pOut++;		bytes_read++;	}		dprintk(DEBUG_VERBOSE, "read_fifo_crq: len=%d %02x:%02x {%x,%x,%x}\n",			bytes_read, crq->bRequest, crq->bRequestType,			crq->wValue, crq->wIndex, crq->wLength);		return bytes_read;}/*------------------------- usb state machine -------------------------------*/static void handle_ep0(struct s3c2410_udc *dev){	u32			ep0csr;	struct s3c2410_ep	*ep = &dev->ep [0];	struct s3c2410_request	*req;	struct usb_ctrlrequest	crq;	if (list_empty(&ep->queue))    		req = 0;	else		req = list_entry(ep->queue.next, struct s3c2410_request, queue);  		__raw_writel(0, S3C2410_UDC_INDEX_REG);	ep0csr = __raw_readl(S3C2410_UDC_IN_CSR1_REG);	/* clear stall status */	if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) {		/* FIXME */		nuke(dev, ep);	    	dprintk(DEBUG_NORMAL, "... clear SENT_STALL ...\n");	    	clear_ep0_sst();	    	ep0csr &= ~(S3C2410_UDC_EP0_CSR_SENTSTL|S3C2410_UDC_EP0_CSR_SENDSTL);

⌨️ 快捷键说明

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