Passer des irps d’alimentation

Les irps d’alimentation doivent être passés jusqu’à la pile des appareils jusqu’à l’AOP pour garantir que les transitions d’alimentation sont gérées correctement. Les pilotes gèrent une IRP qui réduit la puissance de l’appareil à mesure que l’IRP se déplace vers le bas de la pile des appareils. Les pilotes gèrent une IRP qui applique l’alimentation des appareils dans les routines IoCompletion à mesure que l’IRP remonte la pile des appareils.

La figure suivante montre les étapes que les pilotes doivent suivre pour passer une IRP d’alimentation dans une pile de périphériques dans Windows 7 et Windows Vista.

diagramme illustrant la transmission d’un irp d’alimentation dans windows vista.

Comme le montre la figure précédente, dans Windows 7 et Windows Vista, un pilote doit effectuer les opérations suivantes :

  1. Appelez IoCopyCurrentIrpStackLocationToNext si vous définissez une routine IoCompletion , ou IoSkipCurrentIrpStackLocation si vous ne définissez pas une routine IoCompletion .

    Ces deux routines définissent l’emplacement de la pile IRP pour le pilote inférieur suivant. La copie de l’emplacement actuel de la pile garantit que le pointeur de pile IRP est défini sur l’emplacement approprié lors de l’exécution de la routine IoCompletion .

    Si un pilote mal écrit fait l’erreur d’appeler IoSkipCurrentIrpStackLocation , puis de définir une routine d’achèvement, ce pilote peut remplacer une routine d’achèvement définie par le pilote en dessous.

  2. Appelez IoSetCompletionRoutine pour définir une routine IoCompletion , si une routine complète est requise.

  3. Appelez IoCallDriver pour passer l’IRP au pilote inférieur suivant dans la pile.

La figure suivante montre les étapes que les pilotes doivent suivre pour passer un IRP d’alimentation vers le bas d’une pile de périphériques dans Windows Server 2003, Windows XP et Windows 2000.

transmission d’un irp d’alimentation (windows server 2003, windows xp et windows 2000).

Comme le montre la figure précédente, un pilote doit effectuer les opérations suivantes :

  1. Selon le type de pilote, appelez éventuellement PoStartNextPowerIrp. Pour plus d’informations, consultez Calling PoStartNextPowerIrp.

  2. Appelez IoCopyCurrentIrpStackLocationToNext si vous définissez une routine IoCompletion , ou IoSkipCurrentIrpStackLocation si vous ne définissez pas une routine IoCompletion .

    Ces deux routines définissent l’emplacement de la pile IRP pour le pilote inférieur suivant. La copie de l’emplacement actuel de la pile garantit que le pointeur de pile IRP est défini sur l’emplacement approprié lors de l’exécution de la routine IoCompletion .

  3. Appelez IoSetCompletionRoutine pour définir une routine IoCompletion . Dans la routine IoCompletion , la plupart des pilotes appellent PoStartNextPowerIrp pour indiquer qu’il est prêt à gérer la prochaine IRP d’alimentation.

  4. Appelez PoCallDriver pour passer l’IRP au pilote inférieur suivant dans la pile.

    Les pilotes doivent utiliser PoCallDriver, plutôt que IoCallDriver (comme pour les autres IRP) pour s’assurer que le système synchronise correctement les IRPs d’alimentation. Pour plus d’informations, consultez Appel d’IoCallDriver et Appel de PoCallDriver.

N’oubliez pas que les routines IoCompletion peuvent être appelées à l’adresse IRQL = DISPATCH_LEVEL. Par conséquent, si un pilote nécessite un traitement supplémentaire à IRQL = PASSIVE_LEVEL une fois que les pilotes de niveau inférieur ont terminé l’IRP, la routine d’achèvement du pilote doit mettre en file d’attente un élément de travail, puis retourner STATUS_MORE_PROCESSING_REQUIRED. Le thread de travail doit terminer l’IRP.

Dans Windows 98/Me, les pilotes doivent effectuer les irps d’alimentation à l’adresse IRQL = PASSIVE_LEVEL.

Ne pas modifier les codes de fonction dans un IRP d’alimentation

En plus des règles habituelles qui régissent le traitement des IRP, IRP_MJ_POWER IRP ont l’exigence spéciale suivante : un pilote qui reçoit un IRP d’alimentation ne doit pas modifier les codes de fonction principaux et secondaires dans les emplacements de pile d’E/S dans l’IRP qui ont été définis par le gestionnaire d’alimentation ou par des pilotes de niveau supérieur. Le gestionnaire d’alimentation s’appuie sur ces codes de fonction qui restent inchangés jusqu’à ce que l’IRP soit terminé. Les violations de cette règle peuvent entraîner des problèmes difficiles à déboguer. Par exemple, le système d’exploitation peut cesser de répondre ou « se bloquer ».

Ne pas bloquer lors de la gestion d’un IRP d’alimentation

Les pilotes ne doivent pas provoquer de longs retards lors de la gestion des irps d’alimentation.

Lors de la transmission d’un IRP d’alimentation, un pilote doit revenir de sa routine DispatchPower dès que possible après avoir appelé IoCallDriver (dans Windows 7 et Windows Vista) ou PoCallDriver (dans Windows Server 2003, Windows XP et Windows 2000). Un pilote ne doit pas attendre un événement du noyau ou retarder avant de revenir. Si un pilote ne peut pas gérer une IRP d’alimentation dans un court laps de temps, il doit retourner STATUS_PENDING et mettre en file d’attente tous les IRP entrants jusqu’à ce que l’IRP d’alimentation se termine. (Notez que ce comportement est différent de celui des runtimes d’intégration PnP et des routines DispatchPnP , qui sont autorisées à être bloquées.)

Si le pilote doit attendre une action d’alimentation d’un autre pilote plus loin dans la pile de périphériques, il doit retourner STATUS_PENDING de sa routine DispatchPower et définir une routine IoCompletion pour l’IRP d’alimentation. Le pilote peut effectuer toutes les tâches nécessaires dans la routine IoCompletion , puis appeler PoStartNextPowerIrp (Windows Server 2003, Windows XP et Windows 2000 uniquement) et IoCompleteRequest.

Par exemple, le propriétaire de la stratégie d’alimentation d’un appareil envoie généralement un IRP d’alimentation de l’appareil tout en conservant un IRP d’alimentation du système afin de définir l’état d’alimentation de l’appareil approprié pour l’état d’alimentation du système demandé.

Dans ce cas, le propriétaire de la stratégie d’alimentation doit définir une routine IoCompletion dans l’IRP d’alimentation du système, passer l’IRP d’alimentation système au pilote inférieur suivant et retourner STATUS_PENDING de sa routine DispatchPower .

Dans la routine IoCompletion , il appelle PoRequestPowerIrp pour envoyer l’IRP d’alimentation de l’appareil, en passant un pointeur vers une routine de rappel dans la requête. La routine IoCompletion doit retourner STATUS_MORE_PROCESSING_REQUIRED.

Enfin, le pilote transmet l’IRP système de la routine de rappel. Le pilote ne doit pas attendre un événement du noyau dans sa routine DispatchPower et son signal avec la routine IoCompletion pour l’IRP qu’il gère actuellement ; un interblocage système peut se produire. Pour plus d’informations, consultez Gestion d’un Set-Power IRP système dans un propriétaire de stratégie d’alimentation d’appareil.

Dans une situation similaire, lorsque le système est en veille, un propriétaire de la stratégie d’alimentation peut avoir besoin d’effectuer des E/S en attente avant d’envoyer l’IRP de l’appareil pour mettre son appareil hors tension. Au lieu de signaler un événement lorsque l’E/S se termine et attend dans sa routine DispatchPower , le pilote doit mettre en file d’attente un élément de travail et retourner STATUS_PENDING de la routine DispatchPower . Dans le thread de travail, il attend que les E/S se terminent, puis envoie l’IRP d’alimentation de l’appareil. Pour plus d’informations, consultez IoAllocateWorkItem.