Padrão de chamada básico para rotinas de DMA versão 3
Para executar uma transferência de DMA que usa as rotinas na versão 3 da interface de operações de DMA, o driver deve seguir as etapas descritas na lista a seguir. Essas etapas são comuns a dispositivos subordinados e dispositivos de barramento master. A versão 3 dessa interface está disponível a partir do Windows 8. Para obter mais informações sobre as rotinas nessa interface, consulte DMA_OPERATIONS.
Etapa 1: Obter um objeto de adaptador DMA
Em preparação para uma transferência de DMA, o driver chama a rotina IoGetDmaAdapter para obter um objeto de adaptador de DMA. Um objeto de adaptador DMA é um objeto de software que representa um dispositivo master barramento ou uma linha de solicitação em um controlador DMA do sistema. Esse objeto contém a interface de operações de DMA para o barramento usado para transferir dados de ou para o dispositivo. Além disso, esse objeto sincroniza o acesso do driver aos recursos compartilhados necessários para executar a transferência. Para obter mais informações, consulte Introdução aos objetos do adaptador.
Etapa 2: obter uma descrição dos recursos de DMA necessários
O driver chama a rotina GetDmaTransferInfo para obter uma descrição dos recursos de DMA necessários para executar a transferência.
Os parâmetros de entrada para essa chamada descrevem o buffer de memória a ser usado para a transferência e a direção (leitura ou gravação) da transferência.
Os requisitos de recurso obtidos dessa chamada incluem o número de registros de mapa e o tamanho da lista de dispersão/coleta necessária para descrever o buffer de dados para a transferência. Na chamada subsequente para a rotina AllocateAdapterChannelEx (consulte a etapa 3), o driver fornece a contagem de registros de mapa como um parâmetro de entrada.
Etapa 3: Solicitar os recursos de AMD necessários
O driver chama a rotina AllocateAdapterChannelEx para alocar recursos a serem atribuídos ao objeto do adaptador DMA. Esses recursos incluem um canal DMA e registros de mapa.
Uma chamada AllocateAdapterChannelEx pode ser assíncrona ou síncrona.
Se o sinalizador DMA_SYNCHRONOUS_CALLBACK não estiver definido, a chamada será assíncrona. Nesse caso, o parâmetro ExecutionRoutine aponta para uma rotina de execução fornecida pelo chamador que é chamada quando os recursos solicitados estão disponíveis. Se tiver êxito, uma chamada assíncrona AllocateAdapterChannelEx retornará STATUS_SUCCESS sem aguardar a execução da rotina de execução.
Se o sinalizador DMA_SYNCHRONOUS_CALLBACK estiver definido, a chamada AllocateAdapterChannelEx será síncrona. Nesse caso, o parâmetro ExecutionRoutine na chamada é opcional e AllocateAdapterChannelEx se comporta da seguinte maneira:
Se ExecutionRoutine não for NULL e os recursos de DMA puderem ser alocados imediatamente, AllocateAdapterChannelEx chamará a rotina de execução no contexto do thread de chamada. Depois que a rotina de execução terminar de ser executada, AllocateAdapterChannelEx retornará STATUS_SUCCESS. Se os recursos não estiverem disponíveis imediatamente, AllocateAdapterChannelEx falhará e retornará o erro status código STATUS_INSUFFICIENT_RESOURCES.
Se ExecutionRoutine for NULL e AllocateAdapterChannelEx puder alocar imediatamente os recursos de DMA, AllocateAdapterChannelEx retornará STATUS_SUCCESS. Se todos os recursos não estiverem disponíveis imediatamente, a chamada falhará com o erro status código STATUS_INSUFFICIENT_RESOURCES.
Para chamadas síncronas que retornam STATUS_SUCCESS, se o parâmetro MapRegisterBase para AllocateAdapterChannelEx não for NULL, AllocateAdapterChannelEx gravará o endereço base dos registros de mapa alocados no endereço apontado pelo parâmetro MapRegisterBase . Se ExecutionRoutine for NULL, MapRegisterBase deverá ser não NULL. Se ExecutionRoutine não for NULL, o parâmetro MapRegisterBase para AllocateAdapterChannelEx será opcional e a rotina de execução receberá o endereço base do registro de mapa como um parâmetro de entrada.
Para chamadas assíncronas AllocateAdapterChannelEx , ExecutionRoutine deve ser não NULL e a rotina de execução recebe o endereço base do registro de mapa como um parâmetro de entrada.
Em chamadas subsequentes para a rotina MapTransferEx (consulte a etapa 5), o driver fornece o endereço base do registro de mapa como um parâmetro de entrada.
Se ExecutionRoutine não for NULL, a rotina de execução retornará um valor status para indicar a disposição dos recursos alocados. Para transferências de DMA do sistema, esse valor retornado deve ser KeepObject. Esse valor informa ao sistema operacional que o objeto do adaptador (e todos os seus recursos alocados) está em uso e não deve ser liberado. Se nenhuma rotina de execução for fornecida, o driver deverá chamar a rotina FreeAdapterObject e fornecer KeepObject como o parâmetro AllocationOption .
Etapa 4: se necessário, cancele a solicitação de recurso pendente
Depois que uma chamada AllocateAdapterChannelEx enfileira um adaptador DMA para aguardar os recursos de DMA, o driver pode, se necessário, chamar a rotina CancelAdapterChannel para cancelar a solicitação de recurso pendente.
Se CancelAdapterChannel retornar TRUE, a solicitação de recurso será cancelada com êxito. Se uma rotina de execução tiver sido fornecida na chamada AllocateAdapterChannelEx , essa rotina não será executada.
Se CancelAdapterChannel retornar FALSE, a solicitação de recurso não poderá ser cancelada porque já foi concedida. Se uma rotina de execução tiver sido fornecida na chamada AllocateAdapterChannelEx , essa rotina será chamada.
Etapa 5: Inicializar os recursos de AMD e iniciar a transferência de AMD
O driver chama MapTransferEx para inicializar os recursos de DMA e iniciar a transferência de DMA. Essa chamada pode ocorrer no mesmo thread de driver que chama AllocateAdapterChannelEx ou pode ocorrer na rotina de execução fornecida pelo driver para AllocateAdapterChannelEx. Se mais de uma chamada MapTransferEx for necessária para transferir todo o buffer de dados de DMA, uma chamada mapTransferEx posterior poderá ocorrer na rotina de conclusão da chamada mapTransferEx anterior.
MapTransferEx dá suporte a MDLs encadeados como parâmetros de entrada. Cada MDL descreve uma região do buffer de DMA contígua na memória virtual. Quando MapTransferEx compila a lista de dispersão/coleta, ele manipula automaticamente as transições de uma região de buffer virtualmente contígua para a próxima sem intervenção do driver. Para obter mais informações, consulte Usando a rotina MapTransferEx.
Para uma transferência de DMA do sistema, um ponteiro para uma rotina de conclusão de DMA pode ser passado para MapTransferEx no parâmetro DmaCompletionRoutine opcional. Essa rotina está agendada para ser executada no nível de expedição em resposta a uma interrupção do controlador de DMA do sistema que indica que a transferência de DMA foi concluída.
Se MapTransferEx não conseguir mapear todo o tamanho de transferência solicitado, ele definirá o parâmetro de saída *Length para o comprimento que foi mapeado e retornará STATUS_SUCCESS.
Etapa 6: se necessário, execute operações específicas de hardware
MapTransferEx retorna STATUS_SUCCESS para indicar que a transferência de DMA foi iniciada com êxito. Em algumas plataformas, o driver pode precisar executar alguma ação adicional, fora da chamada MapTransferEx , para iniciar a transferência, mas esse tipo de início atrasado não é necessário para todas as plataformas. Os drivers não devem depender desses atrasos para decisões sobre como usar e liberar recursos alocados.
As rotinas na interface de operações de DMA mantêm a coerência de cache para transferências de DMA de maneira transparente para os drivers que usam essas rotinas. Em plataformas que não impõem a coerência de cache no hardware, MapTransferEx garante que os caches de dados do processador sejam liberados antes das transferências de gravação (memória para dispositivo). Para transferências de leitura (dispositivo para memória), os caches são invalidados durante a chamada para a rotina FlushAdapterBuffersEx (consulte a etapa 8) que segue cada chamada mapTransferEx .
Etapa 7: Receber notificação quando a transferência de AMD for concluída
Quando uma transferência de DMA é concluída, o driver é notificado de uma destas duas maneiras:
- Uma interrupção no driver do dispositivo, para um dispositivo master ônibus
- Execução da rotina de conclusão fornecida pelo driver para um dispositivo subordinado que usa um controlador de DMA do sistema
Para uma transferência de DMA do sistema, um driver pode fornecer uma rotina de conclusão para MapTransferEx como um parâmetro de entrada.
Etapa 8: Liberar todos os dados que permanecem no cache
Depois que a transferência de DMA for concluída, o driver deverá chamar a rotina FlushAdapterBuffersEx para liberar todos os dados que permanecem no cache. O driver deve chamar FlushAdapterBuffersEx após cada chamada mapTransferEx .
Se uma chamada MapTransferEx mapear apenas uma parte do buffer de dados DMA, o driver deverá chamar MapTransferEx novamente para mapear os dados restantes. Uma transferência complexa pode exigir várias chamadas MapTransferEx . Para cada chamada mapTransferEx adicional, repita as etapas de 5 a 8.
Etapa 9: Liberar o canal do AMD e os registros de mapa
Depois que todo o buffer de dados de DMA for mapeado com êxito e a transferência final for concluída, o driver deverá chamar a rotina FreeAdapterChannel para liberar o canal DMA e quaisquer registros de mapa alocados anteriormente.
Etapa 10: Liberar o objeto do adaptador DMA
Depois que todas as transferências de DMA forem concluídas e todos os registros de mapa alocados anteriormente forem liberados, o driver chamará a rotina PutDmaAdapter para liberar o objeto do adaptador.