共用方式為


使用 MapTransferEx 常式

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

MapTransferEx 與 MapTransfer 的比較

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

相反地, 對 MapTransferEx 的呼叫可以傳輸整個資料緩衝區,以進行複雜的 DMA 傳輸。 下列三個 MapTransferEx 參數描述用於傳輸的緩衝區記憶體。

參數 描述
Mdl

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

Offset

緩衝區的位元組位移,從 MDL 鏈結所描述的記憶體開頭。

長度

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

MapTransferEx 呼叫開始時, MapTransferEx 常式會通過 MDL 鏈結來尋找緩衝區的開頭。 緩衝區的開頭是由 Offset 參數所指定。 接下來,從緩衝區的開頭到結尾, MapTransferEx 會建構散佈/收集清單,其中清單中的每個緩衝區片段都是 MDL 鏈結中實際連續的記憶體區塊。 若要建構此清單, MapTransferEx 會從一個實際連續記憶體區塊到每個 MDL 內的下一個區塊,以及從一個 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 呼叫只能對位 = B 和 *Length = N (輸入) 的緩衝區傳輸 X 個位元組,則傳回時,*Length = X。在下一次呼叫 MapTransferEx時,驅動程式應該設定 Offset = B + X 和 *Length = N - X。在這兩個呼叫中,都會使用相同的 MDL 鏈結,而不需修改。

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