新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > DMA操作驅動

        DMA操作驅動

        作者: 時間:2016-11-21 來源:網絡 收藏
        驅動源碼:
        #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 "asm/arch/regs-gpio.h"
        #include "asm/hardware.h"
        #include "linux/poll.h"
        #include "linux/dma-mapping.h"
        #define MEM_CPY_NO_DMA 0
        #define MEM_CPY_DMA 1
        #define BUF_SIZE (512*1024)
        #define DMA0_BASE_ADDR 0x4B000000
        #define DMA1_BASE_ADDR 0x4B000040
        #define DMA2_BASE_ADDR 0x4B000080
        #define DMA3_BASE_ADDR 0x4B0000C0
        struct s3c_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 int major = 0;
        static char *src;
        static u32 src_phys;
        static char *dst;
        static u32 dst_phys;
        static struct class *cls;
        static volatile struct s3c_dma_regs *dma_regs;
        static DECLARE_WAIT_QUEUE_HEAD(dma_waitq);
        // 中斷事件標志, 中斷服務程序將它置1,ioctl將它清0 //
        static volatile int ev_dma = 0;
        static int s3c_dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
        {
        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 OKn");
        }
        else
        {
        printk("MEM_CPY_DMA ERRORn");
        }
        break;
        }
        case MEM_CPY_DMA :
        {
        ev_dma = 0;
        // 把源,目的,長度告訴DMA //
        dma_regs->disrc = 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<<30)|(1<<29)|(0<<28)|(1<<27)|(0<<23)|(0<<20)|(BUF_SIZE<<0); // 使能中斷,單個傳輸,軟件觸發, //
        // 啟動DMA //
        dma_regs->dmasktrig = (1<<1) | (1<<0);
        // 如何知道DMA什么時候完成? //
        // 休眠 //
        wait_event_interruptible(dma_waitq, ev_dma);
        if (memcmp(src, dst, BUF_SIZE) == 0)
        {
        printk("MEM_CPY_DMA OKn");
        }
        else
        {
        printk("MEM_CPY_DMA ERRORn");
        }
        break;
        }
        }
        return 0;
        }
        static struct file_operations dma_fops = {
        .owner = THIS_MODULE,
        .ioctl = s3c_dma_ioctl,
        };
        static irqreturn_t s3c_dma_irq(int irq, void *devid)
        {
        // 喚醒 //
        ev_dma = 1;
        wake_up_interruptible(&dma_waitq); // 喚醒休眠的進程 //
        return IRQ_HANDLED;
        }
        static int s3c_dma_init(void)
        {
        if (request_irq(IRQ_DMA3, s3c_dma_irq, 0, "s3c_dma", 1))
        {
        printk("cant request_irq for DMAn");
        return -EBUSY;
        }
        // 分配SRC, DST對應的緩沖區 //
        src = dma_alloc_writecombine(NULL, BUF_SIZE, &src_phys, GFP_KERNEL);
        if (NULL == src)
        {
        printk("cant alloc buffer for srcn");
        free_irq(IRQ_DMA3, 1);
        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("cant alloc buffer for dstn");
        return -ENOMEM;
        }
        major = register_chrdev(0, "s3c_dma", &dma_fops);
        // 為了自動創建設備節點 //
        cls = class_create(THIS_MODULE, "s3c_dma");
        class_device_create(cls, NULL, MKDEV(major, 0), NULL, "dma");
        dma_regs = ioremap(DMA3_BASE_ADDR, sizeof(struct s3c_dma_regs));
        return 0;
        }
        static void s3c_dma_exit(void)
        {
        iounmap(dma_regs);
        class_device_destroy(cls, MKDEV(major, 0));
        class_destroy(cls);
        unregister_chrdev(major, "s3c_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(s3c_dma_init);
        module_exit(s3c_dma_exit);
        MODULE_LICENSE("GPL");
        ==================================================================
        測試程序:
        #include "stdio.h"
        #include "sys/types.h"
        #include "sys/stat.h"
        #include "fcntl.h"
        #include "sys/ioctl.h"
        #include "string.h"
        // ./dma_test nodma
        // ./dma_test dma
        //
        #define MEM_CPY_NO_DMA 0
        #define MEM_CPY_DMA 1
        void print_usage(char *name)
        {
        printf("Usage:n");
        printf("%s n", name);
        }
        int main(int argc, char **argv)
        {
        int fd;
        if (argc != 2)
        {
        print_usage(argv[0]);
        return -1;
        }
        fd = open("/dev/dma", O_RDWR);
        if (fd < 0)
        {
        printf("cant open /dev/dman");
        return -1;
        }
        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操作驅

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 毕节市| 垣曲县| 益阳市| 水富县| 边坝县| 宜春市| 留坝县| 宁城县| 华安县| 高唐县| 樟树市| 寿光市| 吉水县| 泗阳县| 武宁县| 吕梁市| 屯门区| 左贡县| 隆安县| 宁波市| 中西区| 天峨县| 临汾市| 肃南| 镇康县| 宁化县| 嘉义市| 长沙市| 乌审旗| 偃师市| 察哈| 虞城县| 大荔县| 新乐市| 竹山县| 平果县| 吉隆县| 建平县| 柘荣县| 新泰市| 东方市|