Usando o DMA do sistema Common-Buffer
Um driver que usa o modo de inicialização automática de um controlador de DMA do sistema deve alocar memória para um buffer no qual ou a partir do qual as transferências de DMA podem ser realizadas. O driver chama AllocateCommonBuffer para obter esse buffer, normalmente da rotina DispatchPnP que manipula uma solicitação de IRP_MN_START_DEVICE . A figura a seguir mostra como um driver aloca o buffer e mapeia seu intervalo de endereços virtuais para a memória física do sistema.
Como mostra a figura anterior, um driver executa as seguintes etapas para alocar um buffer para o DMA do sistema:
O driver chama AllocateCommonBuffer, passando um ponteiro para o objeto do adaptador que foi retornado por IoGetDmaAdapter, juntamente com o comprimento em bytes solicitados para seu buffer. Para usar a memória economicamente, o valor length de entrada para o buffer deve ser menor ou igual a PAGE_SIZE ou deve ser um múltiplo integral de PAGE_SIZE.
Se AllocateCommonBuffer retornar um ponteiro NULL , o driver deverá liberar todos os recursos do sistema já reivindicados e retornar STATUS_INSUFFICIENT_RESOURCES em resposta à solicitação de IRP_MN_START_DEVICE .
Caso contrário, AllocateCommonBuffer aloca a quantidade solicitada de memória no espaço de endereço virtual do sistema e retorna dois tipos diferentes de ponteiros para esse buffer:
O LogicalAddress do buffer (BufferLogicalAddress na figura anterior), para o qual o driver deve fornecer armazenamento, mas que deve ignorar depois disso
O endereço virtual do buffer (BufferVirtualAddress na figura anterior), que o driver também deve armazenar para que ele possa criar um MDL descrevendo seu buffer para operações de DMA
O driver deve armazenar esses ponteiros na extensão do dispositivo ou em outra memória residente alocada pelo driver.
O driver chama IoAllocateMdl para alocar um MDL para o buffer. O driver passa o VirtualAddress do buffer retornado por AllocateCommonBuffer e o Comprimento de seu buffer para alocar um MDL.
O driver chama MmBuildMdlForNonPagedPool com o ponteiro retornado por IoAllocateMdl para mapear o intervalo de endereços virtuais do buffer residente para a memória física do sistema.
Depois de alocar um buffer comum e mapear seu intervalo de endereços virtuais, o driver de um dispositivo subordinado pode começar a processar um IRP que solicita uma transferência de DMA. Para fazer isso, o driver chama a seguinte sequência geral de rotinas de suporte:
A critério do gravador de driver, RtlMoveMemory para copiar dados de um buffer de usuário bloqueado para o buffer comum alocado pelo driver para uma transferência para o dispositivo
AllocateAdapterChannel quando o driver estiver pronto para programar seu dispositivo para DMA e precisar do controlador de DMA do sistema
MapTransfer, com o MDL que descreve o buffer comum alocado pelo driver, para configurar o controlador de DMA do sistema para a operação de transferência
Observe que o driver chama MapTransfer apenas uma vez para configurar o controlador de DMA do sistema para usar seu buffer comum. Durante uma transferência, o driver pode chamar ReadDmaCounter para determinar quantos bytes ainda serão transferidos e, se necessário, chamar RtlMoveMemory para copiar mais dados de ou para um buffer de usuário.
FlushAdapterBuffers quando o driver tiver concluído sua transferência de DMA de/para o dispositivo subordinado
FreeAdapterChannel assim que todos os dados solicitados forem transferidos ou se o driver precisar falhar no IRP devido a um erro de E/S do dispositivo
O ponteiro de objeto do adaptador retornado por IoGetDmaAdapter é um parâmetro necessário para cada uma dessas rotinas de suporte, exceto RtlMoveMemory.
Drivers individuais chamam essa sequência de rotinas de suporte em pontos diferentes, dependendo de como cada driver é implementado para atender seu dispositivo. Por exemplo, a rotina StartIo de um driver pode fazer a chamada para AllocateAdapterChannel, outro driver pode fazer essa chamada de uma rotina que remove IRPs de uma fila interconectada criada pelo driver e ainda outro driver pode fazer essa chamada quando seu dispositivo DMA subordinado indicar que está pronto para transferir dados.