共用方式為


使用 MapTransferEx 例程

MapTransferEx 例程會初始化一組先前配置的 DMA 資源,並啟動 DMA 傳輸。 此例程可在 DMA 作業介面的第 3 版中使用。 從 Windows 8 開始,支援此介面的版本 3。 如需 DMA 作業介面的詳細資訊,請參閱 DMA_OPERATIONS

MapTransferEx 與 MapTransfer 的比較

MapTransferExMapTransfer 例程的改良版本。 從 Windows 2000 的第 1 版開始,MapTransfer 適用於所有版本的 DMA 作業介面。 一次呼叫MapTransfer 就能從 MDL 對應一個連續的實體記憶體區塊。 不過,複雜 DMA 傳輸的數據緩衝區可能會由 MDL 鏈結描述,而鏈結中的每個 MDL 可能會描述數個實體連續記憶體區塊。 若要使用 MapTransfer 來傳輸這類緩衝區,驅動程式必須多次呼叫 MapTransfer。 一般而言,這些呼叫是在一對巢狀循環內進行。 內部迴圈會從一個連續物理記憶體區塊逐一查看到每個 MDL 中的下一個區塊,而外部迴圈會從一個 MDL 逐一查看到 MDL 鏈結中的下一個區塊。

相反地, 對 MapTransferEx 的呼叫可以傳輸整個數據緩衝區,以進行複雜的 DMA 傳輸。 下列三個 MapTransferEx 參數描述要用於傳輸的緩衝區內存。

參數 說明
Mdl

指向一個或多個 MDL 鏈結中第一個 MDL 的指標。 如需 MDL 鏈結的詳細資訊,請參閱使用 MDL

位移

緩衝區的位元組位移是指從 MDL 鏈結描述的記憶體開頭開始的偏移量。

長度

包含數據緩衝區長度之位置的指標,以位元組為單位。

MapTransferEx 呼叫開始時, MapTransferEx 例程會透過 MDL 鏈結前進,以尋找緩衝區的開頭。 緩衝區的開頭是由 Offset 參數指定。 接下來,從緩衝區開頭到結尾, MapTransferEx 會建構散佈/收集清單,其中清單中的每個緩衝區片段都是來自 MDL 鏈結的記憶體實體連續區塊。 若要建構此清單,MapTransferEx 會依次從一個實體連續的記憶體區塊移動到每個 MDL 內的下一個區塊,並從一個 MDL 移動到 MDL 鏈結中的下一個。 當散佈/收集清單所描述的緩衝區內存總數等於 *Length 輸入參數所指定的位元組數目時,清單建構就會完成。 產生的散佈/收集清單中的緩衝區片段順序符合 MDL 鏈結中實體連續區塊的順序。

多次呼叫 MapTransferEx

MapTransferEx 不一定能在一次呼叫中傳輸整個 DMA 數據緩衝區。 下列清單描述了一些可能需要多次呼叫 MapTransferEx 才能完成傳輸的條件:

  • DMA 配接器需要地圖緩存器,而指派給配接器的對應緩存器數目不足以描述整個緩衝區。
  • 驅動程式配置來包含散佈/收集清單的記憶體不夠大,無法包含整個緩衝區的散佈/收集清單。
  • 傳輸會使用系統 DMA 控制器,限制可在硬體散佈/收集清單中指定之緩衝區片段的數目。

在上述所有情況下,MapTransferEx 會在一次呼叫中盡可能地對映數據緩衝區,並告知驅動程式此次呼叫對映了多少緩衝區。 上述清單不包含其他條件,例如平臺特定的快取行為,可能需要多次呼叫 MapTransferEx 才能完成傳輸。 未來的硬體平臺可能會對 DMA 傳輸長度施加額外的限制。 基於這些原因,驅動程式開發人員應該設計其驅動程式,以正確處理 MapTransferEx 無法在一次呼叫中對應整個 DMA 數據緩衝區的情況。

呼叫 MapTransferEx 之前,呼叫端會將 *Length 參數設定為 DMA 數據緩衝區中仍然需要對應的位元組數目。 在傳回之前, MapTransferEx 會將 *Length 設定為呼叫實際對應之緩衝區中的位元組數目。 當 MapTransferEx 呼叫無法對應整個緩衝區長度時,如 *Length 輸入值所指定,*Length 的輸出值會小於其輸入值。 如果 DMA 傳輸需要兩個以上的 MapTransferEx 呼叫,呼叫驅動程式必須先從一個呼叫取得 *Length 輸出值,才能指定下一個呼叫的 *Length 輸入值。

例如,如果 MapTransferEx 呼叫只能將 X 個字節傳送到緩衝區, 而 Offset = B 和 *Length = N (在輸入時),則傳回時為 *Length = X。在下一次呼叫 MapTransferEx 時,驅動程式應該設定 Offset = B + X 和 *Length = N - X。在這兩個呼叫中,都會使用相同的 MDL 鏈結而不修改。

如果呼叫端指定了 DmaCompletionRoutine,那麼 MapTransferEx 將在安排 DmaCompletionRoutine 執行之前寫入 *Length 輸出值。 此行為可確保更新的 *Length 值一律可在 DmaCompletionRoutine 執行之前使用。 例如,如果 DMA 傳輸需要兩個 MapTransferEx 呼叫,則第一次呼叫排程的 DmaCompletionRoutine 可以從第一次呼叫取得 *Length 輸出值。 然後,例程可以使用此值來計算第二次呼叫的 *Length 輸入值。 一般而言,Length 參數會指向提供給 DmaCompletionRoutine 做為參數的 *CompletionContext 值中的位置。