Linux驱动之DMA

上代码之前说一点自己的总结:不能用kmalloc,因为 kmalloc分配的物理地址有可能是不连续的,dma不能识别   DMA负责读取数据,读取的过程和CPU无关,当读取完了产生一次中断,让CPU来处理数据这样大大节省了时间,而不是让CPU去负责读取数据。DMA在产品效率开发过程中用的比较多,当你的CPU忙不过来的时候后你可以使用DMA,像读取数据,解析数据这些完全可以让DMA去做,CPU只来处理读出来的指令就行,免得CPU既要去读取
数据还得处理数据,这样效率不是很高。还有代码有可能你看不懂,但是没有关系,你结合你的Linux内核版本,不懂得函数用sourceInsight去查找。

下面有一个测试程序来教大家怎么使用DMA,由于个人能力有限,如果读者发现了那些错误,望请指正。

头文件根据自己内核版本添加,这个问题很好解决,我相信难不倒大家。

static char *src;                                         /*分配的SRC, 对应的缓冲区*/
static u32 src_phys;                                  /*物理地址*/

static char *dst;                        //分配的dst, 对应的缓冲区
static u32 dst_phys;                       //物理地址

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 OK\n");
}
else
{
printk("MEM_CPY_DMA ERROR\n");
}
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 OK\n");
}
else
{
printk("MEM_CPY_DMA ERROR\n");
}

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)                             //DMA数据传输完成就触发这个中断
{
/* 唤醒 */
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("can't request_irq for DMA\n");
return -EBUSY;
}

/* 分配SRC, DST对应的缓冲区 */
src = dma_alloc_writecombine(NULL, BUF_SIZE, &src_phys, GFP_KERNEL);
if (NULL == src)
{
printk("can't alloc buffer for src\n");
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("can't alloc buffer for dst\n");
return -ENOMEM;
}
   dma_regs = ioremap(DMA3_BASE_ADDR, sizeof(struct s3c_dma_regs));

}

static void s3c_dma_exit(void)
{
iounmap(dma_regs);
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);

}

这个驱动程序不是很完整,但是DMA所使用到的功能应该基本讲解完了,具体在项目中怎么使用还得依靠你的聪明才智了,这篇文章只起到引导的作用。

时间: 2024-09-18 04:05:43

Linux驱动之DMA的相关文章

Linux驱动技术(三) _DMA编程

DMA即Direct Memory Access,是一种允许外设直接存取内存数据而没有CPU参与的技术,当外设对于该块内存的读写完成之后,DMAC通过中断通知CPU,这种技术多用于对数据量和数据传输速度都有很高要求的外设控制,比如显示设备等. DMA和Cache一致性 我们知道,为了提高系统运行效率,现代的CPU都采用多级缓存结构,其中就包括使用多级Cache技术来缓存内存中的数据来缓解CPU和内存速度差异问题.在这种前提下,显而易见,如果DMA内存的数据已经被Cache缓存了,而外设又修改了其

Linux驱动开发必看详解神秘内核(完全转载)

Linux驱动开发必看详解神秘内核 完全转载-链接:http://blog.chinaunix.net/uid-21356596-id-1827434.html   IT168 技术文档]在开始步入Linux设备驱动程序的神秘世界之前,让我们从驱动程序开发人员的角度看几个内核构成要素,熟悉一些基本的内核概念.我们将学习内核定时器.同步机制以及内存分配方法.不过,我们还是得从头开始这次探索之旅.因此,本章要先浏览一下内核发出的启动信息,然后再逐个讲解一些有意思的点. 2.1 启动过程 图2-1显示

linux驱动-Linux驱动结构体中probe函数的参数怎么得到?

问题描述 Linux驱动结构体中probe函数的参数怎么得到? 解决方案 他既然都写了那在驱动文件里面应该会有这个函数啊,这种敦泰的TP驱动在SDK里面能找到好几个吧 解决方案二: static int ft5x_ts_probe(struct i2c_client *client const struct i2c_device_id *id) 函数原型是这个,我疑问的是原函数的这两个参数怎么确定的?{...

linux驱动加载后能找到设备,但是/dev下不能找到设备文件

问题描述 linux驱动加载后能找到设备,但是/dev下不能找到设备文件 linux驱动加载后能找到设备,但是/dev下不能找到设备文件,我用的是动态分配设备号,insmod也能通过,但是/dev下就是找不到设备文件,加载后也不能通过测试程序我基本上直接用的板子例程,静态动态我都试了,就是不行,日志文件里面也什么都没有,板子是2410的,主机是红帽的,希望大神能够指点迷津/*****************************************Copyright (c)********

【ARM】Linux驱动移植

1驱动模块移植过程 1模块的第一种编译方法改kconfig 2模块的第二种编译方法Makefile 2Linux驱动原理 0从哪里切入 1什么是注册 2register_chrdev提交哪些数据 21设备号为什么是231 22设备名随便给 23文件操作结构体怎么设置 什么是THIS_MODULE Opencloseread这些都好理解 3register_chrdev返回什么 31 简洁而高效的goto 32 还记得什么是三目运算符吗 33 返回0表示什么 34 什么情况下返回cd-major

Linux驱动之虚拟网卡

写网卡驱动之前我总结一下个人的一些观点:其实写驱动并不是大家想想的那么难,这里我客观评价一下内核层和应用层的区别: 底层: 工作在内核层的朋友应该有这种感觉,才开始学的时候真的很难,也就是说上手难,我就拿Linux驱动来说吧,写一个完整的驱动,你得装一个虚拟机跑Linux吧,用来编译驱动程序,虚拟机里面需要安装一些库和工具,驱动程序必须跑在一个完整的系统上,所以首先你得搭建好整个系统,你还得了解硬件时序等,这些东西对新手来说真的是够头痛了,但是你会发现你真正的成为一个驱动开发人员后你就有一种豁然

linux驱动

知识结构: 1.    Linux驱动程序设计模式(40%)2.内核相关知识(30%)3. 硬件相关知识(30%)z 驱动分类:字符,网络,块 字符设备:以字节为最小单位,不可以乱序读写. 块设备: 一次传送一个整体数据(512字节),Linux可以以字节访问块设备(仅仅是驱动与内核的接口不同,访问的顺序的不同(字符只可顺序访问,块驱动可随机访问))   网络接口:硬件(eth0),纯软件(lo) 驱动的安装:模块,编译进内核(Linux启动的时候会自动加载init段) 使用驱动程序:字符设备文

linux内核 访问外设-Linux驱动中访问外设端口的outb为什么不是访问内存空间

问题描述 Linux驱动中访问外设端口的outb为什么不是访问内存空间 原文如下面,其中第一个宏的意思不是把值v赋给了内存地址为a的内存空间吗,为什么是访问outb是往外设端口写数据的? 在linux的驱动程序中,都会使用大量的outb.outw.inb.inw等等宏来访问硬件或寄存器.这些宏的定义都在相应处理器体系下的include/asm目录下的io.h中定义.追究下去,这些宏最终就是一个volatile变量的的赋值: #define arch_putb(v,a) (*(volatile u

软件-linux驱动问题详解led灯实现

问题描述 linux驱动问题详解led灯实现 请问linux下led灯驱动实现的全过程,从硬件到软件,谢谢 解决方案 http://wenku.baidu.com/view/4cf8391314791711cc7917ea.html 解决方案二: 驱动led无非是操作GPIO输出的搞低电平而已,给你个我操作2440GPIO的例子:http://blog.csdn.net/xiangpingli/article/details/39610729