DMA是一种无需CPU的参加就可以让外设与系统内存之间进行双向数据传输的硬件机制。它可以使系统CPU从实际的I/O数据传输过程中摆脱出来,大大提高系统的吞吐率,并且在传输期间,CPU还可以并发执行其他任务。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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;iif(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
#include
#include
#include
#include
void print_usage(char *name)
{
printf("usage:\n");
printf("%s\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看不同的效果