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 srcn');
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 dstn');
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');
附上测试程序2.
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 } 三.映射s3c的DMA内存地址 测试程序时,不知道大家有没有发现,当我们运行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的四个通道的基地址,接着定义一个s3c的dma的寄存器结构体. 分别再入口函数中映射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 DMAn'); 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 OKn'); 22 } 23 else 24 { 25 printk('MEM_CPY_DMA ERRORn'); 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 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include 11 #include 12 #include 13 #include 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)
上一篇:S3C2440实现dm9000网卡驱动程序移植
下一篇:S3C2440 nand_flash驱动程序
推荐阅读最新更新时间:2024-11-13 17:25
设计资源 培训 开发板 精华推荐
- 用于自动电流选择的 LTC1174-5 降压转换器的典型应用电路
- 低压2级电磁加速器
- 使用 Analog Devices 的 ADuM4135RWZ 的参考设计
- 【ESP32-S3】1.69寸触摸屏迷你控制器~
- 使用 ON Semiconductor 的 KA7809E 的参考设计
- 使用 NXP Semiconductors 的 PCA9533D 的参考设计
- PCIE X1转显卡接口
- 基于BT-STA2416C2蓝牙模块的AN2612 BT_HTS_RX_R2评估板
- ADA4927-1YCP-EBZ,用于单 16 引脚 3 mm + 3 mm LFCSP 封装的差分放大器评估板
- 带有用于 dSPIN L6470 微步进电机驱动器的 STM32 固件库的应用电路