Pasar IRP de Power
Los IRP de energía deben pasarse hasta la pila del dispositivo al PDO para asegurarse de que las transiciones de energía se administran de forma limpia. Los controladores controlan un IRP que reduce la energía del dispositivo a medida que el IRP viaja por la pila del dispositivo. Los controladores controlan un IRP que aplica la energía del dispositivo en las rutinas de IoCompletion a medida que irP realiza una copia de seguridad de la pila del dispositivo.
En la ilustración siguiente se muestran los pasos que los controladores deben llevar a cabo para pasar un IRP de energía a una pila de dispositivos en Windows 7 y Windows Vista.
Como se muestra en la ilustración anterior, en Windows 7 y Windows Vista, un controlador debe hacer lo siguiente:
Llame a IoCopyCurrentIrpStackLocationToNext si establece una rutina de IoCompletion o IoSkipCurrentIrpStackLocation si no establece una rutina de IoCompletion .
Estas dos rutinas establecen la ubicación de la pila IRP para el controlador inferior siguiente. Al copiar la ubicación de la pila actual, se garantiza que el puntero de pila irP esté establecido en la ubicación correcta cuando se ejecute la rutina de IoCompletion .
Si un controlador mal escrito comete el error de llamar a IoSkipCurrentIrpStackLocation y, a continuación, establecer una rutina de finalización, este controlador podría sobrescribir una rutina de finalización establecida por el controlador debajo.
Llame a IoSetCompletionRoutine para establecer una rutina de IoCompletion , si se requiere una rutina completa.
Llame a IoCallDriver para pasar el IRP al controlador inferior siguiente de la pila.
En la ilustración siguiente se muestran los pasos que deben seguir los controladores para pasar un IRP de energía a una pila de dispositivos en Windows Server 2003, Windows XP y Windows 2000.
Como se muestra en la ilustración anterior, un controlador debe hacer lo siguiente:
Dependiendo del tipo de controlador, posiblemente llame a PoStartNextPowerIrp. Para obtener más información, vea Llamar a PoStartNextPowerIrp.
Llame a IoCopyCurrentIrpStackLocationToNext si establece una rutina de IoCompletion o IoSkipCurrentIrpStackLocation si no establece una rutina de IoCompletion .
Estas dos rutinas establecen la ubicación de la pila IRP para el controlador inferior siguiente. Al copiar la ubicación de la pila actual, se garantiza que el puntero de pila irP esté establecido en la ubicación correcta cuando se ejecute la rutina de IoCompletion .
Llame a IoSetCompletionRoutine para establecer una rutina de IoCompletion . En la rutina IoCompletion , la mayoría de los controladores llaman a PoStartNextPowerIrp para indicar que está listo para controlar el siguiente IRP de energía.
Llame a PoCallDriver para pasar el IRP al controlador inferior siguiente de la pila.
Los controladores deben usar PoCallDriver, en lugar de IoCallDriver (como para otros IRP) para asegurarse de que el sistema sincroniza los IRP de energía correctamente. Para obtener más información, vea Llamar a IoCallDriver frente a llamar a PoCallDriver.
Recuerde que las rutinas de IoCompletion se pueden llamar en IRQL = DISPATCH_LEVEL. Por lo tanto, si un controlador requiere procesamiento adicional en IRQL = PASSIVE_LEVEL después de que los controladores de nivel inferior hayan terminado con el IRP, la rutina de finalización del controlador debe poner en cola un elemento de trabajo y, a continuación, devolver STATUS_MORE_PROCESSING_REQUIRED. El subproceso de trabajo debe completar el IRP.
En Windows 98/Me, los controladores deben completar irP de energía en IRQL = PASSIVE_LEVEL.
No cambiar los códigos de función en un IRP de Power
Además de las reglas habituales que rigen el procesamiento de IRP, IRP_MJ_POWER IRP tienen el siguiente requisito especial: Un controlador que recibe un IRP de energía no debe cambiar los códigos de función principales y menores en las ubicaciones de pila de E/S en el IRP que el administrador de energía o los controladores de nivel superior han establecido. El administrador de energía se basa en estos códigos de función que permanecen sin cambios hasta que se completa el IRP. Las infracciones de esta regla pueden causar problemas difíciles de depurar. Por ejemplo, el sistema operativo podría dejar de responder o "colgar".
No bloquear al controlar un IRP de energía
Los controladores no deben causar retrasos prolongados al controlar los IRP de energía.
Al pasar un IRP de energía, un controlador debe volver de su rutina DispatchPower lo antes posible después de llamar a IoCallDriver (en Windows 7 y Windows Vista) o PoCallDriver (en Windows Server 2003, Windows XP y Windows 2000). Un controlador no debe esperar a un evento de kernel ni retrasarlo antes de devolverlo. Si un controlador no puede controlar un IRP de energía en un breve tiempo, debe devolver STATUS_PENDING y poner en cola todos los IRP entrantes hasta que finalice el IRP de alimentación. (Tenga en cuenta que este comportamiento es diferente del de las rutinas IRP de PnP y DispatchPnP , que pueden bloquearse).
Si el controlador debe esperar una acción de alimentación por otro controlador más abajo de la pila del dispositivo, debe devolver STATUS_PENDING de su rutina DispatchPower y establecer una rutina de IoCompletion para el IRP de energía. El controlador puede realizar las tareas que requiera en la rutina ioCompletion y, a continuación, llamar a PoStartNextPowerIrp (Solo Windows Server 2003, Windows XP y Windows 2000) e IoCompleteRequest.
Por ejemplo, el propietario de la directiva de energía para un dispositivo normalmente envía un IRP de alimentación del dispositivo mientras mantiene un IRP de alimentación del sistema para establecer el estado de alimentación del dispositivo adecuado para el estado de alimentación del sistema solicitado.
En esta situación, el propietario de la directiva de energía debe establecer una rutina de IoCompletion en el IRP de energía del sistema, pasar el IRP de energía del sistema al controlador inferior siguiente y devolver STATUS_PENDING de su rutina DispatchPower .
En la rutina IoCompletion , llama a PoRequestPowerIrp para enviar el IRP de energía del dispositivo, pasando un puntero a una rutina de devolución de llamada en la solicitud. La rutina IoCompletion debe devolver STATUS_MORE_PROCESSING_REQUIRED.
Por último, el controlador pasa el IRP del sistema desde la rutina de devolución de llamada. El controlador no debe esperar a un evento de kernel en su rutina DispatchPower y indicar con la rutina ioCompletion para el IRP que está controlando actualmente; Se puede producir un interbloqueo del sistema. Para obtener más información, consulte Control de un IRP del sistema Set-Power en un propietario de la directiva de energía del dispositivo.
En una situación similar, cuando el sistema va a dormir, es posible que un propietario de la directiva de energía necesite completar alguna E/S pendiente antes de enviar el IRP del dispositivo para apagar su dispositivo. En lugar de señalar un evento cuando la E/S se completa y espera en su rutina DispatchPower , el controlador debe poner en cola un elemento de trabajo y devolver STATUS_PENDING de la rutina DispatchPower . En el subproceso de trabajo, espera a que se complete la E/S y, a continuación, envía el IRP de alimentación del dispositivo. Para más información, consulte IoAllocateWorkItem.