-
- /*
- Power Management defines a few roles that drivers can play in their own,
- and other drivers', power management. We briefly define those here.
-
- Many drivers implement their policy maker and power controller within the same
- IOService object, but that is not required.
-
-== Policy Maker ==
- * Virtual IOService PM methods a "policy maker" may implement
- * maxCapabilityForDomainState()
- * initialPowerStateForDomainState()
- * powerStateForDomainState()
-
- * Virtual IOService PM methods a "policy maker" may CALL
- * PMinit()
-
-== Power Controller ==
- * Virtual IOService PM methods a "power controller" may implement
- * setPowerState()
-
- * Virtual IOService PM methods a "power controller" may CALL
- * joinPMtree()
- * registerPowerDriver()
-
-=======================
- There are two different kinds of power state changes.
- * One is initiated by a subclassed device object which has either decided
- to change power state, or its controlling driver has suggested it, or
- some other driver wants to use the idle device and has asked it to become
- usable.
- * The second kind of power state change is initiated by the power domain
- parent.
- The two are handled through different code paths.
-
- We maintain a queue of "change notifications," or change notes.
- * Usually the queue is empty.
- * When it isn't, usually there is one change note in it
- * It's possible to have more than one power state change pending at one
- time, so a queue is implemented.
- Example:
- * The subclass device decides it's idle and initiates a change to a lower
- power state. This causes interested parties to be notified, but they
- don't all acknowledge right away. This causes the change note to sit
- in the queue until all the acks are received. During this time, the
- device decides it isn't idle anymore and wants to raise power back up
- again. This change can't be started, however, because the previous one
- isn't complete yet, so the second one waits in the queue. During this
- time, the parent decides to lower or raise the power state of the entire
- power domain and notifies the device, and that notification goes into
- the queue, too, and can't be actioned until the others are.
-
- == SelfInitiated ==
- This is how a power change initiated by the subclass device is handled:
- -> First, all interested parties are notified of the change via their
- powerStateWillChangeTo method. If they all don't acknowledge via return
- code, then we have to wait. If they do, or when they finally all
- acknowledge via our acknowledgePowerChange method, then we can continue.
- -> We call the controlling driver, instructing it to change to the new state
- -> Then we wait for power to settle. If there is no settling-time, or after
- it has passed,
- -> we notify interested parties again, this time via their
- powerStateDidChangeTo methods.
- -> When they have all acked, we're done.
- If we lowered power and don't need the power domain to be in its current power
- state, we suggest to the parent that it lower the power domain state.
-
- == PowerDomainDownInitiated ==
-How a change to a lower power domain state initiated by the parent is handled:
- -> First, we figure out what power state we will be in when the new domain
- state is reached.
- -> Then all interested parties are notified that we are moving to that new
- state.
- -> When they have acknowledged, we call the controlling driver to assume
- that state and we wait for power to settle.
- -> Then we acknowledge our preparedness to our parent. When all its
- interested parties have acknowledged,
- -> it lowers power and then notifies its interested parties again.
- -> When we get this call, we notify our interested parties that the power
- state has changed, and when they have all acknowledged, we're done.
-
- == PowerDomainUpInitiated ==
-How a change to a higher power domain state initiated by the parent is handled:
- -> We figure out what power state we will be in when the new domain state is
- reached.
- -> If it is different from our current state we acknowledge the parent.
- -> When all the parent's interested parties have acknowledged, it raises
- power in the domain and waits for power to settle.
- -> Then it notifies everyone that the new state has been reached.
- -> When we get this call, we call the controlling driver, instructing it to
- assume the new state, and wait for power to settle.
- -> Then we notify our interested parties. When they all acknowledge we are
- done.
-
- In either of the two power domain state cases above, it is possible that we
- will not be changing state even though the domain is.
- Examples:
- * A change to a lower domain state may not affect us because we are already
- in a low enough state,
- * We will not take advantage of a change to a higher domain state, because
- we have no need of the higher power. In such cases, there is nothing to
- do but acknowledge the parent. So when the parent calls our
- powerDomainWillChange method, and we decide that we will not be changing
- state, we merely acknowledge the parent, via return code, and wait.
- When the parent subsequently calls powerStateDidChange, we acknowledge again
- via return code, and the change is complete.
-
- == 4 Paths Through State Machine ==
- Power state changes are processed in a state machine, and since there are four
- varieties of power state changes, there are four major paths through the state
- machine.
-
- == 5. No Need To change ==
- The fourth is nearly trivial. In this path, the parent is changing the domain
- state, but we are not changing the device state. The change starts when the
- parent calls powerDomainWillChange. All we do is acknowledge the parent. When
- the parent calls powerStateDidChange, we acknowledge the parent again, and
- we're done.
-
- == 1. OurChange Down == XXX gvdl
- The first is fairly simple. It starts:
- * when a power domain child calls requestPowerDomainState and we decide to
- change power states to accomodate the child,
- * or if our power-controlling driver calls changePowerStateTo,
- * or if some other driver which is using our device calls makeUsable,
- * or if a subclassed object calls changePowerStateToPriv.
- These are all power changes initiated by us, not forced upon us by the parent.
-
- -> We start by notifying interested parties.
- -> If they all acknowledge via return code, we can go on to state
- "msSetPowerState".
- -> Otherwise, we start the ack timer and wait for the stragglers to
- acknowlege by calling acknowledgePowerChange.
- -> We move on to state "msSetPowerState" when all the
- stragglers have acknowledged, or when the ack timer expires on
- all those which didn't acknowledge.
- In "msSetPowerState" we call the power-controlling driver to change the
- power state of the hardware.
- -> If it returns saying it has done so, we go on to state
- "msWaitForPowerSettle".
- -> Otherwise, we have to wait for it, so we set the ack timer and wait.
- -> When it calls acknowledgeSetPowerState, or when the ack timer
- expires, we go on.
- In "msWaitForPowerSettle", we look in the power state array to see if
- there is any settle time required when changing from our current state to the
- new state.
- -> If not, we go right away to "msNotifyInterestedDriversDidChange".
- -> Otherwise, we set the settle timer and wait. When it expires, we move on.
- In "msNotifyInterestedDriversDidChange" state, we notify all our
- interested parties via their powerStateDidChange methods that we have finished
- changing power state.
- -> If they all acknowledge via return code, we move on to "msFinish".
- -> Otherwise we set the ack timer and wait. When they have all
- acknowledged, or when the ack timer has expired for those that didn't,
- we move on to "msFinish".
- In "msFinish" we remove the used change note from the head of the queue
- and start the next one if one exists.
-
- == 2. Parent Change Down ==
- Start at Stage 2 of OurChange Down XXX gvdl
-
- == 3. Change Up ==
- Start at Stage 4 of OurChange Down XXX gvdl
-
-Note all parent requested changes need to acknowledge the power has changed to the parent when done.
- */
-