Coordinamento delle richieste di I/O con lo stato di alimentazione del componente
[Si applica solo a KMDF]
Un driver KMDF per un dispositivo a più componenti deve inviare solo richieste ai componenti che si trovano in uno stato attivo. In genere, il driver assegna code di I/O a componenti o set di componenti.
Si consideri prima una coda assegnata a un singolo componente. Il driver avvia la coda quando il componente diventa attivo e arresta la coda quando il componente diventa inattiva. Di conseguenza, quando kmDF chiama un gestore di richieste per la coda, il dispositivo si trova completamente nello stato (D0) e il componente richiesto è attivo. Il gestore delle richieste può accedere in modo sicuro all'hardware del componente.
Lo stesso concetto si applica a una coda assegnata a un set di componenti. In questo caso, il driver avvia la coda quando tutti i componenti del set sono attivi. Il driver arresta la coda quando uno dei componenti diventa inattiva.
Questo argomento descrive come un driver KMDF per un dispositivo a più componenti potrebbe implementare tale supporto in una situazione che coinvolge più tipi di richiesta che richiedono combinazioni diverse di componenti.
Esempio
Per ogni tipo di richiesta supportato dal driver, identificare i componenti necessari. Si consideri ad esempio un dispositivo con tre componenti: 0, 1 e 2, per cui il driver riceve tre tipi di richieste: A, B e C. I requisiti dei componenti delle richieste sono i seguenti:
Tipo di richiesta | Componenti necessari |
---|---|
Una | 0,2 |
B | 1 |
C | 0,1,2 |
In questo esempio sono presenti tre set distinti di componenti, uno per ogni tipo di richiesta. Il driver fornisce una coda di I/O predefinita, gestita dall'alimentazione per il dispositivo, oltre a una coda aggiuntiva gestita da alimentazione corrispondente a ogni set di componenti. Nell'esempio precedente, il driver crea una coda primaria e tre code secondarie, una corrispondente a ogni set di componenti. Questa configurazione della coda è illustrata nel diagramma seguente:
Il driver gestisce una maschera bit per ogni set di componenti. Ogni bit nella maschera di bit rappresenta lo stato attivo/inattiva di uno dei componenti. Se il bit è impostato, il componente è attivo. Se il bit viene cancellato, il componente è inattiva.
Quando arriva una richiesta, un gestore delle richieste per la coda di livello superiore determina i componenti necessari per la richiesta e chiama PoFxActivateComponent per ognuno di essi. Il gestore della richiesta inoltra quindi la richiesta alla coda di I/O secondaria corrispondente al set del componente.
Quando un componente diventa attivo, il framework di gestione energia (PoFx) chiama la routine ComponentActiveConditionCallback del driver. In questo callback, il driver imposta il bit corrispondente al componente specificato, in ogni maschera di bit in cui è rappresentato tale componente. Se tutti i bit in una maschera di bit specificata sono impostati, tutti i componenti del set corrispondente sono attivi. Per ogni set di componenti completamente attivo, il driver chiama WdfIoQueueStart per avviare la coda di I/O secondaria corrispondente.
Si consideri ad esempio il dispositivo ipotetico precedente. Si supponga che il componente 0 sia attivo, mentre i componenti 1 e 2 sono inattive. Quando il componente 2 diventa attivo, PoFx chiama la routine ComponentActiveConditionCallback del componente. I tipi di richiesta A e C usano il componente 2, quindi il driver modifica le maschera bit per questi due tipi di richiesta. Poiché tutti i bit nella maschera bit per il tipo di richiesta A sono ora impostati, il driver avvia la coda per il tipo di richiesta A. Tuttavia, non tutti i bit sono impostati per il tipo di richiesta C (il componente 1 è ancora inattiva). Il driver non avvia la coda per il tipo di richiesta C.
Quando viene avviata una coda di I/O secondaria, il framework inizia a recapitare le richieste archiviate nella coda. Nel gestore della richiesta per la coda di I/O secondaria, il driver può elaborare in modo sicuro le richieste perché il componente è attivo e un riferimento di alimentazione è stato assunto sul componente per ognuna delle richieste.
Al termine dell'elaborazione di una richiesta, il driver chiama PoFxIdleComponent per ogni componente usato dalla richiesta e quindi completa la richiesta. Quando non sono presenti più richieste usando un componente, il framework di alimentazione chiama la routine ComponentIdleConditionCallback del driver.
In questo callback il driver cancella il bit corrispondente al componente specificato, in ogni maschera di bit in cui è rappresentato tale componente. Se una maschera di bit specifica indica che il componente è il primo del set corrispondente per passare alla condizione inattiva, il driver chiama WdfIoQueueStop per arrestare la coda di I/O secondaria corrispondente. In questo modo, il driver garantisce che la coda non invii richieste a meno che tutti i componenti del set corrispondente siano attivi.
Si consideri di nuovo l'esempio precedente. Si supponga che tutti i componenti siano attivi e pertanto vengono avviate tutte le code. Quando il componente 1 diventa inattiva, PoFx chiama la routine ComponentIdleConditionCallback per il componente 1. In questo callback il driver modifica i maschera bit per i tipi di richiesta B e C perché usano il componente 1. Poiché il componente 1 è il primo componente che diventa inattiva per entrambi questi tipi di richiesta, il driver arresta le code per i tipi di richiesta B e C.
Si supponga che a questo punto, il componente 0 diventa inattiva. Nel ComponentIdleConditionCallback per il componente 0, il driver modifica imask di bit per i tipi di richiesta A e C. Poiché il componente 0 è il primo componente che diventa inattiva per il tipo di richiesta A (componente 2 è ancora attivo), il driver arresta la coda per il tipo di richiesta A. Tuttavia, per il tipo di richiesta C, il componente 0 non è il primo componente che diventa inattiva. Il driver non arresta la coda per il tipo di richiesta C (lo ha fatto in precedenza).
Per usare la tecnica descritta in questo esempio, il driver deve anche registrare una funzione di callback EvtIoCanceledOnQueue per ogni coda secondaria. Se una richiesta deve essere annullata durante la coda secondaria, il driver potrebbe usare questo callback per chiamare PoFxIdleComponent per ogni componente corrispondente. In questo modo, rilascia il riferimento all'alimentazione che il gestore della richiesta ha preso quando ha chiamato PoFxActivateComponent prima di inoltrare la richiesta alla coda secondaria.