linux驱动之DMA驱动

xiaoxiao2021-02-27  302

DMA是一种无需CPU的参加就可以让外设与系统内存之间进行双向数据传输的硬件机制。它可以使系统CPU从实际的I/O数据传输过程中摆脱出来,大大提高系统的吞吐率,并且在传输期间,CPU还可以并发执行其他任务。

#include<linux/module.h> #include<linux/kernel.h> #include<linux/fs.h> #include<linux/init.h> #include<linux/delay.h> #include<linux/irq.h> #include<asm/uaccess.h> #include<asm/irq.h> #include<asm/io.h> #include<linux/cdev.h> #include<linux/device.h> #include<linux/dma-mapping.h> static int major = 0; #define MEM_CPY_NO_DMA 0 #define MEM_CPY_DMA 1 #define BUF_SIZE (512*1024) static char *src; static u32 src_phys; static char *dst; static u32 dst_phys; static struct class *cls; #define DMA0_BASE_ADDR 0x4B000000 #define DMA0_BASE_ADDR 0x4B000000 #define DMA0_BASE_ADDR 0x4B000000 #define DMA0_BASE_ADDR 0x4B000000 struct ex4412_dma_regs{ unsigned long disrc; unsigned long disrcc; unsigned long didst; unsigned long didstc; unsigned long dcon; unsigned long dstat; unsigned long dcsrc; unsigned long dcdst; unsigned long dmasktrig; }; static struct ex4412_dma_regs *dma_regs; static DECLARE_WAIT_QUEUE_HEAD(dma_waitq); static volatile int ev_dma = 0; #define BUF_SIZE (512*1024) static long ex_dma_ioctl(struct file *file, unsigned int node, unsigned long temp) { int i; memset(src, 0xAA,BUF_SIZE); memset(dst,0x55,BUF_SIZE); switch(cmd) { case MEM_CPY_NO_DMA: { for(i=0;i<BUF_SIZE;i++) dst[i]=src[i]; if(memcmp(src,dst,BUF_SIZE)==0) { printk("MEM_CPY_NO_DMA OK\n"); } else { printk("MEM_CPY_DMA_ERROR") } break; } case MEM_CPY_DMA: { /*把源,目的,长度告诉DMA*/ dma_regs->dcsrc=src_phys;//源物理地址 dma_regs->disrcc=(0<<1)|(0<<0);//源位于AHB总线,源地址 dma_regs->didst=dst_phys;//目的物理地址 dma_regs->didstc=(0<<2)|(0<<1)|(0<<0);//目的位于AHB dma_regs->dcon=(1<<29)|(0<<28)|(0<<23)|(0<<20)|(BUF_SIZE<<0);//使能中断,单个传输 //启动DMA dma_regs->dmasktrig=(1<<1)|(1<<0); wait_event_interruptible(dma_waitq,ev_dma); if(memcmp(src,dst,BUF_SIZE)==0) { printk("MEM_CPY_NO_DMA OK\n"); } else { printk("MEM_CPY_DMA_ERROR") } break; } } } static struct file_operations dma_fops={ .owner=THIS_MODULE, ..unlocked_ioctl =ex_dma_ioctl, } static irqreturn_t ex4412_dma_irq(int irq, void *devid) { ev_dma=1; wake_up_interruptible(&dma_waitq); return IRQ_HANDLED; } static int ex4412_dma_init() { if(request_irq(IRQ_DMA0,ex4412_dma_irq,0,"ex4412_dma",1)) { printk("can't request_irq for dma\n"); return -EBUSY; } src = dma_alloc_writecombine(NULL,BUF_SIZE,&src_phys,GFP_KERNEL); if(NULL==src) { free_irq(IRQ_DMA3, 1); printk("can't alloc buffer for src\n"); return -ENOMEM; } dst = dma_alloc_writecombine(NULL,BUF_SIZE,&dst_phys,GFP_KERNEL); if(NULL==dst) { free_irq(IRQ_DMA3, 1); dma_free_writecombine(NULL,BUF_SIZE,src,&src_phys); printk("can't alloc buffer dst\n"); return -ENOMEM; } major = register_chrdev(0,"ex4412_dma",&dma_fops); cls = class_create(THIS_MODULE,"s3c_dma"); device_create(cls,NULL,MKDEV(major,0),NULL,"dma");//dev/dma dma_regs=ioremap(DMA0_BASE_ADDR, sizeof(struct ex4412_dma_regs)); return 0; } static void ex4412_dma_exit() { iounmap(dma_regs); device_destroy(cls,MKDEV(major,0)); class_destroy(cls); unregister_chrdev(major,"ex4412_dma"); dma_free_writecombine(NULL,BUF_SIZE,src,&src_phys); dma_free_writecombine(NULL,BUF_SIZE,dst,&dst_phys); free_irq(IRQ_DMA3, 1); } module_init(ex4412_dma_init); module_exit(ex4412_dma_exit);

应用程序:

/*./dma_test nodma 100 ./dma_test dma 100 */ #include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<sys/ioctl.h> void print_usage(char *name) { printf("usage:\n"); printf("%s<nodma | dma>\n",name); } int main(int argc,char **argv) { int fd; if(argc!=3) { print_usage(argv[0]); return -1; } fd=open("/dev/dma",O_RDWR); if(fd<0) { printf("can't open /dev/dma\n"); } if(strcmp(argv[1],"nodma")==0) { while(1) { ioctl(fd,MEM_CPY_NO_DMA) } } else if(strcmp(argv[1],dma)==0) { while(1) { ioctl(fd,MEM_CPY_DMA); } } else { print_usage(argv[0]); return -1; } return 0; }

分别执行./dma_test nodma 100 ././dma_test dma 100看不同的效果

转载请注明原文地址: https://www.6miu.com/read-10379.html

最新回复(0)