linux驱动之DMA驱动

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cmh477660693/article/details/72879150

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看不同的效果

猜你喜欢

转载自blog.csdn.net/cmh477660693/article/details/72879150