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 OKn');
70 }
71 else
72 {
73 printk('MEM_CPY_DMA ERRORn');
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 OKn');
99 }
100 else
101 {
102 printk('MEM_CPY_DMA ERRORn');
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 DMAn');
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 srcn');
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 dstn');
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');
附上测试程序3:
1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 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:n'); 17 printf('%s 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/dman'); 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工作流程. 简单来说,我觉得DMA编程总共分为配置和运行两个步骤. 配置: ①注册中断 ②分配供模拟拷贝数据的源.目的地址的内存空间. ③注册字符设备 ④映射ioremapDMA的IO空间 运行: ①应用程序调用ioctl(fd,MEM_CPY_DMA),进入case语句 ②在case语句中配置号DMA传输数据所需要的源,目的,大小,便启动DMA传输. ③启动DMA传输后,程序进入可中断的休眠,让出CPU ④一旦DMA传输完毕,便会触发中断,再中断中唤醒,然后打印MEM_CPY_DMA OK告诉应用程序DMA传输成功了.
上一篇:S3C2440实现dm9000网卡驱动程序移植
下一篇:S3C2440 nand_flash驱动程序
推荐阅读最新更新时间:2024-11-13 17:22
设计资源 培训 开发板 精华推荐
- LTC3851EMSE-1、1.5V/15A 同步降压稳压器 (350kHz) 的典型应用电路
- C8051F560DK,C8051F565 8051 MCU 工业应用开发系统
- 使用 Analog Devices 的 ADR444A 的参考设计
- MIC4576-3.3BT、6V-36V转3.3V/3A降压转换器通孔典型应用电路
- RT9193 300mA、超低噪声、超快CMOS LDO稳压器的典型应用
- DS51815B,零 802.11 PICtail Plus 子板
- RDR-721 - 基于LinkSwitch-TN2的用于家庭自动化的2.75W非隔离降压转换器
- OP213ESZ-REEL 超低噪声、单电源仪表放大器的典型应用
- 在电池供电的患者监护应用中为 ECG 前端供电
- 具有基本抑制功能的 LF33ABDT-TR 3.3V 超低压降稳压器的典型应用