使用分散/聚合 DMA
执行系统或总线主控、基于数据包的 DMA 的驱动程序可以使用专为散点/收集 DMA 设计的支持例程。 驱动程序可以使用 GetScatterGatherList 和 PutScatterGatherList,而不是调用 Using Packet-Based System DMA 和 Packet-based Bus-Master DMA 中所述的例程序列。
设备不需要为其驱动程序提供内置的散点/收集支持即可使用这些例程。
使用基于数据包的 DMA 的驱动程序调用以下散点/收集操作支持例程的常规序列:
MmGetMdlVirtualAddress 用于获取 MDL 中的索引,在调用 GetScatterGatherList 时需要作为参数
当驱动程序准备好针对 DMA 对设备进行编程并且需要系统 DMA 控制器或总线-主适配器时,GetScatterGatherList
GetScatterGatherList 分配系统 DMA 控制器或总线-主适配器,确定所需的映射寄存器数并分配它们,填充散点/收集列表,并在 DMA 控制器或适配器和映射寄存器可用时调用驱动程序的 AdapterListControl 例程。
传输所有请求的数据或驱动程序因设备 I/O 错误而使 IRP 失败后,PutScatterGatherList 立即
PutScatterGatherList 刷新适配器缓冲区,释放映射寄存器,并释放散点/收集列表。 驱动程序必须先调用 PutScatterGatherList ,然后才能访问缓冲区中的数据。
IoGetDmaAdapter 返回的适配器对象指针是除 MmGetMdlVirtualAddress 以外的每个例程的必需参数,MmGetMdlVirtualAddress 需要指向 Irp-MdlAddress > 处的 MDL 的指针。
GetScatterGatherList 例程包括对 AllocateAdapterChannel 和 MapTransfer 的调用,因此驱动程序不必进行这些调用。 例程采用以下参数:
指向 IoGetDmaAdapter 返回的 DMA_ADAPTER 结构的指针
指向 DMA 操作的目标设备对象的指针
指向 MDL 的指针,用于描述 Irp-MdlAddress> 中的缓冲区
指向 Mdl 描述的缓冲区中当前虚拟地址的指针
要映射的字节数
指向执行传输的 AdapterListControl 例程的指针
指向要传递给 AdapterListControl 例程的驱动程序定义的上下文区域的指针
一个布尔值:TRUE 表示传输到设备;否则为 FALSE
确定所需的映射寄存器数、分配适配器通道和映射寄存器、填写散点/收集列表并准备传输后, GetScatterGatherList 调用驱动程序提供的 AdapterListControl 例程。 AdapterListControl 例程在 IRQL = DISPATCH_LEVEL的任意线程上下文中运行。
驱动程序在调用 GetScatterGatherList 时提供的 AdapterListControl 例程与传递给 AllocateAdapterChannel 的 AdapterControl 例程在以下重要方面不同:
AdapterListControl 例程没有返回值,而 AdapterControl 例程返回IO_ALLOCATION_ACTION。
AdapterListControl 例程的第三个参数而不是指向系统分配的映射寄存器的 MapRegisterBase 的指针,而是指向驱动程序可以通过该结构执行 DMA 的SCATTER_GATHER_LIST结构。
AdapterListControl 例程执行 AdapterControl 例程中所需的任务的子集。
AdapterListControl 例程不调用 AllocateAdapterChannel 或 MapTransfer。 它的唯一职责是保存输入散点/收集列表指针,设置其设备,并使用散点/收集列表执行 DMA。
散点/收集列表结构包括 SCATTER_GATHER_ELEMENT 数组和数组中的元素数。 数组的每个元素提供物理连续散点/收集区域的长度和起始物理地址。 驱动程序在数据传输中使用长度和地址。
驱动程序可以使用 GetScatterGatherList ,无论其设备是否支持散点/收集 DMA。 对于不支持散点/收集 DMA 的设备,散点/收集列表将仅包含一个元素。
使用散点/收集例程可以比调用 AllocateAdapterChannel (提高性能,如前面 使用 Packet-Based 系统 DMA 和使用 Packet-Based Bus-Master DMA) 中所述。 与调用 AllocateAdapterChannel 不同,对 GetScatterGatherList 的多次调用可以随时排队等待设备对象。 在其 AdapterListControl 例程完成执行之前,驱动程序可以针对同一驱动程序对象上的另一个 DMA 操作再次调用 GetScatterGatherList。
从驱动程序提供的 AdapterListControl 例程返回时, GetScatterGatherList 会保留映射寄存器,但释放 DMA 适配器结构。
当驱动程序满足当前 IRP 的传输请求或由于设备或总线 I/O 错误而使 IRP 失败时,它必须先调用 PutScatterGatherList ,然后才能访问缓冲区中传输的数据。 PutScatterGatherList 刷新适配器缓冲区并释放映射寄存器和散点/收集列表。