linux駆動のDMA駆動
12047 ワード
DMAは、CPUの参加を必要とせずに、周辺機器とシステムメモリとの双方向データ伝送を可能にするハードウェア機構である.これにより、システムCPUを実際のI/Oデータ伝送から解放し、システムのスループットを大幅に向上させ、伝送中に他のタスクを同時に実行することもできる.
アプリケーション:
それぞれ実行./dma_test nodma 100 ././dma_test dma 100は異なる効果を見る
#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
");
}
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
");
}
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
");
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
");
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
");
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:
");
printf("%s
" ,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
");
}
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は異なる効果を見る