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");