Использование процедуры MapTransferEx

Подпрограмма MapTransferEx инициализирует набор ранее выделенных ресурсов DMA и запускает передачу DMA. Эта подпрограмма доступна в интерфейсе операций DMA версии 3. Версия 3 этого интерфейса поддерживается начиная с Windows 8. Дополнительные сведения об интерфейсе операций DMA см. в DMA_OPERATIONS.

Сравнение MapTransferEx с MapTransfer

MapTransferEx — улучшенная версия подпрограммы MapTransfer . MapTransfer доступен во всех версиях интерфейса операций DMA, начиная с версии 1 в Windows 2000. Один вызов 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. Построение списка завершается, когда общий объем буферной памяти, описанной в списке scatter/gather, равен числу байтов, заданных параметром ввода *Length. Порядок фрагментов буфера в результирующем списке разброса/сбора соответствует порядку физически смежных блоков в цепочке MDL.

Несколько вызовов MapTransferEx

MapTransferEx может не всегда передавать весь буфер данных DMA в одном вызове. В следующем списке описаны некоторые условия, которые могут потребовать вызова MapTransferEx несколько раз для завершения передачи:

  • Адаптер DMA требует регистров карты, а количество регистров карты, назначенных адаптеру, недостаточно для описания всего буфера.
  • Хранилище, выделенное драйвером для хранения списка scatter/gather, недостаточно велико, чтобы содержать этот список для всего буфера.
  • Передача использует системный контроллер 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 записывает выходное значение *Length перед тем, как запланировать DmaCompletionRoutine для выполнения. Это поведение гарантирует, что обновленное значение *Length всегда доступно перед запуском DmaCompletionRoutine . Например, если для передачи DMA требуется два вызова MapTransferEx, то DmaCompletionRoutine, запланированная первым вызовом, может получить выходное значение *Length из первого вызова. Затем подпрограмма может использовать это значение для вычисления входного значения *Length для второго вызова. Обычно параметр Length указывает на местоположение в значении *CompletionContext, которое передается в DmaCompletionRoutine в качестве параметра.