共用方式為


第 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的同步呼叫,如果 MapRegisterBase 參數至 AllocateAdapterChannelEx 不是 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 完成常式的指標可以傳遞至選擇性DmaCompletionRoutine參數中的MapTransferEx。 此常式會排程在分派層級執行,以回應系統 DMA 控制器的中斷,指出 DMA 傳輸已完成。

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

步驟 6:如有必要,請執行硬體特定作業

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

DMA 作業介面中的常式會以使用這些常式的驅動程式透明的方式,維護 DMA 傳輸的快取一致性。 在未在硬體中強制執行快取共通的平臺上, MapTransferEx 可確保處理器資料快取會在寫入 (記憶體到裝置) 傳輸之前排清。 如需讀取 (裝置到記憶體) 傳輸,快取會在呼叫FlushAdapterBuffersEx常式期間失效, (請參閱遵循每個MapTransferEx呼叫的步驟 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 常式來釋放配接器物件。