Help regarding power management and USB selective suspend with UMDF2

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!

I am a bit surprised by this behavior and was expecting EvtDeviceD0Entry() to be called

I’m surprised by that behavior as well. Your expectations are the same as mine.

Your device isn’t waking itself after going into idle, is it? That’s the most common cause for what you’re seeing.

When the system transitions to hibernate a low power state (S4), and your device is in D0, you don’t get called at D0Exit?

BTW… “idleSettings.Enabled = WdfTrue;” should be "idleSettings.Enabled = WdfUseDefault; " Because you set “idleSettings.UserControlOfIdleSettings = IdleAllowUserControl” – This isn’t your problem, but it’s likely not what you want as written.

These settings all interact, especially for USB, in complex ways. MY personal approach is to specify as few of these parameters as possible. For example, I wouldn’t specifically assign DxState unless you feel like you really need to. Let the Framework work with the rest of the system to figure it out (it’s going to be USB Selective Suspend in any case).

Hope that’s at least SOME help,

Peter

Thanks for your answer.

When settings “idleSettings.IdleCaps = IdleCannotWakeFromS0” I have the “expected” behavior (I don’t renter in D0 immediately), but I don’t know if with this configuration, the underlying USB bus goes into selective suspend.

I guess I will have to look closer to the device to see if it is behaving properly and try to spy what happens on the USB bus.

For transition to S4 you are right, I have a notification. But I don’t have any when going into suspend. That could be alright except, because of modern standby I suppose, the system ends-up killing my driver…

I’m sure somebody at MSFT has a clear, detailed, vision of how Modern Standby is supposed to work these days with each and every class of device… but I (I’m embarrassed to say) sure don’t.

You need a USB bus analyzer (a real one, not a software one) to verify what’s going on.

Can you say more about what “killing your driver” means? Have you dumped your WDF log (!wdfkd.wdflogdump)? That could be enlightening. Also, be sure both WDF verifier, verbose tracing, and Windows Driver Verifier are enables when you test… just in case you can get some hints.

Peter

The service using my driver returns 0x8007050B (ERROR_DRIVER_PROCESS_TERMINATED) when I wake up the PC.

And the system events logs shows the following messages:

  • USB device draining system power when system is idle.
    USB Device: VID: xxxx PID: yyyy REV: wwww
    Removal action failed: SkippedAsRecentIoObservered

  • The device ‘xxxxxx’ (location Port#0001.Hub_#0004) is offline due to a user-mode driver crash. Windows will attempt to restart the device 5 more times. Please contact the device manufacturer for more information about this problem._

  • A problem has occurred with one or more user-mode drivers and the hosting process has been terminated. This may temporarily interrupt your ability to access the devices.

The last trace from my driver is when I enter WdfUsbTargetPipeReadSynchronously() to wait for the device data.

One of the awkwardnesses is that the USB power model does not align perfectly with the Windows power model. USB Selective Suspend means the system is allows to kill power to the entire hub containing your device. If your device has any state information that doesn’t survive a power cut, then you have to be able to bring it back to life. That takes some thought.

You’ve read this? It’s about UMDF 1, but some of the concepts are still useful.

https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/selective-suspend-in-umdf-drivers

@OP has this custom USB device been validated, passed USB compliance tests? If not, there’s no reason to have any expectations and be surprised.
(“works in Linux” does not count as validation).
– pa

Let me once again recommend you looking at the output from !wdflogdump, with verbose tracing enabled. This can provide additional info for ALL the issues you are seeing.

The last trace from my driver is when I enter WdfUsbTargetPipeReadSynchronously() to wait for the device data

Hmmmm… Is this a long-running read, the WdfUsbTargetPipeReadSynchronously. The “usual” way we “wait for device data” (when you always want to get the data that may be arriving on a given IN endpoint) is with a Continuous Reader.

Peter

@Tim_Roberts

One of the awkwardnesses is that the USB power model does not align perfectly with the Windows power model. USB Selective Suspend means the system is allows to kill power to the entire hub containing your device. If your device has any state information that doesn’t survive a power cut, then you have to be able to bring it back to life. That takes some thought.

Maybe I missed something but I thought you could limit selective suspend to only stop polling devices to limit power consumption. If device is bus-powered and has wake-up capability, it would imply you cannot completely cut the device power. This was my assumption anyway, but my short experience with windows and usb is that the behavior often depends on the platform and rarely matches my understanding…

Indeed, my device has state information that are shared with a service on the PC. We have no control on the service and the service expects the device to be always running. But if I have a notification about when the power will be cut and if the device can re-enumerate cleanly afterwards, I could live with that for now.

You’ve read this? It’s about UMDF 1, but some of the concepts are still useful.

I did and tried to match the settings with UMDF 2, but I must have missed something.

@Peter_Viscarola_(OSR)

I have tried to run !wdflogdump per your recommendation but I have a hard time to interpret all the power state changes.
What I would like to know is the cause for going back to D0 immediately but I am not sure it appears in the dump attach.
We have ordered a logic analyzer to better understand what happens at the device level.

I will look into the continuous reader as it is cleaner than using an infinite timeout.

Hmmmm… The only thing that I see from that trace is that your device is (a) entering Selective Suspend, (b) waking itself up.

Is it possible your device is generating an interrupt while you have it “asleep”?? Because that LOOKS to me like it could be what’s happening… your device is generating an interrupt and that’s being interpreted as a wake request. I need to emphasize that is a guess.

And yes… If what you want is to “always have a Request in progress in case the device generates something” the Continuous Reader is definitely the way to go.

Peter

@Paul_B ,
were you able to resolve the issue?
I am facing the same issue.

USB device draining system power when system is idle.
USB Device: VID: xxxx PID: yyyy REV: wwww
Removal action failed: SkippedAsRecentIoObservered

The device 'xxxxxx' (location Port#0001.Hub_#0004) is offline due to a user-mode driver crash. Windows will attempt to restart the device 5 more times. Please contact the device manufacturer for more information about this problem._

A problem has occurred with one or more user-mode drivers and the hosting process has been terminated. This may temporarily interrupt your ability to access the devices.

Please help me.

It sounds to me like you need to get the user mode crash dump file of the user mode driver that led to the crash and send it to the company that developed it. You can of course separate that user mode driver to run in a separate UMDF process of its own so you can guarantee that only your driver is running in that process. You may be seeing a different issue than the OP. Not a lot of details here.

An then there’s the fact that this is a necropost… so, 14 month after the discussion was ended.

@umeshkumar10 not really unfortunately…

We have solved the issue by retrofitting our sensor into one particular platform and use this platform exclusively for testing and sending this platform to MSFT for certification. The platform we choose did not show this problem and the driver was ultimately approved by Microsoft.

Also, from what I recall at the time, there was a different behavior in regards to entering/leaving Sx when using SecureBio container or not…

Then project was then moved to another division and I don’t know what happened since then…

Probably not the right way to fix the core problem but meh. Anyhow, good luck :wink: