Uso delle routine del servizio di interruzione di Passive-Level

A partire da Windows 8, un driver può usare la routine IoConnectInterruptEx per registrare una routine InterruptService (ISR) a livello passivo. Quando si verifica l'interrupt associato, il gestore di trap di interrupt del kernel pianifica l'esecuzione di questa routine in IRQL = PASSIVE_LEVEL. Un ISR potrebbe dover essere eseguito a livello passivo se può accedere ai registri hardware di un dispositivo solo tramite richieste di I/O. Un ISR a livello passivo può inviare in modo sincrono una richiesta di I/O a un dispositivo e bloccare fino al completamento della richiesta.

Registrazione di un isr di Passive-Level

Il parametro di input per IoConnectInterruptEx è un puntatore a una struttura IO_CONNECT_INTERRUPT_PARAMETERS . Per registrare un ISR a livello passivo, impostare il membro Version di questa struttura su CONNECT_FULLY_SPECIFIED o CONNECT_LINE_BASED. Se Version = CONNECT_FULLY_SPECIFIED, impostare il membro Irql su PASSIVE_LEVEL, il membro SynchronizeIrql su PASSIVE_LEVEL e il membro SpinLock su NULL. Se Version = CONNECT_LINE_BASED, impostare SynchronizeIrql = PASSIVE_LEVEL e SpinLock = NULL.

Se l'oggetto interrupt specifica un ISR a livello passivo, la routine KeSynchronizeExecution usa un oggetto evento di sincronizzazione del kernel anziché un blocco spin per sincronizzare l'esecuzione della routine SynchCritSection con l'ISR.

Questo oggetto evento viene allocato dalla routine IoConnectInterruptEx nella chiamata che registra l'ISR a livello passivo. Il chiamante non deve fornire un blocco spin in questa chiamata. In altri termini, il chiamante deve impostare il membro SpinLock della struttura IO_CONNECT_INTERRUPT_PARAMETERS su NULL se l'ISR deve essere eseguito a livello passivo. In caso contrario, IoConnectInterruptEx ha esito negativo e restituisce lo stato di errore STATUS_INVALID_PARAMETER.

Le routine KeAcquireInterruptSpinLock e KeReleaseInterruptSpinLock causano un controllo di bug se l'ISR per l'oggetto interrupt fornito viene eseguito in IRQL = PASSIVE_LEVEL.

Dispositivi che richiedono la gestione degli interrupt Passive-Level

Per un dispositivo mappato alla memoria che segnala una richiesta di interrupt attivata a livello, l'ISR del dispositivo viene in genere chiamato in DIRQL dall'interno del gestore trap di interrupt del kernel. L'ISR modifica i registri hardware nel dispositivo per disattivare l'interrupt.

Tuttavia, potrebbe essere necessario eseguire un ISR in IRQL = PASSIVE_LEVEL se il dispositivo associato segnala una richiesta di interrupt attivata a livello, ma non è possibile accedere ai registri hardware del dispositivo direttamente da un ISR chiamato in DIRQL dall'interno del gestore di trap di interrupt del kernel. Ad esempio, i registri dei dispositivi potrebbero non essere mappati alla memoria o l'ISR potrebbe essere temporaneamente bloccato durante un accesso al registro.

A partire da Windows 8, un driver può registrare un ISR a livello passivo. Quando si verifica l'interrupt, il gestore di interrupt trap del kernel pianifica l'esecuzione dell'ISR in IRQL = PASSIVE_LEVEL. Prima che il gestore venga restituito, deve disattivare l'interrupt nel controller di interrupt (o nel controller GPIO). Se un dispositivo segnala un interrupt attivato da edge, il gestore cancella l'interrupt nel controller di interrupt. Se il dispositivo segnala un interrupt attivato a livello, il gestore maschera temporaneamente l'interrupt nel controller di interrupt; dopo l'esecuzione dell'ISR, il kernel annulla il mascherato dell'interrupt.

Esempio

Un esempio di dispositivo che potrebbe richiedere un ISR a livello passivo è un dispositivo sensore connesso a un bus seriale a basso consumo, ad esempio I²C. A partire da Windows 8, il supporto per I²C e per altri semplici bus periferici (SPB) viene fornito dall'estensione spb framework (SpbCx).

Per accedere ai registri del dispositivo sensore connesso A²C, il driver del sensore invia al dispositivo sensore una richiesta di I/O, gestita congiuntamente da SpbCx e dal driver controller per il bus. Per eseguire l'operazione richiesta, il controller SPB deve trasferire i dati in modo seriale sul bus. Questo trasferimento è relativamente lento e non può essere eseguito entro i vincoli temporali di un ISR eseguito in DIRQL. Tuttavia, un ISR a livello passivo può inviare la richiesta di I/O in modo sincrono e quindi bloccare fino al completamento della richiesta.

L'ISR a livello passivo in questo esempio potrebbe essere bloccato per un periodo di tempo più lungo se il controller del bus I²C è disattivato quando l'ISR invia la richiesta di I/O al dispositivo di interruzione. In questo caso, il controller deve completare la transizione allo stato di alimentazione D0 prima di poter trasferire i dati sul bus.

A differenza di un bus come PCI, il bus I²C in questo esempio non fornisce mezzi specifici del bus per trasmettere richieste di interruzione dai dispositivi periferici al processore. Al contrario, il dispositivo sensore potrebbe segnalare un interrupt a un pin in un dispositivo controller GPIO, che quindi inoltra la richiesta di interrupt al processore. Per altre informazioni, vedere Interrupt GPIO.

In genere, i registri hardware di un controller GPIO sono mappati alla memoria e sono accessibili a DIRQL dal gestore di trap interrupt del kernel. Quando il dispositivo sensore causa un'interruzione, il gestore deve disattivare l'interrupt modificando i bit di interrupt nei registri del controller GPIO.

Per un interrupt attivato a livello, il gestore di trap interrupt del kernel maschera la richiesta di interrupt al pin GPIO e quindi pianifica l'esecuzione dell'ISR del dispositivo sensore a livello passivo. L'ISR deve cancellare la richiesta di interruzione dal dispositivo sensore. Al termine della restituzione dell'ISR, il kernel annulla il maschera la richiesta di interrupt al pin GPIO.

Per un interrupt attivato da edge, il gestore trap del kernel cancella la richiesta di interrupt al pin GPIO e quindi pianifica l'esecuzione dell'ISR del dispositivo sensore a livello passivo.

Routine di lavoro

Nella chiamata a IoConnectInterruptEx, un driver ha la possibilità di suddividere l'elaborazione dell'interrupt tra un ISR a livello passivo e una routine di lavoro. Come regola generale, l'ISR deve eseguire l'elaborazione iniziale dell'interrupt (ad esempio, disattivare un interrupt attivato dal livello) e rinviare l'elaborazione aggiuntiva al ruolo di lavoro. Anche se sia l'ISR che il ruolo di lavoro vengono eseguiti a livello passivo, l'ISR viene eseguito con priorità relativamente elevata e potrebbe ritardare altre attività con priorità elevata. Queste attività possono includere isr a livello passivo per nuovi interrupt.

In rari casi, un interrupt potrebbe richiedere un'elaborazione così piccola che l'ISR a livello passivo possa eseguire tutta l'elaborazione per l'interrupt e non è necessaria alcuna routine di lavoro.

Per informazioni sull'uso di ISR a livello passivo nei driver KMDF, vedere Supporto di Passive-Level interrupt.