共用方式為


第 3 版 DMA 例程的基本呼叫模式

若要執行使用 DMA 作業介面第 3 版中常式的 DMA 傳輸,您的驅動程式應該遵循下列清單中所述的步驟。 這些步驟對於從屬設備和總線主控裝置來說都是通用的。 此介面的第 3 版從 Windows 8 開始可用。 如需此介面中常式的詳細資訊,請參閱 DMA_OPERATIONS

步驟 1:取得 DMA 配接器物件

在準備 DMA 傳輸時,驅動程式會呼叫 IoGetDmaAdapter 常式來取得 DMA 配接器物件。 DMA 配接器物件是一種軟體物件,代表匯流排主裝置或系統 DMA 控制器上的要求線。 此物件包含匯流排的 DMA 作業介面,可用來將資料傳輸至裝置或從裝置傳輸資料。 此外,此物件會同步處理驅動程式對執行傳輸所需共用資源的存取權。 如需詳細資訊,請參閱適配器物件的介紹

步驟 2:取得所需 DMA 資源的描述

驅動程式會呼叫 GetDmaTransferInfo 常式,以取得執行傳輸所需的 DMA 資源描述。

此呼叫的輸入參數會描述要用於傳輸的記憶體緩衝區,以及傳輸的方向 (讀取或寫入) 。

從此呼叫取得的資源需求包括對映暫存器的數量,以及為描述傳輸數據緩衝區所需的散佈/收集清單的大小。 在後續呼叫 AllocateAdapterChannelEx 常式 (請參閱 步驟 3) 中,驅動程式會提供對應暫存器計數作為輸入參數。

步驟 3:要求必要的 DMA 資源

驅動程式會呼叫 AllocateAdapterChannelEx 常式,以配置要指派給 DMA 配接器物件的資源。 這些資源包括 DMA 通道和映射暫存器。

AllocateAdapterChannelEx 呼叫可以是非同步或同步。

如果未設定DMA_SYNCHRONOUS_CALLBACK旗標,則呼叫是非同步的。 在此情況下, ExecutionRoutine 參數會指向呼叫端提供的執行常式,該常式會在要求的資源可用時呼叫。 如果成功,非同步 AllocateAdapterChannelEx 呼叫會傳回 STATUS_SUCCESS,並且不需要等待程式執行。

如果已設定 DMA_SYNCHRONOUS_CALLBACK 旗標,則 AllocateAdapterChannelEx 呼叫會同步。 在此情況下,呼叫中的 ExecutionRoutine 參數是選擇性的,而 AllocateAdapterChannelEx 的行為如下:

  • 如果 ExecutionRoutine 為非 Null,而且可以立即配置 DMA 資源,則 AllocateAdapterChannelEx 會在呼叫執行緒的內容中呼叫執行常式。 執行常式完成執行之後, AllocateAdapterChannelEx 會傳回STATUS_SUCCESS。 如果資源無法立即使用, AllocateAdapterChannelEx 會失敗,並傳回錯誤狀態碼 STATUS_INSUFFICIENT_RESOURCES。

  • 如果 ExecutionRoutine 為 Null,且 AllocateAdapterChannelEx 可以立即配置 DMA 資源,則 AllocateAdapterChannelEx 會傳回 STATUS_SUCCESS。 如果所有資源都無法立即使用,則呼叫會失敗,並顯示錯誤狀態碼STATUS_INSUFFICIENT_RESOURCES。

針對傳回STATUS_SUCCESS的同步呼叫,如果 AllocateAdapterChannelExMapRegisterBase 參數為非 Null,則 AllocateAdapterChannelEx 會將配置對應暫存器的基底位址寫入 MapRegisterBase 參數所指向的位址。 如果 ExecutionRoutine 為 Null,則 MapRegisterBase 必須是非 Null。 如果 ExecutionRoutine 為非 Null,則 AllocateAdapterChannelExMapRegisterBase 參數是選擇性的,而且執行常式會接收對應暫存器基底位址作為輸入參數。

針對非同步 AllocateAdapterChannelEx 呼叫,ExecutionRoutine 必須是非 NULL,而且執行常式會接收映射暫存器的基址作為輸入參數。

MapTransferEx 常式的後續呼叫中 (請參閱 步驟 5) ,驅動程式會提供對應暫存器基底位址作為輸入參數。

如果 ExecutionRoutine 為非 Null,則執行常式會傳回狀態值,以指出已配置資源的處置方式。 針對系統 DMA 傳輸,此傳回值必須是 KeepObject。 此值會通知作業系統配接器物件 (及其所有配置的資源) 正在使用中,而且不應釋放。 如果未提供任何執行常式,驅動程式必須改為呼叫 FreeAdapterObject 常式,並提供 KeepObject 作為 AllocationOption 參數。

步驟 4:如有必要,取消待處理的資源請求

AllocateAdapterChannelEx 呼叫將 DMA 配接器排入佇列以等候 DMA 資源之後,驅動程式可以視需要呼叫 CancelAdapterChannel 常式來取消擱置的資源要求。

如果 CancelAdapterChannel 傳回 TRUE,則會成功取消資源要求。 如果在 AllocateAdapterChannelEx 呼叫中提供執行常式,則不會執行此常式。

如果 CancelAdapterChannel 傳回 FALSE,則無法取消資源要求,因為它已授與。 如果在 AllocateAdapterChannelEx 呼叫中提供執行常式,則會呼叫此常式。

步驟 5:初始化 DMA 資源並啟動 DMA 傳輸

驅動程式會呼叫 MapTransferEx 來初始化 DMA 資源,並啟動 DMA 傳輸。 此呼叫可能會發生在呼叫 AllocateAdapterChannelEx 的相同驅動程式執行緒中,或可能發生在驅動程式提供給 AllocateAdapterChannelEx 的執行常式中。 如果需要多個 MapTransferEx 呼叫來傳輸整個 DMA 數據緩衝區,則先前 MapTransferEx 呼叫的完成常式中可能會發生稍後的 MapTransferEx 呼叫。

MapTransferEx 支援鏈結的 MDL 作為輸入參數。 每個 MDL 都會描述在虛擬記憶體中連續的 DMA 緩衝區區域。 當 MapTransferEx 建置散佈/收集清單時,它會自動處理從一個幾乎連續的緩衝區區域轉換到下一個緩衝區區域,而不需要驅動程式介入。 如需詳細資訊,請參閱使用 MapTransferEx 例程

針對系統 DMA 傳輸,DMA 完成常式的指標可以傳遞至 MapTransferEx 在選擇性 DmaCompletionRoutine 參數中。 此常式排程在分派層級執行,以回應系統 DMA 控制器發出的中斷,該中斷指示 DMA 傳輸已完成。

如果 MapTransferEx 無法對應整個要求的傳輸大小,它會將 *Length 輸出參數設定為對應的長度,並傳回STATUS_SUCCESS。

步驟6:如有必要,執行特定於硬體的操作

MapTransferEx 會傳回 STATUS_SUCCESS,指出 DMA 傳輸已成功起始。 在某些平臺上,驅動程式可能必須在 MapTransferEx 呼叫之外採取一些額外的動作,才能開始傳輸,但並非所有平臺都需要這種類型的延遲啟動。 驅動程式不得依賴此類延遲來決定使用和釋放已配置的資源。

DMA 作業介面中的常式會以對使用這些常式的驅動程式透明的方式維護 DMA 傳輸的快取一致性。 在未在硬體中強制執行快取一致性的平臺上, MapTransferEx 可確保在寫入 (記憶體至裝置) 傳輸之前排清處理器資料快取。 針對讀取傳輸(裝置對記憶體),在每個 MapTransferEx 呼叫之後的FlushAdapterBuffersEx例程呼叫期間(請參閱步驟 8),快取會被失效。

步驟 7:DMA 傳輸完成時收到通知

當 DMA 傳輸完成時,會以下列兩種方式之一通知驅動程式:

  • 匯流排主要裝置的裝置驅動程式中斷
  • 針對使用系統 DMA 控制器的次級裝置執行驅動程式提供的完成常式

針對系統 DMA 傳輸,驅動程式可以提供完成常式給 MapTransferEx 作為輸入參數。

步驟 8:清除快取中保留的任何資料

DMA 傳輸完成之後,驅動程式必須呼叫 FlushAdapterBuffersEx 常式,以排清快取中保留的任何數據。 驅動程式必須在每次 MapTransferEx 呼叫之後呼叫 FlushAdapterBuffersEx

如果 MapTransferEx 呼叫只對應 DMA 資料緩衝區的一部分,驅動程式必須再次呼叫 MapTransferEx 來對應剩餘的資料。 複雜的傳輸可能需要數個 MapTransferEx 呼叫。 針對每個額外的 MapTransferEx 呼叫,重複步驟 5 到 8。

步驟 9:釋放 DMA 通道和映射暫存器

成功對應整個 DMA 資料緩衝區且完成最後的傳輸之後,驅動程式必須呼叫 FreeAdapterChannel 常式,以釋放 DMA 通道和任何先前分配的映射暫存器。

步驟 10:釋放 DMA 配接器物件

完成所有 DMA 傳輸,並釋放任何先前配置的對應暫存器之後,驅動程式會呼叫 PutDmaAdapter 常式來釋放配接器物件。