Condividi tramite


Sospensione selettiva nei driver di funzione KMDF USB

Questo articolo descrive come i driver di funzione KMDF supportano la sospensione selettiva USB.

Se il driver USB richiede funzionalità o risorse non disponibili in modalità utente, è necessario fornire un driver di funzione KMDF. I driver KMDF implementano la sospensione selettiva impostando i valori pertinenti in una struttura di inizializzazione KMDF e fornendo quindi le funzioni di callback appropriate. KMDF gestisce i dettagli della comunicazione con driver inferiori per sospendere e riprendere il dispositivo.

Linee guida per la sospensione selettiva nei driver KMDF

I driver KMDF che supportano la sospensione selettiva devono seguire queste linee guida:

  • Un driver di funzione KMDF deve essere il PPO per lo stack di dispositivi. Per impostazione predefinita, i driver di funzione KMDF sono PPO.
  • Un driver di funzione KMDF che supporta la sospensione selettiva può usare code gestite dall'alimentazione o code che non sono gestite dall'alimentazione. Per impostazione predefinita, gli oggetti coda per gli oggetti PPO sono gestiti dall'alimentazione.

Proprietà dei criteri di alimentazione e driver USB KMDF

Per impostazione predefinita, il driver di funzione KMDF per un dispositivo USB è il modello PPO per lo stack di dispositivi. KMDF gestisce la sospensione selettiva e la ripresa per conto di questo driver.

Configurazione della coda di I/O nei driver KMDF

Un driver di funzione KMDF che supporta la sospensione selettiva può usare code gestite dall'alimentazione o code che non sono gestite dall'alimentazione. In genere, un driver configura una coda che non è gestita dall'alimentazione per ricevere le richieste di controllo di I/O dei dispositivi in ingresso e configura una o più code gestite dall'alimentazione per ricevere richieste di lettura, scrittura e altre richieste dipendenti dall'alimentazione. Quando una richiesta arriva a una coda gestita dall'alimentazione, KMDF garantisce che il dispositivo sia in D0 prima di presentare la richiesta al driver.

Se si scrive un driver di filtro KMDF a più livelli sopra l'PPO nello stack di dispositivi, non è necessario usare code gestite dall'alimentazione. Il motivo è identico a quello dei driver UMDF. Il framework non presenta richieste da code gestite dall'alimentazione mentre il dispositivo è sospeso, quindi l'uso di tali code potrebbe bloccare lo stack di dispositivi.

Meccanismo di sospensione selettiva per i driver di funzione KMDF

KMDF gestisce la maggior parte del lavoro necessario per supportare la sospensione selettiva USB. Tiene traccia dell'attività di I/O, gestisce il timer di inattività e invia le richieste di controllo di I/O del dispositivo che causano la sospensione e la ripresa del dispositivo da parte del driver padre (Usbhub.sys o Usbccgp.sys).

Se un driver di funzione KMDF supporta la sospensione selettiva, KMDF tiene traccia dell'attività di I/O in tutte le code gestite dall'alimentazione di cui è proprietario ogni oggetto dispositivo. Il framework avvia un timer inattivo ogni volta che il conteggio di I/O raggiunge lo zero. Il valore di timeout predefinito è 5 secondi.

Se una richiesta di I/O arriva a una coda gestita dall'alimentazione appartenente all'oggetto dispositivo prima della scadenza del periodo di timeout di inattività, il framework annulla il timer di inattività e non sospende il dispositivo.

Alla scadenza del timer di inattività, KMDF invia le richieste necessarie per inserire il dispositivo USB nello stato sospeso. Se un driver di funzione usa un lettore continuo in un endpoint USB, il polling ripetuto del lettore non viene conteggiato come attività verso il timer di inattività kmDF. Tuttavia, nella funzione di callback EvtDeviceD0Exit , il driver USB deve arrestare manualmente il lettore continuo e tutte le altre destinazioni di I/O alimentato da code che non sono gestite dall'alimentazione per garantire che il driver non invii richieste di I/O mentre il dispositivo non è nello stato di lavoro. Per arrestare le destinazioni, il driver chiama WdfIoTargetStop e specifica WdfIoTargetWaitForSentIoToComplete come azione di destinazione. In risposta, il framework arresta la destinazione di I/O solo dopo che tutte le richieste di I/O presenti nella coda di I/O di destinazione sono state completate e tutti i callback di completamento di I/O associati sono stati eseguiti.

Per impostazione predefinita, KMDF esegue la transizione del dispositivo da D0 allo stato di alimentazione del dispositivo specificato nelle impostazioni di inattività. Come parte della transizione, KMDF chiama le funzioni di callback di alimentazione del driver allo stesso modo per qualsiasi altra sequenza di risparmio energia.

Dopo la sospensione del dispositivo, il framework riprende automaticamente il dispositivo quando si verifica uno degli eventi seguenti:

Per riprendere il dispositivo, KMDF invia una richiesta di alimentazione verso il basso nello stack di dispositivi e quindi richiama le funzioni di callback del driver nello stesso modo in cui sarebbe per qualsiasi altra sequenza di alimentazione.

Per informazioni dettagliate sui callback coinvolti nelle sequenze di accensione e accensione, vedere il white paper Plug and Play e Risparmio energia nei driver WDF.

Supporto della sospensione selettiva USB in un driver di funzione KMDF

Per implementare la sospensione selettiva USB in un driver di funzione KMDF:

  • Inizializzare le impostazioni dei criteri di risparmio energia correlate all'inattività, incluso il timeout di inattività.
  • Facoltativamente, includere la logica per impedire temporaneamente l'operazione di sospensione o ripresa quando il driver determina che il dispositivo non deve essere sospeso a causa di un handle aperto o di un altro motivo non correlato alle code di I/O del dispositivo.
  • In un driver USB per un dispositivo di interfaccia umana (HID), indicare nell'INF che supporta la sospensione selettiva.

Inizializzazione delle impostazioni di Power Policy in un driver di funzione KMDF

Per configurare il supporto per la sospensione selettiva USB, un driver KMDF usa la struttura WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS . Il driver deve innanzitutto inizializzare la struttura e quindi impostare campi che forniscono dettagli sulle funzionalità del driver e del relativo dispositivo. In genere, il driver compila questa struttura nella relativa funzione EvtDriverDeviceAdd o EvtDevicePrepareHardware .

Per inizializzare la struttura WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS

Dopo che il driver crea l'oggetto dispositivo, il driver usa la funzione WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT per inizializzare la struttura. Questa funzione accetta due argomenti:

  • Puntatore alla struttura WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS da inizializzare.
  • Valore di enumerazione che indica il supporto per la sospensione selettiva. Il driver deve specificare IdleUsbSelectiveSuspend.

Se il driver specifica IdleUsbSelectiveSuspend, la funzione inizializza i membri della struttura come indicato di seguito:

  • IdleTimeout è impostato su IdleTimeoutDefaultValue (attualmente 5000 millisecondi o 5 secondi).
  • UserControlOfIdleSettings è impostato su IdleAllowUserControl .
  • Enabled è impostato su WdfUseDefault, che indica che la sospensione selettiva è abilitata, ma un utente può disabilitarlo se il membro UserControlOfIdleSettings lo consente.
  • DxState è impostato su PowerDeviceMaximum, che usa le funzionalità di alimentazione segnalate per il dispositivo per determinare lo stato in cui eseguire la transizione del dispositivo inattiva.

Per configurare la sospensione selettiva USB

Dopo che il driver inizializza la struttura WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS , il driver può impostare altri campi nella struttura e quindi chiamare WdfDeviceAssignS0IdleSettings per passare queste impostazioni al framework. I campi seguenti si applicano ai driver di funzione USB:

  • IdleTimeout: intervallo, in millisecondi, che deve trascorrere senza ricevere una richiesta di I/O prima che il framework consideri l'inattività del dispositivo. Il driver può specificare un valore ULONG o può accettare l'impostazione predefinita.

  • UserControlOfIdleSettings: indica se l'utente può modificare le impostazioni di inattività del dispositivo. I valori possibili sono IdleDoNotAllowUserControl e IdleAllowUserControl.

  • DxState: stato di alimentazione del dispositivo a cui il framework sospende il dispositivo. I valori possibili sono PowerDeviceD1, PowerDeviceD2 e PowerDeviceD3.

    I driver USB non devono modificare l'impostazione iniziale di questo valore. La funzione WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT imposta questo valore su PowerDeviceMaximum, che garantisce che il framework scelga il valore corretto in base alle funzionalità del dispositivo.

Il frammento di codice seguente proviene dal file Device.c del driver di esempio Osrusbfx2:

WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings;
NTSTATUS    status = STATUS_SUCCESS;
//
// Initialize the idle policy structure.
//
WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, 
     IdleUsbSelectiveSuspend);
idleSettings.IdleTimeout = 10000; // 10 sec

status = WdfDeviceAssignS0IdleSettings(Device, &idleSettings);
if ( !NT_SUCCESS(status)) {
     TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
                 "WdfDeviceSetPowerPolicyS0IdlePolicy failed %x\n", 
                 status);
    return status;
}

Nell'esempio il driver chiama WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT, specificando IdleUsbSelectiveSuspend. Il driver imposta IdleTimeout su 10.000 millisecondi (10 secondi) e accetta le impostazioni predefinite del framework per DxState e UserControlOfIdleSettings. Di conseguenza, il framework passa il dispositivo allo stato D3 quando è inattiva e crea una pagina delle proprietà Gestione dispositivi che consente agli utenti con privilegi di amministratore di abilitare o disabilitare il supporto di inattività del dispositivo. Il driver chiama quindi WdfDeviceAssignS0IdleSettings per abilitare il supporto inattiva e registrare queste impostazioni con il framework.

Un driver può chiamare WdfDeviceAssignS0IdleSettings in qualsiasi momento dopo la creazione dell'oggetto dispositivo. Anche se la maggior parte dei driver chiama inizialmente questo metodo dal callback EvtDriverDeviceAdd , questo potrebbe non essere sempre possibile o addirittura auspicabile. Se un driver supporta più dispositivi o versioni del dispositivo, il driver potrebbe non conoscere tutte le funzionalità del dispositivo fino a quando non esegue query sull'hardware. Tali driver possono posticipare la chiamata a WdfDeviceAssignS0IdleSettings fino al callback evtDevicePrepareHardware .

In qualsiasi momento dopo la chiamata iniziale a WdfDeviceAssignS0IdleSettings, il driver può modificare il valore di timeout di inattività e lo stato del dispositivo in cui il dispositivo è inattivo. Per modificare una o più impostazioni, il driver inizializza semplicemente un'altra struttura WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS come descritto in precedenza e chiama di nuovo WdfDeviceAssignS0IdleSettings .

Prevenzione della sospensione del dispositivo USB

A volte, un dispositivo USB non deve essere spento anche se non sono presenti richieste di I/O entro il periodo di timeout, in genere quando un handle è aperto al dispositivo o il dispositivo è in carica. Un driver USB può impedire al framework di sospendere un dispositivo inattiva in situazioni di questo tipo chiamando WdfDeviceStopIdle e chiamando WdfDeviceResumeIdle quando è di nuovo accettabile per la sospensione del dispositivo.

WdfDeviceStopIdle arresta il timer di inattività. Se il periodo IdleTimeout non è scaduto e il dispositivo non è ancora stato sospeso, il framework annulla il timer di inattività e non sospende il dispositivo. Se il dispositivo è già stato sospeso, il framework restituisce il dispositivo allo stato di lavoro. WdfDeviceStopIdlenon impedisce al framework di sospendere il dispositivo quando il sistema passa a uno stato di sospensione Sx. L'unico effetto è impedire la sospensione del dispositivo mentre il sistema si trova nello stato di funzionamento S0. WdfDeviceResumeIdle riavvia il timer di inattività. Questi due metodi gestiscono un conteggio dei riferimenti nel dispositivo, quindi se il driver chiama WdfDeviceStopIdle più volte, il framework non sospende il dispositivo finché il driver non ha chiamato WdfDeviceResumeIdle lo stesso numero di volte. Un driver non deve chiamare WdfDeviceResumeIdlesenza prima chiamare WdfDeviceStopIdle.

Inclusione di una chiave del Registro di sistema (solo driver HID)

I driver di filtro superiore kmDF per i dispositivi USB HID devono indicare in INF che supportano la sospensione selettiva in modo che il driver della porta HIDClass.sys fornito da Microsoft possa abilitare la sospensione selettiva per lo stack HID. InF deve includere una direttiva AddReg che aggiunge la chiave SelectiveSuspendEnabled e impostarne il valore su 1, come illustrato nella stringa seguente:

HKR,,"SelectiveSuspendEnabled",0x00000001,0x1

Per un esempio, vedere Hidusbfx2.inx in WDK in %WinDDK%\BuildNumber\Src\Hid\ Hidusbfx2\sys.

Supporto della riattivazione remota per i driver KMDF

Come per la sospensione selettiva, KMDF incorpora il supporto per la riattivazione, in modo che un dispositivo USB possa attivare un segnale di riattivazione mentre il dispositivo è inattivo e il sistema si trova nello stato di lavoro (S0) o in uno stato di sospensione (S1-S4). In termini kmdf, queste due funzionalità sono denominate rispettivamente "riattivazione da S0" e "riattivazione da Sx".

Per i dispositivi USB, la riattivazione indica semplicemente che il dispositivo stesso può avviare la transizione da uno stato di alimentazione inferiore allo stato di lavoro. Pertanto, in termini USB, la riattivazione da S0 e la riattivazione da Sx sono le stesse e sono chiamate "riattivazione remota".

I driver di funzione USB KMDF non richiedono codice per supportare la riattivazione da S0 perché KMDF fornisce questa funzionalità come parte del meccanismo di sospensione selettiva. Tuttavia, per supportare la riattivazione remota quando il sistema si trova in Sx, un driver di funzione deve:

I driver KMDF configurano in genere il supporto della riattivazione contemporaneamente che configurano il supporto per la sospensione selettiva USB nella funzione EvtDriverDeviceAdd o EvtDevicePrepareHardware .

Controllo delle funzionalità del dispositivo

Prima che un driver di funzioni USB KMDF inizializzi le impostazioni dei criteri di risparmio energia per l'inattività e la riattivazione, deve verificare che il dispositivo supporti la riattivazione remota. Per ottenere informazioni sulle funzionalità hardware del dispositivo, il driver inizializza una struttura WDF_USB_DEVICE_INFORMATION e chiama WdfUsbTargetDeviceRetrieveInformation, in genere nel callback EvtDriverDeviceAdd o EvtDevicePrepareHardware .

Nella chiamata a WdfUsbTargetDeviceRetrieveInformation il driver passa un handle all'oggetto dispositivo e un puntatore alla struttura WDF_USB_DEVICE_INFORMATION inizializzata. Al termine della restituzione dalla funzione, il campo Traits della struttura contiene flag che indicano se il dispositivo è auto-alimentato, può funzionare ad alta velocità e supporta la riattivazione remota.

L'esempio seguente di Osrusbfx2 KMDF illustra come chiamare questo metodo per determinare se un dispositivo supporta la riattivazione remota. Dopo l'esecuzione di queste righe di codice, la variabile waitWakeEnable contiene TRUE se il dispositivo supporta la riattivazione remota e FALSE in caso contrario:

    WDF_USB_DEVICE_INFORMATION          deviceInfo;
// Retrieve USBD version information, port driver capabilities and device
// capabilities such as speed, power, etc.
//

WDF_USB_DEVICE_INFORMATION_INIT(&deviceInfo);

status = WdfUsbTargetDeviceRetrieveInformation(
                            pDeviceContext->UsbDevice,
                            &deviceInfo);
waitWakeEnable = deviceInfo.Traits & WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE;

Abilitazione della riattivazione remota

Nella terminologia USB, un dispositivo USB è abilitato per la riattivazione remota quando è impostata la relativa funzionalità di DEVICE_REMOTE_WAKEUP. In base alla specifica USB, il software host deve impostare la funzionalità di riattivazione remota in un dispositivo "solo prima" per mettere il dispositivo in sospensione. Il driver della funzione KMDF è necessario solo per inizializzare le impostazioni di riattivazione. KMDF e i driver del bus USB forniti da Microsoft emettono le richieste di I/O e gestiscono la manipolazione hardware necessaria per abilitare la riattivazione remota.

Per inizializzare le impostazioni di riattivazione

  1. Chiamare WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT per inizializzare una struttura WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS . Questa funzione imposta il membro Enabled della struttura su WdfUseDefault, imposta il membro DxState su PowerDeviceMaximum e imposta il membro UserControlOfWakeSettings su WakeAllowUserControl.
  2. Chiamare WdfDeviceAssignSxWakeSettings con la struttura inizializzata. Di conseguenza, il dispositivo è abilitato per la riattivazione dallo stato D3 e l'utente può abilitare o disabilitare il segnale di riattivazione dalla pagina delle proprietà del dispositivo in Gestione dispositivi.

Il frammento di codice seguente dell'esempio Osrusbfx2 illustra come inizializzare le impostazioni di riattivazione ai valori predefiniti:

WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings;

WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings);
status = WdfDeviceAssignSxWakeSettings(Device, &wakeSettings);
if (!NT_SUCCESS(status)) {
    return status;
}

Per i dispositivi USB che supportano la sospensione selettiva, il driver del bus sottostante prepara l'hardware del dispositivo per la riattivazione. Pertanto, i driver di funzione USB richiedono raramente un callback EvtDeviceArmWakeFromS0 . Il framework invia una richiesta di sospensione selettiva al driver del bus USB alla scadenza del timeout di inattività.

Per lo stesso motivo, i driver di funzione USB richiedono raramente un callback EvtDeviceWakeFromS0Triggered o EvtDeviceWakeFromSxTriggered . Il framework e il driver del bus sottostante gestiscono invece tutti i requisiti per restituire il dispositivo allo stato di lavoro.