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

📄 wmmx.c

📁 S3C2440ARM9开发板的USB驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * wmmx.c -- Bulverde USB Device Controller driver. * * 09/04/2003 * Stanley Cai (stanley.cai@intel.com) ported the driver to Bulverde  * Mainstone. * * Changes Copyright (c) 2003 MontaVista Software Inc. * Author: MontaVista Software, Inc. *      source@mvista.com * * Based on work: * Copyright (c) 2000, 2001, 2002 Lineo * * By:  *      Stuart Lynne <sl@lineo.com>,  *      Tom Rushworth <tbr@lineo.com>,  * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * *  * *//* * This code was developed on the Intel Mainstone with Bulverde processor */#include <linux/config.h>#include <linux/module.h>#include "../usbd-export.h"#include "../usbd-build.h"#include "../usbd-module.h"#include "../usbd-debug.h"MODULE_DESCRIPTION ("WMMX USB Device Bus Interface");USBD_MODULE_INFO ("wmmx_bi 0.2-alpha");MODULE_LICENSE("GPL");#include <linux/kernel.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/init.h>#include <asm/atomic.h>#include <asm/io.h>#include <linux/proc_fs.h>#include <linux/vmalloc.h>#include <linux/netdevice.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/types.h>#include <asm/uaccess.h>#include <asm/io.h>#include <linux/delay.h>#include <asm/hardware.h>#include <asm/dma.h>#include "../usbd.h"#include "../usbd-func.h"#include "../usbd-bus.h"#include "../usbd-inline.h"#include "usbd-bi.h"#include "wmmx.h"#define WMMX_TRACE#undef WMMX_TRACE#define WMMX_XFER_DIR_OUT		0#define WMMX_XFER_DIR_IN		1#ifdef WMMX_TRACE#define TRACE_MAX       		10000#define WMMX_XFER_MAX_TRACE_SIZE	16typedef enum wwmx_trace_type {       wmmx_regs,        wmmx_setup,        wmmx_xmit,        wmmx_ccr,        wmmx_iro,       wmmx_xfer} wmmx_trace_type_t;typedef struct wmmx_regs {        u32     cs0;        char *  msg;} wmmx_regs_t;typedef struct wmmx_xmit {        u32     size;} wmmx_xmit_t;typedef struct wmmx_ccr {        u32     ccr;        char *  msg;} wmmx_ccr_t;typedef struct wmmx_iro {        u32     iro;        char *  msg;} wmmx_iro_t;typedef struct wmmx_xfer {	char	dir;	u32	size;	char    data[WMMX_XFER_MAX_TRACE_SIZE];} wmmx_xfer_t;typedef struct wmmx_trace {        wmmx_trace_type_t        trace_type;        u32     interrupts;        u32     ocsr;        u64     jiffies;        union {                wmmx_regs_t       regs;                wmmx_xmit_t       xmit;                wmmx_ccr_t        ccr;                wmmx_iro_t        iro;		wmmx_xfer_t	  xfer;                struct usb_device_request       setup;        } trace;} wmmx_trace_t;int trace_next;wmmx_trace_t *wmmx_traces;static __inline__ void WMMX_REGS(u32 cs0, char *msg){	if ((trace_next < TRACE_MAX) && wmmx_traces) {		wmmx_trace_t *p = wmmx_traces + trace_next++;		p->ocsr = OSCR;		p->jiffies = jiffies;		p->interrupts = udc_interrupts;		p->trace_type = wmmx_regs;		p->trace.regs.cs0 = cs0;		p->trace.regs.msg = msg;	}}static __inline__ void WMMX_SETUP(struct usb_device_request *setup){	if ((trace_next < TRACE_MAX) && wmmx_traces) {		wmmx_trace_t *p = wmmx_traces + trace_next++;		p->ocsr = OSCR;		p->jiffies = jiffies;		p->interrupts = udc_interrupts;		p->trace_type = wmmx_setup;		memcpy(&p->trace.setup, setup, sizeof(struct usb_device_request));	}}static __inline__ void WMMX_XMIT(u32 size){	if ((trace_next < TRACE_MAX) && wmmx_traces) {		wmmx_trace_t *p = wmmx_traces + trace_next++;		p->ocsr = OSCR;		p->jiffies = jiffies;		p->interrupts = udc_interrupts;		p->trace_type = wmmx_xmit;		p->trace.xmit.size = size;	}}static __inline__ void WMMX_CCR(u32 ccr, char *msg){	if ((trace_next < TRACE_MAX) && wmmx_traces) {		wmmx_trace_t *p = wmmx_traces + trace_next++;		p->ocsr = OSCR;		p->jiffies = jiffies;		p->interrupts = udc_interrupts;		p->trace_type = wmmx_ccr;		p->trace.ccr.ccr = ccr;		p->trace.ccr.msg = msg;	}}static __inline__ void WMMX_IRO(u32 iro, char *msg){	if ((trace_next < TRACE_MAX) && wmmx_traces) {		wmmx_trace_t *p = wmmx_traces + trace_next++;		p->ocsr = OSCR;		p->jiffies = jiffies;		p->interrupts = udc_interrupts;		p->trace_type = wmmx_iro;		p->trace.iro.iro = iro;		p->trace.iro.msg = msg;	}}static __inline__ void WMMX_XFER(char dir, u32 size, char *data){	if ((trace_next < TRACE_MAX) && wmmx_traces) {		wmmx_trace_t *p = wmmx_traces + trace_next++;		p->ocsr = OSCR;		p->jiffies = jiffies;		p->interrupts = udc_interrupts;		p->trace_type = wmmx_xfer;		p->trace.xfer.dir = dir;		p->trace.xfer.size = size;		if (size > WMMX_XFER_MAX_TRACE_SIZE)			size = WMMX_XFER_MAX_TRACE_SIZE;		memcpy(&p->trace.xfer.data, data, size);	}}#elsestatic __inline__ void WMMX_REGS(u32 cs0, char *msg){}static __inline__ void WMMX_SETUP(struct usb_device_request *setup){}static __inline__ void WMMX_XMIT(u32 size){}static __inline__ void WMMX_CCR(u32 ccr, char *msg){}static __inline__ void WMMX_IRO(u32 iro, char *msg){}static __inline__ void WMMX_XFER(char dir, u32 size, char *data){}#endif#define WMMX_XFER_DIR_OUT		0#define WMMX_XFER_DIR_IN		1static int winhost_flag = 0;static int udcbegin_flag = 1;static int udc_suspended;static struct usb_device_instance *udc_device; /* *  physical endpoints to logical endpoints */static struct usb_endpoint_instance *phys_ep_to_endpoints[UDC_MAX_ENDPOINTS];static int logic_to_phys_eps[MAX_LOGICAL_CONFIGURATIONS][MAX_LOGICAL_ENDPOINTS];static struct urb *ep0_urb;extern unsigned int udc_interrupts;static int jifs(void){	static unsigned long jiffies_last;	int elapsed = OSCR - jiffies_last;	jiffies_last = OSCR;	return elapsed;}/* * Map logical to physical */typedef enum ep {        ep_control   = 0x0, 	ep_bulk_in   = 0x5, 	ep_bulk_out  = 0x4, 	ep_iso_in    = 0x3, 	ep_iso_out   = 0x2, 	ep_interrupt = 0x7} ep_t;struct ep_map {	int             logical;	ep_t            eptype;	int             size;	int             dma_chan;	volatile u32 *  drcmr;	int             accum_size;};static struct ep_map ep_maps[UDC_MAX_ENDPOINTS]={	{ logical: 0, eptype: ep_control,   size: 16, },};struct wmmx_usb_dma_config {	int dma_enabled;	int dma_channel;	int ep;					/* physical endpoints */	struct usb_endpoint_instance* endpoint;	/* endpoint instance */	int size;	u8* dma_buffer; 			/* DMA data buffer */	dma_addr_t dma_phys_buffer;};struct wmmx_usb_dma_config wmmx_usb_dma_configs[UDC_MAX_ENDPOINTS];struct wmmx_usb_dma_config *wmmx_dmach_to_configs[16];#define DMA_BUFFER_SIZE 4096unsigned char* wmmx_usb_dma_buffer,*wmmx_usb_dma_next;dma_addr_t wmmx_usb_dma_phys_buffer;#define WMMX_STORAGE_ACCUM_SIZE	512/* Note:  Please don't add any instruction to try print some messages in the  * function. Any careless operation will cause the timing runing away. */static __inline__ int  wmmx_logic_to_phys_ep(int logic){	int config;	config = (UDCCR & UDCCR_ACN) >> UDCCR_ACN_S;	return logic_to_phys_eps[config][logic];}static __inline__ void wmmx_enable_ep_interrupt(int phys_ep, u8 irq_type){	irq_type &= (UDC_INT_FIFOERROR | UDC_INT_PACKETCMP);        if (phys_ep < 16) {                UDCICR0 |= irq_type << (phys_ep << 1);        } else {                UDCICR1 |= irq_type << ((phys_ep - 16) << 1);        }}static __inline__ void wmmx_disable_ep_interrupt(int phys_ep, u8 irq_type){	irq_type &= (UDC_INT_FIFOERROR | UDC_INT_PACKETCMP);	if (phys_ep < 16) {		UDCICR0 &= ~(irq_type << (phys_ep << 1));	} else {		UDCICR1 &= ~(irq_type << ((phys_ep - 16) << 1));        }}static __inline__ void wmmx_ep_reset_interrupt_status(int phys_ep){	const int intstat = (UDC_INT_FIFOERROR | UDC_INT_PACKETCMP);	if (phys_ep < 16) {		UDCISR0 = (intstat << (phys_ep << 1));	} else {		UDCISR1 = (intstat << ((phys_ep - 16) << 1));	}}static __inline__ void wmmx_out_flush(int phys_ep) {	u32 data;	int len = UDCBCN(phys_ep);		WMMX_XMIT(len);		while (len > 0) {                data = UDCDN(phys_ep);		len -= 4;        }}static void wmmx_out_n(int phys_ep, struct usb_endpoint_instance *endpoint){	wmmx_ep_reset_interrupt_status(phys_ep);	if (UDCCSN(phys_ep) & UDCCSR_PC) {		if (endpoint) {			if (!endpoint->rcv_urb) {				endpoint->rcv_urb = 					first_urb_detached(&endpoint->rdy);                        }                         if (endpoint->rcv_urb) {				int len = 0;				int stop_accumulation;				u32 *cp = (u32*)(endpoint->rcv_urb->buffer + 						 endpoint->rcv_urb->actual_length);				if (cp) {					int count = MIN(UDCBCN(phys_ep), 							endpoint->rcv_packetSize);					len = count;					while (count > 0) {						*cp++ = UDCDN(phys_ep);						count -= 4;					}					/* clear PC and interrupt */					UDCCSN(phys_ep) = UDCCSR_PC | 							  (UDCCSR_WR_MASK &							   UDCCSN(phys_ep));				} else {					wmmx_out_flush(phys_ep);				}        								stop_accumulation = ((ep_maps[phys_ep].accum_size > 0) &&						     (endpoint->rcv_urb->actual_length + len ==						      ep_maps[phys_ep].accum_size));				WMMX_XFER(WMMX_XFER_DIR_OUT, len, endpoint->rcv_urb->buffer +					  endpoint->rcv_urb->actual_length);				/* fall through if error of any type, len = 0 */				usbd_rcv_complete_irq (endpoint, len, 0);				/* simulate ZLP to stop accumulating the data and				 * send the received data to the storage driver				 */				if (stop_accumulation)				{					usbd_rcv_complete_irq (endpoint, 0, 0);				}				return;			} else {				wmmx_out_flush(phys_ep);			}		}	}	UDCCSN(phys_ep) = (UDCCSN(phys_ep) & UDCCSR_WR_MASK) |			  UDCCSR_PC;}static void wmmx_start_n_dma(unsigned int phys_ep, 			     struct usb_endpoint_instance *endpoint){	if (endpoint->tx_urb) {		int last;		struct wmmx_usb_dma_config* config = &wmmx_usb_dma_configs[phys_ep];		int channel = config->dma_channel;		struct urb* urb = endpoint->tx_urb;		if ((last = MIN(urb->actual_length - 				(endpoint->sent + endpoint->last), 				endpoint->tx_packetSize))) {			config->size = last;						WMMX_XFER(WMMX_XFER_DIR_IN, last, urb->buffer + endpoint->sent);						memcpy(config->dma_buffer, 			       urb->buffer + endpoint->sent, 			       last);			/* Enable End of Receive IRQ */			DCSR(channel) = DCSR_NODESC | DCSR_EORIRQEN;			DTADR(channel) = PHYS_UDCDN(phys_ep);			DSADR(channel) = config->dma_phys_buffer;			DCMD(channel) = DCMD_INCSRCADDR | 					DCMD_FLOWTRG | 					DCMD_ENDIRQEN | 					DCMD_BURST32 | 					DCMD_WIDTH4 | 					(last & DCMD_LENGTH);			DRCMRUDC(phys_ep) = DRCMR_MAPVLD | channel;			DCSR(channel) |= DCSR_RUN;		} else {			usbd_tx_complete_irq (endpoint, 0);		}	}}static void wmmx_usb_dma_tx_irq(int dmach, void* dev_id, struct pt_regs *regs){	unsigned int dcsr = DCSR(dmach);	struct wmmx_usb_dma_config* config = wmmx_dmach_to_configs[dmach];	struct usb_endpoint_instance* endpoint = config->endpoint;	static int timeout;	DCSR(dmach) &= ~DCSR_RUN;	if (dcsr & DCSR_BUSERR) {		DCSR(dmach) |= DCSR_BUSERR;		printk(KERN_ERR "BUS error.\n");	} else if (dcsr & DCSR_ENDINTR) {		DCSR(dmach) |= DCSR_ENDINTR;		if (config->size < endpoint->tx_packetSize) {			UDCCSN(config->ep) = (UDCCSN(config->ep) & 					      UDCCSR_WR_MASK) |					      UDCCSR_SP;#if 0			/* It may be incorrect to wait in the interrupt handler			 * until the FIFO will have enough room for at least			 * one packet			 */			/* Here we should add some delays */			timeout = 0;			while (!(UDCCSN(config->ep) & UDCCSR_FS)) {				if (timeout++ == 100) {					printk(KERN_ERR "UDCCSN(%d)=%08x\n", 					       config->ep, UDCCSN(config->ep));					break;				}				udelay(1);			}#endif		}		endpoint->last += config->size;	} else		printk(KERN_ERR"DCSR(%d) = 0x%08x\n", dmach, DCSR(dmach));

⌨️ 快捷键说明

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