Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Alguns IRPs de PnP e de energia devem ser processados primeiro pelo controlador de barramento principal de um dispositivo e, em seguida, por cada controlador subsequente na pilha de dispositivos. Por exemplo, o driver de barramento pai deve ser o primeiro driver a executar suas operações de início para um dispositivo (IRP_MN_START_DEVICE), seguido por cada driver mais alto. Para tal IRP, os drivers de função e filtro devem definir uma rotina de conclusão de E/S, passar o IRP para o próximo driver inferior e adiar quaisquer atividades para processar o IRP até que os drivers inferiores tenham terminado com o IRP.
Uma rotina IoCompletion pode ser chamada em IRQL DISPATCH_LEVEL, mas uma função ou driver de filtro pode precisar processar o IRP em IRQL = PASSIVE_LEVEL. Para retornar ao PASSIVE_LEVEL de uma rotina IoComplete, um driver pode usar um evento do kernel. O driver registra uma rotina IoCompletion que define um evento de modo kernel e, em seguida, o driver aguarda o evento em sua rotina DispatchPnP . Quando o evento é definido, os drivers de nível inferior já completaram o IRP e o driver tem permissão para processar o IRP.
Observe que um driver não deve usar esta técnica para esperar que os drivers de nível inferior terminem um IRP de potência (IRP_MJ_POWER). Esperar um evento na rotina DispatchPower definida na rotina IoCompletion pode causar um impasse. Consulte Passando IRPs de energia para obter mais informações.
As duas figuras a seguir mostram um exemplo de como um driver aguarda que drivers de nível inferior concluam um Pedido de Pacotes Plug and Play (IRP PnP). O exemplo mostra o que a função e os drivers de barramento devem fazer, além de como eles interagem com o gestor PnP e o gestor de E/S.
As seguintes notas correspondem aos números circulares da figura anterior:
O gerenciador PnP chama o gerente de E/S para enviar um IRP para o driver superior na pilha de dispositivos.
O gerenciador de E/S chama a rotina DispatchPnP do driver superior. Neste exemplo, há apenas dois drivers na pilha de dispositivos (o driver de função e o driver de barramento pai) e o driver de função é o driver superior.
O driver de função declara e inicializa um evento de modo kernel, configura o local da pilha para o próximo driver inferior e define uma rotina IoCompletion para esse IRP.
O driver de função pode usar IoCopyCurrentIrpStackLocationToNext para configurar o local da pilha.
Na chamada para IoSetCompletionRoutine, o controlador de funções define InvokeOnSuccess, InvokeOnError e InvokeOnCancel como TRUE e passa o evento no modo kernel como parte do parâmetro de contexto.
O driver de função envia o IRP para a camada inferior da pilha de dispositivos com IoCallDriver antes de executar quaisquer operações para lidar com o IRP.
O gestor de E/S envia o IRP para o próximo driver mais baixo na pilha de dispositivos chamando a rotina DispatchPnP desse driver.
No exemplo, o driver imediatamente inferior é o driver mais baixo na hierarquia de dispositivos, que é o driver de barramento principal. O motorista do ônibus executa suas operações para iniciar o dispositivo. O driver de barramento define Irp-IoStatus.Status, define Irp-IoStatus.Information, caso seja relevante para este IRP, e conclui o IRP ao chamar IoCompleteRequest.
Se o motorista de barramento chamar outras rotinas de driver ou enviar E/S para o dispositivo a fim de iniciá-lo, o driver de barramento não conclui o IRP PnP em sua rotina DispatchPnP . Em vez disso, ele deve marcar o IRP como pendente com IoMarkIrpPending e retornar STATUS_PENDING a partir de sua rotina DispatchPnP. Mais tarde, o driver chama IoCompleteRequest de outra rotina de driver, possivelmente uma rotina DPC.
A figura a seguir mostra a segunda parte do exemplo, onde os drivers mais altos na pilha de dispositivos retomam seu processamento IRP adiado.
As seguintes notas correspondem aos números circulares da figura anterior:
Quando o motorista de barramento chama IoCompleteRequest, o gerente de E/S examina os locais de pilha dos drivers superiores e chama quaisquer rotinas IoCompletion encontradas. Neste exemplo, o gerenciador de E/S localiza e chama a rotina IoCompletion para o próximo driver superior, o driver de função.
A rotina IoCompletion do driver de função estabelece o evento em modo kernel fornecido no parâmetro de contexto e retorna STATUS_MORE_PROCESSING_REQUIRED.
A rotina IoCompletion deve retornar STATUS_MORE_PROCESSING_REQUIRED para evitar que o gerente de E/S chame rotinas IoCompletion definidas por drivers superiores neste momento. A rotina IoCompletion usa esse status para adiar a conclusão para que a rotina DispatchPnP do controlador possa recuperar o controle. O gerente de E/S voltará a chamar rotinas IoCompletion de drivers superiores para este IRP quando a rotina DispatchPnP desse driver concluir o IRP.
O gerenciador de E/S para de concluir o IRP e retorna o controle para a rotina chamada IoCompleteRequest, que neste exemplo é a rotina DispatchPnP do motorista de barramento.
O motorista de autocarro retorna da sua rotina DispatchPnP com um status indicando o resultado do processamento de IRP: STATUS_SUCCESS ou um status de erro.
IoCallDriver retorna o controle para seu chamador, que neste exemplo é a rotina DispatchPnP do driver de função.
A rotina DispatchPnP do driver de função retoma o processamento do IRP.
Se IoCallDriver retornar STATUS_PENDING, a rotina DispatchPnP foi retomada antes de sua rotina IoCompletion ter sido chamada. A rotina DispatchPnP , portanto, deve aguardar que o evento do kernel seja sinalizado por sua rotina IoComplete . Isso garante que a rotina DispatchPnP não continuará processando o IRP até que todos os drivers inferiores o tenham concluído.
Se Irp->IoStatus.Status estiver definido como um erro, um driver de nível inferior falhou no IRP, e o driver de função não deve continuar a manipulá-lo (exceto para qualquer limpeza necessária).
Uma vez que os drivers de nível inferior tenham concluído com sucesso o IRP, o driver de função processa o IRP.
Para IRPs que estão a ser tratados primeiro pelo driver de barramento pai, o driver de barramento normalmente coloca um estado de sucesso em Irp-IoStatus.Status> e, opcionalmente, coloca um valor em Irp-IoStatus.Information>. Os drivers de função e filtro deixam os valores em IoStatus como estão, a menos que falhem no IRP.
A rotina do driver de função DispatchPnP chama IoCompleteRequest para concluir o IRP. O gerente de E/S retoma o processamento de conclusão de E/S. Neste exemplo, não há drivers de filtro acima do driver de função e, portanto, não há mais rotinas IoCompletion para chamar. Quando IoCompleteRequest retorna o controle para a rotina do driver de função DispatchPnP, a rotina DispatchPnP retorna o status.
Para alguns IRPs, se uma função ou driver de filtro falhar na devolução do IRP na pilha de dispositivos, o gestor PnP informa os drivers inferiores. Por exemplo, se uma função ou driver de filtro falhar em um IRP_MN_START_DEVICE, o gerenciador PnP enviará um IRP_MN_REMOVE_DEVICE para a pilha de dispositivos.