-//*********************************************************************************
-// settle_timer_expired
-//
-// Thread call function. Holds a retain while the callout is in flight.
-//*********************************************************************************
-
-static void
-settle_timer_expired ( thread_call_param_t arg0, thread_call_param_t arg1 )
-{
- IOService * me = (IOService *) arg0;
-
- if (gIOPMWorkLoop && gIOPMReplyQueue)
- {
- gIOPMWorkLoop->runAction(
- OSMemberFunctionCast(IOWorkLoop::Action, me, &IOService::settleTimerExpired),
- me);
- gIOPMReplyQueue->signalWorkAvailable();
- }
- me->release();
-}
-
-//*********************************************************************************
-// [private] ParentChangeStart
-//
-// Here we begin the processing of a power change initiated by our parent.
-//*********************************************************************************
-
-IOReturn IOService::ParentChangeStart ( void )
-{
- PM_ASSERT_IN_GATE();
- OUR_PMLog( kPMLogStartParentChange, fHeadNotePowerState, fCurrentPowerState );
-
- // Power domain is lowering power
- if ( fHeadNotePowerState < fCurrentPowerState )
- {
- setParentInfo( fHeadNoteParentFlags, fHeadNoteParentConnection, true );
-
-#if ROOT_DOMAIN_RUN_STATES
- getPMRootDomain()->handlePowerChangeStartForService(
- /* service */ this,
- /* RD flags */ &fRootDomainState,
- /* new pwr state */ fHeadNotePowerState,
- /* change flags */ fHeadNoteFlags );
-#endif
-
- // tell apps and kernel clients
- fInitialChange = false;
- fMachineState = kIOPM_ParentDownTellPriorityClientsPowerDown;
- tellChangeDown1(fHeadNotePowerState);
- return IOPMWillAckLater;
- }
-
- // Power domain is raising power
- if ( fHeadNotePowerState > fCurrentPowerState )
- {
- if ( fDesiredPowerState > fCurrentPowerState )
- {
- if ( fDesiredPowerState < fHeadNotePowerState )
- {
- // We power up, but not all the way
- fHeadNotePowerState = fDesiredPowerState;
- fHeadNotePowerArrayEntry = &fPowerStates[fDesiredPowerState];
- OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
- }
- } else {
- // We don't need to change
- fHeadNotePowerState = fCurrentPowerState;
- fHeadNotePowerArrayEntry = &fPowerStates[fCurrentPowerState];
- OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
- }
- }
-
- if ( fHeadNoteFlags & kIOPMDomainDidChange )
- {
- if ( fHeadNotePowerState > fCurrentPowerState )
- {
-#if ROOT_DOMAIN_RUN_STATES
- getPMRootDomain()->handlePowerChangeStartForService(
- /* service */ this,
- /* RD flags */ &fRootDomainState,
- /* new pwr state */ fHeadNotePowerState,
- /* change flags */ fHeadNoteFlags );
-#endif
-
- // Parent did change up - start our change up
- fInitialChange = false;
- notifyAll( kIOPM_ParentUpSetPowerState, kNotifyWillChange );
- return IOPMWillAckLater;
- }
- else if (fHeadNoteFlags & kIOPMSynchronize)
- {
- // We do not need to change power state, but notify
- // children to propagate tree synchronization.
- fMachineState = kIOPM_SyncNotifyDidChange;
- fDriverCallReason = kDriverCallInformPreChange;
- notifyChildren();
- return IOPMWillAckLater;
- }
- }
-
- all_done();
- return IOPMAckImplied;
-}
-
-//*********************************************************************************
-// [private] OurChangeStart
-//
-// Here we begin the processing of a power change initiated by us.
-//*********************************************************************************
-
-void IOService::OurChangeStart ( void )
-{
- PM_ASSERT_IN_GATE();
- OUR_PMLog( kPMLogStartDeviceChange, fHeadNotePowerState, fCurrentPowerState );
-
- // fMaxCapability is our maximum possible power state based on the current
- // power state of our parents. If we are trying to raise power beyond the
- // maximum, send an async request for more power to all parents.
-
- if (!IS_PM_ROOT() && (fMaxCapability < fHeadNotePowerState))
- {
- fHeadNoteFlags |= kIOPMNotDone;
- ask_parent(fHeadNotePowerState);
- OurChangeFinish();
- return;
- }
-
- // Redundant power changes skips to the end of the state machine.
-
- if (!fInitialChange && (fHeadNotePowerState == fCurrentPowerState))
- {
- OurChangeFinish();
- return;
- }
- fInitialChange = false;
-
-#if ROOT_DOMAIN_RUN_STATES
- getPMRootDomain()->handlePowerChangeStartForService(
- /* service */ this,
- /* RD flags */ &fRootDomainState,
- /* new pwr state */ fHeadNotePowerState,
- /* change flags */ fHeadNoteFlags );
-#endif
-
- // Two separate paths, depending if power is being raised or lowered.
- // Lowering power is subject to client approval.
-
- if ( fHeadNotePowerState < fCurrentPowerState )
- {
- // Next state when dropping power.
- fMachineState = kIOPM_OurChangeTellClientsPowerDown;
- fDoNotPowerDown = false;
-
- // Ask apps and kernel clients permission to lower power.
- fOutOfBandParameter = kNotifyApps;
- askChangeDown(fHeadNotePowerState);
- }
- else
- {
- // Notify interested drivers and children.
- notifyAll( kIOPM_OurChangeSetPowerState, kNotifyWillChange );
- }
-}
-
-//*********************************************************************************
-// [private] OurSyncStart
-//*********************************************************************************
-
-void IOService::OurSyncStart ( void )
-{
- PM_ASSERT_IN_GATE();
-
- if (fInitialChange)
- return;
-
-#if ROOT_DOMAIN_RUN_STATES
- getPMRootDomain()->handlePowerChangeStartForService(
- /* service */ this,
- /* RD flags */ &fRootDomainState,
- /* new pwr state */ fHeadNotePowerState,
- /* change flags */ fHeadNoteFlags );
-#endif
-
- fMachineState = kIOPM_SyncNotifyDidChange;
- fDriverCallReason = kDriverCallInformPreChange;
-
- notifyChildren();
-}
-
-//*********************************************************************************
-// [private] ask_parent
-//
-// Call the power domain parent to ask for a higher power state in the domain
-// or to suggest a lower power state.
-//*********************************************************************************
-
-IOReturn IOService::ask_parent ( unsigned long requestedState )
-{
- OSIterator * iter;
- OSObject * next;
- IOPowerConnection * connection;
- IOService * parent;
- const IOPMPowerState * powerStatePtr;
- unsigned long ourRequest;
-
- PM_ASSERT_IN_GATE();
- if (requestedState >= fNumberOfPowerStates)
- return IOPMNoErr;
-
- powerStatePtr = &fPowerStates[requestedState];
- ourRequest = powerStatePtr->inputPowerRequirement;
-
- if ( powerStatePtr->capabilityFlags & (kIOPMChildClamp | kIOPMPreventIdleSleep) )
- {
- ourRequest |= kIOPMPreventIdleSleep;
- }
- if ( powerStatePtr->capabilityFlags & (kIOPMChildClamp2 | kIOPMPreventSystemSleep) )
- {
- ourRequest |= kIOPMPreventSystemSleep;
- }
-
- // is this a new desire?
- if ( fPreviousRequest == ourRequest )
- {
- // no, the parent knows already, just return
- return IOPMNoErr;
- }
-
- if ( IS_PM_ROOT() )
- {
- return IOPMNoErr;
- }
- fPreviousRequest = ourRequest;
-
- iter = getParentIterator(gIOPowerPlane);
- if ( iter )
- {
- while ( (next = iter->getNextObject()) )
- {
- if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
- {
- parent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
- if ( parent ) {
- if ( parent->requestPowerDomainState(
- ourRequest, connection, IOPMLowestState) != IOPMNoErr )
- {
- OUR_PMLog(kPMLogRequestDenied, fPreviousRequest, 0);
- }
- parent->release();
- }
- }
- }
- iter->release();
- }
-
- return IOPMNoErr;
-}
-