Поделиться через


Использование процедуры 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.

Offset

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