www.pudn.com > d11_dma.rar > d11_dma.c


/* 
********************************************************** 
* 
*			emp-d11 dma  linux driver program 
* 
********************************************************** 
*/ 
 
 
#include  
#include 		// must be include. 
#include 		// define printk() 
#include 			// define module_init &module_exit 
#include 			// define ioctl number. 
#include 		// define kmallloc ... 
#include  
#include  
#include  
#include 		// for proc filesystem. 
 
#include  
#include  
#include  
#include 			// define irq number. ex IRQ_EINTx etc. 
#include  
#include  
#include  
#include  
 
#include "d11.h" 
 
// define tracy function 
#ifdef DEBUG 
	#define DPRINTK( x... )	printk("d11_dma:" ##x) 
#else 
	#define DPRINTK( x... ) 
#endif 
 
 
#define DEVICE_NAME 		"d11_dma" 
#define DMA_MINOR			1 
 
static int  d11_dma_major = 0;		/* Define major device number -- auto allocate!*/ 
 
struct image_dma_t image_review_buf; 
static unsigned int d11_dma_ucount = 0; 
static unsigned char flag_unfreeze = 0; 
wait_queue_head_t d11_dma_queue; 
 
static struct proc_dir_entry *d11_dma_proc_entry; 
 
#define FPGA_DMA0	0x28000000	/* fpga's dma source address */ 
 
/* 
**************************************************************** 
* 
*			EINT2 ISR 
* 
**************************************************************** 
*/ 
static void handler_isr_eint2(int irq, void* dev_irq, struct pt_regs* reg) 
{ 
	dma_addr_t d11_dma_phy; 
	 
	DPRINTK("d11b dma module EINT2 happen!\n"); 
	 
	#if 0 
	if(flag_unfreeze){ 
		flag_unfreeze = 0; 
		DMTRIG0 |= 4;	 
		d11_dma_phy = image_review_buf.image_dma_mmphy[image_review_buf.tail_index]; 
		DIDST0 = d11_dma_phy; 
		DMTRIG0 = (0<<2) + (1<<1) + 0;	// |= 2;	 
	} 
	#endif 
	 
	#if 0 
	Eint2_Done++; 
	 
	if (FlagUnfreeze==1){ 
		FlagUnfreeze=0; 
 		rDMASKTRIG0= rDMASKTRIG0|4;      
 		// 重新初始化DMA,纠正刚开机时数据传输错位的问题。 
		Dma0Xdreq();  
	} 
	#endif 
} 
 
/* 
***************  Only for dma test ***************************** 
*/ 
void dma_tester(void) 
{ 
	int i,j; 
	unsigned char *pattern; 
 
	pattern = (unsigned char *)vmalloc(IMG_SIZE); 
	 
	for(j=0; j (image_review_buf.nr_mmblks)){ 
			image_review_buf.nr_images = image_review_buf.nr_mmblks; 
			 
			image_review_buf.head_index++;		 
			if(image_review_buf.head_index > (image_review_buf.nr_mmblks)){ 
				image_review_buf.head_index = 0; 
			} 
			 
		} 
		else{ 
		} 
		 
		image_review_buf.tail_index++; 
		if(image_review_buf.tail_index > (image_review_buf.nr_mmblks)){ 
				image_review_buf.tail_index = 0; 
		} 
		 
		DPRINTK("image count = %d\n",image_review_buf.nr_images); 
	} 
	else{ 
		image_review_buf.nr_images = 0; 
		//image_review_buf.head_index = image_review_buf.tail_index = 0; 
	} 
	 
	//d11_dma_buf = image_review_buf.image_dma_mmblk[image_review_buf.tail_index]; 
	d11_dma_phy = image_review_buf.image_dma_mmphy[image_review_buf.tail_index]; 
	 
	//DPRINTK("dma0 dst kerneladdr[%d]= 0x%lx\n", image_review_buf.tail_index, (unsigned long)d11_dma_buf); 
	DPRINTK("dma0 dst phyaddr[%d] = 0x%lx\n", image_review_buf.tail_index, d11_dma_phy);	 
		 
	DIDST0 = d11_dma_phy; 
	DMTRIG0 |= 2;	 
	 
} 
 
static unsigned int d11_dma_poll(struct file *filp, struct poll_table_struct *wait) 
{ 
	unsigned int mask = 0; 
	poll_wait(filp, &d11_dma_queue, wait); 
 
	mask |= POLLIN | POLLWRNORM;		//can read always. (test) 
	return mask; 
} 
 
void d11_dma_vma_open(struct vm_area_struct *vma) 
{ 
	 
} 
 
void d11_dma_vma_close(struct vm_area_struct *vma) 
{ 
	 
} 
 
struct page *d11_dma_vma_nopage(struct vm_area_struct *vma, unsigned long address, int write) 
{ 
	int phy_index; 
	int phy_offset; 
	unsigned long blksize = image_review_buf.image_blksize; 
	struct page *ptrpage = NOPAGE_SIGBUS; 
	unsigned long phyaddr; 
	unsigned long viroff = address - vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT); 
	//DPRINTK("viroff=0x%lx; blksize=0x%lx\n", viroff, blksize); 
	phy_index = viroff / blksize; 
	phy_offset = viroff % blksize; 
	 
	phyaddr = image_review_buf.image_dma_mmphy[phy_index] + phy_offset; 
 
	/* 
	if(phy_offset % 32*4*1024 == 0) 
		DPRINTK("nopage: phyaddr=0x%lx\n",phyaddr); 
	*/ 
	 
	/*********   需要在此处追加检查phyaddr 合法范围的程序段***********/ 
	if(!phyaddr){ 
		return ptrpage; 
	} 
	ptrpage = virt_to_page(__va(phyaddr)); 
	get_page(ptrpage); 
	return ptrpage;	 
} 
 
 
struct vm_operations_struct d11_dma_vm_ops = { 
	open:  d11_dma_vma_open, 
	close:  d11_dma_vma_close, 
	nopage:   d11_dma_vma_nopage, 
}; 
 
static unsigned int d11_dma_mmap(struct file *filp, struct vm_area_struct *vma) 
{ 
	vma->vm_page_prot=pgprot_noncached(vma->vm_page_prot); 
	vma->vm_flags |= VM_RESERVED; 
	vma->vm_ops = &d11_dma_vm_ops; 
	 
	return 0; 
} 
 
ssize_t d11_dma_read(struct file *filp, char *buff, size_t count, loff_t *offp) 
{ 
	return 0; 
} 
 
ssize_t d11_dma_write(struct file *filp, char *buff, size_t count, loff_t *offp) 
{ 
	short head_tmp; 
	unsigned short write_index = image_review_buf.tail_index;	 
	copy_from_user(image_review_buf.image_dma_mmblk[write_index], buff, count); 
	write_index++; 
	if(write_index > image_review_buf.nr_mmblks) { 
		write_index = 0; 
	} 
	image_review_buf.tail_index = write_index; 
	 
	if(image_review_buf.nr_images < image_review_buf.nr_mmblks) { 
		image_review_buf.nr_images++; 
	} 
	 
	/*****************  calculate the head_index of review area **********************/ 
	head_tmp = image_review_buf.tail_index - image_review_buf.nr_images; 
	if(head_tmp >= 0) { 
		image_review_buf.head_index = head_tmp; 
	} 
	else { 
		image_review_buf.head_index = head_tmp + image_review_buf.nr_mmblks; 
	} 
	return count; 
} 
 
/*******************  PROC FS **********************************************/ 
static int d11_dma_proc_read(char* buf, char **start, off_t offset, int count, int *eof, void *data) 
{ 
	int len = 0; 
	len += sprintf(buf+len, "========= debug infomation for d11_dma ========\n"); 
	len += sprintf(buf+len, "INTMSK=0x%8x\n", INTMSK); 
	len += sprintf(buf+len, "GPBCON=0x%8x\n", GPBCON); 
	len += sprintf(buf+len, "GPBUP=0x%8x\n", GPBUP); 
	len += sprintf(buf+len, "MISCCR=0x%8x\n", MISCCR); 
	len += sprintf(buf+len, "DISRC0=0x%8x\n", DISRC0); 
	len += sprintf(buf+len, "DISRCC0=0x%8x\n", DISRCC0); 
	len += sprintf(buf+len, "DIDST0=0x%8x\n", DIDST0); 
	len += sprintf(buf+len, "DIDSTC0=0x%8x\n", DIDSTC0); 
	len += sprintf(buf+len, "DCON0=0x%8x\n", DCON0); 
	len += sprintf(buf+len, "DMTRIG0=0x%8x\n", DMTRIG0); 
	len += sprintf(buf+len, "=====================\n"); 
	len += sprintf(buf+len, "SRCPND=0x%8x\n", SRCPND); 
	len += sprintf(buf+len, "INTPND=0x%8x\n", INTPND); 
	len += sprintf(buf+len, "DSTAT0=0x%8x\n", DSTAT0); 
	len += sprintf(buf+len, "DCSRC0=0x%8x\n", DCSRC0); 
	len += sprintf(buf+len, "DCDST0=0x%8x\n", DCDST0); 
	len += sprintf(buf+len, "=====================\n"); 
	len += sprintf(buf+len, "nr_mmblk=%d\n", image_review_buf.nr_mmblks); 
	len += sprintf(buf+len, "nr_images=%d\n", image_review_buf.nr_images); 
	len += sprintf(buf+len, "head_index=%d\n", image_review_buf.head_index); 
	len += sprintf(buf+len, "tail_index=%d\n", image_review_buf.tail_index); 
	len += sprintf(buf+len, "freeze=%d\n", image_review_buf.freeze); 
	len += sprintf(buf+len, "=====================\n"); 
	len += sprintf(buf+len, "BWSCON=%8x\n", BWSCON); 
	len += sprintf(buf+len, "BANKCON3=%8x\n", BANKCON3); 
	len += sprintf(buf+len, "BANKCON5=%8x\n", BANKCON5); 
	 
	len += sprintf(buf+len, "LCDCON1=%8x\n", LCDCON1); 
	len += sprintf(buf+len, "LCDCON2=%8x\n", LCDCON2); 
	len += sprintf(buf+len, "LCDCON3=%8x\n", LCDCON3); 
	len += sprintf(buf+len, "LCDCON4=%8x\n", LCDCON4); 
	len += sprintf(buf+len, "LCDCON5=%8x\n", LCDCON5); 
	 
	len += sprintf(buf+len, "LCDADDR1=%8x\n", LCDADDR1); 
	len += sprintf(buf+len, "LCDADDR2=%8x\n", LCDADDR2); 
	len += sprintf(buf+len, "LCDADDR3=%8x\n", LCDADDR3); 
	return len; 
} 
 
static ssize_t d11_dma_proc_write(struct file *filp, const char *buf, unsigned long len, void *data) 
{	 
	return 0; 
} 
 
static int d11_dma_create_proc(void) 
{	 
	d11_dma_proc_entry = create_proc_entry("d11_dma", 0644, NULL); 
	if(d11_dma_proc_entry == NULL){ 
		printk("d11_dma: Couldn't create proc entry!\n"); 
		return -ENOMEM; 
	} 
	d11_dma_proc_entry->read_proc = d11_dma_proc_read; 
	d11_dma_proc_entry->write_proc = d11_dma_proc_write; 
	d11_dma_proc_entry->owner = THIS_MODULE; 
	return 0; 
} 
 
static void d11_dma_remove_proc(void) 
{ 
	remove_proc_entry("d11_dma", NULL); 
} 
/**************************************************************************/ 
static int d11_dma_open(struct inode * inode, struct file * filp) 
{		 
	if(d11_dma_ucount){			// restrict one process open this device. 
		return -EBUSY; 
	} 
	d11_dma_ucount++; 
	MOD_INC_USE_COUNT;	 
	DPRINTK("open\n"); 
		 
	return 0; 
} 
 
static int d11_dma_release(struct inode * inode, struct file * filp) 
{ 
	d11_dma_ucount--; 
	MOD_DEC_USE_COUNT; 
	DPRINTK("release\n"); 
	return 0; 
} 
 
static int d11_dma_ioctl(struct inode * inode, struct file * filp, unsigned int command, unsigned long arg) 
{ 
	struct image_dma_t image_dma_data; 
			 
	copy_from_user(&image_dma_data, (struct image_dma_t *)(arg), sizeof(image_dma_data)); 
		 
	switch(command){ 
		case D11_DMA_IOCWRITE: 
			if(image_review_buf.freeze && (!image_dma_data.freeze)){ 
				flag_unfreeze = 1; 
			} 
			image_review_buf.freeze = image_dma_data.freeze; 
			 
			/*********  请求写入的新回放区小于原回放区大小***************/ 
			if(image_dma_data.nr_mmblks < image_review_buf.nr_mmblks) { 
				return 0; 
			} 
			/******************************************************************************* 
				  请求写入的新回放区大于原回放区大小且 
				         不超过IMG_MAX_NR 定义的最大回放区大小 
			*******************************************************************************/ 
			else if((image_dma_data.nr_mmblks > image_review_buf.nr_mmblks)  
					&& (image_dma_data.nr_mmblks <= IMG_MAX_NR)) { 
				return 0; 
			} 
			return 0; 
			 
		/*********************** 读取回放区数据***********************************/	 
		case D11_DMA_IOCREAD: 
			copy_to_user((struct image_dma_t *)(arg), &image_review_buf, sizeof(image_review_buf)); 
			return 0;			 
		 
		#ifdef D11_DMA_DEBUG 
		case D11_DMA_IOCDBGRST: 
			/*  
				in debug mode, this can remove module forcely  
			*/ 
			while(MOD_IN_USE) 
					MOD_DEC_USE_COUNT; 
			MOD_INC_USE_COUNT; 
			return 0; 
		#endif		/* D11_DMA_DEBUG */ 
 
		default: 
			return -ENOTTY;		// Inappropriate ioctl for device. 
			 
	} 
	return -ENOTTY;				// can't recognize the command. 
} 
 
 
static struct file_operations d11_dma_fops = { 
	ioctl:	d11_dma_ioctl, 
	poll:		d11_dma_poll, 
	mmap:	d11_dma_mmap, 
	read:	d11_dma_read, 
	write:	d11_dma_write, 
	open:	d11_dma_open, 
	release:	d11_dma_release, 
}; 
 
#ifdef CONFIG_DEVFS_FS 
	static devfs_handle_t devfs_d11_dma_dir, devfs_d11_dma; 
#endif 
 
static int __init init_xdreq0_dma(void) 
{ 
	int ret; 
	 
	set_external_irq(IRQ_EINT2, EXT_RISING_EDGE, GPIO_PULLUP_EN);	// 设置外中断2 
	ret = request_irq(IRQ_EINT2, handler_isr_eint2, SA_INTERRUPT, DEVICE_NAME, NULL); 
	if(ret < 0){ 
		printk(" unable to get EINT2 interrupts\n" ); 
		return -EBUSY; 
	} 
 
	ret = request_irq(IRQ_DMA0, handler_Dma0Done, SA_INTERRUPT, DEVICE_NAME, NULL); 
	if(ret < 0){ 
		printk(" unable to get DMA0 interrupts\n" ); 
		return -EBUSY; 
	} 
 
	set_gpio_ctrl(GPIO_B9 | GPIO_PULLUP_EN | GPIO_MODE_nXDACK);		// GPB9=nXDACK0 
	set_gpio_ctrl(GPIO_B10 | GPIO_PULLUP_EN | GPIO_MODE_nXDREQ);		// GPB10=nXDREQ0 
 
	//(void *)fpga_dma0_reg = ioremap(FPGA_DMA0, 4);					// Can delete. 
 
	GPHCON &= (~(0x0f << 18)); 
	GPHCON |=  (0x0a << 18);		//GPH9、GPH10 set as clkout. 
	MISCCR=0x10410;	  			// clkout0=48M,clkout1=PCLK 
	DISRC0 = FPGA_DMA0;			// Bank5 0x28000000 
	DISRCC0 = (0<<1)+(1<<0);	// AHB,fixed 
	DIDST0 = image_review_buf.image_dma_mmphy[0]; 
	DIDSTC0 = (0<<1)+(0<<0);	// AHB, inc 
	DCON0 = (1<<31)+(1<<30)+(1<<29)+(1<<28)+(0<<27)+(0<<24)+(1<<23)+(1<<22)+(2<<20)+IMG_SIZE/16; 
	//handshake, sync HCLK, TC int, burst tx, single service, nXDREQ0, H/W request, auto-reload off, word, 64hw 
	DMTRIG0 = (0<<2)+(1<<1)+0;    //no-stop, DMA0 channel on, no-sw trigger	 
	 
	DPRINTK("INTMSK=0x%8x\n", INTMSK); 
	DPRINTK("GPBCON=0x%8x\n", GPBCON);	 
	DPRINTK("MISCCR=0x%8x\n", MISCCR); 
	DPRINTK("DISRC0=0x%8x\n", DISRC0); 
	DPRINTK("DISRCC0=0x%8x\n", DISRCC0); 
	DPRINTK("DIDST0=0x%8x\n", DIDST0); 
	DPRINTK("DIDSTC0=0x%8x\n", DIDSTC0); 
	DPRINTK("DCON0=0x%8x\n", DCON0); 
	DPRINTK("DMTRIG0=0x%8x\n", DMTRIG0); 
	 
	DPRINTK("dma init finished!\n"); 
	return 0; 
} 
 
static int __init image_init_dma(void) 
{ 
	int ret; 
	ret = init_xdreq0_dma(); 
	//s3c2410_request_dma("XDREQ0", DMA_CH0, handler_Dma0Done, NULL); 
	return ret;	 
} 
 
static int __init d11_dma_init(void) 
{ 
	int ret; 
	int i; 
	int d11_dma_size = 0; 
	unsigned long *d11_dma_buf = (unsigned long *)0; 
	dma_addr_t 	   d11_dma_phy = 0; 
 
	SET_MODULE_OWNER(&d11_dma_fops); 
	 
	ret = register_chrdev(d11_dma_major, DEVICE_NAME, &d11_dma_fops); 
	if(ret < 0){ 
		printk("d11_dma:Cant't get major number!\n"); 
		return ret; 
	} 
	if (d11_dma_major == 0) d11_dma_major = ret; /* dynamic */	 
 
	#ifdef CONFIG_DEVFS_FS 
		devfs_d11_dma_dir = devfs_mk_dir(NULL, "d11_dma", NULL); 
		if (!devfs_d11_dma_dir) return -EBUSY; 		/* problem */ 
		devfs_d11_dma = devfs_register(devfs_d11_dma_dir, "0",  
			DEVFS_FL_DEFAULT, d11_dma_major, DMA_MINOR,  
			S_IFCHR | S_IRUSR | S_IWUSR, &d11_dma_fops, NULL); 
	#endif 
	 
	DPRINTK("Major device no. -> %d\n",d11_dma_major); 
	 
	//******** alloce image review buffer ************* 
	image_review_buf.head_index = 0; 
	image_review_buf.tail_index = 0; 
	image_review_buf.nr_images = 0; 
	image_review_buf.nr_mmblks = 0; 
	image_review_buf.freeze = 0; 
	d11_dma_size = 4*1024*128;					//PAGE_ALIGN(IMG_SIZE + PAGE_SIZE); 
	image_review_buf.image_blksize = d11_dma_size; 
	 
	for(i=0; i"); 
MODULE_DESCRIPTION("dma driver for emp-d11");