使用 MapTransferEx 常式
MapTransferEx常式會初始化一組先前配置的 DMA 資源,並啟動 DMA 傳輸。 此常式可在 DMA 作業介面的第 3 版中使用。 從 Windows 8 開始,支援此介面第 3 版。 如需 DMA 作業介面的詳細資訊,請參閱 DMA_OPERATIONS。
MapTransferEx 與 MapTransfer 的比較
MapTransferEx 是 MapTransfer 常式的改良版本。 從 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 鏈結,而不需修改。
如果呼叫端指定DmaCompletionRoutine,MapTransferEx會在排程要執行的 DmaCompletionRoutine之前寫入 *Length輸出值。 此行為可確保DmaCompletionRoutine執行之前,一律會提供更新的 *Length值。 例如,如果 DMA 傳輸需要兩個 MapTransferEx 呼叫,則第一次呼叫排程的 DmaCompletionRoutine 可以從第一次呼叫取得 *Length 輸出值。 然後,常式可以使用此值來計算第二次呼叫的 *Length 輸入值。 一般而言, Length 參數會指向 *CompletionCoNtext 值中提供給 DmaCompletionRoutine 做為參數的位置。