Compartir a través de


Suspensión selectiva en controladores de función KMDF USB

En este artículo se describe cómo los controladores de función KMDF admiten la suspensión selectiva USB.

Si el controlador USB requiere características o recursos que no están disponibles en modo de usuario, debe proporcionar un controlador de función KMDF. Los controladores KMDF implementan la suspensión selectiva estableciendo valores relevantes en una estructura de inicialización de KMDF y, a continuación, proporcionando las funciones de devolución de llamada adecuadas. KMDF controla los detalles de la comunicación con controladores inferiores para suspender y reanudar el dispositivo.

Directrices para la suspensión selectiva en controladores KMDF

Los controladores KMDF que admiten la suspensión selectiva deben seguir estas directrices:

  • Un controlador de función KMDF debe ser el PPO para su pila de dispositivos. De forma predeterminada, los controladores de función KMDF son el PPO.
  • Un controlador de funciones de KMDF que admita la suspensión selectiva puede usar colas administradas por energía o colas que no estén administradas por energía. De forma predeterminada, los objetos de cola para los PPO se administran con energía.

Propiedad de la directiva de alimentación y controladores USB de KMDF

De forma predeterminada, el controlador de función KMDF para un dispositivo USB es el PPO para la pila de dispositivos. KMDF administra la suspensión y reanudación selectiva en nombre de este controlador.

Configuración de cola de E/S en controladores kmdf

Un controlador de funciones de KMDF que admita la suspensión selectiva puede usar colas administradas por energía o colas que no estén administradas por energía. Normalmente, un controlador configura una cola que no se administra para recibir solicitudes de control de E/S de dispositivos entrantes y configura una o varias colas administradas por energía para recibir solicitudes de lectura, escritura y otras solicitudes dependientes de energía. Cuando una solicitud llega a una cola administrada por energía, KMDF garantiza que el dispositivo está en D0 antes de presentar la solicitud al controlador.

Si está escribiendo un controlador de filtro KMDF que se superpone a la PPO en la pila de dispositivos, no debe usar colas administradas por energía. La razón es la misma que para los controladores UMDF. El marco de trabajo no presenta solicitudes de colas administradas por energía mientras se suspende el dispositivo, por lo que el uso de estas colas podría detenerse en la pila de dispositivos.

Mecanismo de suspensión selectiva para controladores de funciones kmdf

KMDF controla la mayor parte del trabajo necesario para admitir la suspensión selectiva usb. Realiza un seguimiento de la actividad de E/S, administra el temporizador de inactividad y envía las solicitudes de control de E/S del dispositivo que hacen que el controlador primario (Usbhub.sys o Usbccgp.sys) suspenda y reanude el dispositivo.

Si un controlador de funciones de KMDF admite la suspensión selectiva, KMDF realiza un seguimiento de la actividad de E/S en todas las colas administradas por energía que posee cada objeto de dispositivo. El marco inicia un temporizador de inactividad cada vez que el recuento de E/S alcanza cero. El valor de tiempo de espera predeterminado es de 5 segundos.

Si una solicitud de E/S llega a una cola administrada por energía que pertenece al objeto de dispositivo antes de que expire el período de tiempo de espera de inactividad, el marco cancela el temporizador de inactividad y no suspende el dispositivo.

Cuando expira el temporizador de inactividad, KMDF emite las solicitudes necesarias para colocar el dispositivo USB en el estado suspendido. Si un controlador de función usa un lector continuo en un punto de conexión USB, el sondeo repetido del lector no cuenta como actividad para el temporizador de inactividad de KMDF. Sin embargo, en la función de devolución de llamada EvtDeviceD0Exit , el controlador USB debe detener manualmente el lector continuo y cualquier otro destino de E/S alimentado por colas que no estén administrados para asegurarse de que el controlador no envía solicitudes de E/S mientras el dispositivo no está en estado de funcionamiento. Para detener los destinos, el controlador llama a WdfIoTargetStop y especifica WdfIoTargetWaitForSentIoToComplete como la acción de destino. En respuesta, el marco detiene el destino de E/S solo después de que se hayan completado todas las solicitudes de E/S que se encuentran en la cola de E/S del destino y se hayan ejecutado las devoluciones de llamada de finalización de E/S asociadas.

De forma predeterminada, KMDF realiza la transición del dispositivo fuera de D0 y al estado de alimentación del dispositivo que el controlador especificó en la configuración inactiva. Como parte de la transición, KMDF llama a las funciones de devolución de llamada de alimentación del controlador de la misma manera que lo haría para cualquier otra secuencia de apagado.

Una vez suspendido el dispositivo, el marco reanuda automáticamente el dispositivo cuando se produce cualquiera de los siguientes eventos:

Para reanudar el dispositivo, KMDF envía una solicitud de encendido hacia abajo en la pila de dispositivos y, a continuación, invoca las funciones de devolución de llamada del controlador de la misma manera que lo haría para cualquier otra secuencia de encendido.

Para obtener información detallada sobre las devoluciones de llamada implicadas en las secuencias de encendido y encendido, consulte las notas del producto Plug and Play y Administración de energía en controladores WDF.

Compatibilidad con la suspensión selectiva usb en un controlador de función KMDF

Para implementar la suspensión selectiva usb en un controlador de función KMDF:

  • Inicialice la configuración de la directiva de energía relacionada con la inactividad, incluido el tiempo de espera de inactividad.
  • Opcionalmente, incluya lógica para evitar temporalmente la suspensión o reanudar la operación cuando el controlador determina que el dispositivo no debe suspenderse debido a un identificador abierto u otro motivo que no esté relacionado con las colas de E/S del dispositivo.
  • En un controlador USB para un dispositivo de interfaz humana (HID), indique en el INF que admite la suspensión selectiva.

Inicialización de la configuración de la directiva de energía en un controlador de función KMDF

Para configurar la compatibilidad con la suspensión selectiva usb, un controlador KMDF usa la estructura WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS . El controlador debe inicializar primero la estructura y, a continuación, puede establecer campos que proporcionen detalles sobre las funcionalidades del controlador y su dispositivo. Normalmente, el controlador rellena esta estructura en su función EvtDriverDeviceAdd o EvtDevicePrepareHardware .

Para inicializar la estructura de WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS

Una vez que el controlador crea el objeto de dispositivo, el controlador usa la función WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT para inicializar la estructura. Esta función toma dos argumentos:

  • Puntero a la estructura WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS que se va a inicializar.
  • Valor de enumeración que indica la compatibilidad con la suspensión selectiva. El controlador debe especificar IdleUsbSelectiveSuspend.

Si el controlador especifica IdleUsbSelectiveSuspend, la función inicializa los miembros de la estructura de la siguiente manera:

  • IdleTimeout se establece en IdleTimeoutDefaultValue (actualmente 5000 milisegundos o 5 segundos).
  • UserControlOfIdleSettings se establece en IdleAllowUserControl .
  • Enabled se establece en WdfUseDefault, lo que indica que la suspensión selectiva está habilitada, pero un usuario puede deshabilitarla si el miembro UserControlOfIdleSettings lo permite.
  • DxState se establece en PowerDeviceMaximum, que usa las funcionalidades de energía notificadas para el dispositivo para determinar el estado al que se va a realizar la transición del dispositivo inactivo.

Para configurar la suspensión selectiva de USB

Una vez que el controlador inicializa la estructura de WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS , el controlador puede establecer otros campos en la estructura y, a continuación, llamar a WdfDeviceAssignS0IdleSettings para pasar esta configuración al marco. Los siguientes campos se aplican a los controladores de función USB:

  • IdleTimeout: intervalo, en milisegundos, que debe transcurrir sin recibir una solicitud de E/S antes de que el marco considere que el dispositivo está inactivo. El controlador puede especificar un valor ULONG o puede aceptar el valor predeterminado.

  • UserControlOfIdleSettings: indica si el usuario puede modificar la configuración inactiva del dispositivo. Los valores posibles son IdleDoNotAllowUserControl y IdleAllowUserControl.

  • DxState: estado de alimentación del dispositivo al que el marco suspende el dispositivo. Los valores posibles son PowerDeviceD1, PowerDeviceD2 y PowerDeviceD3.

    Los controladores USB no deben cambiar la configuración inicial de este valor. La función WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT establece este valor en PowerDeviceMaximum, lo que garantiza que el marco elija el valor correcto en función de las funcionalidades del dispositivo.

El siguiente fragmento de código procede del archivo Device.c del controlador de ejemplo 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;
}

En el ejemplo, el controlador llama a WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT, especificando IdleUsbSelectiveSuspend. El controlador establece IdleTimeout en 10 000 milisegundos (10 segundos) y acepta los valores predeterminados del marco para DxState y UserControlOfIdleSettings. Como resultado, el marco pasa el dispositivo al estado D3 cuando está inactivo y crea una página de propiedades de Administrador de dispositivos que permite a los usuarios con privilegios de administrador habilitar o deshabilitar la compatibilidad inactiva del dispositivo. A continuación, el controlador llama a WdfDeviceAssignS0IdleSettings para habilitar la compatibilidad inactiva y registrar esta configuración en el marco.

Un controlador puede llamar a WdfDeviceAssignS0IdleSettings en cualquier momento después de crear el objeto de dispositivo. Aunque la mayoría de los controladores llaman inicialmente a este método desde la devolución de llamada EvtDriverDeviceAdd , es posible que esto no siempre sea posible o incluso deseable. Si un controlador admite varios dispositivos o versiones de dispositivo, es posible que el controlador no conozca todas las funcionalidades del dispositivo hasta que consulte el hardware. Estos controladores pueden posponer la llamada a WdfDeviceAssignS0IdleSettings hasta la devolución de llamada EvtDevicePrepareHardware .

En cualquier momento después de su llamada inicial a WdfDeviceAssignS0IdleSettings, el controlador puede cambiar el valor de tiempo de espera de inactividad y el estado del dispositivo en el que el dispositivo está inactivo. Para cambiar una o varias configuraciones, el controlador simplemente inicializa otra estructura de WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS como se ha descrito anteriormente y llama a WdfDeviceAssignS0IdleSettings de nuevo.

Impedir la suspensión del dispositivo USB

A veces, un dispositivo USB no debe apagarse incluso si no hay solicitudes de E/S presentes dentro del período de tiempo de espera, normalmente cuando un controlador está abierto al dispositivo o el dispositivo se está cargando. Un controlador USB puede impedir que el marco suspenda un dispositivo inactivo en tales situaciones llamando a WdfDeviceStopIdle y llamando a WdfDeviceResumeIdle cuando se vuelva a aceptar que el dispositivo se suspenda.

WdfDeviceStopIdle detiene el temporizador de inactividad. Si el período IdleTimeout no ha expirado y el dispositivo aún no se ha suspendido, el marco cancela el temporizador de inactividad y no suspende el dispositivo. Si el dispositivo ya se ha suspendido, el marco devuelve el dispositivo al estado de trabajo. WdfDeviceStopIdleno impide que el marco suspenda el dispositivo cuando el sistema cambia a un estado de suspensión Sx. Su único efecto es evitar la suspensión del dispositivo mientras el sistema está en estado de funcionamiento S0. WdfDeviceResumeIdle reinicia el temporizador de inactividad. Estos dos métodos administran un recuento de referencias en el dispositivo, por lo que si el controlador llama a WdfDeviceStopIdle varias veces, el marco no suspende el dispositivo hasta que el controlador haya llamado a WdfDeviceResumeIdle el mismo número de veces. Un controlador no debe llamar a WdfDeviceResumeIdlesin llamar primero a WdfDeviceStopIdle.

Incluir una clave del Registro (solo controladores HID)

Los controladores de filtro superior de KMDF para dispositivos USB HID deben indicar en el INF que admiten la suspensión selectiva para que el controlador de puerto de HIDClass.sys proporcionado por Microsoft pueda habilitar la suspensión selectiva para la pila HID. El INF debe incluir una directiva AddReg que agregue la clave SelectiveSuspendEnabled y establezca su valor en 1, como se muestra en la cadena siguiente:

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

Para obtener un ejemplo, vea Hidusbfx2.inx en el WDK en %WinDDK%\BuildNumber\Src\Hid\ Hidusbfx2\sys.

Compatibilidad con reactivación remota para controladores KMDF

Al igual que con la suspensión selectiva, KMDF incorpora compatibilidad para reactivación, de modo que un dispositivo USB pueda desencadenar una señal de reactivación mientras el dispositivo está inactivo y el sistema está en estado de trabajo (S0) o en estado de suspensión (S1–S4). En términos de KMDF, estas dos características se denominan "reactivar desde S0" y "reactivar desde Sx", respectivamente.

En el caso de los dispositivos USB, la reactivación simplemente indica que el propio dispositivo puede iniciar la transición desde un estado de baja potencia al estado de trabajo. Por lo tanto, en términos USB, la reactivación de S0 y la reactivación de Sx son las mismas y se denominan "reactivación remota".

Los controladores de función USB de KMDF no requieren ningún código para admitir la reactivación desde S0 porque KMDF proporciona esta funcionalidad como parte del mecanismo de suspensión selectiva. Sin embargo, para admitir la reactivación remota cuando el sistema está en Sx, un controlador de función debe:

Normalmente, los controladores KMDF configuran la compatibilidad de reactivación al mismo tiempo que configuran la compatibilidad con la suspensión selectiva usb en la función EvtDriverDeviceAdd o EvtDevicePrepareHardware .

Comprobación de las funcionalidades del dispositivo

Antes de que un controlador de función USB KMDF inicialice su configuración de directiva de energía para inactivo y reactivación, debe comprobar que el dispositivo admite la reactivación remota. Para obtener información sobre las características de hardware del dispositivo, el controlador inicializa una estructura de WDF_USB_DEVICE_INFORMATION y llama a WdfUsbTargetDeviceRetrieveInformation, normalmente en su devolución de llamada EvtDriverDeviceAdd o EvtDevicePrepareHardware .

En la llamada a WdfUsbTargetDeviceRetrieveInformation, el controlador pasa un identificador al objeto de dispositivo y un puntero a la estructura de WDF_USB_DEVICE_INFORMATION inicializada. Tras la devolución correcta de la función, el campo Rasgos de la estructura contiene marcas que indican si el dispositivo está auto-alimentado, puede funcionar a alta velocidad y admite la reactivación remota.

En el ejemplo siguiente del ejemplo de KMDF de Osrusbfx2 se muestra cómo llamar a este método para determinar si un dispositivo admite la reactivación remota. Una vez ejecutadas estas líneas de código, la variable waitWakeEnable contiene TRUE si el dispositivo admite reactivación remota y FALSE si no:

    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;

Habilitación de la reactivación remota

En la terminología de USB, se habilita un dispositivo USB para la reactivación remota cuando se establece su característica de DEVICE_REMOTE_WAKEUP. Según la especificación USB, el software host debe establecer la característica de reactivación remota en un dispositivo "solo antes" para poner el dispositivo en suspensión. El controlador de función KMDF solo es necesario para inicializar la configuración de reactivación. KMDF y los controladores de bus USB proporcionados por Microsoft emiten las solicitudes de E/S y controlan la manipulación de hardware necesaria para habilitar la reactivación remota.

Para inicializar la configuración de reactivación

  1. Llame a WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT para inicializar una estructura de WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS . Esta función establece el miembro Enabled de la estructura en WdfUseDefault, establece el miembro DxState en PowerDeviceMaximum y establece el miembro UserControlOfWakeSettings en WakeAllowUserControl.
  2. Llame a WdfDeviceAssignSxWakeSettings con la estructura inicializada. Como resultado, el dispositivo está habilitado para reactivarse desde el estado D3 y el usuario puede habilitar o deshabilitar la señal de reactivación de la página de propiedades del dispositivo en Administrador de dispositivos.

El siguiente fragmento de código del ejemplo Osrusbfx2 muestra cómo inicializar la configuración de reactivación en sus valores predeterminados:

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;
}

En el caso de los dispositivos USB que admiten la suspensión selectiva, el controlador de bus subyacente prepara el hardware del dispositivo para reactivarse. Por lo tanto, los controladores de funciones USB rara vez requieren una devolución de llamada EvtDeviceArmWakeFromS0 . El marco envía una solicitud de suspensión selectiva al controlador del bus USB cuando expira el tiempo de espera de inactividad.

Por la misma razón, los controladores de funciones USB rara vez requieren una devolución de llamada EvtDeviceWakeFromS0Triggered o EvtDeviceWakeFromSxTriggered . En su lugar, el marco y el controlador de bus subyacente controlan todos los requisitos para devolver el dispositivo al estado de trabajo.