Today's guest blogger is Abhishek Ram. Abhishek owns the PNP and Power Management code for UMDF now, and has been working on getting idle detection and wait-wake support into UMDF for a future release. In the interim he spent some time looking at how to enable selective suspend and system wakeup in the current UMDF Fx2 sample.
If you’re writing as UMDF driver for a USB device, you’ve probably installed the WinUSB driver as a lower filter driver for your device (like the UMDF OSR USB Fx2 driver sample in the WDK) and you’re probably using the WinUSB driver to read from, write to and control the device. In this post, I’ll talk about how you can use the WinUSB driver to enable USB selective suspend and system wake for your device.
Power policy ownership
The WinUSB driver should be the power policy owner in your driver stack. Meaning, it is the WinUSB driver that makes the decisions on what power state the device should be in. Note that WinUSB assumes power policy ownership of the driver stack by default – you don’t need to do anything special to enable this. You do need to make sure that your driver does not try to claim power policy ownership for the device stack. (UMDF drivers can claim power policy ownership by calling IWDFDeviceInitialize::SetPowerPolicyOwnership(). Make sure you’re not doing this in this case).
I/O Queues
You need to make sure that you do not use power-managed queues if you decide that you want to enable USB selective suspend through WinUSB. If you are interested in enabling only system wake and not USB selective suspend, you may use power-managed queues. You can specify whether or not a queue is power-managed during queue creation – it is a parameter to the IWDFDevice::CreateIoQueue() method.
Here’s the reason why you should not use a power-managed queue if you’ve enabled USB selective suspend through WinUSB. By definition, the framework (UMDF) will not deliver to the driver a request that arrives on a power-managed queue, unless the device is in a powered-up state. Now let’s say you’ve enabled USB selective suspend and your device idles out because it has been inactive for a while. Now, if you receive a request on a power-managed queue after the device has idled out, the framework will not deliver the request to your driver because the device is not currently powered up. And since you’re not the power policy owner for the stack, the framework will not be able to power-up the device either, as only the power policy owner of the stack can make decisions about the power state of the device. Hence the request will remain stuck in your power-managed queue.
On the other hand, if you were to use a non-power-managed queue, then if a request arrives when the device has idled out the framework would still deliver the request to your driver. Your driver would then forward it to the WinUSB driver (assuming it cannot complete it by itself). Upon receiving the request, the WinUSB driver can make the decision on whether the device needs to be powered-up. If it does need to be powered up, WinUSB can take the necessary steps to do so, as it is the power policy owner for the device stack.
Setting values in the device’s hardware key via the INF
In order to enable USB selective suspend and system wake using the WinUSB driver, it is necessary to set some values in the device’s hardware key via the INF. Refer to the topic “INF AddReg directive” on MSDN for details on how to do this.
USB selective suspend
A UMDF driver must do the following in order to enable USB selective suspend through WinUSB –
1. Through its INF file, the driver must set a value named “DeviceIdleEnabled” in the device’s hardware key to 1. This value will tell the WinUSB driver that the device is capable of supporting USB selective suspend.
HKR,,"DeviceIdleEnabled",0x00010001,1
Setting this value is a prerequisite. In the absence of this value, WinUSB will ignore requests to enable device selective suspend. However, the presence of this value alone is not enough to enable selective suspend. You’ll need to follow the next step as well.
2. The driver must instruct WinUSB to enable selective suspend. The driver can do this either programmatically or through its INF file.
a. Programmatic method – The IWDFUsbTargetDevice::SetPowerPolicy() method allows you to tell the WinUSB driver to enable selective suspend by setting the AUTO_SUSPEND policy. You can also configure the idle timeout by setting the SUSPEND_DELAY policy.
b. INF method – The driver must set a value named “DefaultIdleState” in the device’s hardware key to 1. This will tell WinUSB that by default, selective suspend should be enabled. The driver can also specify the default idle timeout by setting a value named “DefaultIdleTimeout” in the device’s hardware key to the desired timeout value in milliseconds.
HKR,,"DefaultIdleState",0x00010001,1
HKR,,"DefaultIdleTimeout",0x00010001,5000
Note that the INF method allows you to specify the defaults at the time of device install and these defaults can be overridden at run-time using the programmatic method.
A UMDF driver can also decide whether or not the user can enable or disable USB selective suspend for the device. If the driver wants to allow the user to enable or disable USB selective suspend, it must set a value named “UserSetDeviceIdleEnabled” in the device’s hardware key to 1.
HKR,,"UserSetDeviceIdleEnabled",0x00010001,1
Doing so will cause a check box to show up in the power management settings property page for the device in the Device Manager UI. The user can check or uncheck the box to enable or disable USB selective suspend.
System wake
System wake refers to the ability to a device to wake a system when the system is in a lower-power state. In order to enable system wake through WinUSB, a UMDF driver must set a registry value named “SystemWakeEnabled” in the device’s hardware key to 1.
HKR,,"SystemWakeEnabled",0x00010001,1
Setting this value also allows the user to control the ability of the device to wake the system from a low-power state. A check box shows up in the power management settings property page for the device in the Device Manager UI and the user can or uncheck the box to enable or disable system wake.
Troubleshooting tip
There are some known hardware and operating system issues due to which some devices are unable to wake from the idle state even if USB selective suspend is enabled for them. If you hit this issue, one thing to try would be to ensure that the USB hub that the device is connected to is enabled for idle. This is not guaranteed to work, but it has proved to be a useful technique to work around some USB device wake problems. Details on how to apply this workaround –
- In the Device Manager UI, choose “View” from the menu and then choose “Devices by connection” from the drop-down list. The Device Manager UI should refresh and display the devices by connection.
- Find your device and locate the parent USB hub device that it is connected to. Right click on the parent USB hub and select “Properties” to view its properties
- Go to the “Power Management” tab and check the box titled “Allow the computer to turn off this device to save power”.