共用方式為


使用 Common-Buffer System DMA

使用系統 DMA 控制器自動初始化模式的驅動程式必須配置記憶體給可以執行 DMA 傳輸的緩衝區或從中執行。驅動程式會呼叫 AllocateCommonBuffer 來取得此緩衝區,通常是從處理IRP_MN_START_DEVICE要求的 DispatchPnP 例程。 下圖顯示驅動程式如何配置緩衝區,並將其虛擬位址範圍對應至系統物理記憶體。

圖表說明驅動程式如何配置系統 dma 的通用緩衝區。

如上圖所示,驅動程式會採取下列步驟來配置系統 DMA 的緩衝區:

  1. 驅動程式會呼叫 AllocateCommonBuffer,將指標傳遞至 IoGetDmaAdapter 所傳回的配接器物件,以及其緩衝區所要求的位元組長度。 若要在經濟上使用記憶體,緩衝區的輸入 Length 值應小於或等於PAGE_SIZE,或應該是PAGE_SIZE的整數倍數。

  2. 如果 AllocateCommonBuffer 傳回 NULL 指標,驅動程式應該釋放它已宣告的任何系統資源,並傳回STATUS_INSUFFICIENT_RESOURCES以回應 IRP_MN_START_DEVICE 要求。

    否則, AllocateCommonBuffer 會在系統虛擬位址空間中配置要求的記憶體數量,並將兩種不同類型的指標傳回給該緩衝區:

    • 緩衝區的 LogicalAddress(上圖中的 BufferLogicalAddress),驅動程式必須提供儲存空間,但隨後應該忽略它。

    • 緩衝區的虛擬位址(上圖中的 BufferVirtualAddress),驅動程式也必須儲存該位址,以便建置描述其 DMA 作業緩衝區的 MDL

    驅動程式應該將這些指標儲存在裝置擴充功能或其他驅動程式配置的常駐記憶體中。

  3. 驅動程式會呼叫 IoAllocateMdl 來配置緩衝區的 MDL。 驅動程式會傳遞 AllocateCommonBuffer 所傳回之緩衝區的 VirtualAddress,以及其緩衝區的 Length,以配置 MDL。

  4. 驅動程式會使用IoAllocateMdl傳回的指標,呼叫MmBuildMdlForNonPagedPool,將其常駐緩衝區的虛擬位址範圍對應至系統物理記憶體。

配置通用緩衝區並對應其虛擬位址範圍之後,次級裝置的驅動程式可以開始處理要求 DMA 傳輸的 IRP。 若要這樣做,驅動程式會呼叫下列一般支援例程:

  1. 在驅動程式寫入器的判斷權下, RtlMoveMemory 將數據從鎖定的用戶緩衝區複製到驅動程式配置的通用緩衝區,以傳輸至裝置

  2. 當驅動程式準備好要為其裝置進行 DMA 程式設計且需要系統 DMA 控制器時,AllocateAdapterChannel

  3. MapTransfer,其中包含描述驅動程式配置的通用緩衝區的 MDL,以設定傳輸作業的系統 DMA 控制器

    請注意,驅動程式只會呼叫 MapTransfer 一次,以設定系統 DMA 控制器使用其通用緩衝區。 在傳輸期間,驅動程式可以呼叫 ReadDmaCounter 來判斷要傳輸多少個字節,如有必要,請呼叫 RtlMoveMemory ,以將更多數據複製到用戶緩衝區或從用戶緩衝區複製。

  4. FlushAdapterBuffers 當驅動程式完成從次級裝置的 DMA 傳輸時

  5. 當所有要求的數據已經傳輸完成,或因裝置 I/O 錯誤驅動程式必須讓 IRP 失敗時,FreeAdapterChannel

IoGetDmaAdapter 所傳回的配接器對象指標是除了 RtlMoveMemory 之外,這些支援例程的必要參數。

個別驅動程式會根據每個驅動程序的實作方式,在不同的時間點呼叫此序列的支援例程,以服務其裝置。 例如,一個驅動程式的 StartIo 例程可能會呼叫 AllocateAdapterChannel,另一個驅動程式可能會從從驅動程式建立的聯結佇列中移除 IRP 的例程進行此呼叫,而另一個驅動程式可能會在其次級 DMA 裝置指出已準備好傳輸數據時進行此呼叫。