Hello,
I am new to windows driver development and need help regarding power management and selective suspend.
I am writing an UMD2 driver for a custom USB device. My starting point for the driver code was https://github.com/microsoft/Windows-driver-samples/tree/master/usb/umdf2_fx2
My driver exposes a dozen of IOCTL that are processed sequentially through one power managed I/O queue. Most of the IOCLs are translated to one or several synchronous USB control requests. Few IOCTLs however will start some asynchronous operation on the device. In this case, a background thread is started to issue one USB read on the input pipe with an infinite timeout. At any time, the device will send a USB wakeup event and push the data on the IN endpoint. The USB read request will complete and the IOCTL will return the device data.
This works pretty well but I am now trying to enable selective suspend on the driver to limit overall power consumption while waiting for asynchronous operation to complete or when device is doing nothing.
I have made my driver the policy owner and have defined the idle and wake-up power policy as follow:
WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleUsbSelectiveSuspend);
idleSettings.DxState = PowerDeviceD2;
idleSettings.Enabled = WdfTrue;
idleSettings.UserControlOfIdleSettings = IdleAllowUserControl;
idleSettings.IdleTimeout = 10000;
idleSettings.ExcludeD3Cold = WdfTrue;
WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings);
wakeSettings.Enabled = WdfTrue;
wakeSettings.DxState = PowerDeviceD2;
However, I have noticed, while the driver is idling (no IOCTL to process), the framework will call EvtDeviceD0Exit(TargetState=WdfPowerDeviceD2) after idle timeout, but will immediately call EvtDeviceD0Entry(PreviousState=WdfPowerDeviceD2) and will do that every idle timeout seconds (there was only my device on the USB hub).
I am a bit surprised by this behavior and was expecting EvtDeviceD0Entry() to be called only when there is an IOCTL or when the device or bus send a USB wakeup event. **Is it expected ? **
My other question is how to put the USB bus in suspended state while my INPUT request is pending ?
I was thinking about canceling the USB read request after some timeout to let the USB bus be suspended. When the device sends the wakeup signal, the driver would re-issue the USB read to get the data and complete the pending IOCTL. Is it the right approach ?
And my final question is how to catch events in the driver when the system is about to go into suspend or hibernate or when the usb bus power is about to get shutdown ?
I was surprised to see that EvtDeviceD0Exit(TargetState=WdfPowerDeviceD3) is only called when disabling the device from the device manager. It is not called when the system goes into sleep. And I was also surprised to see the system force killing my driver after some time because of too much power drain, which cause the device to stop working upon system wakeup.
Thanks for your help!