Verwenden von Passive-Level InterruptService-Routinen

Ab Windows 8 kann ein Treiber die IoConnectInterruptEx-Routine verwenden, um eine Passive-Level InterruptService-Routine (ISR) zu registrieren. Wenn der zugeordnete Interrupt auftritt, plant der Interrupt-Trap-Handler des Kernels diese Routine für die Ausführung bei IRQL = PASSIVE_LEVEL. Eine ISR muss möglicherweise auf passiver Ebene ausgeführt werden, wenn sie nur über E/A-Anforderungen auf die Hardwareregister eines Geräts zugreifen kann. Eine Passive-Level ISR kann eine E/A-Anforderung synchron an ein Gerät senden und eine Blockierung vornehmen, bis die Anforderung abgeschlossen ist.

Registrieren einer Passive-Level ISR

Der Eingabeparameter für IoConnectInterruptEx ist ein Zeiger auf eine IO_CONNECT_INTERRUPT_PARAMETERS-Struktur. Um eine Passive-Level ISR zu registrieren, legen Sie den Version-Member dieser Struktur entweder auf CONNECT_FULLY_SPECIFIED oder CONNECT_LINE_BASED fest. Wenn Version = CONNECT_FULLY_SPECIFIED, legen Sie den Irql-Member auf PASSIVE_LEVEL fest, den SynchronizeIrql-Member auf PASSIVE_LEVEL und den SpinLock-Member auf NULL. Wenn Version = CONNECT_LINE_BASED, legen Sie SynchronizeIrql = PASSIVE_LEVEL und SpinLock = NULL fest.

Wenn das Interrupt-Objekt eine Passive-Level ISR angibt, verwendet die KeSynchronizeExecution-Routine ein Kernel-Synchronisierungsereignisobjekt anstelle eines Spinlock, um die Ausführung der SynchCritSection-Routine mit der ISR zu synchronisieren.

Dieses Ereignisobjekt wird von der IoConnectInterruptEx-Routine in dem Aufruf zugewiesen, der die ISR auf passiver Ebene registriert. Der Aufrufer darf in diesem Aufruf keinen Spinlock angeben. (Das heißt, der Aufrufer muss den SpinLock-Member der IO_CONNECT_INTERRUPT_PARAMETERS-Struktur auf NULL festlegen, wenn die ISR auf passiver Ebene ausgeführt werden soll.) Andernfalls schlägt AoConnectInterruptEx fehl und gibt den Fehlerstatus STATUS_INVALID_PARAMETER zurück.

Die Routinen KeAcquireInterruptSpinLock und KeReleaseInterruptSpinLock veranlassen eine Fehlerüberprüfung, wenn die ISR für das bereitgestellte Interruptobjekt bei IRQL = PASSIVE_LEVEL ausgeführt wird.

Geräte, die eine Interruptbehandlung auf passiver Ebene erfordern

Bei einem Gerät mit Speicherzuordnung, das eine von der Ebene ausgelöste Interruptanforderung signalisiert, wird die ISR des Geräts in der Regel innerhalb des Interrupt-Trap-Handlers des Kernels auf DIRQL aufgerufen. Die ISR bearbeitet die Hardwareregister des Geräts und deaktiviert den Interrupt.

Eine ISR muss jedoch möglicherweise auf IRQL = PASSIVE_LEVEL ausgeführt werden, wenn das zugeordnete Gerät eine von der Ebene ausgelöste Interruptanforderung signalisiert. Auf die Hardwareregister des Geräts kann aber nicht direkt von einer ISR zugegriffen werden, die auf DIRQL aus dem Interrupt-Trap-Handler des Kernels heraus aufgerufen wird. Es kann beispielsweise sein, dass die Geräteregister keine Speicherzuordnung haben oder die ISR während eines Registrierungszugriffs vorübergehend blockiert ist.

Ab Windows 8 kann ein Treiber eine Passive-Level ISR registrieren. Wenn der Interrupt auftritt, plant der Interrupt-Trap-Handler des Kernels, dass die ISR bei IRQL = PASSIVE_LEVEL ausgeführt wird. Bevor der Handler ein Ergebnis zurückgibt, muss er den Interrupt im Interruptcontroller (oder GPIO-Controller) deaktivieren. Wenn ein Gerät einen vom Edge auslösten Interrupt signalisiert, löscht der Handler den Interrupt im Interruptcontroller. Wenn das Gerät einen von der Ebene ausgelösten Interrupt signalisiert, maskiert der Handler den Interrupt vorübergehend im Interruptcontroller. Nach dem Ausführen der ISR hebt der Kernel die Maskierung des Interrupts auf.

Beispiel

Ein mit einem seriellen Bus von niedriger Leistung verbundes Sensorgerät, z. B. I²C, ist ein Beispiel für ein Gerät, das eine Passive-Level ISR erfordert. Ab Windows 8 wird die Unterstützung für I²C und für andere einfache Peripheriebusse (SPB) von der SPB-Frameworkerweiterung (SpbCx) bereitgestellt.

Um auf die Register des mit I²C verbundenen Sensorgeräts zuzugreifen, sendet der Sensortreiber dem Sensorgerät eine E/A-Anforderung, die gemeinsam von SpbCx und vom Controllertreiber für den Bus verarbeitet wird. Um den angeforderten Vorgang auszuführen, muss der SPB-Controller Daten seriell über den Bus übertragen. Diese Übertragung ist relativ langsam und kann nicht innerhalb der Zeitvorgabe einer ISR ausgeführt werden, die auf DIRQL ausgeführt wird. Eine Passive-Level ISR kann die E/A-Anforderung jedoch synchron senden und dann eine Blockierung vornehmen, bis die Anforderung abgeschlossen ist.

Die Passive-Level ISR in diesem Beispiel kann länger blockiert sein, wenn der I²C-Buscontroller beim Senden der E/A-Anforderung von der ISR an das Unterbrechungsgerät deaktiviert ist. In diesem Fall muss der Controller den Übergang zum D0-Energiezustand abschließen, bevor er die Daten über den Bus übertragen kann.

Im Gegensatz zu einem Bus wie PCI verfügt der I²C-Bus in diesem Beispiel über keine busspezifischen Mittel, um Interruptanforderungen von Peripheriegeräten an den Prozessor zu übermitteln. Stattdessen signalisiert das Sensorgerät möglicherweise einen Interrupt an einen Pin auf einem GPIO-Controllergerät, das dann die Interruptanforderung an den Prozessor weitergibt. Weitere Informationen finden Sie unter GPIO-Interrupts.

In der Regel werden die Hardwareregister eines GPIO-Controllers im Speicher zugeordnet und können über den Interrupt-Trap-Handler des Kernels auf DIRQL zugegriffen werden. Wenn das Sensorgerät einen Interrupt verursacht, muss der Handler den Interrupt deaktivieren, indem er die Interruptbits in den Registern des GPIO-Controllers bearbeitet.

Bei einem auf Ebene ausgelösten Interrupt maskiert der Interrupt-Trap-Handler des Kernels die Interruptanforderung am GPIO-Pin und plant dann die Ausführung der ISR des Sensorgeräts auf passiver Ebene. Die ISR muss die Interruptanforderung vom Sensorgerät löschen. Nachdem die ISR ein Ergebnis zurückgegeben hat, hebt der Kernel die Maskierung der Interruptanforderung am GPIO-Pin auf.

Bei einem vom Edge ausgelösten Interrupt löscht der Trap-Handler des Kernels die Interruptanforderung am GPIO-Pin und plant dann die Ausführung der ISR des Sensorgeräts auf passiver Ebene.

Workerroutinen

Beim Aufruf von IoConnectInterruptEx kann ein Treiber die Verarbeitung des Interrupts zwischen einer Passive-Level ISR und einer Workerroutine aufteilen. Im Allgemeinen sollte die ISR die anfängliche Verarbeitung des Interrupts (z. B. Deaktivieren eines auf der Ebene ausgelösten Interrupts) vornehmen und die weitere Verarbeitung an den Worker übergeben. Obwohl sowohl die ISR als auch der Worker auf passiver Ebene ausgeführt werden, wird die ISR mit relativ hoher Priorität ausgeführt und kann andere wichtige Vorgänge verzögern. Zu diesen Vorgängen können Passive-Level ISRs für neue Interrupts gehören.

In seltenen Fällen erfordert ein Interrupt vielleicht so wenig Verarbeitung, dass die Passive-Level ISR die gesamte Verarbeitung für den Interrupt ausführen kann und keine Workerroutine nötig ist.

Informationen zur Verwendung von Passive-Level ISRs bei KMDF-Treibern finden Sie unter Unterstützung von Passive-Level Interrupts.