使用分散/聚合 DMA

执行系统或总线主控、基于数据包的 DMA 的驱动程序可以使用专为散点/收集 DMA 设计的支持例程。 驱动程序可以使用 GetScatterGatherListPutScatterGatherList,而不是调用 Using Packet-Based System DMAPacket-based 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 以外的每个例程的必需参数,MmGetMdlVirtualAddress 需要指向 Irp-MdlAddress > 处的 MDL 的指针。

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

  • 指向 IoGetDmaAdapter 返回的 DMA_ADAPTER 结构的指针

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

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

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

  • 要映射的字节数

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

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

  • 一个布尔值:TRUE 表示传输到设备;否则为 FALSE

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

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

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

  • AdapterListControl 例程的第三个参数而不是指向系统分配的映射寄存器的 MapRegisterBase 的指针,而是指向驱动程序可以通过该结构执行 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 刷新适配器缓冲区并释放映射寄存器和散点/收集列表。