Condividi tramite


Come scrivere il primo driver client USB (UMDF)

In questo articolo si userà il modello Driver modalità utente, USB (UMDF V2) fornito con Microsoft Visual Studio 2022 per scrivere un driver client basato su UMDF (User-Mode Driver Framework). Dopo aver compilato e installato il driver client, si visualizzerà il driver client in Gestione dispositivi e si visualizzerà l'output del driver in un debugger.

UMDF (definito framework in questo articolo) è basato sul modello a oggetti del componente (COM). Per impostazione predefinita, ogni oggetto framework deve implementare IUnknown e i relativi metodi, QueryInterface, AddRef e Release. I metodi AddRef e Release gestiscono la durata dell'oggetto, quindi il driver client non deve mantenere il conteggio dei riferimenti. Il metodo QueryInterface consente al driver client di ottenere puntatori di interfaccia ad altri oggetti framework nel modello a oggetti WDF (Windows Driver Frameworks). Gli oggetti framework eseguono attività di driver complesse e interagiscono con Windows. Alcuni oggetti framework espongono interfacce che consentono a un driver client di interagire con il framework.

Un driver client basato su UMDF viene implementato come server COM (DLL) in-process e C++ è il linguaggio preferito per la scrittura di un driver client per un dispositivo USB. In genere, il driver client implementa diverse interfacce esposte dal framework. Questo articolo fa riferimento a una classe definita dal driver client che implementa le interfacce del framework come classe di callback. Dopo aver creato un'istanza di queste classi, gli oggetti di callback risultanti vengono associati a determinati oggetti framework. Questa partnership offre al driver client la possibilità di rispondere a eventi correlati al dispositivo o al sistema segnalati dal framework. Ogni volta che Windows notifica al framework alcuni eventi, il framework richiama il callback del driver client, se disponibile. In caso contrario, il framework procede con l'elaborazione predefinita dell'evento. Il codice modello definisce classi di callback driver, dispositivo e coda.

Per una spiegazione del codice sorgente generato dal modello, vedere Informazioni sul codice del modello UMDF per il driver client USB.

Prima di iniziare

Per lo sviluppo, il debug e l'installazione di un driver in modalità utente, sono necessari due computer:

  • Un computer host che esegue Windows 10 o una versione successiva del sistema operativo Windows. Il computer host è l'ambiente di sviluppo, in cui si scrive ed esegue il debug del driver.
  • Un computer di destinazione che esegue la versione del sistema operativo in cui si vuole testare il driver, ad esempio Windows 11 versione 22H2. Il computer di destinazione ha il driver in modalità utente di cui si vuole eseguire il debug e uno dei debugger.

In alcuni casi, in cui i computer host e di destinazione eseguono la stessa versione di Windows, è possibile avere solo un computer che esegue Windows 10 o una versione successiva di Windows. Questo articolo presuppone che si usino due computer per lo sviluppo, il debug e l'installazione del driver in modalità utente.

Prima di iniziare, assicurarsi di soddisfare i requisiti seguenti:

Requisiti software

  • Nel computer host è disponibile Visual Studio 2022.

  • Il computer host ha la versione più recente di Windows Driver Kit (WDK) per Windows 11 versione 22H2.

    Il kit include intestazioni, librerie, strumenti, documentazione e gli strumenti di debug necessari per sviluppare, compilare ed eseguire il debug di un driver client USB. È possibile ottenere la versione più recente di WDK da Come ottenere il wdk.

  • Il computer host ha la versione più recente degli strumenti di debug per Windows. È possibile ottenere la versione più recente da WDK oppure scaricare e installare gli strumenti di debug per Windows.

  • Se si usano due computer, è necessario configurare i computer host e di destinazione per il debug in modalità utente. Per altre informazioni, vedere Configurazione del debug in modalità utente in Visual Studio.

Requisiti hardware

Ottenere un dispositivo USB per il quale si scriverà il driver client. Nella maggior parte dei casi, viene fornito un dispositivo USB e la relativa specifica hardware. La specifica descrive le funzionalità del dispositivo e i comandi del fornitore supportati. Usare la specifica per determinare la funzionalità del driver USB e le decisioni di progettazione correlate.

Se non si ha familiarità con lo sviluppo di driver USB, usare il kit di apprendimento OSR USB FX2 per studiare esempi USB inclusi in WDK. Contiene il dispositivo USB FX2 e tutte le specifiche hardware necessarie per implementare un driver client.

Passaggio 1: Generare il codice del driver

Per informazioni dettagliate sulla scrittura di codice del driver UMDF, vedere Scrittura di un driver UMDF basato su un modello.

Per il codice specifico dell'USB, selezionare le opzioni seguenti in Visual Studio 2022

  1. Nella casella di ricerca nella parte superiore della finestra di dialogo Nuovo progetto digitare USB.
  2. Nel riquadro centrale selezionare Driver modalità utente, USB (UMDF V2).
  3. Selezionare Avanti.
  4. Immettere un nome di progetto, scegliere un percorso di salvataggio e selezionare Crea.

Gli screenshot seguenti mostrano la finestra di dialogo Nuovo progetto per il modello driver usb in modalità utente.

Screenshot delle opzioni di creazione del progetto di Visual Studio.

Screenshot della schermata di configurazione del progetto di creazione di Visual Studio.

Questo articolo presuppone che il nome del progetto sia MyUSBDriver_UMDF_. Contiene i file seguenti:

File Descrizione
Driver.h; Driver.c Contiene l'implementazione del punto di ingresso del modulo driver. Funzionalità e callback correlati a DriverEntry e WDFDRIVER.
Device.h; Device.c WDFDEVICE e WDFUSBDEVICE funzionalità correlate e callback.
Queue.h; Queue.c Funzionalità e callback correlati a WDFQUEUE.
Trace.h Definisce il GUID dell'interfaccia del dispositivo. Dichiara anche funzioni di traccia e macro.
<>Nome progetto.inf File INF necessario per installare il driver client nel computer di destinazione.

Passaggio 2: Aggiungere informazioni sul dispositivo

Prima di compilare il driver, è necessario aggiungere informazioni sul dispositivo, in particolare l'ID hardware. Per specificare l'ID hardware:

  1. Nella finestra Esplora soluzioni fare clic con il pulsante destro del mouse su MyUSBDriver_UMDF_ e scegliere Proprietà.
  2. Nella finestra pagine delle proprietà MyUSBDriver_UMDF_ passare a Proprietà > di configurazione Installazione driver, >come illustrato di seguito. Screenshot della finestra delle pagine delle proprietà di Visual Studio 2022.
  3. Selezionare Rimuovi le versioni precedenti del driver prima della distribuzione.
  4. In Target Device Name (Nome dispositivo di destinazione) selezionare il nome del computer configurato per il test e il debug.
  5. Selezionare Hardware ID Driver Update (Aggiornamento driver ID hardware) e immettere l'ID hardware per il driver. In questo esercizio l'ID hardware è Root\MyUSBDriver_UMDF_. Seleziona OK.

Nota

In questo esercizio l'ID hardware non identifica un componente hardware reale. Identifica un dispositivo immaginario che verrà assegnato un posto nell'albero del dispositivo come figlio del nodo radice. Per l'hardware reale, non selezionare Aggiornamento driver ID hardware. Selezionare invece Installa e verifica. È possibile visualizzare l'ID hardware nel file inF (Information) del driver. Nella finestra Esplora soluzioni passare a MyUSBDriver_UMDF_ > File driver e fare doppio clic su MyUSBDriver_UMDF_.inf. L'ID hardware è in [Standard.NT$ARCH$].

Tutti i driver client USB basati su UMDF richiedono due driver forniti da Microsoft, il reflector e WinUSB.

  • Reflector: se il driver viene caricato correttamente, il riflettore viene caricato come driver principale nello stack in modalità kernel. Il riflettore deve essere il driver principale nello stack in modalità kernel. Per soddisfare questo requisito, il file INF del modello specifica il riflettore come servizio e WinUSB come driver di filtro inferiore in INF:

    [MyDevice_Install.NT.Services]
    AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall  ; flag 0x2 sets this as the service for the device
    AddService=WinUsb,0x000001f8,WinUsb_ServiceInstall  ; this service is installed because its a filter.
    
  • WinUSB: il pacchetto di installazione deve contenere coinstallatori per Winusb.sys perché per il driver client, WinUSB è il gateway allo stack di driver USB in modalità kernel. Un altro componente caricato è una DLL in modalità utente, denominata WinUsb.dll, nel processo host del driver client (Wudfhost.exe). Winusb.dll espone funzioni WinUSB che semplificano il processo di comunicazione tra il driver client e WinUSB.

Passaggio 3: Compilare il codice del driver client USB

Per compilare il driver:

  1. Aprire il progetto o la soluzione driver in Visual Studio 2022.
  2. Fare clic con il pulsante destro del mouse sulla soluzione nel Esplora soluzioni e scegliere Configuration Manager.
  3. Da Configuration Manager selezionare la configurazione della soluzione attiva (ad esempio Debug o Versione) e la piattaforma della soluzione attiva (ad esempio, x64) che corrispondono al tipo di compilazione a cui si è interessati.
  4. Verificare che il GUID dell'interfaccia del dispositivo sia accurato in tutto il progetto.
    • Il GUID dell'interfaccia del dispositivo è definito in Trace.h e viene fatto riferimento da MyUSBDriverUMDFCreateDevice in Device.c. Quando si crea il progetto con il nome MyUSBDriver_UMDF_, Visual Studio 2022 definisce il GUID dell'interfaccia del dispositivo con il nome GUID_DEVINTERFACE_MyUSBDriver_UMDF_ , ma chiama WdfDeviceCreateDeviceInterface con il parametro &GUID_DEVINTERFACE_MyUSBDriverUMDFerrato . Sostituire il parametro errato con il nome definito in Trace.h per assicurarsi che il driver venga compilato correttamente.
  5. Dal menu Compila scegliere Compila soluzione.

Per altre informazioni, vedere Compilazione di un driver.

Passaggio 4: Configurare un computer per il test e il debug

Per testare ed eseguire il debug di un driver, eseguire il debugger nel computer host e nel driver nel computer di destinazione. Finora è stato usato Visual Studio nel computer host per compilare un driver. Successivamente è necessario configurare un computer di destinazione. Per configurare un computer di destinazione, seguire le istruzioni riportate in Effettuare il provisioning di un computer per la distribuzione e il test dei driver.

Passaggio 5: Abilitare la traccia per il debug del kernel

Il codice del modello contiene diversi messaggi di traccia (TraceEvents) che consentono di tenere traccia delle chiamate di funzione. Tutte le funzioni nel codice sorgente contengono messaggi di traccia che contrassegnano la voce e l'uscita di una routine. Per gli errori, il messaggio di traccia contiene il codice di errore e una stringa significativa. Poiché la traccia WPP è abilitata per il progetto driver, il file di simboli PDB creato durante il processo di compilazione contiene istruzioni di formattazione dei messaggi di traccia. Se si configurano i computer host e di destinazione per la traccia WPP, il driver può inviare messaggi di traccia a un file o al debugger.

Per configurare il computer host per la traccia WPP

  1. Creare file TMF (Trace Message Format) estraendo le istruzioni di formattazione dei messaggi di traccia dal file di simboli PDB.

    È possibile usare Tracepdb.exe per creare file TMF. Lo strumento si trova nella <cartella di installazione windows Kits\10\bin\<architecture> della cartella>WDK. Il comando seguente crea file TMF per il progetto driver.

    tracepdb -f <PDBFiles> -p <TMFDirectory>
    

    L'opzione -f specifica il percorso e il nome del file di simboli PDB. L'opzione -p specifica il percorso per i file TMF creati da Tracepdb. Per altre informazioni, vedere Comandi tracepdb.

    Sono presenti tre file nel percorso specificato, uno per ogni file di codice C nel progetto. Vengono assegnati nomi di file GUID.

  2. Nel debugger digitare i comandi seguenti:

    .load Wmitrace
    .chain
    !wmitrace.searchpath + <TMF file location>
    

Questi comandi:

  • Caricare l'estensione Wmitrace.dll.
  • Verifica che l'estensione del debugger sia caricata.
  • Aggiunge il percorso dei file TMF al percorso di ricerca dell'estensione del debugger.

L'output è simile al seguente:

Trace Format search path is: 'C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE;c:\drivers\tmf

Per configurare il computer di destinazione per la traccia WPP

  1. Assicurarsi di disporre dello strumento Tracelog nel computer di destinazione. Lo strumento si trova nella cartella install_folder>Windows Kits\10\Tools\<arch> di WDK.< Per altre informazioni, vedere Sintassi dei comandi tracelog.

  2. Aprire una finestra di comando ed eseguire come amministratore.

  3. Digitare il comando seguente:

    tracelog -start MyTrace -guid \#c918ee71-68c7-4140-8f7d-c907abbcb05d -flag 0xFFFF -level 7-rt -kd
    

Il comando avvia una sessione di traccia denominata MyTrace.

L'argomento GUID specifica il GUID del provider di traccia, ovvero il driver client. È possibile ottenere il GUID da Trace.h nel progetto di Visual Studio 2022. Come altra opzione, è possibile digitare il comando seguente e specificare il GUID in un file con estensione guid. Il file contiene il GUID in formato trattino:

tracelog -start MyTrace -guid c:\\drivers\\Provider.guid -flag 0xFFFF -level 7-rt -kd

È possibile arrestare la sessione di traccia digitando il comando seguente:

tracelog -stop MyTrace

Passaggio 6: Distribuire il driver nel computer di destinazione

  1. Nella finestra Esplora soluzioni fare clic con il pulsante destro del mouse sul nome del progetto (MyUSBDriver_UMDF_) e scegliere Proprietà.
  2. Nel riquadro sinistro passare a Proprietà > di configurazione Installazione driver > Distribuzione.
  3. Per Target Device Name (Nome dispositivo di destinazione) specificare il nome del computer di destinazione.
  4. Selezionare Installa/Reinstalla e verifica.
  5. Selezionare OK.
  6. Scegliere Avvia debug dal menu Debug oppure premere F5 sulla tastiera.

Nota

Non specificare l'ID hardware del dispositivo in Aggiornamento driver ID hardware. L'ID hardware deve essere specificato solo nel file INF (Information) del driver.

Passaggio 7: Visualizzare il driver in Gestione dispositivi

  1. Immettere il comando seguente per aprire Gestione dispositivi.

    devmgmt
    
  2. Verificare che Gestione dispositivi mostri il nodo seguente.

    Dispositivo USB

    MyUSBDriver_UMDF_Device

Passaggio 8: Visualizzare l'output nel debugger

Verificare che i messaggi di traccia vengano visualizzati nella finestra immediata del debugger nel computer host.

L'output avrà un aspetto analogo al seguente:

[0]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::OnPrepareHardware Entry
[0]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::OnPrepareHardware Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::CreateInstanceAndInitialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Initialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Initialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::CreateInstanceAndInitialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Configure Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::CreateInstanceAndInitialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::Initialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::Initialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::CreateInstanceAndInitialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Configure Exit

Osservazioni:

Di seguito viene illustrato come il framework e il driver client interagiscono per interagire con Windows e gestire le richieste inviate al dispositivo USB. Questa figura mostra i moduli caricati nel sistema per un driver client USB basato su UMDF.

Diagramma dell'architettura del driver client in modalità utente.

Lo scopo di ogni modulo è descritto di seguito:

  • Applicazione: processo in modalità utente che invia richieste di I/O per comunicare con il dispositivo USB.
  • Gestione I/O: un componente Windows che crea pacchetti di richieste di I/O (IRP) per rappresentare le richieste dell'applicazione ricevute e le inoltra all'inizio dello stack di dispositivi in modalità kernel per il dispositivo di destinazione.
  • Reflector: un driver in modalità kernel fornito da Microsoft installato nella parte superiore dello stack di dispositivi in modalità kernel (WUDFRd.sys). Il riflettore reindirizza i runtime di integrazione ricevuti dal gestore di I/O al processo host del driver client. Dopo aver ricevuto la richiesta, il framework e il driver client gestiscono la richiesta.
  • Processo host: processo in cui viene eseguito il driver in modalità utente (Wudfhost.exe). Ospita anche il framework e il dispatcher di I/O.
  • Driver client: driver di funzione in modalità utente per il dispositivo USB.
  • UMDF: modulo framework che gestisce la maggior parte delle interazioni con Windows per conto del driver client. Espone le interfacce DDI (Device Driver Interface) in modalità utente che il driver client può usare per eseguire attività di driver comuni.
  • Dispatcher: meccanismo eseguito nel processo host; determina come inoltrare una richiesta alla modalità kernel dopo che è stata elaborata dai driver in modalità utente e ha raggiunto la fine dello stack in modalità utente. Nell'illustrazione il dispatcher inoltra la richiesta alla DLL in modalità utente Winusb.dll.
  • Winusb.dll: dll in modalità utente fornita da Microsoft che espone funzioni WinUSB che semplificano il processo di comunicazione tra il driver client e WinUSB (Winusb.sys, caricato in modalità kernel).
  • Winusb.sys: un driver fornito da Microsoft richiesto da tutti i driver client UMDF per i dispositivi USB. Il driver deve essere installato sotto il riflettore e funge da gateway per lo stack di driver USB in modalità kernel. Per altre informazioni, vedere Introduzione a WinUSB per sviluppatori.
  • Stack di driver USB: un set di driver, fornito da Microsoft, che gestisce la comunicazione a livello di protocollo con il dispositivo USB. Per altre informazioni, vedere Driver lato host USB in Windows.

Ogni volta che un'applicazione effettua una richiesta per lo stack di driver USB, gestione I/O di Windows invia la richiesta al riflettore, che lo indirizza al driver client in modalità utente. Il driver client gestisce la richiesta chiamando metodi UMDF specifici, che chiamano internamente Funzioni WinUSB per inviare la richiesta a WinUSB. Dopo aver ricevuto la richiesta, WinUSB elabora la richiesta o la inoltra allo stack di driver USB.