Uso di interfacce Driver-Defined
I driver possono definire interfacce specifiche del dispositivo a cui possono accedere altri driver. Queste interfacce definite dal driver possono essere costituite da un set di routine chiamabili, un set di strutture di dati o 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 per 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 queste informazioni non sono disponibili nell'elenco delle risorse del dispositivo figlio.
Per un esempio di un set di interfacce definite dal driver documentate in WDK, vedere Routine USB. Vedere anche la versione basata sul framework dell'esempio di tostapane .
Creare un'interfaccia
Ogni interfaccia definita dal driver è specificata da:
GUID
Numero di versione
Struttura dell'interfaccia definita dal driver
Routine di riferimento e dereferenza
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 definita.
Nota
Quando si usa WDF_QUERY_INTERFACE_CONFIG, WDF non supporta più versioni di una singola interfaccia che usa lo stesso GUID dell'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 i campi Dimensioni o Versione 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 operazioni seguenti:
- 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 dell'evento EvtDeviceProcessQueryInterfaceRequest , che chiama il framework quando un altro driver chiede 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.
Un driver chiama in genere WdfFdoQueryForInterface dall'interno di una funzione evtDriverDeviceAdd callback. In alternativa, se il driver deve rilasciare l'interfaccia quando il dispositivo non si trova nello stato di lavoro, il driver può chiamare WdfFdoQueryForInterface dall'interno di una funzione di callback EvtDevicePrepareHardware e chiamare la routine di dereferenza dell'interfaccia dall'interno di una funzione di callback EvtDeviceReleaseHardware .
Se driver A chiede al driver B di 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 che il framework crea viaggi fino alla parte inferiore dello stack di driver. Se uno stack di driver semplice è costituito da tre driver, A, B e C, e se il driver A chiede 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. Driver C. Può fornire una funzione di callback EvtDeviceProcessQueryInterfaceRequest che esamina il contenuto della struttura dell'interfaccia e eventualmente le modifica.
Se driver A deve accedere all'interfaccia del driver B e 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 comunicazione Two-Way
È possibile definire un'interfaccia che fornisce una comunicazione unidirezionale o una che fornisce una comunicazione bidirezionale. Per specificare la comunicazione bidirezionale, il driver imposta il membro ImportInterface della relativa struttura WDF_QUERY_INTERFACE_CONFIG su TRUE.
Se l'interfaccia fornisce una comunicazione unidirezionale e se driver A chiede l'interfaccia del driver B, i flussi di dati dell'interfaccia vengono trasmessi 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 definiti dal driver nella struttura dell'interfaccia del driver A. Chiama quindi la funzione di callback EvtDeviceProcessQueryInterfaceRequest del driver B, in modo che possa esaminare e modificare i valori dell'interfaccia.
Se l'interfaccia fornisce una comunicazione bidirezionale, la struttura dell'interfaccia contiene alcuni membri che il driver A riempie prima di inviare la richiesta al driver B. 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 di driver A per un'interfaccia che supporta la comunicazione bidirezionale, il framework chiama la funzione di callback EvtDeviceProcessQueryInterfaceRequest del driver in modo che possa esaminare i valori ricevuti e fornire valori di output. Per la comunicazione bidirezionale, la funzione di callback è necessaria perché il framework non copia i valori dell'interfaccia nella struttura dell'interfaccia di A del driver.
Gestione di un conteggio dei riferimenti
Ogni interfaccia deve includere una funzione di riferimento e una funzione di dereferenza, che incrementa e decrementa un conteggio dei riferimenti per l'interfaccia. Il driver che definisce l'interfaccia specifica gli indirizzi di queste funzioni nella struttura INTERFACE .
Quando driver A chiede al driver B di 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 dereferenza dell'interfaccia.
Le funzioni di riferimento e dereferenza per la maggior parte delle interfacce possono essere funzioni no op che non fanno nulla. Il framework fornisce funzioni di conteggio di riferimenti non op, 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 dereferenza 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, 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 driver B, che definisce un'interfaccia, è necessario decidere se l'interfaccia del driver verrà accessibile da uno stack di driver diverso. Il driver B non può 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 numero di riferimenti.
Se si progetta driver A, che accede all'interfaccia nella destinazione di 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 B del driver viene rimosso a sorpresa e un EvtIoTargetRemoveCanceled funzione di callback che riacquise l'interfaccia se è stato annullato un tentativo di rimozione del dispositivo.