驱动开发-DMA的开发原理讲解

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

DMAsigang@mti.xidian.edu.cnDMADMA即DirectMemoryaccess无需计算机的CPU的干预就可以在内存和外设之间传输数据通常都有DMA控制器来进行DMA操作,DMA控制器可能是主板上的,也有可能是外设特有的。为什么需要DMA?传输模型Windows中的DMA传输基于这个模型适配器对象(adapter)Windows2000内核使用一个称为适配器对象的数据结构来描述设备上的DMA特征,并用它来控制访问潜在的共享资源,如系统DMA通道和映射寄存器通常在StartDevice函数中调用IoGetDmaAdapter获得适配器对象适配器对象中有一个指针,指向一个DmaOperations的结构,该结构包含了所有需要的DMA相关的其它函数,这些函数如下表DmaOperationsFunctionPointerDescriptionPutDmaAdapterDestroysadapterobjectAllocateCommonBufferAllocatesacommonbufferFreeCommonBufferReleasesacommonbufferAllocateAdapterChannelReservesadapterandmapregistersFlushAdapterBuffersFlushesintermediatedatabuffersaftertransferFreeAdapterChannelReleasesadapterobjectandmapregistersFreeMapRegistersReleasesmapregistersonlyMapTransferProgramsonestageofatransferGetDmaAlignmentGetsaddressalignmentrequiredforadapterReadDmaCounterDeterminesresidualcountGetScatterGatherListReservesadapterandconstructsscatter/gatherlistPutScatterGatherListReleasesscatter/gatherlist传输策略选择1。如果设备有总线主控能力,那么它就有访问主存的必要硬件部件,因此只需要告诉它几个基本事实,如从哪开始,需要传输多少单位的数据,是输入操作还是输出操作,等等。可以向硬件设计者咨询或者固件程序员咨询以得到细节部分,否则只能参考许多硬件级的说明文档。传输策略选择2。一个有分散/聚集(scatter/gather)能力的设备可以在自身与不连续的物理内存区之间传输大块数据。设备的分散/聚集能力对软件十分有利,它可以避免对具有连续页帧的大块的内存的需求。页可以被简单地锁定在所在的物理内存,只要把内存地址告诉设备就可以进行。传输策略选择3。如果设备不是总线主控设备,那么需要使用计算机主板上的系统DMA控制器。这种形式的DMA传输被称为从属DMA(slaveDMA)。与ISA总线连接的系统DMA控制器对所能访问的物理内存和一次传输的数据量会有些限制。EISA总线的DMA控制器去掉了这些限制。在Windows2000中,不必知道硬件具体插入到哪种类型的总线,因为系统自动参考这些不同的限定。传输策略选择4。通常,DMA操作将包括编程硬件映射寄存器或操作前后的数据复制。如果设备需要连续地读写数据,我们不希望在每次I/O请求中都做这两步,这将大大地降低处理速度,在某些情况下也是不能接受的。因此,应该分配一个公用缓冲区(commonbuffer),设备和驱动程序可以在任何时间同时访问这个缓冲区。说明在涉及DMA传输的过程中策略的选择是第一步也是最重要的一步。不仅需要参考硬件,还要参考可能的软件需求(主控,从属,包,通用缓冲区)尽管这四种因素的相互影响会产生许多种不同的结果,但执行的步骤中有许多共同的特征。如下图显示了一次传输过程:执行DMA传输基于包(packet-based)的DMA传输。在这种方式中,将使用IRP携带的数据缓冲区来传输一定量的数据。为了简单,让我们假设面对当前最普通的情况:一个基于PCI的总线主控设备并且没有分散/聚集能力。为什么简单?下面按照程序编写的通常步骤来详细说明DMA的过程缓冲方式当创建设备对象时,通常指定使用Direct缓冲方式,即设置DO_DIRECT_IO标志。或者在定义CTL_CODE时指定directinput或者directoutput方式。因为调用的MapTransfer函数需要一个MDL作为参数,这种方式会在每一个IRP的MdlAddress保存描述用户缓冲区的MDL创建和销毁适配器对象在处理startdevice的pnp请求时,我们除了要取得IO,内存,中断资源外,还要创建一个适配器对象(adapterobiect)。在处理stopdevice请求时,除了释放映射的IO,内存资源,断开中断的连接外,还要销毁适配器对象。例如:DMA.doc和其它资源区别前面讲过的IO,内存,和中断资源,我们都回在一个CmResourceTypeXxx类型的case子句中获得,这里不需要CmResourceTypeDma类型的case子句,因为设备是总线主控方式,硬件本身包含有执行DMA传输所必须的所有电路逻辑,所以系统没必要赋予设备DMA资源。获取DMA通道为了初始化一个I/O操作,StartIo例程必须首先调用适配器对象的AllocateAdapterChannel例程以获取适配器对象。该函数的一个参数是AdapterControl例程的地址,I/O管理器将在获取操作完成后调用这个例程。AllocateAdapterChannel函数的准备和调用过程:DMA.docAllocateAdapterChannel何时完成AllocateAdapterChannel做什么?等待DMA控制器,和映射寄存器可用主控,从属,支持映射寄否?当DMA控制器,和映射寄存器都可用时,AllocateAdapterChannel调用AdapterControl例程调用AdapterControlAllocateAdapterChannel最终将调用驱动程序提供的AdapterControl例程(在DISPATCH_LEVEL,就象StartIo例程一样)。AdapterControl例程的两个任务:AdapterControl例程的两个任务第一,应该调用适配器对象的MapTransfer例程以便为I/O操作的第一阶段准备映射寄存器和其它系统资源。如果是总线主控设备,MapTransfer将返回一个代表传输第一阶段开始点的逻辑地址。这个逻辑地址可能会与CPU的物理内存地址相同,但也可能会不同。所需要知道的就是该地址就是编程设备硬件的正确地址。第二个任务是执行与“通知设备这个物理地址”操作中涉及的任何设备相关的操作步骤,然后开始操作设备硬件:DMA.docDPC中断通常都发生在传输启动后的很短一段时间后,并且Isr只做很少的事情,比如判断中断类型清除中断状态位之后,Isr通常都请求一个DPC来处理传输第一阶段的完成,并开始下一个操作。DMA.doc使用分散集中列表进行传输如果硬件支持分散/聚集能力,那么系统可以更容易地处理设备的DMA传输。分散/聚集能力允许设备传输所涉及的页在物理内存中不连续。这种设备的StartDevice例程在创建适配器对象上使用与前面讨论的同样的方式,除了ScatterGather标志应该设为TRUE。传统方法在安排一个涉及分散/聚集功能的DMA传输时,几乎等同于前面段“执行DMA传输”中的基于包的例子。唯一不同之处是它需要为传输的每个阶段多次调用MapTransfer。每次调用后都会得到分散/聚集列表中的一个包含物理地址和长度的数组元素。当循环完成时,可以使用设备专用的方法把分散/聚集列表发送到设备,然后开始传输。DMA.doc使用GetScatterGatherList这种方法不用手动构建Scatter/gather列表DMA.doc在决定使用GetScatterGatherList前,以下的前提需要满足:程序运行在2000及以后系统,98/ME不支持这个函数如果不确定或者为了程序的兼容性,应该使用传统的循环获取Scatter/gather列表使用系统DMA控制器即slaveDMA所有slave设备必须共享有限的DMA通道数量。AllocateAdapterChannel在这种共享情形中具有真正意义,因为一次只能有一个设备可以使用特定的通道可以在PnP管理器发送的I/O资源列表中找到一个CmResourceTypeDma资源。大部分方面和总线Master设备类似,一些差别使用公用缓冲区通常应该在StartDevice中,在创建适配器对象后分配公用缓冲区:DMA.doc使用公用缓冲区的Slave模式DMA传输必须为接收数据的虚拟地址创建一个MDL。MDL的实际目的是在最后调用MapTransfer中占用一个参数,这个MDL指名不需要任何数据复制。通常应该在StartDevice函数中,紧接着分配公用缓冲区之后创建该MDL为了执行一个输出操作,首先应通过某些手段(如一个明确的内存复制)使公用缓冲区中包含有要发往到设备的数据在输入操作的结尾,应该把数据从公用缓冲区复制到其它某个地方使用公用缓冲区的Slave模式DMA传输其它部分和进行基于包的DMA传输类似:调用AllocateAdapterChannel,该函数调用驱动程序提供的适配器控制例程,这个例程又调用KeFlushIoBuffers(如果分配了一个可被高速缓冲的缓冲区),最后调用MapTransfer。DPC例程将调用FlushAdapterBuffers和FreeAdapterChannel函数。唯一要注意的是应该指定公用缓冲区的MDL来代替读写IRP携带的MDL使用公用缓冲区的master模式DMA传输如果设备是总线主控模式,那么在分配公用缓冲区后就没有必要调用AllocateAdapterChannel、MapTransfer、FreeMapRegisters函数。因为AllocateCommonBuffer也能保留必要的映射寄存器。每个总线主控设备都有一个适配器对象,该对象不与其它设备共享,因此不必等待。由于拥有可以在任何时间都能访问缓冲区的虚拟地址,又由于设备的总线主控能力允许使用物理地址(由AllocateCommonBuffer返回)访问该缓冲区,所以没有额外的工作需要做。这是所有形式的DMA传输中最简单的。使用公用缓冲区的注意事项在运行系统中,物理上连续的内存是十分稀有的,有时根本得不到这样的内存,除非在系统启动的早期请求这样的内存。内存管理器为了满足请求会对内存页进行重排列,但它的尝试十分有限,并且这个过程会推迟AllocateCommonBuffer的返回。有时尝试会失败,所以必须能够处理这种失败情况。公用缓冲区不仅与稀有的物理内存页相关,而且还与其它设备争用映射寄存器。释放公用缓冲区在处理停止设备时需要释放公用缓冲区(*pdx-AdapterObject-DmaOperations-FreeCommonBuffer)(pdx-AdapterObject,length,pdx-paCommonBuffer,pdx-vaCommonBuffer,FALSE);

1 / 29
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功