使用分散/聚合 DMA

执行系统或总线主、基于数据包的 DMA 的驱动程序可以使用专为散点/收集 DMA 设计的支持例程。 驱动程序可以使用 GetScatterGatherListPutScatterGatherList,而不是调用使用 Packet-Based System DMA 和基于数据包的 Bus-Master DMA 中概述的例程序列。

设备不需要具有内置散点图/集合支持,其驱动程序可以使用这些例程。

使用基于数据包的 DMA 的驱动程序调用以下用于散点/收集操作的支持例程的常规序列:

  1. MmGetMdlVirtualAddress,用于将索引获取到 MDL 中,在调用 GetScatterGatherList 时需要作为参数

  2. 当驱动程序准备好为 DMA 编程其设备并且需要系统 DMA 控制器或总线主适配器时,GetScatterGatherList

    GetScatterGatherList 分配系统 DMA 控制器或总线主适配器,确定需要多少个映射寄存器并分配它们,填充散点/收集列表,当 DMA 控制器或适配器和映射寄存器可用时,调用驱动程序 的 AdapterListControl 例程。

  3. 传输所有请求的数据或驱动程序因设备 I/O 错误而使 IRP 失败后,请尽快提交 PutScatterGatherList

    PutScatterGatherList 刷新适配器缓冲区,释放映射寄存器,并释放散点/收集列表。 驱动程序必须先调用 PutScatterGatherList ,然后才能访问缓冲区中的数据。

IoGetDmaAdapter 返回的适配器对象指针是上述每个例程的必需参数,MmGetMdlVirtualAddress 除外,它需要指向 Irp-MdlAddress > 处 MDL 的指针。

GetScatterGatherList 例程包括对 AllocateAdapterChannelMapTransfer 的调用,因此驱动程序无需进行这些调用。 例程采用以下参数:

  • 指向 IoGetDmaAdapter返回DMA_ADAPTER结构指针

  • 指向 DMA 操作的目标设备对象的指针

  • 指向 MDL 的指针,该 MDL 描述 Irp-MdlAddress> 中的缓冲区

  • 指向 Mdl 描述的缓冲区中的当前虚拟地址的指针

  • 要映射的字节数

  • 指向执行传输的 AdapterListControl 例程的指针

  • 指向要传递给 AdapterListControl 例程的驱动程序定义上下文区的指针

  • 布尔值:用于转移到设备的 TRUE;否则为 FALSE

在确定所需的映射寄存器数、分配适配器通道和映射寄存器、填写散点/收集列表并准备传输后, GetScatterGatherList 将调用驱动程序提供的 AdapterListControl 例程。 AdapterListControl 例程在 IRQL = DISPATCH_LEVEL 的任意线程上下文中运行。

驱动程序在调用 GetScatterGatherList 时提供的 AdapterListControl 例程与传递到 AllocateAdapterChannelAdapterControl 例程在以下方面有所不同:

  • AdapterListControl 例程没有返回值,而 AdapterControl 例程返回IO_ALLOCATION_ACTION。

  • 不是指向系统分配的映射寄存器的 MapRegisterBase 的指针,而是 指向 AdapterListControl 例程的第三个参数,而是指向驱动程序可通过该结构执行 DMA 的 SCATTER_GATHER_LIST 结构。

  • AdapterListControl 例程执行 AdapterControl 例程中所需的一部分任务。

    AdapterListControl 例程不调用 AllocateAdapterChannelMapTransfer。 它的唯一职责是保存输入散点/收集列表指针,设置其设备,并使用散点/收集列表执行 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 刷新适配器缓冲区并释放映射寄存器和散点/收集列表。