Suspension sélective dans les pilotes USB UMDF

Cette rubrique décrit comment les pilotes de fonction UMDF prennent en charge la suspension sélective USB.

API importantes

Les pilotes de fonction UMDF peuvent prendre en charge la suspension sélective USB de deux façons :

  • En réclamant la propriété de la stratégie d’alimentation et en gérant la mise en veille et la reprise de l'appareil.
  • En se basant sur le pilote WinUSB.sys, fourni par Microsoft, pour gérer la suspension sélective. WinUSB.sys est installé en tant que partie de la pile de périphériques en mode noyau pendant l’installation du pilote USB UMDF. WinUSB.sys implémente les mécanismes sous-jacents pour suspendre et reprendre l’opération d’appareil USB.

Les deux approches ne nécessitent que de petites quantités de code. L’exemple IdleWake fourni dans le WDK montre comment prendre en charge la suspension sélective dans un pilote UMDF USB. Vous trouverez cet exemple dans %WinDDK%\BuildNumber\Src\Usb\OsrUsbFx2\ UMDF\Fx2_Driver\IdleWake. Le dossier contient à la fois des versions PPO et non-PPO de l’exemple.

Les pilotes UMDF qui prennent en charge la suspension sélective doivent suivre les instructions suivantes :

  • Le pilote UMDF peut revendiquer la propriété de la stratégie d’alimentation pour sa pile d’appareils, mais il n’est pas obligé de le faire. Par défaut, le pilote WinUSB.sys sous-jacent est responsable de la politique d'alimentation.
  • Un pilote UMDF qui prend en charge la suspension sélective et qui est le propriétaire de la politique d'alimentation (PPO) peut utiliser des files d'attente gérées par l'alimentation ou des files d'attente qui ne sont pas gérées par l'alimentation. Un pilote UMDF qui prend en charge la suspension sélective, mais qui n’est pas considéré comme le PPO, ne doit pas utiliser les files d’attente gérées par l'alimentation.

Propriété de la configuration de l'alimentation dans les pilotes USB UMDF

Par défaut, WinUSB.sys est l’objet PPO d’une pile d’appareils qui contient un pilote USB UMDF. À compter de WDF 1.9, les pilotes USB basés sur UMDF peuvent revendiquer la propriété de la stratégie d’alimentation. Étant donné qu’un seul pilote dans chaque pile de périphériques peut être le propriétaire de la politique d'alimentation (PPO), un pilote USB UMDF qui est PPO doit désactiver explicitement la propriété de la politique d’alimentation dans WinUSB.sys.

Pour revendiquer la propriété de la stratégie d’alimentation dans un pilote USB UMDF

  1. Appelez IWDFDeviceInitialize ::SetPowerPolicyOwnership et passez TRUE, généralement à partir de la méthode IDriverEntry ::OnDeviceAdd sur l’objet de rappel du pilote. Par exemple:

    FxDeviceInit->SetPowerPolicyOwnership(TRUE);
    
  2. Désactiver la gestion de la stratégie d'alimentation dans WinUSB. Dans le fichier INF du pilote, incluez une directive AddReg qui définit la valeur WinUsbPowerPolicyOwnershipDisabled dans le Registre sur une valeur différente de zéro. La directive AddReg doit apparaître dans une section DDInstall.HW. Par exemple:

    [MyDriver_Install.NT.hw]
    AddReg=MyDriver_AddReg
    
    [MyDriver_AddReg]
    HKR,,"WinUsbPowerPolicyOwnershipDisabled",0x00010001,1
    

Les pilotes USB UMDF qui gèrent la suspension sélective et utilisent les versions WDF antérieures à la version 1.9 ne doivent pas revendiquer la gestion de la politique d’alimentation. Avec ces versions antérieures de WDF, la suspension sélective USB fonctionne correctement uniquement si WinUSB.sys est le PPO.

Files d’attente d’E/S dans les pilotes USB UMDF

Pour un pilote UMDF qui prend en charge la suspension sélective, le fait que le pilote UMDF possède une stratégie d’alimentation pour son appareil détermine le type de files d’attente d’E/S qu’il peut utiliser. Les pilotes UMDF qui prennent en charge la suspension sélective et qui sont des PPOs peuvent utiliser des files d’attente qui sont gérées par la gestion de l'alimentation ou non gérées par la gestion de l'alimentation. Les pilotes USB UMDF qui prennent en charge la suspension sélective mais ne sont pas le PPO ne doivent pas utiliser de files d'attente d'E/S à gestion de l'alimentation.

Si une demande d’E/S arrive pour une file d’attente gérée au niveau de l’alimentation pendant que l’appareil est suspendu, le cadre ne présente pas la requête, sauf si le pilote est PPO, comme illustré dans l’image de la suspension sélective dans les pilotes USB. Si le pilote UMDF n’est pas l’objet PPO de l’appareil, l’infrastructure ne peut pas alimenter l’appareil en son nom. Par conséquent, la requête reste bloquée dans la file d’attente gérée par l’alimentation. La requête n’atteint jamais WinUSB. Par conséquent, WinUSB ne peut pas alimenter l’appareil. Par conséquent, la pile d’appareils peut se bloquer.

Si la file d’attente n’est pas gérée par l’alimentation, le framework présente des demandes d’E/S au pilote UMDF même quand l’appareil est hors tension. Le pilote UMDF met en forme la requête et la transfère dans la pile de périphériques jusqu'à la cible d'E/S par défaut de la manière habituelle. Le code spécial n’est pas obligatoire. Lorsque la requête atteint l’objet PPO (WinUSB.sys), WinUSB.sys alimente l’appareil et effectue l’opération d’E/S requise.

L’exemple de pilote dans %WinDDK%\BuildNumber\Src\Usb\OsrUsbFx2\umdf\Fx2_Driver\IdleWake définit la constante _NOT_POWER_POLICY_OWNER_ lorsque vous générez la version non PPO du pilote. Lorsque le pilote crée une file d’attente pour les demandes de lecture et d’écriture, il détermine s’il faut créer une file d’attente gérée par l’alimentation en vérifiant la constante.

Pour créer la file d’attente, le pilote appelle la méthode CMyQueue ::Initialize définie par le pilote, qui accepte les trois paramètres suivants :

  • DispatchType, valeur d’énumération WDF_IO_QUEUE_DISPATCH_TYPE qui indique comment la file d’attente répartit les demandes.
  • Valeur par défaut, valeur booléenne qui indique si la file d’attente est une file d’attente par défaut.
  • PowerManaged, un booléen qui indique si la file d’attente est gérée par l’alimentation électrique.

L’extrait de code suivant montre l’appel du pilote à la méthode CMyQueue ::Initialize dans le cadre de la création de file d’attente en lecture-écriture :

#if defined(_NOT_POWER_POLICY_OWNER_)
    powerManaged = false;
#else
    powerManaged = true;
#endif  
hr = __super::Initialize(WdfIoQueueDispatchParallel,
                         true,
                         powerManaged,
                         );

CMyQueue ::Initialize appelle ensuite IWDFDevice ::CreateIoQueue pour créer la file d’attente comme suit :

hr = m_FxDevice->CreateIoQueue(
                               callback,
                               Default,
                               DispatchType,
                               PowerManaged,
                               FALSE,
                               &fxQueue
                               );

Cette séquence de code entraîne une file d’attente par défaut qui répartit les requêtes en parallèle. Si le pilote est le PPO, la file d'attente est sous gestion de l'alimentation, et si le pilote n'est pas le PPO, la file d'attente n'est pas sous gestion de l'alimentation.

Prise en charge de la suspension sélective USB dans un PPO UMDF

Pour prendre en charge la suspension sélective, un pilote USB UMDF qui est le PPO pour sa pile d’appareils doit effectuer les opérations suivantes :

  1. Revendiquer la propriété de la politique d’alimentation pour la pile d’appareils, généralement dans la méthode IDriverEntry::OnDeviceAdd sur son objet de rappel de pilote, comme décrit précédemment.
  2. Activez la suspension sélective en appelant la méthode IWDFDevice2 ::AssignS0IdleSettings sur l’objet d’appareil framework.

Pour activer la suspension sélective USB depuis un PPO

  • Appelez IWDFDevice2::AssignS0IdleSettings, généralement depuis la méthode OnPrepareHardware sur l’objet de rappel du périphérique. Définissez les paramètres sur AssignS0IdleSettings comme suit :
    • IdleCaps à IdleUsbSelectiveSuspend.
    • DxState vers l'état de veille dans lequel le framework place l'appareil lorsqu'il est inactif. Pour la suspension sélective USB, spécifiez PowerDeviceMaximum, qui indique que l’infrastructure doit utiliser la valeur spécifiée par le pilote de bus.
    • IdleTimeout au nombre de millisecondes que l’appareil doit être inactif avant que l’infrastructure ne le passe à DxState.
    • UserControlOfIdleSettings vers IdleAllowUserControl, si votre pilote permet aux utilisateurs de gérer les paramètres d'inactivité, ou sinon vers IdleDoNotAllowUserControl.
    • Activé pour WdfUseDefault pour activer la suspension sélective par défaut, mais pour autoriser le paramètre de l’utilisateur à remplacer la valeur par défaut.

L’exemple suivant montre comment le pilote IdleWake_PPO appelle cette méthode dans sa méthode CMyDevice ::SetPowerManagement interne :

hr = m_FxDevice->AssignS0IdleSettings( IdleUsbSelectiveSuspend,
                                PowerDeviceMaximum,
                                IDLE_TIMEOUT_IN_MSEC,
                                IdleAllowUserControl,
                                WdfUseDefault);                                                                                                   

Si le matériel de l’appareil peut générer un signal de sortie de veille, le pilote UMDF peut également prendre en charge la mise en éveil du système à partir de S1, S2 ou S3. Pour plus d’informations, consultez System Wake dans un pilote UMDF.

Prise en charge de la suspension sélective USB dans un pilote UMDF non PPO

Un pilote de fonction UMDF qui n’est pas le pilote PPO peut prendre en charge la suspension sélective grâce aux fonctionnalités du pilote sous-jacent WinUSB.sys. Le pilote UMDF doit avertir WinUSB que l’appareil et le pilote prennent en charge la suspension sélective et doivent activer l’interruption sélective dans le fichier INF ou en définissant la stratégie d’alimentation sur l’objet périphérique cible USB.

Si un pilote de fonction UMDF active la suspension sélective, le pilote WinUSB.sys sous-jacent détermine quand l’appareil est inactif. WinUSB démarre un compteur de délai d’attente inactif lorsqu’aucun transfert n’est en attente ou lorsque les seuls transferts en attente sont des transferts IN sur un point de terminaison d’interruption ou en bloc. Par défaut, le délai d’inactivité est de 5 secondes, mais le pilote UMDF peut modifier cette valeur par défaut.

Lorsque WinUSB.sys détermine que l’appareil est inactif, il envoie une demande de suspension de l’appareil vers le bas de la pile d’appareils en mode noyau. Le pilote de bus modifie l’état du matériel selon les besoins. Si toutes les fonctions d’appareil sur le port ont été suspendues, le port entre dans l’état de suspension sélectif USB.

Si une demande d’E/S arrive à WinUSB.sys pendant la suspension de l’appareil, WinUSB.sys reprend l’opération de l’appareil si l’appareil doit être alimenté pour traiter la demande. Le pilote UMDF ne nécessite aucun code pour reprendre l’appareil pendant que le système reste dans S0. Si le matériel de l’appareil peut générer un signal de réveil, le pilote UMDF peut également prendre en charge le réveil du système à partir de S1, S2 ou S3. Pour davantage d’informations, référez-vous à System Wake dans un pilote UMDF.

Un pilote UMDF qui n'est pas le pilote PPO peut prendre en charge la suspension sélective en suivant les deux étapes suivantes :

  1. Notifier WinUSB.sys que l'appareil et le pilote gèrent la suspension sélective.
  2. Activation de la suspension sélective USB.

En outre, le pilote peut éventuellement :

  • Définissez une valeur de délai d’attente pour l’appareil.
  • Autoriser l’utilisateur à activer ou désactiver la suspension sélective.

Pour obtenir un exemple d'implémentation de la suspension sélective USB dans un pilote de fonction USB UMDF qui n'est pas le PPO, consultez l'exemple Fx2_Driver dans le WDK. Cet exemple se trouve à %WinDDK%\BuildNumber\Src\Usb\OsrUsbFx2\Umdf\Fx2_Driver\ IdleWake_Non-PPO.

Pour informer WinUSB de la prise en charge de la suspension sélective

Pour notifier WinUSB.sys que l’appareil peut prendre en charge la suspension sélective USB, l'INF de l’appareil doit ajouter la valeur DeviceIdleEnabled à la clé matérielle de l'appareil et régler cette valeur sur 1. L’exemple suivant montre comment l’exemple Fx2_Driver ajoute et définit cette valeur dans le fichier WUDFOsrUsbFx2_IdleWakeNon-PPO.Inx :

[OsrUsb_Device_AddReg]
...
HKR,,"DeviceIdleEnabled",0x00010001,1

Pour activer la suspension sélective USB

Un pilote USB UMDF peut activer la suspension sélective USB au moment de l’exécution ou pendant l’installation dans l’INF.

  • Pour activer la prise en charge au moment de l’exécution, le pilote de fonction appelle IWDFUsbTargetDevice ::SetPowerPolicy et définit le paramètre PolicyType sur AUTO_SUSPEND et le paramètre Value sur TRUE ou 1. L’exemple suivant montre comment l’exemple Fx2_Driver active la suspension sélective dans le fichier DeviceNonPpo.cpp :

    BOOL AutoSuspend = TRUE;
    hr = m_pIUsbTargetDevice->SetPowerPolicy( AUTO_SUSPEND,
                                              sizeof(BOOL),
                                             (PVOID) &AutoSuspend );
    
  • Pour activer la prise en charge pendant l’installation, l’INF inclut une directive AddReg qui ajoute la valeur DefaultIdleState à la clé matérielle de l’appareil et la définit à 1. Par exemple:

    HKR,,"DefaultIdleState",0x00010001,1
    

Pour définir une valeur de délai d’inactivité

Par défaut, WinUSB suspend l’appareil après 5 secondes si aucun transfert n’est en attente ou si les seuls transferts en attente sont des transferts IN sur un point de terminaison d’interruption ou en bloc. Un pilote UMDF peut modifier cette valeur de délai d’inactivité lors de l’installation dans l’INF ou au moment de l’exécution.

  • Pour définir un délai d’inactivité lors de l’installation, l'INF inclut une directive AddReg qui inscrit la valeur DefaultIdleTimeout dans la clé matérielle de l'appareil, puis définit cette valeur sur l'intervalle de temps d'attente, en millisecondes. L’exemple suivant définit le délai d’expiration sur 7 secondes :

    HKR,,"DefaultIdleTimeout",0x00010001,7000
    
  • Pour définir un délai d’inactivité au moment de l’exécution, le pilote appelle IWDFUsbTargetDevice::SetPowerPolicy avec PolicyType défini sur SUSPEND_DELAY et Value sur le délai d’inactivité, en millisecondes. Dans l’exemple suivant à partir du fichier Device.cpp, l’exemple Fx2_Driver définit le délai d’expiration sur 10 secondes :

    HRESULT hr;
    ULONG value;
    value = 10 * 1000;
    hr = m_pIUsbTargetDevice->SetPowerPolicy( SUSPEND_DELAY,
                                              sizeof(ULONG),
                                             (PVOID) &value );
    

Pour fournir un contrôle par l'utilisateur de la suspension sélective USB

Les pilotes USB UMDF qui utilisent la prise en charge de la suspension sélective WinUSB peuvent éventuellement permettre à l’utilisateur d’activer ou de désactiver la suspension sélective. Pour ce faire, incluez une directive AddReg dans l’inf qui ajoute la valeur UserSetDeviceIdleEnabled à la clé matérielle de l’appareil et définit la valeur sur 1. Voici la chaîne à utiliser pour la directive AddReg :

HKR,,"UserSetDeviceIdleEnabled",0x00010001,1

Si UserSetDeviceIdleEnabled est défini, la boîte de dialogue Propriétés de l’appareil inclut un onglet Gestion de l’alimentation qui permet à l’utilisateur d’activer ou de désactiver la suspension sélective USB.

Sortie de veille système dans un pilote UMDF

Dans un pilote UMDF, la prise en charge du réveil système est indépendante de la prise en charge de la suspension sélective. Un pilote USB UMDF peut prendre en charge à la fois le réveil système et la suspension sélective, ni le réveil système ni la suspension sélective, ou soit le réveil système soit la suspension sélective. Un appareil prenant en charge le réveil système peut réveiller le système à partir d’un état de veille (S1, S2 ou S3).

Un pilote PPO USB UMDF peut prendre en charge le réveil système en fournissant des informations de mise en éveil pour l’objet de pilote du framework. Lorsqu’un événement externe déclenche le réveil du système, l’infrastructure retourne l’appareil à l’état de travail.

Un pilote USB non-PPO peut utiliser le support de réveil système implémenté par le pilote WinUSB.sys.

Pour prendre en charge le réveil système dans un pilote USB UMDF en tant que PPO**

Appelez la méthode IWDFDevice2 ::AssignSxWakeSettings sur l’objet d’appareil du framework avec les paramètres suivants :

  • DxState à l'état d'alimentation vers lequel l’appareil passe lorsque le système entre dans un état Sx réveillable. Pour les périphériques USB, spécifiez PowerDeviceMaximum pour utiliser la valeur spécifiée par le pilote de bus.
  • UserControlOfWakeSettings vers WakeAllowUserControl si votre pilote permet aux utilisateurs de gérer les paramètres de mise en éveil, sinon à WakeDoNotAllowUserControl.
  • Activé pour WdfUseDefault pour activer le réveil par défaut, mais pour autoriser le paramètre de l’utilisateur à remplacer la valeur par défaut.

L’exemple suivant montre comment le pilote IdleWake_PPO appelle cette méthode dans sa méthode CMyDevice ::SetPowerManagement interne :

hr = m_FxDevice->AssignSxWakeSettings( PowerDeviceMaximum,
                                       WakeAllowUserControl,
                                       WdfUseDefault);

Pour activer la mise en éveil du système via WinUSB dans un pilote non PPO**

Pour activer la mise en éveil du système via WinUSB, l’INF du pilote ajoute la valeur de Registre SystemWakeEnabled à la clé matérielle de l’appareil et la définit sur 1. L’échantillon IdleWake_Non-PPO active le réveil du système comme suit :

[OsrUsb_Device_AddReg]
...
HKR,,"SystemWakeEnabled",0x00010001,1

En définissant cette valeur, le pilote active le réveil système et permet à l’utilisateur de contrôler la capacité de l’appareil à réveiller le système. Dans Device Manager, la page de propriétés des paramètres de gestion de l’alimentation de l’appareil inclut une case à cocher avec laquelle l’utilisateur peut activer ou désactiver le réveil système.