Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
I driver possono definire interfacce specifiche del dispositivo a cui possono accedere altri driver. Queste interfacce definite dal driver #B0 #C1 possono essere costituite da un set di routine chiamabili, da un set di strutture di dati o da entrambi. Il driver fornisce in genere puntatori a queste routine e strutture in una struttura di interfaccia definita dal driver, che il driver rende disponibile ad altri driver.
Ad esempio, un driver del bus potrebbe fornire una o più routine che i driver di livello superiore possono chiamare per ottenere informazioni su un dispositivo figlio, se tali informazioni non sono disponibili nell'elenco delle risorse del dispositivo figlio.
Per un esempio di un insieme di interfacce definite dal driver, documentate nel WDK, vedere le routine USB. Guarda anche la versione basata sul framework del campione di toaster.
Creazione di un'interfaccia
Ogni interfaccia definita dal driver è specificata da:
A GUID
Numero di versione
Struttura dell'interfaccia definita dal driver
Routine di riferimento e dereferenziazione
Per creare un'interfaccia e renderla disponibile per altri driver, i driver basati su framework possono usare la procedura seguente:
Definire una struttura di interfaccia.
Il primo membro di questa struttura definita dal driver deve essere una struttura di intestazione INTERFACE. Altri membri possono includere dati di interfaccia e puntatori a strutture o routine aggiuntive che un altro driver può chiamare.
Il driver deve fornire una struttura WDF_QUERY_INTERFACE_CONFIG, che descrive l'interfaccia che hai definito.
Nota
Quando si utilizza WDF_QUERY_INTERFACE_CONFIG, WDF non supporta più versioni di una singola interfaccia che utilizzano lo stesso GUID di interfaccia.
Di conseguenza, quando si introduce una nuova versione di un'interfaccia esistente, è consigliabile creare un nuovo GUID anziché rivedere i campi Size o Version della struttura INTERFACE.
Se il driver riutilizza lo stesso GUID dell'interfaccia con campi Size o Version modificati, il driver non deve fornire WDF_QUERY_INTERFACE_CONFIG e deve invece fornire una routine di callback EvtDeviceWdmIrpPreprocess per IRP_MN_QUERY_INTERFACE.
Chiamare WdfDeviceAddQueryInterface.
Il metodo WdfDeviceAddQueryInterface esegue le seguenti operazioni:
- Archivia informazioni sull'interfaccia, ad esempio il GUID, il numero di versione e le dimensioni della struttura, in modo che il framework possa riconoscere la richiesta di un altro driver per l'interfaccia.
- Registra una funzione di callback per eventi facoltativa EvtDeviceProcessQueryInterfaceRequest, che il framework chiama quando un altro driver richiede l'interfaccia.
Ogni istanza di un'interfaccia definita dal driver è associata a un singolo dispositivo, quindi i driver in genere chiamano WdfDeviceAddQueryInterface dall'interno di una funzione di callback EvtDriverDeviceAdd o EvtChildListCreateDevice.
Accesso a un'interfaccia
Se il driver ha definito un'interfaccia, un altro driver basato su framework può richiedere l'accesso all'interfaccia chiamando WdfFdoQueryForInterface e passando un GUID, un numero di versione, un puntatore a una struttura e le dimensioni della struttura. Il framework crea una richiesta di I/O e la invia all'inizio dello stack di driver.
In genere, un driver chiama WdfFdoQueryForInterface all'interno di una funzione di callback EvtDriverDeviceAdd. In alternativa, se il driver deve rilasciare l'interfaccia quando il dispositivo non è nello stato operativo, il driver può chiamare WdfFdoQueryForInterface dall'interno di una funzione di callback EvtDevicePrepareHardware e chiamare la routine di dereferenziazione dell'interfaccia dall'interno di una funzione di callback EvtDeviceReleaseHardware.
Se il driver A chiede al driver B un'interfaccia definita dal driver B, il framework gestisce la richiesta per il driver B. Il framework verifica che il GUID e la versione rappresentino un'interfaccia supportata e che le dimensioni della struttura fornite dal driver A siano sufficienti per contenere l'interfaccia.
Quando un driver chiama WdfFdoQueryForInterface, la richiesta di I/O creata dal framework passa fino al fondo dello stack di driver. Se uno stack di driver semplice è costituito da tre driver, A, B e C, e se il driver A richiede un'interfaccia, sia il driver B che il driver C possono supportare l'interfaccia. Ad esempio, il driver B potrebbe compilare la struttura dell'interfaccia del driver A prima di passare la richiesta al driver C. Il driver C può fornire una funzione di callback EvtDeviceProcessQueryInterfaceRequest che esamina il contenuto della struttura dell'interfaccia ed eventualmente la modifica.
Se il driver A deve accedere all'interfaccia del driver B e il driver B è una destinazione di I/O remota (ovvero un driver in uno stack di driver diverso), il driver A deve chiamare WdfIoTargetQueryForInterface anziché WdfFdoQueryForInterface.
Uso di One-Way o Two-Way per la comunicazione
È possibile definire un'interfaccia che fornisce una comunicazione unidirezionale o una che fornisce comunicazioni bidirezionali. Per specificare la comunicazione bidirezionale, il driver imposta il membro ImportInterface della struttura WDF_QUERY_INTERFACE_CONFIG su TRUE.
Se l'interfaccia fornisce comunicazioni unidirezionale e se il driver A richiede l'interfaccia del driver B, i dati dell'interfaccia passano solo dal driver B al driver A. Quando il framework riceve la richiesta del driver A per un'interfaccia che supporta la comunicazione unidirezionale, il framework copia i valori dell'interfaccia definita dal driver nella struttura dell'interfaccia del driver A. Chiama quindi la funzione di callback del driver B, EvtDeviceProcessQueryInterfaceRequest, se esistente, in modo che possa esaminare ed eventualmente modificare i valori dell'interfaccia.
Se l'interfaccia fornisce comunicazioni bidirezionali, la struttura dell'interfaccia contiene alcuni membri compilati dal driver A prima di inviare la richiesta al driver B. Il driver B può leggere i valori dei parametri forniti dal driver A e fare scelte, in base a tali valori, sulle informazioni da fornire al driver A. Quando il framework riceve la richiesta del driver A per un'interfaccia che supporta la comunicazione bidirezionale, il framework chiama il driver B #B0 #A1 EvtDeviceProcessQueryInterfaceRequest #A2 #C3 funzione di callback in modo che possa esaminare i valori ricevuti e fornire i valori di output. Per la comunicazione bidirezionale, la funzione di callback è necessaria perché il framework non copia alcun valore di interfaccia nella struttura di interfaccia del driver A.
Gestione di un conteggio dei riferimenti
Ogni interfaccia deve includere una funzione di riferimento e una funzione di dereferenziazione, che incrementa e decrementa un conteggio dei riferimenti per l'interfaccia. Il driver che definisce l'interfaccia specifica gli indirizzi di queste funzioni nella sua struttura INTERFACE.
Quando il driver A chiede al driver B un'interfaccia, il framework chiama la funzione di riferimento dell'interfaccia prima di rendere disponibile l'interfaccia per il driver A. Al termine dell'uso dell'interfaccia, il driver A deve chiamare la funzione di dereferenziazione dell'interfaccia.
Le funzioni di riferimento e dereferenziazione per la maggior parte delle interfacce possono essere no-op funzioni che non eseguono alcuna operazione. Il framework fornisce no-op funzioni di conteggio dei riferimenti, WdfDeviceInterfaceReferenceNoOp e WdfDeviceInterfaceDereferenceNoOp, che la maggior parte dei driver può usare.
L'unica volta che i driver devono tenere traccia del conteggio dei riferimenti di un'interfaccia e fornire funzioni di riferimento e dereferenziazione reali, è quando il driver A richiede un'interfaccia da una destinazione di I/O remota ,ovvero un driver che si trova in uno stack di driver diverso. In questo caso, il driver B (in uno stack diverso) deve implementare un conteggio dei riferimenti in modo che possa impedire la rimozione del dispositivo mentre il driver A usa l'interfaccia del driver B.
Se si progetta il driver B, che definisce un'interfaccia, è necessario decidere se l'interfaccia del driver sarà accessibile da uno stack di driver diverso. Il driver B non è in grado di determinare se una richiesta per l'interfaccia proviene dallo stack di driver locale o da uno stack remoto. Se il driver supporterà le richieste di interfaccia da uno stack remoto, il driver deve implementare un conteggio dei riferimenti.
Se si progetta il driver A, che accede all'interfaccia nella destinazione I/O remota, il driver deve fornire una funzione di callback EvtIoTargetQueryRemove che rilascia l'interfaccia quando il dispositivo del driver B sta per essere rimosso, una funzione di callback EvtIoTargetRemoveComplete che rilascia l'interfaccia quando il dispositivo del driver B viene rimosso a sorpresa, e una funzione di callback EvtIoTargetRemoveCanceled che riacquisisce l'interfaccia se un tentativo di rimuovere il dispositivo è stato annullato.