在IMX257上只有SDMA,SDMA比DMA的功能更加强大,但是为了学习的目的,如果直接学习SDMA,可能会不能消化,
所以,此处,我们从简单到复杂,从S3C2440的DMA驱动程序开始学习,等学懂它之后,我们再进军IMX257的SDMA.
一.一个简单的程序框架
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 srcn");
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 dstn");
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
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
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 srcn");
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 dstn");
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 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 OKn");
16 }
17 else
18 {
19 printk("MEM_CPY_DMA ERRORn");
20 }
21 break;
22 }
23 case MEM_CPY_DMA :
24 {
25 break;
26 }
27 }
28
29 return 0;
30 }
如程序所示,再ioctl函数中不适用DMA的增加内存拷贝功能.
附上驱动程序2
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
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 OKn");
45 }
46 else
47 {
48 printk("MEM_CPY_DMA ERRORn");
49 }