linux 简单的DMA例程

一个简单的使用DMA 例子

示例:下面是一个简单的使用DMA进行传输的驱动程序,它是一个假想的设备,只列出DMA相关的部分来说明驱动程序中如何使用DMA的。

函数dad_transfer是设置DMA对内存buffer的传输操作函数,它使用流式映射将buffer的虚拟地址转换到物理地址,设置好DMA控制器,然后开始传输数据。

int dad_transfer(struct dad_dev *dev, int write, void *buffer,                 size_t count) {    dma_addr_t bus_addr;    unsigned long flags;    /* Map the buffer for DMA */    dev->dma_dir = (write ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);    dev->dma_size = count; //流式映射,将buffer的虚拟地址转化成物理地址    bus_addr = pci_map_single(dev->pci_dev, buffer, count,                              dev->dma_dir);    dev->dma_addr = bus_addr; //DMA传送的buffer物理地址    //将操作控制写入到DMA控制器寄存器,从而建立起设备    writeb(dev->registers.command, DAD_CMD_DISABLEDMA); //设置传输方向--读还是写 writeb(dev->registers.command, write ? DAD_CMD_WR : DAD_CMD_RD);    writel(dev->registers.addr, cpu_to_le32(bus_addr));//buffer物理地址    writel(dev->registers.len, cpu_to_le32(count)); //传输的字节数    //开始激活DMA进行数据传输操作    writeb(dev->registers.command, DAD_CMD_ENABLEDMA);    return 0; }

函数dad_interrupt是中断处理函数,当DMA传输完时,调用这个中断函数来取消buffer上的DMA映射,从而让内核程序可以访问这个buffer。

void dad_interrupt(int irq, void *dev_id, struct pt_regs *regs)

{

struct dad_dev *dev = (struct dad_dev *) dev_id;

/* Make sure it‘s really our device interrupting */

/* Unmap the DMA buffer */   pci_unmap_single(dev->pci_dev, dev->dma_addr, dev->dma_size,        dev->dma_dir);

/* Only now is it safe to access the buffer, copy to user, etc. */   ...

}

函数dad_open打开设备,此时应申请中断号及DMA通道。

int dad_open (struct inode *inode, struct file *filp)

{

struct dad_device *my_device;

// SA_INTERRUPT表示快速中断处理且不支持共享 IRQ 信号线   if ( (error = request_irq(my_device.irq, dad_interrupt,                             SA_INTERRUPT, "dad", NULL)) )       return error; /* or implement blocking open */

if ( (error = request_dma(my_device.dma, "dad")) ) {       free_irq(my_device.irq, NULL);       return error; /* or implement blocking open */   }

return 0;

}

在与open 相对应的 close 函数中应该释放DMA及中断号。

void dad_close (struct inode *inode, struct file *filp)

{

struct dad_device *my_device;   free_dma(my_device.dma);   free_irq(my_device.irq, NULL);   ……

}

函数dad_dma_prepare初始化DMA控制器,设置DMA控制器的寄存器的值,为 DMA 传输作准备。

int dad_dma_prepare(int channel, int mode, unsigned int buf,

unsigned int count)

{

unsigned long flags;

flags = claim_dma_lock();   disable_dma(channel);   clear_dma_ff(channel);   set_dma_mode(channel, mode);   set_dma_addr(channel, virt_to_bus(buf));   set_dma_count(channel, count);   enable_dma(channel);   release_dma_lock(flags);

return 0;

}

函数dad_dma_isdone用来检查 DMA 传输是否成功结束。

int dad_dma_isdone(int channel) {    int residue;    unsigned long flags = claim_dma_lock ();    residue = get_dma_residue(channel);    release_dma_lock(flags);    return (residue == 0); }

时间: 2024-11-13 09:47:02

linux 简单的DMA例程的相关文章

五大Linux简单命令解决系统性能问题

五大Linux简单命令解决系统性能问题 2010-12-17 10:07 James Turnbull TechTarget中国 字号:T | T 管理Linux主机的性能看起来经常象是在变魔术一样.许多管理员在遇到性能问题的时候常常简单化处理,依靠硬件的更新换代,更大的内存和更强的CPU来解决问题.事实上,利用一些简单的命令,可以发现许多管理主机的细节问题并且能迅速而简单地解决性能问题. AD:2014WOT全球软件技术峰会北京站 课程视频发布 管理Linux主机的性能看起来经常象是在变魔术一

[原创]linux简单之美(三)

原文链接:linux简单之美(三) 在linux简单之美(二)中我们尝试使用了C库的函数完成功能,那么能不能用syscall方式来搞呢?显然可以! 1 section .data 2 ft db "now is X",10 3 4 section .text 5 global _start 6 7 _start: 8 mov edi,10 9 again: 10 dec edi 11 mov eax,edi 12 add eax,0x30 13 mov byte [ft+7],al 1

linux简单用于监控队脚本

######################################################################### # File Name: monitor.sh # Author: fangtest # mail: [email protected] # Created Time: Sun 29 Jun 2014 06:55:18 PM EDT ###########################################################

Linux简单命令使用

1.  学会使用tar命令压缩(解压).tar.gz文件 tar zxvf *.tar.gz   tar jxvf  *.tar.gz2 2.  学会简单的拷贝cp命令 cp yuan mudi 3.  普通用户转换为超级用户的命令 su –  su - root 4.  查看当前目录下文件命令 ls ls -l   ls -a  ls 5    学会自动补全命令行的技巧   首字母+Tab键 6.  学会使用多种方法安装rpm软件包  rpm -ivh 11.rpm ——rpm命令的使用 rm

[原创]linux简单之美(二)

原文链接:linux简单之美(二) 我们在前一章中看到了如何仅仅用syscall做一些简单的事,现在我们看能不能直接调用C标准库中的函数快速做一些"复杂"的事: 1 section .data 2 ft db "now is %d",10 3 4 section .text 5 extern puts 6 extern exit 7 extern sleep 8 extern printf 9 global main 10 11 main: 12 mov edi,1

[原创]linux简单之美(一)

原文链接:linux简单之美(一) 话说windows也有syscall,这是必须的.但是win的syscall可以直接call吗?可以是可以但是破费周折,搞成SDT之类的复杂概念.下面看看linux是如何做的吧. 1 section .data 2 msg db "hello hopy!",0x0a 3 4 section .text 5 global _start 6 7 _start: 8 mov eax,4 9 mov ebx,1 10 mov ecx,msg 11 mov e

Linux 简单字符设备驱动程序 (自顶向下)

第零章:扯扯淡 特此总结一下写的一个简单字符设备驱动程序的过程,我要强调一下“自顶向下”这个介绍方法,因为我觉得这样更容易让没有接触过设备驱动程序的童鞋更容易理解,“自顶向下”最初从<计算机网络 自顶向下方法>这本书学到的,我觉得有时候这是一种很好的方式. 第一章:测试程序 咦?你怎么跟别人的思路不一样???自顶向下嘛,我就直接从测试程序来说啦,这样那个不是更熟悉吗?看看下面的测试程序的代码,是不是很熟悉? 1 #include <stdio.h> 2 #include <u

菜鸟学Linux 第002篇笔记 Linux简单介绍

Linux的基本原则: 1.由目的单一的小程序组成: 组合小程序完成复杂任务: 2.一切皆文件: 3.尽量避免捕获用户接口(尽量不和用户交互): 4.配置文件保存为纯文本格式: Linux和用户的交互接口 GUI接口:Graphic User Interface CLI接口:Command-Line Interface 命令提示符,prompt, bash(shell) #: root $: 普通用户 交互接口分类和所使用的交互软件 Linux GUI: Gnome:C开发 KDE:C++ Xf

Linux简单使用

Linux简单使用 1.基本命令 创建目录pathA:mkdir pathA 进入目录pathA:cd pathA 查看目录内容:ls 查看目录下文件的详细信息:ls -l,也可以是:ll(l是小写的L,别看错了) 拷贝文件fileA到目录pathA(同层目录前提):cp fileA pathB 拷贝目录pathA(包括目录下的所有)到目录pathB(同层目录前提):cp -r pathA pathB 删除文件fileA:rm fileA 删除目录pathA(包括目录里面的所有):rm -r p