获取适配器对象
在设备启动时,使用系统或总线主 DMA 的驱动程序会调用 IoGetDmaAdapter 来获取指向适配器对象的指针,并确定每个传输操作可用的映射寄存器的最大数目。 当驱动程序调用 IoGetDmaAdapter 时,I/O 管理器反过来会调用 HAL 以获取特定于平台的必要信息。
驱动程序必须在调用 IoGetDmaAdapter 时,在系统定义的DEVICE_DESCRIPTION结构中提供某些信息。 驱动程序必须使用 RtlZeroMemory 初始化 DEVICE_DESCRIPTION 结构,并在其中设置值。
所需数据包括有关驱动程序设备功能的信息,例如设备是否为总线主机、设备是否具有散点/收集功能,以及设备一次可以传输多少字节的数据, (MaximumLength) 。
所需的设备说明数据还包括特定于平台的信息,例如总线主设备驱动程序控制的特定于平台和系统分配的总线编号。 驱动程序可以通过调用 IoGetDeviceProperty 来获取此信息。
DEVICE_DESCRIPTION结构包括一些可能与某些 DMA 设备或驱动程序无关的字段。 例如,WDM 驱动程序中不使用 BusNumber 字段。 每个驱动程序应为相关结构成员提供值,并应将所有其他成员的值设置为零。
当请求必须分解为两个或更多个 DMA 操作时,除非设备能够等待系统 DMA 控制器重新编程,否则从属设备的驱动程序不应在 ScatterGather 字段中传递 TRUE。
IoGetDmaAdapter 返回指向适配器对象的指针和特定于平台或特定于设备的值,该值指示适配器对象可用于每个 DMA 传输操作的映射寄存器数。
返回的适配器对象包含三个可供驱动程序访问的字段:
版本号 (版本)
大小 (大小)
指向 DmaOperations) (DMA_OPERATIONS 结构的指针
DMA_OPERATIONS 结构包含指向驱动程序在其设备上执行 DMA 操作时必须使用的函数的指针表。 函数只能通过此数据结构中的指针访问;驱动程序无法直接按名称调用它们。 (请注意,这些例程替换以前版本的 Windows NT 中支持的 HalXxx 例程。为了确保旧驱动程序的兼容性,Wdm.h 和 Ntddk.h 头文件提供具有过时名称的宏,但新驱动程序应始终通过 data structure.)
映射寄存器的数量可能因设备以及平台而异。 通常,HAL 根据以下条件分配多个映射寄存器:
如果可能,HAL 将返回一个值,该值比传输 MaximumLength 字节所需的映射寄存器数多一个,如驱动程序对 IoGetDmaAdapter 的调用中所述。
否则,HAL 将返回一个较小的值,该值对于特定平台来说尽可能大。
换句话说,HAL 通常为每个驱动程序提供足够的映射寄存器,以最大化其设备的 DMA 吞吐量,但 HAL 在某些 Windows 平台上可以返回较小的值。 无法保证驱动程序将获取它请求的映射寄存器数,因此驱动程序应始终检查返回的值。
任何 DMA 设备驱动程序都必须为 IoGetDmaAdapter 返回的适配器对象指针和 NumberOfMapRegisters 值提供存储。 此指针是指向系统提供的用于 DMA 的支持例程的必需参数。 由于其中许多支持例程必须在 IRQL = DISPATCH_LEVEL调用,因此驱动程序分配的存储必须是驻留的。 大多数 DMA 驱动程序在 设备扩展中提供必要的存储。 但是,如果驱动程序也使用控制器对象或驱动程序分配的非分页池,则存储可以位于 控制器 扩展中。 有关详细信息,请参阅分配System-Space内存和管理硬件优先级。
驱动程序完成所有 DMA 操作后,会调用 PutDmaAdapter 以释放适配器对象。
以下部分 使用系统 DMA 和使用 Bus-Master DMA) 介绍了 DMA 设备的整体驱动程序如何使用支持例程来满足传输请求。 这些部分假定驱动程序具有以下各项:
标准 StartIo 例程,而不是设置和管理 IRP 的内部队列
用于拆分可用映射寄存器数不足的传输请求的内部例程
没有特定于设备的 DMA 约束
换句话说,这些部分介绍了驱动程序的 DMA 操作的最简单技术,但各个驱动程序不一定使用完全相同的技术。 对于 DMA 设备的任何驱动程序,哪些驱动程序例程应拆分大型 DMA 传输请求取决于驱动程序模型 (类/端口或整体) 、设备的功能以及驱动程序必须处理的任何特定于设备的 DMA 约束。