snifer

【技术分享】【原创】与DMA控制器对话

0
阅读(3306)

嵌入式系统中最常见的就是DMA的控制,下面乘着博客竞赛的风,讲讲这方面的问题。

注册完成后,驱动程序的主要工作是为正确的操作来配置DMA控制器。这项工作并不简单,好在核心引出了所有典型驱动程序所需的函数。

readwrite被调用,或者在预备异步传送时,驱动程序都需要配置DMA控制器。第二种情况,任务在open时或在对一个ioctl命令响应时被执行,这依赖于驱动程序及其实现策略。这里给出的代码一般是由readwrite设备方法调用。

我会对DMA控制器内部给出一个快速的概览,这样你就可以理解这里介绍的代码。如果你想学更多,我鼓励你阅读<asm/dma.h>和一些介绍PC体系结构的硬件手册。特别地,我并不关注8位和16位数据传输的区别。如果你在为ISA设备板子写设备驱动程序,你应该在设备的硬件手册里查找相关信息。

必须装入控制器的信息由三项组成:RAM地址,必须传送的原子项数目(以字节或字为单位),传送的方向。为了这个目的,下面的函数由<asm/dma.h>引出:

void set_dma_mode(unsigned int channel, char mode);

       说明通道是从设备读(DMA_MODE_READ)还是向设备写(DMA_MODE_WRITE)。还有第三个模式,DMA_MODE_CASCADE,用来释放对总线的控制。级联是第一个控制器连到第二个控制器上的方法,但它也可以由真正的ISA bus-master设备使用。我在这里不想讨论bus-master

void set_dma_addr(unsigned int channel, unsigned int addr);

       分配DMA缓冲区的地址。这个函数将addr的低24位存入到控制器。参数addr必须是个总线地址(见“总线地址”)。

void set_dma_count(unsigned int channel, unsigned int count);

       分配要传送的字节数。参数count16位通道仍以字节为单位;在这种情况下,这个数必须是个偶数。

 

除了这几个函数,还有一些必须用来处理DMA设备的杂务工具:

void disable_dma(unsigned int channel);

       一个DMA通道可以在控制器内被关闭。在DMAC被配置之前,通道应该被关闭以防止不正确的操作(控制器通过8位数据传送编程,这样前面的函数都不能被原子地执行。)

void enable_dma(unsigned int channel);

       这个函数告诉控制器这个DMA通道含有效数据。

int get_dma_residue(unsigned int channel);

       驱动程序有时需要知道一个DMA传送是否结束了。这个函数返回尚待传送的字节数。如果成功传送完,则返回0;如果控制器还在工作,返回值则不可预知(但不是0)。这种不可预知性反映一个事实,即这个余数是个16位值,通过两个8位输入操作获得。

void clear_dma_ff(unsigned int channel);

       这个函数清除DMA flip-flopflip-flop用来控制对16位寄存器的访问。这些寄存器由两个连续的8位操作来访问,flip-flop用来选中低字节(当它被清除时)或高字节(当它被置时)。flip-flop8位传输完后自动反转;在访问DMA积存器前必须清除一次flip-flop

 

用这些函数,驱动程序可以实现如下所示的一个函数来预备一个DMA传送:

(代码297

如下的函数用来检查DMA的成功完成:

int dad_dma_isdone(int channel)

{

     return(get_dma_residue(channel)==0);

}

剩下唯一要做的事就是配置设备板子。这个设备特定的任务通常包括读写几个I/O端口。设备在很多地方不同。例如,有的设备期望程序员告诉硬件DMA缓冲区有多大,有时驱动程序必须从设备中读出被硬写入的数值。为了配置板子,硬件手册是你唯一的朋友。

 

DMAPCI设备

DMAPCI实现比ISA上要简单的多。

PCI支持多个bus-master,而DMA就简化成bus-mastering。需要读写主存的设备只需要简单地请求获得总线的控制,接着就可以直接控制电信号。PCI的实现在硬件级更精巧,在设备驱动程序中更容易管理。

编写PCI上的DMA传送由下列步骤组成:

分配一个缓冲区

       DMA缓冲区在内存中必须是物理连续的,但没有16MB寻址能力的限制。一个get_free_page调用就足够了。不必在优先级中指定GFP   _DMA。如果你真的需要它,你可以转向(不鼓励)在前面“分配DMA缓冲区”中介绍过的更具进攻性的技术。

和设备对话

       扩展设备必须被告知DMA缓冲区。这通常意味着将缓冲区的地址和大小写入几个设备积存器。有时,DMA的大小由硬件设备决定,但这是设备相关的。传往PCI设备的地址必须是总线地址。

正如你所看到的,不存在为PCI设备编写的通用代码。一个典型的实现如下所示,但每个设备都不相同,配置信息量变化也很大。

就写这么多吧,夜深了!~~~