Problems associated with arming yourself for wake
Hindsite in this case is 20/20, but arming your device for wake can open yourself up to multitude of race conditions and hard problems. Some of them you can solve in your driver, some of them you must accept that they are there and leave them be. Arming yourself for wake can be broken down into 2 scenarios, arming yourself for wake when your device has gone idle while the machine is running (S0) and arming yourself for wake while when the machine is going into low power (Sx). Here are a few things to consider when writing a WDM driver, a KMDF driver has many of these scenarios handled for you by the framework:
Common races
- After you send the wait wake irp down the stack to the PDO, you don't know when it actually arrives at the PDO and is processed. This is important to know because you don't want to send the Dx power irp until the bus driver has had a chance to process the wake request. The best you can do is request the Dx irp after you send the wait wake irp down the stack and then hope that no driver in between yours and the PDO pends the wait wake irp or changes any of the timing.
- Once you have armed yourself for wake, your device triggers wake while still in D0 (before you can send the Dx irp). Another race that you just have to accept, but one that you can fix in firmware. The device's firmware can be changed to only trigger wake if the device is in a low power state.
Idle while in S0
- After you have requested the wait wake irp and before it arrives, you decide you need to longer arm yourself for wake because of some external event. You must now track this, let the wait wake irp flow through, then cancel it. Another variation is that the wait wake irp has been processed and you make the decision to power up after the Dx irp has been requested, but before the Dx irp has arrived. Same solution as before as well, you must wait for the Dx irp to flow through the stack and then request a D0 irp.
- USB selective suspend introduces another state. You must be idle and then the usb core must let you know when to actually power down and arm your device. This can lead to another state in which you must account for trying to back out of if you are no longer idle.
Wake from Sx
- You have armed yourself for wake and put the device into a lower power state, but the machine is not yet in lower power. At this point your device triggers wake. For instance, let's say you are arming a mouse to wake the machine and the user moves the mouse after it is armed and in low power but the machine is still powered on because it is turning off other devices). There are 2 usability problems here. First, your device triggered too early. Second, your device will not actually wake up the machine once it goes into low power and the user may thing something is wrong!
- Your device has triggered wake and awoken the machine. When do you cancel the wait wake request so that that the underlying bus can turn off wake signaling in the hardware? When you get the S0 irp or after you sent the D0 irp to the PDO? There are some devices which reflect the wake status into an interrupt when they are fully powered on. If you send the D0 irp without canceling the wait wake irp, the device may trigger an interrupt storm when the PDO processes the D0 irp (and you cannot turn off your device's functionality yet because driver's process D0 from the bottom up to the top of the device stack). If your hardware does this, you will have to cancel the wait wake irp and wait for it to complete before requesting a D0 irp when you receive the S0 irp.