linux駆動のDMA駆動


DMAは、CPUの参加を必要とせずに、周辺機器とシステムメモリとの双方向データ伝送を可能にするハードウェア機構である.これにより、システムCPUを実際のI/Oデータ伝送から解放し、システムのスループットを大幅に向上させ、伝送中に他のタスクを同時に実行することもできる.
#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は異なる効果を見る