Partilhar via


Usando interfaces Driver-Defined

Os drivers podem definir interfaces específicas do dispositivo que outros drivers podem acessar. Esses interfaces definidas pelo driver podem consistir em um conjunto de rotinas chamáveis, um conjunto de estruturas de dados ou ambos. O driver normalmente fornece ponteiros para essas rotinas e estruturas em uma estrutura de interface definida pelo driver, que o driver disponibiliza para outros drivers.

Por exemplo, um driver de barramento pode fornecer uma ou mais rotinas a que os drivers de nível superior podem recorrer para obter informações sobre um dispositivo filho, se essas informações não estiverem disponíveis na lista de recursos do dispositivo filho.

Para exemplo de um conjunto de interfaces definidas pelo driver documentadas no WDK, consulte Rotinas USB. Além disso, consulte a versão baseada em framework do exemplo de torradeira .

Criando uma interface

Cada interface definida pelo driver é especificada por:

  • Um GUID

  • Um número de versão

  • Uma estrutura de interface definida pelo driver

  • Rotinas de referência e desreferenciação

Para criar uma interface e disponibilizá-la para outros drivers, os drivers baseados em estrutura podem usar as seguintes etapas:

  1. Defina uma estrutura de interface.

    O primeiro membro dessa estrutura definida pelo driver deve ser uma INTERFACE estrutura de cabeçalho. Membros adicionais podem incluir dados de interface e ponteiros para estruturas ou rotinas adicionais que outro driver pode chamar.

    Seu driver deve fornecer uma estrutura WDF_QUERY_INTERFACE_CONFIG, que descreve a interface que você definiu.

    Observação

    Ao usar WDF_QUERY_INTERFACE_CONFIG, o WDF não suporta várias versões de uma única interface que usam o mesmo GUID de interface.

    Como consequência, ao apresentar uma nova versão de uma interface existente, recomendamos a criação de um novo GUID, em vez de rever os campos de Tamanho ou Versão da estrutura INTERFACE.

    Se o driver reutilizar o mesmo GUID de interface com campos modificados Tamanho ou Versão , o driver não deve fornecer WDF_QUERY_INTERFACE_CONFIG e, em vez disso, deve fornecer uma rotina de retorno de chamada EvtDeviceWdmIrpPreprocess para IRP_MN_QUERY_INTERFACE.

  2. Chame WdfDeviceAddQueryInterface.

    O método WdfDeviceAddQueryInterface faz o seguinte:

    • Armazena informações sobre a interface, como seu GUID, número de versão e tamanho da estrutura, para que a estrutura possa reconhecer a solicitação de outro driver para a interface.
    • Registra um opcional EvtDeviceProcessQueryInterfaceRequest função de retorno de chamada de evento, que a estrutura chama quando outro driver solicita a interface.

Cada instância de uma interface definida pelo driver está associada a um dispositivo individual; portanto, os drivers normalmente chamam WdfDeviceAddQueryInterface de dentro de uma função callback EvtDriverDeviceAdd ou EvtChildListCreateDevice.

Acessando uma interface

Se o driver tiver definido uma interface, outro driver baseado em estrutura poderá solicitar acesso à interface chamando WdfFdoQueryForInterface e passando um GUID, número de versão, ponteiro para uma estrutura e o tamanho da estrutura. O framework cria uma solicitação de E/S e envia-a para o topo da pilha de drivers.

Um driver normalmente chama WdfFdoQueryForInterface de dentro de uma função de callback EvtDriverDeviceAdd. Como alternativa, se o driver deve liberar a interface quando o dispositivo não está no seu estado de trabalho, o driver pode chamar WdfFdoQueryForInterface de dentro de uma função de chamada de retorno EvtDevicePrepareHardware e chamar a rotina de desreferência da interface de dentro de uma função de chamada de retorno EvtDeviceReleaseHardware.

Se o driver A pedir ao driver B uma interface que o driver B definiu, a estrutura manipulará a solicitação para o driver B. A estrutura verifica se o GUID e a versão representam uma interface suportada e se o tamanho da estrutura fornecida pelo driver A é grande o suficiente para manter a interface.

Quando um driver chama WdfFdoQueryForInterface, a solicitação de E/S criada pelo framework percorre todo o caminho até o fundo da pilha de drivers. Se uma pilha de drivers simples consiste em três drivers - A, B e C - e se o driver A pede uma interface, tanto o driver B quanto o driver C podem suportar a interface. Por exemplo, o driver B pode preencher a estrutura de interface do driver A antes de passar a solicitação para o driver C. O driver C pode fornecer uma função de retorno de chamada EvtDeviceProcessQueryInterfaceRequest que examina o conteúdo da estrutura da interface e possivelmente os modifica.

Se o driver A precisar acessar a interface do driver B e o driver B for um destino de E/S remoto (ou seja, um driver que está em uma pilha de driver diferente), o driver A deverá chamar WdfIoTargetQueryForInterface em vez de WdfFdoQueryForInterface.

Usar a Comunicação One-Way ou Two-Way

Você pode definir uma interface que forneça comunicação unidirecional ou uma que forneça comunicação bidirecional. Para especificar a comunicação bidirecional, o driver define o ImportInterface membro da sua estrutura WDF_QUERY_INTERFACE_CONFIG como TRUE.

Se a interface fornecer comunicação unidirecional, e se o driver A solicitar a interface do driver B, os dados da interface fluirão apenas do driver B para o driver A. Quando a estrutura recebe a solicitação do driver A para uma interface que suporta comunicação unidirecional, a estrutura copia os valores da interface definidos pelo driver na estrutura de interface do driver A. Em seguida, chama a função de retorno de chamada EvtDeviceProcessQueryInterfaceRequest do driver B, se existir, para que possa examinar e, possivelmente, modificar os valores da interface.

Se a interface fornece comunicação bidirecional, a estrutura da interface contém alguns membros que o driver A preenche antes de enviar a solicitação ao driver B. O driver B pode ler os valores de parâmetro que o driver A forneceu e fazer escolhas, com base nesses valores, sobre quais informações fornecer ao driver A. Quando a estrutura recebe a solicitação do driver A para uma interface que suporta comunicação bidirecional, a estrutura chama o do driver B EvtDeviceProcessQueryInterfaceRequest função de retorno de chamada para que ele possa examinar os valores recebidos e fornecer valores de saída. Para comunicação bidirecional, a função de retorno de chamada é necessária porque o framework não copia nenhum valor de interface para a estrutura de interface do driver A.

Mantendo uma contagem de referência

Cada interface deve incluir uma função de referência e uma função de desreferenciação, que incrementam e diminuem uma contagem de referência para a interface. O driver que define a interface especifica os endereços dessas funções em sua INTERFACE estrutura.

Quando o driver A solicita ao driver B uma interface, a estrutura chama a função de referência da interface antes de disponibilizar a interface para o driver A. Quando o driver A terminar de usar a interface, ele deve chamar a função de desreferência da interface.

As funções de referência e desreferência para a maioria das interfaces podem ser funções no-op que não executam nenhuma operação. A estrutura fornece no-op funções de contagem de referência, WdfDeviceInterfaceReferenceNoOp e WdfDeviceInterfaceDereferenceNoOp, que a maioria dos drivers pode usar.

O único momento em que os controladores devem acompanhar a contagem de referência de uma interface e fornecer funções reais de referência e desreferência é quando o controlador A solicita uma interface a um destino de E/S remoto (ou seja, um controlador que está numa pilha de controladores diferente). Nesse caso, o driver B (em uma pilha diferente) deve implementar uma contagem de referência para que ele possa impedir que seu dispositivo seja removido enquanto o driver A estiver usando a interface do driver B.

Se estiver a projetar o driver B, que define uma interface, deve decidir se a interface do seu driver será acedida a partir de uma pilha de drivers diferente. (O driver B não pode determinar se uma solicitação para sua interface é da pilha de driver local ou de uma pilha remota.) Se o driver suportar solicitações de interface de uma pilha remota, o driver deve implementar uma contagem de referência.

Se estiveres a projetar o driver A, que acede à interface no alvo de E/S remoto, o driver deve fornecer uma função de retorno de chamada EvtIoTargetQueryRemove que liberta a interface quando o dispositivo do driver B está prestes a ser removido, uma função de retorno de chamada EvtIoTargetRemoveComplete que liberta a interface quando o dispositivo do driver B é removido inesperadamente, e uma função de retorno de chamada EvtIoTargetRemoveCanceled que readquire a interface se uma tentativa de remover o dispositivo for cancelada.