Compartilhar via


Usando a rotina MapTransferEx

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

Comparação de MapTransferEx com MapTransfer

MapTransferEx é uma versão aprimorada da rotina MapTransfer . MapTransfer está disponível em todas as versões da interface de operações de 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 complexa de DMA pode ser descrito por uma cadeia de MDL e cada MDL na cadeia pode descrever vários blocos de memória fisicamente contígua. Para usar MapTransfer para transferir esse buffer, um driver deve fazer muitas 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 outro na cadeia de MDL.

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

Parâmetro Descrição
Mdl

Um ponteiro para o primeiro MDL em uma cadeia de um ou mais MDLs. Para obter mais informações sobre cadeias de MDL, consulte Usando MDLs.

Deslocamento

O deslocamento de bytes do buffer desde o início da memória descrita pela cadeia de MDL.

Comprimento

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

No início de uma chamada MapTransferEx , a rotina MapTransferEx avança pela cadeia de MDL para localizar o início do buffer. O início do buffer é especificado pelo parâmetro Offset . Em seguida, trabalhando do 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 de MDL. Para construir essa lista, MapTransferEx etapas 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 é concluída quando a quantidade total de memória de 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 à ordenação dos blocos fisicamente contíguos na cadeia de MDL.

Várias chamadas para MapTransferEx

MapTransferEx pode nem sempre ser capaz de 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 o 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 de DMA. Por esses motivos, os desenvolvedores de driver 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 como o número de bytes no buffer de dados DMA que ainda precisa ser mapeado. Antes de retornar, MapTransferEx define *Length para o 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 que seu valor de entrada. Se uma transferência de DMA exigir duas ou mais chamadas MapTransferEx , o driver de chamada deverá obter o valor de saída *Comprimento de uma chamada antes de poder especificar o valor de entrada *Comprimento para a próxima chamada.

Por exemplo, se uma chamada MapTransferEx puder transferir apenas bytes X para ou de um buffer para o qual Offset = B e *Length = N (na entrada), em seguida, 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 de MDL é usada sem modificação.

Se o chamador especificar um DmaCompletionRoutine, MapTransferEx gravará o valor de saída *Length antes de agendar a execução de DmaCompletionRoutine . Esse comportamento garante que o valor *Length atualizado esteja sempre disponível antes da execução de DmaCompletionRoutine . Por exemplo, se uma transferência de DMA exigir duas chamadas MapTransferEx , a DmaCompletionRoutine que os primeiros agendamentos de chamada poderão obter o valor de saída *Length da primeira chamada. Em seguida, a rotina pode usar esse valor para calcular o valor de entrada *Length para a segunda chamada. Normalmente, o parâmetro Length aponta para um local no valor *CompletionContext que é fornecido para dmaCompletionRoutine como um parâmetro.