Criando solicitações IOCTL em drivers
Um driver de classe ou outro driver de nível superior pode alocar IRPs para solicitações de controle de E/S e enviá-los para o driver mais baixo da seguinte maneira:
Aloque ou reutilize um IRP (pacote de solicitação de E/S) com o código de função principal IRP_MJ_DEVICE_CONTROL ou IRP_MJ_INTERNAL_DEVICE_CONTROL. Você pode usar a rotina IoBuildDeviceIoControlRequest para alocar especificamente um IRP IOCTL. Você também pode usar rotinas de criação e inicialização de IRP de uso geral, como IoAllocateIrp, IoReuseIrp ou IoInitializeIrp. Para obter mais informações sobre alocação de IRP, consulte Criando IRPs para drivers de Lower-Level.
Configure o local de pilha de E/S do driver inferior para o IRP com o código IOCTL_XXX e os parâmetros apropriados.
Se a solicitação IOCTL for concluída de forma assíncrona, chame a rotina KeInitializeEvent para inicializar um objeto de evento como um evento de notificação. O driver usa esse evento para aguardar a conclusão de uma operação de E/S.
Chame IoSetCompletionRoutine com o IRP para que o driver superior possa fornecer uma rotina IoCompletion , se necessário, para fazer o seguinte:
Determine como o driver inferior lidou com uma determinada solicitação.
Reutilize o IRP para enviar outra solicitação ou descartar o IRP criado pelo driver, depois que o driver inferior concluir uma operação solicitada. O driver não pode reutilizar IRPs que IoBuildDeviceIoControlRequest criou. Para obter mais informações, consulte Reutilizando IRPs.
Chame IoCallDriver para passar a solicitação para o driver inferior.
Se IoCallDriver retornar STATUS_PENDING, chame a rotina KeWaitForSingleObject para colocar o thread atual em um estado de espera. O driver define o parâmetro Object da rotina como o endereço do objeto de evento que foi inicializado na chamada para KeInitializeEvent.
Nota Se o driver chamar KeWaitForSingleObject com seu parâmetro Timeout definido como NULL ou para o endereço de uma variável que contém um valor diferente de zero, o driver deverá estar em execução em IRQL <= APC_LEVEL em um contexto de thread nonarbitrary. Caso contrário, o driver deve estar em execução em IRQL <= DISPATCH_LEVEL.
O evento é sinalizado por sua rotina de IoCompletion quando a solicitação IOCTL é concluída. Depois que o evento é sinalizado, o thread retoma a execução.
Importante Se o driver alocar o objeto de evento como uma variável local na pilha, o driver deverá chamar KeWaitForSingleObject com seu parâmetro WaitMode definido como KernelMode. Esse valor de parâmetro impede que a pilha seja paginada.
Para evitar problemas de sincronização e possíveis violações de acesso, os parâmetros para códigos de controle de E/S raramente incluem ponteiros inseridos. Exceto para determinadas solicitações SCSI, os buffers em Irp-AssociatedIrp>. SystemBuffer, em Irp-MdlAddress > e emParâmetros. DeviceIoControl. Type3InputBuffer no local da pilha de E/S de um driver não contém ponteiros para outros buffers de dados, nem contêm estruturas que contêm ponteiros para códigos de controle de E/S definidos pelo sistema. Para obter mais informações sobre como os buffers de dados são usados com IRPs que contêm códigos de controle de E/S, consulte Descrições de buffer para códigos de controle de E/S.
No entanto, um par de drivers de classe/porta que definem códigos de controle de E/S internos pode passar um ponteiro inserido para a memória alocada pelo driver do driver de nível superior para o driver de nível inferior. Esse par de drivers de classe/porta é responsável por garantir que o seguinte seja verdadeiro:
Somente um driver por vez pode acessar os dados.
Os buffers de dados privados são acessíveis em um contexto de thread arbitrário pelo driver de porta.
Os drivers de exibição podem chamar a função GDI EngDeviceIoControl para enviar solicitações de controle de E/S específicas do dispositivo definidas pelo dispositivo, bem como solicitações de controle de E/S públicas definidas pelo sistema, por meio do driver de porta de vídeo do sistema até os miniportores de vídeo específicos do adaptador correspondente.
Qualquer componente do modo de usuário de um pacote de driver pode chamar DeviceIoControl para enviar solicitações de controle de E/S para uma pilha de driver. O gerente de E/S cria uma solicitação de IRP_MJ_DEVICE_CONTROL e a entrega ao driver de nível mais alto.