Usando rotinas de serviço de interrupção de nível passivo
A partir do Windows 8, um driver pode usar a rotina IoConnectInterruptEx para registrar uma rotina InterruptService (ISR) de nível passivo. Quando a interrupção associada ocorre, o manipulador de interceptação de interrupção do kernel agenda essa rotina para ser executada em IRQL = PASSIVE_LEVEL. Uma ISR pode precisar ser executada no nível passivo se puder acessar os registradores de hardware de um dispositivo somente por meio de solicitações de E/S. Uma ISR de nível passivo pode enviar de forma síncrona uma solicitação de E/S para um dispositivo e bloquear até que a solicitação seja concluída.
Registrando uma ISR de nível passivo
O parâmetro de entrada para IoConnectInterruptEx é um ponteiro para uma estrutura IO_CONNECT_INTERRUPT_PARAMETERS. Para registrar uma ISR de nível passivo, defina o membro Version dessa estrutura como CONNECT_FULLY_SPECIFIED ou CONNECT_LINE_BASED. Se Version = CONNECT_FULLY_SPECIFIED, defina o membro Irql como PASSIVE_LEVEL, o membro SynchronizeIrql como PASSIVE_LEVEL e o membro SpinLock como NULL. Se Version = CONNECT_LINE_BASED, defina SynchronizeIrql = PASSIVE_LEVEL e SpinLock = NULL.
Se o objeto de interrupção especificar uma ISR de nível passivo, a rotina 2KeSynchronizeExecution usará um objeto de evento de sincronização do kernel em vez de um bloqueio de rotação para sincronizar a execução da rotina SynchCritSection com a ISR.
Esse objeto de evento é alocado pela rotina IoConnectInterruptEx na chamada que registra a ISR de nível passivo. O chamador não deve fornecer um bloqueio de rotação nessa chamada. (Ou seja, o chamador deve definir o membro SpinLock da estrutura IO_CONNECT_INTERRUPT_PARAMETERS como NULL se a ISR for executada no nível passivo.) Caso contrário, IoConnectInterruptEx falhará e retornará o status de erro STATUS_INVALID_PARAMETER.
As rotinas KeAcquireInterruptSpinLock e KeReleaseInterruptSpinLock geram uma verificação de bug se a ISR relacionada ao objeto de interrupção fornecido é executada em IRQL = PASSIVE_LEVEL.
Dispositivos que exigem o processamento de interrupção de nível passivo
No caso de um dispositivo mapeado em memória que sinaliza uma solicitação de interrupção acionada por nível, a ISR do dispositivo normalmente é chamada em DIRQL de dentro do manipulador de interceptação de interrupção do kernel. A ISR manipula os registradores de hardware no dispositivo para desativar a interrupção.
No entanto, talvez uma ISR precise ser executada em IRQL = PASSIVE_LEVEL se o dispositivo associado sinalizar uma solicitação de interrupção acionada por nível, mas os registradores de hardware do dispositivo não puderem ser acessados diretamente de uma ISR chamada em DIRQL de dentro do manipulador de interceptação de interrupção do kernel. Por exemplo, os registradores de dispositivo podem não ser mapeados em memória ou a ISR pode ser bloqueada temporariamente durante um acesso de registro.
A partir do Windows 8, um driver pode registrar uma ISR de nível passivo. Quando a interrupção ocorre, o manipulador de interceptação de interrupção do kernel agenda a ISR para ser executada em IRQL = PASSIVE_LEVEL. Antes que o manipulador retorne, ele deve silenciar a interrupção no controlador de interrupção (ou no controlador GPIO). Se um dispositivo sinalizar uma interrupção acionada na borda, o manipulador apagará a interrupção no controlador de interrupção. Se o dispositivo sinalizar uma interrupção acionada por nível, ela será temporariamente mascarada pelo manipulador no controlador de interrupção; depois que a ISR for executada, o kernel desmascarará a interrupção.
Um Exemplo
Um exemplo de dispositivo que pode exigir uma ISR de nível passivo é um dispositivo sensor conectado a um barramento serial de baixo consumo de energia, como o I²C. A partir do Windows 8, o suporte para o I²C e para outros barramentos periféricos simples (SPBs) é dado pela extensão de estrutura SPB (SpbCx).
Para acessar os registradores do dispositivo sensor conectado ao I²C, o driver do sensor envia ao dispositivo sensor uma solicitação de E/S, que é tratada em conjunto pela SpbCx e pelo driver de controlador do barramento. Para executar a operação solicitada, o controlador SPB deve transferir os dados em série pelo barramento. Essa transferência é relativamente lenta e não pode ser executada dentro das restrições de tempo de uma ISR executada em DIRQL. No entanto, uma ISR de nível passivo pode enviar a solicitação de E/S de forma síncrona e, em seguida, bloquear até que a solicitação seja concluída.
A ISR de nível passivo deste exemplo poderá ser bloqueada por mais tempo se o controlador de barramento I²C estiver desativado quando a ISR enviar a solicitação de E/S para o dispositivo de interrupção. Nesse caso, o controlador deve concluir a transição para o estado de energia D0 para transferir os dados pelo barramento.
Ao contrário de um barramento como o PCI, o barramento I²C deste exemplo não fornece nenhum meio específico de barramento para transmitir solicitações de interrupção de dispositivos periféricos para o processador. Em vez disso, o dispositivo sensor pode sinalizar uma interrupção para um pino em um dispositivo controlador GPIO, que então retransmite a solicitação de interrupção ao processador. Para obter mais informações, consulte Interrupções de GPIO.
Normalmente, os registradores de hardware de um controlador GPIO são mapeados em memória e podem ser acessados em DIRQL pelo manipulador de interceptação de interrupção do kernel. Quando o dispositivo sensor causa uma interrupção, o manipulador deve silenciar a interrupção manipulando os bits de interrupção nos registros do controlador GPIO.
No caso de uma interrupção acionada por nível, o manipulador de interceptação de interrupção do kernel mascara a solicitação de interrupção no pino GPIO e, em seguida, agenda a ISR do dispositivo sensor para ser executada no nível passivo. A ISR deve apagar a solicitação de interrupção no dispositivo sensor. Depois que a ISR retorna, o kernel desmascara a solicitação de interrupção no pino GPIO.
No caso de uma interrupção acionada na borda, o manipulador de interceptação do kernel apaga a solicitação de interrupção no pino GPIO e, em seguida, agenda a ISR do dispositivo sensor para ser executada no nível passivo.
Rotinas de trabalho
Na chamada para IoConnectInterruptEx, um driver tem a opção de dividir o processamento da interrupção entre uma ISR de nível passivo e uma rotina de trabalho. Como regra geral, a ISR deve fazer o processamento inicial da interrupção (por exemplo, silenciar uma interrupção acionada por nível) e adiar o processamento adicional para o trabalho. Embora a ISR e o trabalho sejam executados no nível passivo, a ISR é executada com uma prioridade relativamente alta e pode atrasar outras tarefas de alta prioridade. Essas tarefas podem incluir ISRs de nível passivo para novas interrupções.
Em casos raros, uma interrupção pode exigir tão pouco processamento que a ISR de nível passivo pode executar todo o processamento para a interrupção, e nenhuma rotina de trabalho é necessária.
Para obter informações sobre como usar ISRs de nível passivo em drivers KMDF, consulte Suporte a interrupções de nível passivo.