• 20150429 S3C实现DMA驱动程序编写


    20150429 S3C实现DMA驱动程序编写

    2015-04-29 Lover雪儿


    IMX257上只有SDMA,SDMADMA的功能更加强大,但是为了学习的目的,如果直接学习SDMA,可能会不能消化,

    所以,此处,我们从简单到复杂,S3C2440DMA驱动程序开始学习,等学懂它之后,我们再进军IMX257SDMA.


    .一个简单的程序框架

    1.定义一些指针

     1 static int major = 0;
     2 
     3 #define MEM_CPY_NO_DMA  0
     4 #define MEM_CPY_DMA     1
     5 
     6 static char *src;
     7 static u32 src_phys;
     8 
     9 static char *dst;
    10 static u32 dst_phys;
    11 
    12 static struct class *cls;
    13 
    14 #define BUF_SIZE  (512*1024)

    上面代码中主要定义了主设备号,目的地址,源地址等.

     

    2.定义字符设备的file_operation结构体

     1 static int s3c_dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
     2 {
     3     switch (cmd)
     4     {
     5         case MEM_CPY_NO_DMA :
     6         {
     7             break;
     8         }
     9         case MEM_CPY_DMA :
    10         {
    11             break;
    12         }
    13     }
    14     return 0;
    15 }
    16 
    17 static struct file_operations dma_fops = {
    18     .owner  = THIS_MODULE,
    19     .ioctl  = s3c_dma_ioctl,
    20 };

    case,分别定义CPU拷贝数据和DMA拷贝数据两种情况.

    3.入口函数

     1 static int s3c_dma_init(void)
     2 {
     3     /* 分配SRC, DST对应的缓冲区 */
     4     src = dma_alloc_writecombine(NULL, BUF_SIZE, &src_phys, GFP_KERNEL);
     5     if (NULL == src)
     6     {
     7         printk("can't alloc buffer for src
    ");
     8         return -ENOMEM;
     9     }
    10     
    11     dst = dma_alloc_writecombine(NULL, BUF_SIZE, &dst_phys, GFP_KERNEL);
    12     if (NULL == dst)
    13     {
    14         dma_free_writecombine(NULL, BUF_SIZE, src, src_phys);
    15         printk("can't alloc buffer for dst
    ");
    16         return -ENOMEM;
    17     }
    18 
    19     major = register_chrdev(0, "s3c_dma", &dma_fops);
    20 
    21     /* 为了自动创建设备节点 */
    22     cls = class_create(THIS_MODULE, "s3c_dma");
    23     class_device_create(cls, NULL, MKDEV(major, 0), NULL, "dma"); /* /dev/dma */
    24         
    25     return 0;
    26 }

    上面代码中:首先分配了源.目的地址的内存缓冲区,接着就是申请字符设备,自动创建字符设备节点.

     

    4.出口函数

    1 static void s3c_dma_exit(void)
    2 {
    3     class_device_destroy(cls, MKDEV(major, 0));
    4     class_destroy(cls);
    5     unregister_chrdev(major, "s3c_dma");
    6     dma_free_writecombine(NULL, BUF_SIZE, src, src_phys);
    7     dma_free_writecombine(NULL, BUF_SIZE, dst, dst_phys);    
    8 } 

    销毁字符设备的类,卸载字符设备,接着就是释放前面申请的源.目的地址的内存.

    附上驱动代码1:

     1 #include <linux/module.h>
     2 #include <linux/kernel.h>
     3 #include <linux/fs.h>
     4 #include <linux/init.h>
     5 #include <linux/delay.h>
     6 #include <linux/irq.h>
     7 #include <asm/uaccess.h>
     8 #include <asm/irq.h>
     9 #include <asm/io.h>
    10 #include <asm/arch/regs-gpio.h>
    11 #include <asm/hardware.h>
    12 #include <linux/poll.h>
    13 
    14 static int major = 0;
    15 
    16 #define MEM_CPY_NO_DMA  0
    17 #define MEM_CPY_DMA     1
    18 
    19 static char *src;
    20 static u32 src_phys;
    21 
    22 static char *dst;
    23 static u32 dst_phys;
    24 
    25 static struct class *cls;
    26 
    27 #define BUF_SIZE  (512*1024)
    28 
    29 static int s3c_dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
    30 {
    31     switch (cmd)
    32     {
    33         case MEM_CPY_NO_DMA :
    34         {
    35             break;
    36         }
    37 
    38         case MEM_CPY_DMA :
    39         {
    40             break;
    41         }
    42     }
    43 
    44     return 0;
    45 }
    46 
    47 static struct file_operations dma_fops = {
    48     .owner  = THIS_MODULE,
    49     .ioctl  = s3c_dma_ioctl,
    50 };
    51 
    52 static int s3c_dma_init(void)
    53 {
    54     /* 分配SRC, DST对应的缓冲区 */
    55     src = dma_alloc_writecombine(NULL, BUF_SIZE, &src_phys, GFP_KERNEL);
    56     if (NULL == src)
    57     {
    58         printk("can't alloc buffer for src
    ");
    59         return -ENOMEM;
    60     }
    61     
    62     dst = dma_alloc_writecombine(NULL, BUF_SIZE, &dst_phys, GFP_KERNEL);
    63     if (NULL == dst)
    64     {
    65         dma_free_writecombine(NULL, BUF_SIZE, src, src_phys);
    66         printk("can't alloc buffer for dst
    ");
    67         return -ENOMEM;
    68     }
    69 
    70     major = register_chrdev(0, "s3c_dma", &dma_fops);
    71 
    72     /* 为了自动创建设备节点 */
    73     cls = class_create(THIS_MODULE, "s3c_dma");
    74     class_device_create(cls, NULL, MKDEV(major, 0), NULL, "dma"); /* /dev/dma */
    75         
    76     return 0;
    77 }
    78 
    79 static void s3c_dma_exit(void)
    80 {
    81     class_device_destroy(cls, MKDEV(major, 0));
    82     class_destroy(cls);
    83     unregister_chrdev(major, "s3c_dma");
    84     dma_free_writecombine(NULL, BUF_SIZE, src, src_phys);
    85     dma_free_writecombine(NULL, BUF_SIZE, dst, dst_phys);    
    86 }
    87 
    88 module_init(s3c_dma_init);
    89 module_exit(s3c_dma_exit);
    90 
    91 MODULE_LICENSE("GPL");
    dma_1.c

     

    .增加不使用DMA的内存拷贝功能.

     1 static int s3c_dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
     2 {
     3     int i;
     4     memset(src, 0xAA, BUF_SIZE);
     5     memset(dst, 0x55, BUF_SIZE);
     6     
     7     switch (cmd)
     8     {
     9         case MEM_CPY_NO_DMA :
    10         {
    11             for (i = 0; i < BUF_SIZE; i++)
    12                 dst[i] = src[i];
    13             if (memcmp(src, dst, BUF_SIZE) == 0)
    14             {
    15                 printk("MEM_CPY_NO_DMA OK
    ");
    16             }
    17             else
    18             {
    19                 printk("MEM_CPY_DMA ERROR
    ");
    20             }
    21             break;
    22         }
    23         case MEM_CPY_DMA :
    24         {
    25             break;
    26         }
    27     }
    28 
    29     return 0;
    30 }

    如程序所示,ioctl函数中不适用DMA的增加内存拷贝功能.

    附上驱动程序2

      1 #include <linux/module.h>
      2 #include <linux/kernel.h>
      3 #include <linux/fs.h>
      4 #include <linux/init.h>
      5 #include <linux/delay.h>
      6 #include <linux/irq.h>
      7 #include <asm/uaccess.h>
      8 #include <asm/irq.h>
      9 #include <asm/io.h>
     10 #include <asm/arch/regs-gpio.h>
     11 #include <asm/hardware.h>
     12 #include <linux/poll.h>
     13 
     14 static int major = 0;
     15 
     16 #define MEM_CPY_NO_DMA  0
     17 #define MEM_CPY_DMA     1
     18 
     19 static char *src;
     20 static u32 src_phys;
     21 
     22 static char *dst;
     23 static u32 dst_phys;
     24 
     25 static struct class *cls;
     26 
     27 #define BUF_SIZE  (512*1024)
     28 
     29 static int s3c_dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
     30 {
     31     int i;
     32 
     33     memset(src, 0xAA, BUF_SIZE);
     34     memset(dst, 0x55, BUF_SIZE);
     35     
     36     switch (cmd)
     37     {
     38         case MEM_CPY_NO_DMA :
     39         {
     40             for (i = 0; i < BUF_SIZE; i++)
     41                 dst[i] = src[i];
     42             if (memcmp(src, dst, BUF_SIZE) == 0)
     43             {
     44                 printk("MEM_CPY_NO_DMA OK
    ");
     45             }
     46             else
     47             {
     48                 printk("MEM_CPY_DMA ERROR
    ");
     49             }
     50             break;
     51         }
     52 
     53         case MEM_CPY_DMA :
     54         {
     55             break;
     56         }
     57     }
     58 
     59     return 0;
     60 }
     61 
     62 static struct file_operations dma_fops = {
     63     .owner  = THIS_MODULE,
     64     .ioctl  = s3c_dma_ioctl,
     65 };
     66 
     67 static int s3c_dma_init(void)
     68 {
     69     /* 分配SRC, DST对应的缓冲区 */
     70     src = dma_alloc_writecombine(NULL, BUF_SIZE, &src_phys, GFP_KERNEL);
     71     if (NULL == src)
     72     {
     73         printk("can't alloc buffer for src
    ");
     74         return -ENOMEM;
     75     }
     76     
     77     dst = dma_alloc_writecombine(NULL, BUF_SIZE, &dst_phys, GFP_KERNEL);
     78     if (NULL == dst)
     79     {
     80         dma_free_writecombine(NULL, BUF_SIZE, src, src_phys);
     81         printk("can't alloc buffer for dst
    ");
     82         return -ENOMEM;
     83     }
     84 
     85     major = register_chrdev(0, "s3c_dma", &dma_fops);
     86 
     87     /* 为了自动创建设备节点 */
     88     cls = class_create(THIS_MODULE, "s3c_dma");
     89     class_device_create(cls, NULL, MKDEV(major, 0), NULL, "dma"); /* /dev/dma */
     90         
     91     return 0;
     92 }
     93 
     94 static void s3c_dma_exit(void)
     95 {
     96     class_device_destroy(cls, MKDEV(major, 0));
     97     class_destroy(cls);
     98     unregister_chrdev(major, "s3c_dma");
     99     dma_free_writecombine(NULL, BUF_SIZE, src, src_phys);
    100     dma_free_writecombine(NULL, BUF_SIZE, dst, dst_phys);    
    101 }
    102 
    103 module_init(s3c_dma_init);
    104 module_exit(s3c_dma_exit);
    105 
    106 MODULE_LICENSE("GPL");
    dma_2.c

    附上测试程序2.

     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <sys/stat.h>
     4 #include <fcntl.h>
     5 #include <sys/ioctl.h>
     6 #include <string.h>
     7 
     8 /* ./dma_test nodma
     9  * ./dma_test dma
    10  */
    11 #define MEM_CPY_NO_DMA  0
    12 #define MEM_CPY_DMA     1
    13 
    14 void print_usage(char *name)
    15 {
    16     printf("Usage:
    ");
    17     printf("%s <nodma | dma>
    ", name);
    18 }
    19 
    20 
    21 int main(int argc, char **argv)
    22 {
    23     int fd;
    24     
    25      if (argc != 2)
    26     {
    27         print_usage(argv[0]);
    28         return -1;
    29     }
    30 
    31     fd = open("/dev/dma", O_RDWR);
    32     if (fd < 0)
    33     {
    34         printf("can't open /dev/dma
    ");
    35         return -1;
    36     }
    37 
    38     if (strcmp(argv[1], "nodma") == 0)
    39     {
    40         while (1)
    41         {
    42             ioctl(fd, MEM_CPY_NO_DMA);
    43         }
    44     }
    45     else if (strcmp(argv[1], "dma") == 0)
    46     {
    47         while (1)
    48         {
    49             ioctl(fd, MEM_CPY_DMA);
    50         }
    51     }
    52     else
    53     {
    54         print_usage(argv[0]);
    55         return -1;
    56     }
    57     return 0;     
    58 }
    dma_test.c

    .映射s3cDMA内存地址

    测试程序时,不知道大家有没有发现,当我们运行test测试程序时,我们的拷贝进程占用了全部的CPU,以至于我们想运行一条命令都要等好久才能实现,

    为了解决它,我们就引入了DMA,接下来,我们就真正开始DMA的编程

     1 #define DMA0_BASE_ADDR  0x4B000000
     2 #define DMA1_BASE_ADDR  0x4B000040
     3 #define DMA2_BASE_ADDR  0x4B000080
     4 #define DMA3_BASE_ADDR  0x4B0000C0
     5 
     6 struct s3c_dma_regs {
     7     unsigned long disrc;
     8     unsigned long disrcc;
     9     unsigned long didst;
    10     unsigned long didstc;
    11     unsigned long dcon;
    12     unsigned long dstat;
    13     unsigned long dcsrc;
    14     unsigned long dcdst;
    15     unsigned long dmasktrig;
    16 };

    如程序中所示:首先定义DMA的四个通道的基地址,接着定义一个s3cdma的寄存器结构体.

    分别再入口函数中映射DMA的内存IO端口,此处我们使用DMA0,当然如果要使用其他的DMA,类似.

    在入口函数中映射:

    dma_regs = ioremap(DMA0_BASE_ADDR, sizeof(struct s3c_dma_regs));

    在出口函数中解除DMA映射.

    iounmap(dma_regs);


    .注册DMA中断

    前面我们已经映好DMA的内存地址了.

    接下来,要想DMA工作,还需要对齐进行注册DMA中断和DMA配置.

    在入口函数中注册DMA中断,再出口函数中释放DMA中断

    在入口函数中注册中断:

    1 if (request_irq(IRQ_DMA3, s3c_dma_irq, 0, "s3c_dma", 1))
    2     {
    3         printk("can't request_irq for DMA
    ");
    4         return -EBUSY;
    5     }

    在出口函数中释放中断:

    free_irq(IRQ_DMA3, 1);

    当用户程序中定义为 MEM_CPY_DMA 使用DMA传输时,便会在ioctl函数中进入case MEM_CPY_DMA :.

    接着我们便在其中配置号DMA的源.目的参数,接着便启动传输,CPU则进入休眠状态,让出CPU供其他进程使用.DMA拷贝完成时,便会触发中断,从而唤醒.

    ioctl函数的部分程序如下面所示:

     1         case MEM_CPY_DMA :
     2         {
     3             ev_dma = 0;
     4             
     5             /* 把源,目的,长度告诉DMA */
     6             dma_regs->disrc      = src_phys;        /* 源的物理地址 */
     7             dma_regs->disrcc     = (0<<1) | (0<<0); /* 源位于AHB总线, 源地址递增 */
     8             dma_regs->didst      = dst_phys;        /* 目的的物理地址 */
     9             dma_regs->didstc     = (0<<2) | (0<<1) | (0<<0); /* 目的位于AHB总线, 目的地址递增 */
    10             dma_regs->dcon       = (1<<30)|(1<<29)|(0<<28)|(1<<27)|(0<<23)|(0<<20)|(BUF_SIZE<<0);  /* 使能中断,单个传输,软件触发, */
    11 
    12             /* 启动DMA */
    13             dma_regs->dmasktrig  = (1<<1) | (1<<0);
    14 
    15             /* 如何知道DMA什么时候完成? */
    16             /* 休眠 */
    17             wait_event_interruptible(dma_waitq, ev_dma);
    18 
    19             if (memcmp(src, dst, BUF_SIZE) == 0)
    20             {
    21                 printk("MEM_CPY_DMA OK
    ");
    22             }
    23             else
    24             {
    25                 printk("MEM_CPY_DMA ERROR
    ");
    26             }
    27             
    28             break;
    29         }

    中断服务程序:

    1 static irqreturn_t s3c_dma_irq(int irq, void *devid)
    2 {
    3     /* 唤醒 */
    4     ev_dma = 1;
    5     wake_up_interruptible(&dma_waitq);   /* 唤醒休眠的进程 */
    6     return IRQ_HANDLED;
    7 }

    附上驱动程序3:

      1 #include <linux/module.h>
      2 #include <linux/kernel.h>
      3 #include <linux/fs.h>
      4 #include <linux/init.h>
      5 #include <linux/delay.h>
      6 #include <linux/irq.h>
      7 #include <asm/uaccess.h>
      8 #include <asm/irq.h>
      9 #include <asm/io.h>
     10 #include <asm/arch/regs-gpio.h>
     11 #include <asm/hardware.h>
     12 #include <linux/poll.h>
     13 #include <linux/dma-mapping.h>
     14 
     15 #define MEM_CPY_NO_DMA  0
     16 #define MEM_CPY_DMA     1
     17 
     18 #define BUF_SIZE  (512*1024)
     19 
     20 #define DMA0_BASE_ADDR  0x4B000000
     21 #define DMA1_BASE_ADDR  0x4B000040
     22 #define DMA2_BASE_ADDR  0x4B000080
     23 #define DMA3_BASE_ADDR  0x4B0000C0
     24 
     25 struct s3c_dma_regs {
     26     unsigned long disrc;
     27     unsigned long disrcc;
     28     unsigned long didst;
     29     unsigned long didstc;
     30     unsigned long dcon;
     31     unsigned long dstat;
     32     unsigned long dcsrc;
     33     unsigned long dcdst;
     34     unsigned long dmasktrig;
     35 };
     36 
     37 
     38 static int major = 0;
     39 
     40 static char *src;
     41 static u32 src_phys;
     42 
     43 static char *dst;
     44 static u32 dst_phys;
     45 
     46 static struct class *cls;
     47 
     48 static volatile struct s3c_dma_regs *dma_regs;
     49 
     50 static DECLARE_WAIT_QUEUE_HEAD(dma_waitq);
     51 /* 中断事件标志, 中断服务程序将它置1,ioctl将它清0 */
     52 static volatile int ev_dma = 0;
     53 
     54 static int s3c_dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
     55 {
     56     int i;
     57 
     58     memset(src, 0xAA, BUF_SIZE);
     59     memset(dst, 0x55, BUF_SIZE);
     60     
     61     switch (cmd)
     62     {
     63         case MEM_CPY_NO_DMA :
     64         {
     65             for (i = 0; i < BUF_SIZE; i++)
     66                 dst[i] = src[i];
     67             if (memcmp(src, dst, BUF_SIZE) == 0)
     68             {
     69                 printk("MEM_CPY_NO_DMA OK
    ");
     70             }
     71             else
     72             {
     73                 printk("MEM_CPY_DMA ERROR
    ");
     74             }
     75             break;
     76         }
     77 
     78         case MEM_CPY_DMA :
     79         {
     80             ev_dma = 0;
     81             
     82             /* 把源,目的,长度告诉DMA */
     83             dma_regs->disrc      = src_phys;        /* 源的物理地址 */
     84             dma_regs->disrcc     = (0<<1) | (0<<0); /* 源位于AHB总线, 源地址递增 */
     85             dma_regs->didst      = dst_phys;        /* 目的的物理地址 */
     86             dma_regs->didstc     = (0<<2) | (0<<1) | (0<<0); /* 目的位于AHB总线, 目的地址递增 */
     87             dma_regs->dcon       = (1<<30)|(1<<29)|(0<<28)|(1<<27)|(0<<23)|(0<<20)|(BUF_SIZE<<0);  /* 使能中断,单个传输,软件触发, */
     88 
     89             /* 启动DMA */
     90             dma_regs->dmasktrig  = (1<<1) | (1<<0);
     91 
     92             /* 如何知道DMA什么时候完成? */
     93             /* 休眠 */
     94             wait_event_interruptible(dma_waitq, ev_dma);
     95 
     96             if (memcmp(src, dst, BUF_SIZE) == 0)
     97             {
     98                 printk("MEM_CPY_DMA OK
    ");
     99             }
    100             else
    101             {
    102                 printk("MEM_CPY_DMA ERROR
    ");
    103             }
    104             
    105             break;
    106         }
    107     }
    108 
    109     return 0;
    110 }
    111 
    112 static struct file_operations dma_fops = {
    113     .owner  = THIS_MODULE,
    114     .ioctl  = s3c_dma_ioctl,
    115 };
    116 
    117 static irqreturn_t s3c_dma_irq(int irq, void *devid)
    118 {
    119     /* 唤醒 */
    120     ev_dma = 1;
    121     wake_up_interruptible(&dma_waitq);   /* 唤醒休眠的进程 */
    122     return IRQ_HANDLED;
    123 }
    124 
    125 static int s3c_dma_init(void)
    126 {
    127     if (request_irq(IRQ_DMA3, s3c_dma_irq, 0, "s3c_dma", 1))
    128     {
    129         printk("can't request_irq for DMA
    ");
    130         return -EBUSY;
    131     }
    132     
    133     /* 分配SRC, DST对应的缓冲区 */
    134     src = dma_alloc_writecombine(NULL, BUF_SIZE, &src_phys, GFP_KERNEL);
    135     if (NULL == src)
    136     {
    137         printk("can't alloc buffer for src
    ");
    138         free_irq(IRQ_DMA3, 1);
    139         return -ENOMEM;
    140     }
    141     
    142     dst = dma_alloc_writecombine(NULL, BUF_SIZE, &dst_phys, GFP_KERNEL);
    143     if (NULL == dst)
    144     {
    145         free_irq(IRQ_DMA3, 1);
    146         dma_free_writecombine(NULL, BUF_SIZE, src, src_phys);
    147         printk("can't alloc buffer for dst
    ");
    148         return -ENOMEM;
    149     }
    150 
    151     major = register_chrdev(0, "s3c_dma", &dma_fops);
    152 
    153     /* 为了自动创建设备节点 */
    154     cls = class_create(THIS_MODULE, "s3c_dma");
    155     class_device_create(cls, NULL, MKDEV(major, 0), NULL, "dma"); /* /dev/dma */
    156 
    157     dma_regs = ioremap(DMA3_BASE_ADDR, sizeof(struct s3c_dma_regs));
    158         
    159     return 0;
    160 }
    161 
    162 static void s3c_dma_exit(void)
    163 {
    164     iounmap(dma_regs);
    165     class_device_destroy(cls, MKDEV(major, 0));
    166     class_destroy(cls);
    167     unregister_chrdev(major, "s3c_dma");
    168     dma_free_writecombine(NULL, BUF_SIZE, src, src_phys);
    169     dma_free_writecombine(NULL, BUF_SIZE, dst, dst_phys);    
    170     free_irq(IRQ_DMA3, 1);
    171 }
    172 
    173 module_init(s3c_dma_init);
    174 module_exit(s3c_dma_exit);
    175 
    176 MODULE_LICENSE("GPL");
    dma_3.c

    附上测试程序3:

     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <sys/stat.h>
     4 #include <fcntl.h>
     5 #include <sys/ioctl.h>
     6 #include <string.h>
     7 
     8 /* ./dma_test nodma
     9  * ./dma_test dma
    10  */
    11 #define MEM_CPY_NO_DMA  0
    12 #define MEM_CPY_DMA     1
    13 
    14 void print_usage(char *name)
    15 {
    16     printf("Usage:
    ");
    17     printf("%s <nodma | dma>
    ", name);
    18 }
    19 
    20 
    21 int main(int argc, char **argv)
    22 {
    23     int fd;
    24     
    25      if (argc != 2)
    26     {
    27         print_usage(argv[0]);
    28         return -1;
    29     }
    30 
    31     fd = open("/dev/dma", O_RDWR);
    32     if (fd < 0)
    33     {
    34         printf("can't open /dev/dma
    ");
    35         return -1;
    36     }
    37 
    38     if (strcmp(argv[1], "nodma") == 0)
    39     {
    40         while (1)
    41         {
    42             ioctl(fd, MEM_CPY_NO_DMA);
    43         }
    44     }
    45     else if (strcmp(argv[1], "dma") == 0)
    46     {
    47         while (1)
    48         {
    49             ioctl(fd, MEM_CPY_DMA);
    50         }
    51     }
    52     else
    53     {
    54         print_usage(argv[0]);
    55         return -1;
    56     }
    57     return 0;     
    58 }
    dma_test.c

    .总结DMA工作流程.

    简单来说,我觉得DMA编程总共分为配置和运行两个步骤.

    配置:

    注册中断

    分配供模拟拷贝数据的源.目的地址的内存空间.

    注册字符设备

    映射ioremapDMAIO空间

    运行:

    应用程序调用ioctl(fd,MEM_CPY_DMA),进入case语句

    case语句中配置号DMA传输数据所需要的源,目的,大小,便启动DMA传输.

    启动DMA传输后,程序进入可中断的休眠,让出CPU

    一旦DMA传输完毕,便会触发中断,再中断中唤醒,然后打印MEM_CPY_DMA OK告诉应用程序DMA传输成功了.

  • 相关阅读:
    114.完全背包【恰好装满完全背包
    整数划分类型题目
    三目运算符
    关于 xk 的位数。
    多重背包二进制原理拆分问题
    2016.4.2 讲课笔记(动态规划)
    二叉树(2)二叉树创建的3种方法,二叉树的递归遍历,二叉树的销毁
    二叉树(1)已知某2种排序方式,创建这个二叉树并按第3种方式排序
    C++知识点总结(二)
    5款优秀的开源克隆软件
  • 原文地址:https://www.cnblogs.com/lihaiyan/p/4466041.html
Copyright © 2020-2023  润新知