Partilhar via


Usando a rotina MapTransferEx

A rotinaMapTransferExinicializa um conjunto de recursos DMA alocados anteriormente e inicia uma transferência DMA. Essa rotina está disponível na versão 3 da interface de operações DMA. A versão 3 desta interface é suportada a partir do Windows 8. Para obter mais informações sobre a interface de operações DMA, consulte DMA_OPERATIONS.

Comparação de MapTransferEx para MapTransfer

MapTransferEx é uma versão melhorada da rotina MapTransfer. MapTransfer está disponível em todas as versões da interface de operações DMA, começando com a versão 1 no Windows 2000. Uma chamada para MapTransfer pode mapear um bloco contíguo de memória física de um MDL. No entanto, o buffer de dados para uma transferência DMA complexa pode ser descrito por uma cadeia MDL, e cada MDL na cadeia pode descrever vários blocos de memória fisicamente contígua. Para usar MapTransfer para transferir este buffer, um driver deve fazer várias chamadas para MapTransfer. Normalmente, essas chamadas são feitas dentro de um par de loops aninhados. O loop interno itera de um bloco de memória física contígua para o próximo em cada MDL, e o loop externo itera de um MDL para o próximo na cadeia MDL.

Em contraste, uma chamada para MapTransferEx pode transferir todo o buffer de dados para uma transferência DMA complexa. Os três parâmetros MapTransferEx a seguir descrevem a memória buffer a ser usada para a transferência.

Parâmetro Descrição
Mdl

Um ponteiro para a primeira MDL de uma cadeia de uma ou mais MDLs. Para obter mais informações sobre cadeias MDL, consulte Usando MDLs.

Desvio

O deslocamento em bytes do buffer a partir do início da memória descrita pela cadeia MDL.

Comprimento

Um ponteiro para um local que contém o comprimento, em bytes, do buffer de dados.

No início de uma chamada de MapTransferEx, a rotina MapTransferEx avança pela cadeia MDL para encontrar o início do buffer. O início do buffer é especificado pelo parâmetro Offset. Em seguida, trabalhando desde o início do buffer até o final, MapTransferEx constrói uma lista de dispersão/coleta na qual cada fragmento de buffer na lista é um bloco de memória fisicamente contíguo da cadeia MDL. Para construir essa lista, MapTransferEx passa de um bloco de memória fisicamente contíguo para o próximo dentro de cada MDL e de um MDL para o próximo na cadeia MDL. A construção da lista termina quando a quantidade total de memória buffer descrita pela lista de dispersão/coleta é igual ao número de bytes especificado pelo parâmetro de entrada *Length. A ordenação dos fragmentos de buffer na lista de dispersão/coleta resultante corresponde à ordem dos blocos fisicamente contíguos na cadeia MDL.

Várias chamadas para MapTransferEx

MapTransferEx nem sempre consegue transferir um buffer de dados DMA inteiro em uma chamada. A lista a seguir descreve algumas das condições que podem exigir que MapTransferEx seja chamado mais de uma vez para concluir a transferência:

  • O adaptador DMA requer registros de mapa, e o número de registros de mapa atribuídos ao adaptador não é suficiente para descrever todo o buffer.
  • O armazenamento alocado pelo driver para conter a lista de dispersão/coleta não é grande o suficiente para conter a lista de dispersão/coleta para todo o buffer.
  • A transferência usa um controlador DMA do sistema que limita o número de fragmentos de buffer que podem ser especificados em uma lista de dispersão/coleta de hardware.

Em todos esses casos, MapTransferEx mapeia o máximo possível do buffer de dados em uma chamada e informa ao driver quanto do buffer foi mapeado pela chamada. A lista anterior não inclui outras condições, como comportamento de cache específico da plataforma, que podem exigir mais de uma chamada para MapTransferEx para concluir uma transferência. Futuras plataformas de hardware podem impor restrições adicionais ao comprimento da transferência DMA. Por esses motivos, os desenvolvedores de drivers devem projetar seus drivers para lidar corretamente com o caso em que MapTransferEx não pode mapear um buffer de dados DMA inteiro em uma chamada.

Antes de chamar MapTransferEx, o chamador define o parâmetro *Length para o número de bytes no buffer de dados DMA que ainda precisam ser mapeados. Antes de retornar, MapTransferEx define *Length ao número de bytes no buffer que foram realmente mapeados pela chamada. Quando uma chamada MapTransferEx não pode mapear todo o comprimento do buffer, conforme especificado pelo valor de entrada *Length, o valor de saída de *Length é menor do que seu valor de entrada. Se uma transferência DMA requer duas ou mais chamadas MapTransferEx, o driver de chamada deve obter o valor de saída *Length de uma chamada antes de poder especificar o valor de entrada *Length para a próxima chamada.

Por exemplo, se uma chamada MapTransferEx pode transferir apenas X bytes de ou para um buffer para o qual Offset = B e *Length = N (na entrada), então, no retorno, *Length = X. Para a próxima chamada para MapTransferEx, o driver deve definir Offset = B + X e *Length = N - X. Em ambas as chamadas, a mesma cadeia MDL é usada sem modificação.

Se o chamador especificar um DmaCompletionRoutine, o MapTransferEx gravará o valor de saída *Length antes de agendar o DmaCompletionRoutine para ser executado. Esse comportamento garante que o valor atualizado de comprimento esteja sempre disponível antes que a rotina de conclusão DMA seja executada. Por exemplo, se uma transferência DMA requer duas chamadas MapTransferEx, o DmaCompletionRoutine que as agendas da primeira chamada podem obter o valor de saída *Length da primeira chamada. A rotina pode então usar esse valor para calcular o *Length valor de entrada para a segunda chamada. Normalmente, o parâmetro Length aponta para um local no valor *CompletionContext que é fornecido como parâmetro ao DmaCompletionRoutine.