Usando Passive-Level rotinas de serviço de interrupção

A partir do Windows 8, um driver pode usar a rotina IoConnectInterruptEx para registrar uma ISR (rotina InterruptService) de nível passivo. Quando ocorre a interrupção associada, o manipulador de interceptação de interrupção do kernel agenda essa rotina para ser executada em IRQL = PASSIVE_LEVEL. Um ISR pode precisar ser executado em nível passivo se puder acessar os registros de hardware de um dispositivo somente por meio de solicitações de E/S. Um ISR de nível passivo pode enviar uma solicitação de E/S de forma síncrona para um dispositivo e bloquear até que a solicitação seja concluída.

Registrando um ISR Passive-Level

O parâmetro de entrada para IoConnectInterruptEx é um ponteiro para uma estrutura IO_CONNECT_INTERRUPT_PARAMETERS . Para registrar um 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 um ISR de nível passivo, a rotina KeSynchronizeExecution usará um objeto de evento de sincronização de kernel em vez de um bloqueio de rotação para sincronizar a execução da rotina SynchCritSection com o ISR.

Esse objeto de evento é alocado pela rotina IoConnectInterruptEx na chamada que registra o ISR de nível passivo. O chamador não deve fornecer um bloqueio de rotação nesta chamada. (Ou seja, o chamador deve definir o membro SpinLock da estrutura IO_CONNECT_INTERRUPT_PARAMETERS como NULL se o ISR for executado no nível passivo.) Caso contrário, IoConnectInterruptEx falhará e retornará status STATUS_INVALID_PARAMETER de erro.

As rotinas KeAcquireInterruptSpinLock e KeReleaseInterruptSpinLock causarão um bug marcar se o ISR do objeto de interrupção fornecido for executado em IRQL = PASSIVE_LEVEL.

Dispositivos que exigem Passive-Level tratamento de interrupção

Para um dispositivo mapeado em memória que sinaliza uma solicitação de interrupção disparada por nível, o ISR do dispositivo normalmente é chamado no DIRQL de dentro do manipulador de interceptação de interrupção do kernel. O ISR manipula os registros de hardware no dispositivo para desativar a interrupção.

No entanto, um ISR pode precisar ser executado em IRQL = PASSIVE_LEVEL se o dispositivo associado sinalizar uma solicitação de interrupção disparada em nível, mas os registros de hardware do dispositivo não puderem ser acessados diretamente de um ISR que é chamado no DIRQL de dentro do manipulador de interceptação de interrupção do kernel. Por exemplo, os registros de dispositivo podem não ser mapeados na memória ou o ISR pode ser temporariamente bloqueado durante um acesso de registro.

Começando com Windows 8, um driver pode registrar um ISR de nível passivo. Quando a interrupção ocorre, o manipulador de interceptação de interrupção do kernel agenda o ISR para ser executado em IRQL = PASSIVE_LEVEL. Antes que o manipulador retorne, ele deve silenciar a interrupção no controlador de interrupção (ou controlador GPIO). Se um dispositivo sinalizar uma interrupção disparada por borda, o manipulador limpará a interrupção no controlador de interrupção. Se o dispositivo sinalizar uma interrupção disparada por nível, o manipulador mascara temporariamente a interrupção no controlador de interrupção; após a execução do ISR, o kernel desmascara a interrupção.

Um Exemplo

Um exemplo de um dispositivo que pode exigir um ISR de nível passivo é um dispositivo de sensor conectado a um barramento serial de baixa potência, como I²C. A partir do Windows 8, o suporte para I²C e para outros SPBs (barramentos periféricos simples) é fornecido pela SpbCx (extensão de estrutura do SPB).

Para acessar os registros do dispositivo de sensor conectado ao I²C, o driver do sensor envia ao dispositivo do sensor uma solicitação de E/S, que é tratada em conjunto pelo SpbCx e pelo driver do controlador para o barramento. Para executar a operação solicitada, o controlador SPB deve transferir dados em série pelo barramento. Essa transferência é relativamente lenta e não pode ser executada dentro das restrições de tempo de um ISR executado no DIRQL. No entanto, um 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.

O ISR de nível passivo neste exemplo poderá ser bloqueado por mais tempo se o controlador de barramento I²C estiver desativado quando o 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 antes de poder transferir os dados pelo barramento.

Ao contrário de um barramento como o PCI, o barramento I²C neste exemplo não fornece meios específicos de barramento para transmitir solicitações de interrupção de dispositivos periféricos para o processador. Em vez disso, o dispositivo de sensor pode sinalizar uma interrupção para um pino em um dispositivo controlador GPIO, que, em seguida, retransmite a solicitação de interrupção para o processador. Para obter mais informações, consulte Interrupções de GPIO.

Normalmente, os registros 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 do sensor causa uma interrupção, o manipulador deve silenciar a interrupção manipulando os bits de interrupção nos registros do controlador GPIO.

Para uma interrupção disparada por nível, o manipulador de interceptação de interrupção do kernel mascara a solicitação de interrupção no pino GPIO e agenda o ISR do dispositivo de sensor para ser executado no nível passivo. O ISR deve limpar a solicitação de interrupção do dispositivo do sensor. Depois que o ISR retorna, o kernel desmascara a solicitação de interrupção no pino gpio.

Para uma interrupção disparada por borda, o manipulador de interceptação do kernel limpa a solicitação de interrupção no pino GPIO e agenda o ISR do dispositivo do sensor para ser executado 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 um ISR de nível passivo e uma rotina de trabalho. Como regra geral, o ISR deve fazer o processamento inicial da interrupção (por exemplo, silenciar uma interrupção disparada por nível) e adiar o processamento adicional para o trabalho. Embora o ISR e o trabalho sejam executados em nível passivo, o ISR é executado 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 o 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 Passive-Level.