Requesting Power State Changes

So far we have looked at how a driver responds to requests from the system to change its power state in response to events such as the system being put into the sleep state. However, there are times when a driver may wish to initiate a change in the power state of its device independent of the overall power state of the system. For example, an LCD monitor may dim its backlight after a few minutes of inactivity, or a disk may spin down if it hasn't been accessed for some time.

A driver should use the I/O Kit's power management API even for power state changes that affect only the device that it is controlling. Doing so will not only ensure that any change of power state that is initiated by the driver is synchronized with power state changes requested by the system but it also allows your driver to take advantage of support provided by the I/O Kit for such tasks as installing a timer to monitor the device's activity and request a transition to a lower power state if the device is not accessed for a period of time. Lastly, if there are devices that rely on your hardware for their power, you will need to use the I/O Kit methods to transition your hardware's power so that any children devices are informed of possible changes to their input power.

There are three methods that can be called to change the current power state of a device:

  • changePowerStateTo(powerStateOrdinal): Requests a change to the power state at the specified index in the registered power state array.
  • changePowerStateToPriv(powerStateOrdinal): Performs a similar function to the previous method, with the difference that this is a protected method in the IOService class, and so cannot be called by objects other than the driver itself.
  • makeUsable(): Requests a power change to the highest power state supported by the driver. This method is typically called by another client of this driver (such as the driver's user client) to ensure that the device is fully functional before it makes further use of the device.

These three methods are implemented by the IOService class, and there is typically no need for a driver to override any of these methods. Internally, the implementation of the makeUsable() method calls through to the same code path as changePowerStateToPriv(), which means that each driver has two power states associated with it: the value requested through changePowerStateTo() and the value requested through changePowerStateToPriv()/makeUsable().

The power state that the I/O Kit ultimately switches the device to is the maximum of the value requested by changePowerStateTo(), the value requested by changePowerStateToPriv(), and the maximum state that satisfies the requirements of any children that are dependent on the device for power. If the device has any children in the power plane that require power, then the parent device cannot be placed in a power state that has an outputPowerCharacter property that is not kIOPMPowerOn.

You may be wondering why the I/O Kit provides two nearly identical methods for setting a device's power state. The private method changePowerStateToPriv() allows a driver to set a minimum power level that cannot be affected by any clients of the driver, which only have the ability to call the public changePowerStateTo() method. A client may raise the power state above the level set by changePowerStateToPriv(), but the driver will never be placed into a power state lower than the value set by changePowerStateToPriv(). The one exception to this behavior is when the system is placed into the sleep state, at which time the device will be put into the lowest power state, overriding the power state that has been set through changePowerStateToPriv(). When the system wakes from sleep, it returns to the power state that was previously active.

By convention, a driver should set its power state through the protected method changePowerStateToPriv(). To remove any influence from the public power level, a driver should place a call to the public method changePowerStateTo(0) in its start() method after registering the driver for power management. Setting the public power state to 0 allows the power state that is requested by changePowerStateToPriv() to be applied without alteration (providing that the power requirements of any children devices can be satisfied).

Because the power state for the device is derived from three possible values, it is recalculated whenever the power state of one of its power children changes or a call it made to either the changePowerStateTo() or changePowerStateToPriv() method is called. If the calculated power state differs from the current power state of the driver, the I/O Kit will send the driver a request to change its power state. The driver will receive this request as described in the previous section of this chapter, “Responding to Power State Changes”, and should respond to the request in the way previously described.

The methods changePowerStateTo(), changePowerStateToPriv(), and makeUsable() are all asynchronous, and may return to the caller before the device has transitioned to its new power state. The implication of this is that a driver that wishes to change its own power state (using, for example, the changePowerStateToPriv() method) should wait until its setPowerState() method is called before reprogramming its hardware to the new power state. A client that wishes to change the power state of another driver by calling a public method (such as changePowerStateTo() or makeUsable()) cannot assume that the device is running in the new power state when the method returns. Instead, it should register to receive notifications when the device's state changes. This is discussed in the section “Observing Device Power State Changes” later in this chapter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.238.31