The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/iokit/Kernel/IOServicePM.cpp

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
    5  * 
    6  * This file contains Original Code and/or Modifications of Original Code
    7  * as defined in and that are subject to the Apple Public Source License
    8  * Version 2.0 (the 'License'). You may not use this file except in
    9  * compliance with the License. The rights granted to you under the License
   10  * may not be used to create, or enable the creation or redistribution of,
   11  * unlawful or unlicensed copies of an Apple operating system, or to
   12  * circumvent, violate, or enable the circumvention or violation of, any
   13  * terms of an Apple operating system software license agreement.
   14  * 
   15  * Please obtain a copy of the License at
   16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
   17  * 
   18  * The Original Code and all software distributed under the License are
   19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   23  * Please see the License for the specific language governing rights and
   24  * limitations under the License.
   25  * 
   26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
   27  */
   28 
   29 #include <IOKit/assert.h>
   30 #include <IOKit/IOKitDebug.h>
   31 #include <IOKit/IOLib.h>
   32 #include <IOKit/IOMessage.h>
   33 #include <IOKit/IOPlatformExpert.h>
   34 #include <IOKit/IOService.h>
   35 #include <IOKit/IOTimerEventSource.h>
   36 #include <IOKit/IOWorkLoop.h>
   37 #include <IOKit/IOCommand.h>
   38 
   39 #include <IOKit/pwr_mgt/IOPMlog.h>
   40 #include <IOKit/pwr_mgt/IOPMinformee.h>
   41 #include <IOKit/pwr_mgt/IOPMinformeeList.h>
   42 #include <IOKit/pwr_mgt/IOPowerConnection.h>
   43 #include <IOKit/pwr_mgt/RootDomain.h>
   44 
   45 #include <sys/proc.h>
   46 
   47 // Required for notification instrumentation
   48 #include "IOServicePrivate.h"
   49 #include "IOServicePMPrivate.h"
   50 #include "IOKitKernelInternal.h"
   51 
   52 static void settle_timer_expired(thread_call_param_t, thread_call_param_t);
   53 static void PM_idle_timer_expired(OSObject *, IOTimerEventSource *);
   54 void        tellAppWithResponse(OSObject * object, void * context) { /*empty*/ }
   55 void        tellClientWithResponse(OSObject * object, void * context) { /*empty*/ }
   56 void        tellClient(OSObject * object, void * context);
   57 IOReturn    serializedAllowPowerChange(OSObject *, void *, void *, void *, void *);
   58 
   59 static uint64_t computeTimeDeltaNS( const AbsoluteTime * start )
   60 {
   61     AbsoluteTime    now;
   62     uint64_t        nsec;
   63 
   64     clock_get_uptime(&now);
   65     SUB_ABSOLUTETIME(&now, start);
   66     absolutetime_to_nanoseconds(now, &nsec);
   67     return nsec;
   68 }
   69 
   70 OSDefineMetaClassAndStructors(IOPMprot, OSObject)
   71 
   72 // log setPowerStates longer than (ns):
   73 #define LOG_SETPOWER_TIMES      (50ULL * 1000ULL * 1000ULL)
   74 // log app responses longer than (ns):
   75 #define LOG_APP_RESPONSE_TIMES  (100ULL * 1000ULL * 1000ULL)
   76 
   77 //*********************************************************************************
   78 // Globals
   79 //*********************************************************************************
   80 
   81 static bool                 gIOPMInitialized   = false;
   82 static IOItemCount          gIOPMBusyCount     = 0;
   83 static IOWorkLoop *         gIOPMWorkLoop      = 0;
   84 static IOPMRequestQueue *   gIOPMRequestQueue  = 0;
   85 static IOPMRequestQueue *   gIOPMReplyQueue    = 0;
   86 static IOPMRequestQueue *   gIOPMFreeQueue     = 0;
   87 
   88 //*********************************************************************************
   89 // Macros
   90 //*********************************************************************************
   91 
   92 #define PM_ERROR(x...)          do { kprintf(x); IOLog(x); } while (false)
   93 #define PM_DEBUG(x...)          do { kprintf(x); } while (false)
   94 
   95 #define PM_TRACE(x...)          do {  \
   96         if (kIOLogDebugPower & gIOKitDebug) kprintf(x); } while (false)
   97 
   98 #define PM_CONNECT(x...)
   99 
  100 #define PM_ASSERT_IN_GATE(x)          \
  101 do {                                  \
  102     assert(gIOPMWorkLoop->inGate());  \
  103 } while(false)
  104 
  105 #define PM_LOCK()                     IOLockLock(fPMLock)
  106 #define PM_UNLOCK()                   IOLockUnlock(fPMLock)
  107 
  108 #define ns_per_us                     1000
  109 #define k30seconds                    (30*1000000)
  110 #define kMinAckTimeoutTicks           (10*1000000)
  111 #define kIOPMTardyAckSPSKey           "IOPMTardyAckSetPowerState"
  112 #define kIOPMTardyAckPSCKey           "IOPMTardyAckPowerStateChange"
  113 #define kPwrMgtKey                    "IOPowerManagement"
  114 
  115 #define OUR_PMLog(t, a, b) \
  116     do { fPlatform->PMLog( fName, t, a, b); } while(0)
  117 
  118 #define NS_TO_MS(nsec)                ((int)((nsec) / 1000000ULL))
  119 
  120 //*********************************************************************************
  121 // PM machine states
  122 //*********************************************************************************
  123 
  124 enum {
  125     kIOPM_OurChangeTellClientsPowerDown                 = 1,
  126     kIOPM_OurChangeTellPriorityClientsPowerDown         = 2,
  127     kIOPM_OurChangeNotifyInterestedDriversWillChange    = 3,
  128     kIOPM_OurChangeSetPowerState                        = 4,
  129     kIOPM_OurChangeWaitForPowerSettle                   = 5,
  130     kIOPM_OurChangeNotifyInterestedDriversDidChange     = 6,
  131     kIOPM_OurChangeFinish                               = 7,
  132     kIOPM_ParentDownTellPriorityClientsPowerDown        = 8,
  133     kIOPM_ParentDownNotifyInterestedDriversWillChange   = 9,
  134     /* 10 not used */
  135     kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange = 11,
  136     kIOPM_ParentDownSetPowerState                       = 12,
  137     kIOPM_ParentDownWaitForPowerSettle                  = 13,
  138     kIOPM_ParentDownAcknowledgeChange                   = 14,
  139     kIOPM_ParentUpSetPowerState                         = 15,
  140     /* 16 not used */
  141     kIOPM_ParentUpWaitForSettleTime                     = 17,
  142     kIOPM_ParentUpNotifyInterestedDriversDidChange      = 18,
  143     kIOPM_ParentUpAcknowledgePowerChange                = 19,
  144     kIOPM_Finished                                      = 20,
  145     kIOPM_DriverThreadCallDone                          = 21,
  146     kIOPM_NotifyChildrenDone                            = 22
  147 };
  148 
  149 
  150  /*
  151  Power Management defines a few roles that drivers can play in their own, 
  152  and other drivers', power management. We briefly define those here.
  153  
  154  Many drivers implement their policy maker and power controller within the same 
  155  IOService object, but that is not required. 
  156  
  157 == Policy Maker == 
  158  * Virtual IOService PM methods a "policy maker" may implement
  159     * maxCapabilityForDomainState()
  160     * initialPowerStateForDomainState()
  161     * powerStateForDomainState()
  162     
  163  * Virtual IOService PM methods a "policy maker" may CALL
  164     * PMinit()
  165  
  166 == Power Controller ==
  167  * Virtual IOService PM methods a "power controller" may implement
  168     * setPowerState() 
  169  
  170  * Virtual IOService PM methods a "power controller" may CALL
  171     * joinPMtree()
  172     * registerPowerDriver()
  173  
  174 =======================
  175  There are two different kinds of power state changes.  
  176     * One is initiated by a subclassed device object which has either decided
  177       to change power state, or its controlling driver has suggested it, or
  178       some other driver wants to use the idle device and has asked it to become
  179       usable.  
  180     * The second kind of power state change is initiated by the power domain 
  181       parent.  
  182  The two are handled through different code paths.
  183  
  184  We maintain a queue of "change notifications," or change notes.
  185     * Usually the queue is empty. 
  186     * When it isn't, usually there is one change note in it 
  187     * It's possible to have more than one power state change pending at one 
  188         time, so a queue is implemented. 
  189  Example:  
  190     * The subclass device decides it's idle and initiates a change to a lower
  191         power state. This causes interested parties to be notified, but they 
  192         don't all acknowledge right away.  This causes the change note to sit 
  193         in the queue until all the acks are received.  During this time, the 
  194         device decides it isn't idle anymore and wants to raise power back up 
  195         again.  This change can't be started, however, because the previous one 
  196         isn't complete yet, so the second one waits in the queue.  During this 
  197         time, the parent decides to lower or raise the power state of the entire
  198         power domain and notifies the device, and that notification goes into 
  199         the queue, too, and can't be actioned until the others are.
  200  
  201  == SelfInitiated ==
  202  This is how a power change initiated by the subclass device is handled:
  203     -> First, all interested parties are notified of the change via their 
  204        powerStateWillChangeTo method.  If they all don't acknowledge via return
  205        code, then we have to wait.  If they do, or when they finally all
  206        acknowledge via our acknowledgePowerChange method, then we can continue.  
  207     -> We call the controlling driver, instructing it to change to the new state
  208     -> Then we wait for power to settle. If there is no settling-time, or after 
  209        it has passed, 
  210     -> we notify interested parties again, this time via their 
  211        powerStateDidChangeTo methods.  
  212     -> When they have all acked, we're done.
  213  If we lowered power and don't need the power domain to be in its current power 
  214  state, we suggest to the parent that it lower the power domain state.
  215  
  216  == PowerDomainDownInitiated ==
  217 How a change to a lower power domain state initiated by the parent is handled:
  218     -> First, we figure out what power state we will be in when the new domain 
  219         state is reached.  
  220     -> Then all interested parties are notified that we are moving to that new 
  221         state.  
  222     -> When they have acknowledged, we call the controlling driver to assume
  223         that state and we wait for power to settle.  
  224     -> Then we acknowledge our preparedness to our parent.  When all its 
  225         interested parties have acknowledged, 
  226     -> it lowers power and then notifies its interested parties again.  
  227     -> When we get this call, we notify our interested parties that the power 
  228         state has changed, and when they have all acknowledged, we're done.
  229  
  230  == PowerDomainUpInitiated ==
  231 How a change to a higher power domain state initiated by the parent is handled:
  232     -> We figure out what power state we will be in when the new domain state is 
  233         reached.  
  234     -> If it is different from our current state we acknowledge the parent.  
  235     -> When all the parent's interested parties have acknowledged, it raises 
  236         power in the domain and waits for power to settle.  
  237     -> Then it  notifies everyone that the new state has been reached.  
  238     -> When we get this call, we call the controlling driver, instructing it to 
  239         assume the new state, and wait for power to settle.
  240     -> Then we notify our interested parties. When they all acknowledge we are 
  241         done.
  242  
  243  In either of the two power domain state cases above, it is possible that we 
  244  will not be changing state even though the domain is. 
  245  Examples:
  246     * A change to a lower domain state may not affect us because we are already 
  247         in a low enough state, 
  248     * We will not take advantage of a change to a higher domain state, because 
  249         we have no need of the higher power. In such cases, there is nothing to 
  250         do but acknowledge the parent.  So when the parent calls our 
  251         powerDomainWillChange method, and we decide that we will not be changing 
  252         state, we merely acknowledge the parent, via return code, and wait.
  253  When the parent subsequently calls powerStateDidChange, we acknowledge again 
  254  via return code, and the change is complete.
  255  
  256  == 4 Paths Through State Machine ==
  257  Power state changes are processed in a state machine, and since there are four 
  258  varieties of power state changes, there are four major paths through the state 
  259  machine.
  260  
  261  == 5. No Need To change ==
  262  The fourth is nearly trivial.  In this path, the parent is changing the domain 
  263  state, but we are not changing the device state. The change starts when the 
  264  parent calls powerDomainWillChange.  All we do is acknowledge the parent. When 
  265  the parent calls powerStateDidChange, we acknowledge the parent again, and 
  266  we're done.
  267  
  268  == 1. OurChange Down ==    XXX gvdl
  269  The first is fairly simple.  It starts: 
  270     * when a power domain child calls requestPowerDomainState and we decide to 
  271         change power states to accomodate the child, 
  272     * or if our power-controlling driver calls changePowerStateTo, 
  273     * or if some other driver which is using our device calls makeUsable, 
  274     * or if a subclassed object calls changePowerStateToPriv.  
  275  These are all power changes initiated by us, not forced upon us by the parent.  
  276  
  277  -> We start by notifying interested parties.  
  278         -> If they all acknowledge via return code, we can go on to state 
  279             "msSetPowerState".  
  280         -> Otherwise, we start the ack timer and wait for the stragglers to 
  281             acknowlege by calling acknowledgePowerChange.  
  282             -> We move on to state "msSetPowerState" when all the 
  283                 stragglers have acknowledged, or when the ack timer expires on 
  284                 all those which didn't acknowledge.  
  285  In "msSetPowerState" we call the power-controlling driver to change the 
  286  power state of the hardware.  
  287     -> If it returns saying it has done so, we go on to state 
  288         "msWaitForPowerSettle".
  289     -> Otherwise, we have to wait for it, so we set the ack timer and wait.  
  290         -> When it calls acknowledgeSetPowerState, or when the ack timer 
  291             expires, we go on.  
  292  In "msWaitForPowerSettle", we look in the power state array to see if 
  293  there is any settle time required when changing from our current state to the 
  294  new state.  
  295     -> If not, we go right away to "msNotifyInterestedDriversDidChange".  
  296     -> Otherwise, we set the settle timer and wait. When it expires, we move on.  
  297  In "msNotifyInterestedDriversDidChange" state, we notify all our 
  298  interested parties via their powerStateDidChange methods that we have finished 
  299  changing power state.  
  300     -> If they all acknowledge via return code, we move on to "msFinish".  
  301     -> Otherwise we set the ack timer and wait.  When they have all 
  302         acknowledged, or when the ack timer has expired for those that didn't, 
  303         we move on to "msFinish".
  304  In "msFinish" we remove the used change note from the head of the queue 
  305  and start the next one if one exists.
  306 
  307  == 2. Parent Change Down ==
  308  Start at Stage 2 of OurChange Down    XXX gvdl
  309 
  310  == 3. Change Up ==
  311  Start at Stage 4 of OurChange Down    XXX gvdl
  312 
  313 Note all parent requested changes need to acknowledge the power has changed to the parent when done.
  314  */
  315 
  316 //*********************************************************************************
  317 // [public virtual] PMinit
  318 //
  319 // Initialize power management.
  320 //*********************************************************************************
  321 
  322 void IOService::PMinit ( void )
  323 {
  324     if ( !initialized )
  325         {
  326                 if ( !gIOPMInitialized )
  327                 {
  328                         gIOPMWorkLoop = IOWorkLoop::workLoop();
  329                         if (gIOPMWorkLoop)
  330                         {
  331                                 gIOPMRequestQueue = IOPMRequestQueue::create(
  332                                         this, OSMemberFunctionCast(IOPMRequestQueue::Action,
  333                                                 this, &IOService::servicePMRequestQueue));
  334 
  335                                 gIOPMReplyQueue = IOPMRequestQueue::create(
  336                                         this, OSMemberFunctionCast(IOPMRequestQueue::Action,
  337                                                 this, &IOService::servicePMReplyQueue));
  338 
  339                                 gIOPMFreeQueue = IOPMRequestQueue::create(
  340                                         this, OSMemberFunctionCast(IOPMRequestQueue::Action,
  341                                                 this, &IOService::servicePMFreeQueue));
  342 
  343                                 if (gIOPMWorkLoop->addEventSource(gIOPMRequestQueue) !=
  344                                         kIOReturnSuccess)
  345                                 {
  346                                         gIOPMRequestQueue->release();
  347                                         gIOPMRequestQueue = 0;
  348                                 }
  349 
  350                                 if (gIOPMWorkLoop->addEventSource(gIOPMReplyQueue) !=
  351                                         kIOReturnSuccess)
  352                                 {
  353                                         gIOPMReplyQueue->release();
  354                                         gIOPMReplyQueue = 0;
  355                                 }
  356 
  357                                 if (gIOPMWorkLoop->addEventSource(gIOPMFreeQueue) !=
  358                                         kIOReturnSuccess)
  359                                 {
  360                                         gIOPMFreeQueue->release();
  361                                         gIOPMFreeQueue = 0;
  362                                 }
  363                         }
  364 
  365                         if (gIOPMRequestQueue && gIOPMReplyQueue && gIOPMFreeQueue)
  366                                 gIOPMInitialized = true;
  367                 }
  368                 if (!gIOPMInitialized)
  369                         return;
  370 
  371         pwrMgt = new IOServicePM;
  372         pwrMgt->init();
  373         setProperty(kPwrMgtKey, pwrMgt);
  374 
  375         fOwner                      = this;
  376         fWeAreRoot                  = false;
  377         fPMLock                     = IOLockAlloc();
  378         fInterestedDrivers          = new IOPMinformeeList;
  379         fInterestedDrivers->initialize();
  380         fDesiredPowerState          = 0;
  381         fDriverDesire               = 0;
  382         fDeviceDesire               = 0;
  383         fInitialChange              = true;
  384         fNeedToBecomeUsable         = false;
  385         fPreviousRequest            = 0;
  386         fDeviceOverrides            = false;
  387         fMachineState               = kIOPM_Finished;
  388         fIdleTimerEventSource       = NULL;
  389         fActivityLock               = IOLockAlloc();
  390         fClampOn                    = false;
  391         fStrictTreeOrder            = false;
  392         fActivityTicklePowerState   = -1;
  393         fControllingDriver          = NULL;
  394         fPowerStates                = NULL;
  395         fNumberOfPowerStates        = 0;
  396         fCurrentPowerState          = 0;
  397         fParentsCurrentPowerFlags   = 0;
  398         fMaxCapability              = 0;
  399         fName                       = getName();
  400         fPlatform                   = getPlatform();
  401         fParentsKnowState           = false;
  402         fSerialNumber               = 0;
  403         fResponseArray              = NULL;
  404         fDoNotPowerDown             = true;
  405         fCurrentPowerConsumption    = kIOPMUnknown;
  406 
  407         for (unsigned int i = 0; i <= kMaxType; i++)
  408         {
  409                 fAggressivenessValue[i] = 0;
  410                 fAggressivenessValid[i]  = false;
  411         }
  412 
  413         fAckTimer = thread_call_allocate(
  414                         &IOService::ack_timer_expired, (thread_call_param_t)this);
  415         fSettleTimer = thread_call_allocate(
  416                         &settle_timer_expired, (thread_call_param_t)this);
  417                 fDriverCallEntry = thread_call_allocate(
  418                         (thread_call_func_t) &IOService::pmDriverCallout, this);
  419                 assert(fDriverCallEntry);
  420 
  421 #if PM_VARS_SUPPORT
  422         IOPMprot * prot = new IOPMprot;
  423         if (prot)
  424         {
  425             prot->init();
  426             prot->ourName = fName;
  427             prot->thePlatform = fPlatform;
  428             fPMVars = prot;
  429             pm_vars = prot;
  430                 }
  431 #else
  432         pm_vars = (IOPMprot *) true;
  433 #endif
  434 
  435         initialized = true;
  436     }
  437 }
  438 
  439 //*********************************************************************************
  440 // [public] PMfree
  441 //
  442 // Free up the data created in PMinit, if it exists.
  443 //*********************************************************************************
  444 
  445 void IOService::PMfree ( void )
  446 {
  447         initialized = false;
  448     pm_vars = 0;
  449 
  450     if ( pwrMgt )
  451         {
  452                 assert(fMachineState == kIOPM_Finished);
  453                 assert(fInsertInterestSet == NULL);
  454                 assert(fRemoveInterestSet == NULL);
  455         assert(fNotifyChildArray  == NULL);
  456 
  457         if ( fIdleTimerEventSource != NULL ) {
  458             getPMworkloop()->removeEventSource(fIdleTimerEventSource);
  459             fIdleTimerEventSource->release();
  460             fIdleTimerEventSource = NULL;
  461         }
  462         if ( fSettleTimer ) {
  463             thread_call_cancel(fSettleTimer);
  464             thread_call_free(fSettleTimer);
  465             fSettleTimer = NULL;
  466         }
  467         if ( fAckTimer ) {
  468             thread_call_cancel(fAckTimer);
  469             thread_call_free(fAckTimer);
  470             fAckTimer = NULL;
  471         }
  472         if ( fDriverCallEntry ) {
  473             thread_call_free(fDriverCallEntry);
  474             fDriverCallEntry = NULL;
  475         }
  476         if ( fPMLock ) {
  477             IOLockFree(fPMLock);
  478             fPMLock = NULL;
  479         }
  480         if ( fActivityLock ) {
  481             IOLockFree(fActivityLock);
  482             fActivityLock = NULL;
  483         }
  484                 if ( fInterestedDrivers ) {
  485                         fInterestedDrivers->release();
  486                         fInterestedDrivers = NULL;
  487                 }
  488                 if ( fPMWorkQueue ) {
  489                         getPMworkloop()->removeEventSource(fPMWorkQueue);
  490                         fPMWorkQueue->release();
  491                         fPMWorkQueue = 0;
  492                 }
  493                 if (fDriverCallParamSlots && fDriverCallParamPtr) {
  494                         IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
  495                         fDriverCallParamPtr = 0;
  496                         fDriverCallParamSlots = 0;
  497                 }
  498         if ( fResponseArray ) {
  499             fResponseArray->release();
  500             fResponseArray = NULL;
  501         }
  502         if (fPowerStates && fNumberOfPowerStates) {
  503             IODelete(fPowerStates, IOPMPowerState, fNumberOfPowerStates);
  504             fNumberOfPowerStates = 0;
  505             fPowerStates = NULL;
  506         }
  507 
  508 #if PM_VARS_SUPPORT
  509                 if (fPMVars)
  510                 {
  511                         fPMVars->release();
  512                         fPMVars = 0;
  513                 }
  514 #endif
  515 
  516         pwrMgt->release();
  517                 pwrMgt = 0;
  518     }
  519 }
  520 
  521 //*********************************************************************************
  522 // [public virtual] joinPMtree
  523 //
  524 // A policy-maker calls its nub here when initializing, to be attached into
  525 // the power management hierarchy.  The default function is to call the
  526 // platform expert, which knows how to do it.  This method is overridden
  527 // by a nub subclass which may either know how to do it, or may need to
  528 // take other action.
  529 //
  530 // This may be the only "power management" method used in a nub,
  531 // meaning it may not be initialized for power management.
  532 //*********************************************************************************
  533 
  534 void IOService::joinPMtree ( IOService * driver )
  535 {
  536     IOPlatformExpert * platform;
  537 
  538     platform = getPlatform();
  539     assert(platform != 0);
  540     platform->PMRegisterDevice(this, driver);
  541 }
  542 
  543 //*********************************************************************************
  544 // [public virtual] youAreRoot
  545 //
  546 // Power Managment is informing us that we are the root power domain.
  547 // The only difference between us and any other power domain is that
  548 // we have no parent and therefore never call it.
  549 //*********************************************************************************
  550 
  551 IOReturn IOService::youAreRoot ( void )
  552 {
  553     fWeAreRoot = true;
  554     fParentsKnowState = true;
  555     attachToParent( getRegistryRoot(), gIOPowerPlane );
  556     return IOPMNoErr;
  557 }
  558 
  559 //*********************************************************************************
  560 // [public virtual] PMstop
  561 //
  562 // Immediately stop driver callouts. Schedule an async stop request to detach
  563 // from power plane.
  564 //*********************************************************************************
  565 
  566 void IOService::PMstop ( void )
  567 {
  568         IOPMRequest * request;
  569 
  570         if (!initialized)
  571                 return;
  572 
  573         // Schedule an async PMstop request, but immediately stop any further
  574         // calls to the controlling or interested drivers. This device will
  575         // continue to exist in the power plane and participate in power state
  576         // changes until the PMstop async request is processed.
  577 
  578         PM_LOCK();
  579         fWillPMStop = true;
  580     if (fDriverCallBusy)
  581         PM_DEBUG("%s::PMstop() driver call busy\n", getName());
  582     PM_UNLOCK();
  583 
  584         request = acquirePMRequest( this, kIOPMRequestTypePMStop );
  585         if (request)
  586         {
  587                 PM_TRACE("[%s] %p PMstop\n", getName(), this);
  588                 submitPMRequest( request );
  589         }
  590 }
  591 
  592 //*********************************************************************************
  593 // handlePMstop
  594 //
  595 // Disconnect the node from its parents and children in the Power Plane.
  596 //*********************************************************************************
  597 
  598 void IOService::handlePMstop ( IOPMRequest * request )
  599 {
  600     OSIterator *                iter;
  601     OSObject *                  next;
  602     IOPowerConnection * connection;
  603     IOService *                 theChild;
  604     IOService *                 theParent;
  605 
  606         PM_ASSERT_IN_GATE();
  607         PM_TRACE("[%s] %p %s start\n", getName(), this, __FUNCTION__);
  608 
  609     // remove the property
  610     removeProperty(kPwrMgtKey);                 
  611 
  612     // detach parents
  613     iter = getParentIterator(gIOPowerPlane);
  614     if ( iter )
  615     {
  616         while ( (next = iter->getNextObject()) )
  617         {
  618             if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
  619             {
  620                 theParent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
  621                 if ( theParent )
  622                 {
  623                     theParent->removePowerChild(connection);
  624                     theParent->release();
  625                 }
  626             }
  627         }
  628         iter->release();
  629     }
  630 
  631     // detach IOConnections
  632     detachAbove( gIOPowerPlane );
  633     
  634     // no more power state changes
  635     fParentsKnowState = false;
  636 
  637     // detach children
  638     iter = getChildIterator(gIOPowerPlane);
  639     if ( iter )
  640     {
  641         while ( (next = iter->getNextObject()) )
  642         {
  643             if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
  644             {
  645                 theChild = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
  646                 if ( theChild )
  647                 {
  648                     // detach nub from child
  649                     connection->detachFromChild(theChild, gIOPowerPlane);
  650                     theChild->release();
  651                 }
  652                 // detach us from nub
  653                 detachFromChild(connection, gIOPowerPlane);
  654             }
  655         }
  656         iter->release();
  657     }
  658 
  659     // Remove all interested drivers from the list, including the power
  660     // controlling driver.
  661     //
  662     // Usually, the controlling driver and the policy-maker functionality
  663     // are implemented by the same object, and without the deregistration,
  664     // the object will be holding an extra retain on itself, and cannot
  665     // be freed.
  666 
  667     if ( fInterestedDrivers )
  668     {
  669                 IOPMinformeeList *      list = fInterestedDrivers;
  670         IOPMinformee *          item;
  671 
  672                 PM_LOCK();
  673                 while ((item = list->firstInList()))
  674                 {
  675                         list->removeFromList(item->whatObject);
  676                 }
  677                 PM_UNLOCK();
  678         }
  679 
  680         // Tell PM_idle_timer_expiration() to ignore idle timer.
  681         fIdleTimerPeriod = 0;
  682 
  683         fWillPMStop = false;
  684         PM_TRACE("[%s] %p %s done\n", getName(), this, __FUNCTION__);
  685 }
  686 
  687 //*********************************************************************************
  688 // [public virtual] addPowerChild
  689 //
  690 // Power Management is informing us who our children are.
  691 //*********************************************************************************
  692 
  693 IOReturn IOService::addPowerChild ( IOService * child )
  694 {
  695         IOPowerConnection *     connection  = 0;
  696         IOPMRequest *           requests[3] = {0, 0, 0};
  697     OSIterator *                iter;
  698         bool                            ok = true;
  699 
  700         if (!child)
  701                 return kIOReturnBadArgument;
  702 
  703     if (!initialized || !child->initialized)
  704                 return IOPMNotYetInitialized;
  705 
  706     OUR_PMLog( kPMLogAddChild, 0, 0 );
  707 
  708         do {
  709                 // Is this child already one of our children?
  710 
  711                 iter = child->getParentIterator( gIOPowerPlane );
  712                 if ( iter )
  713                 {
  714                         IORegistryEntry *       entry;
  715                         OSObject *                      next;
  716 
  717                         while ((next = iter->getNextObject()))
  718                         {
  719                                 if ((entry = OSDynamicCast(IORegistryEntry, next)) &&
  720                                         isChild(entry, gIOPowerPlane))
  721                                 {
  722                                         ok = false;
  723                                         break;
  724                                 }                       
  725                         }
  726                         iter->release();
  727                 }
  728                 if (!ok)
  729                 {
  730                         PM_DEBUG("[%s] %s (%p) is already a child\n",
  731                                 getName(), child->getName(), child);
  732                         break;
  733                 }
  734 
  735                 // Add the child to the power plane immediately, but the
  736                 // joining connection is marked as not ready.
  737                 // We want the child to appear in the power plane before
  738                 // returning to the caller, but don't want the caller to
  739                 // block on the PM work loop.
  740 
  741                 connection = new IOPowerConnection;
  742                 if (!connection)
  743                         break;
  744 
  745                 // Create a chain of PM requests to perform the bottom-half
  746                 // work from the PM work loop.
  747 
  748                 requests[0] = acquirePMRequest(
  749                                         /* target */ this,
  750                                         /* type */   kIOPMRequestTypeAddPowerChild1 );
  751 
  752                 requests[1] = acquirePMRequest(
  753                                         /* target */ child,
  754                                         /* type */   kIOPMRequestTypeAddPowerChild2 );
  755 
  756                 requests[2] = acquirePMRequest(
  757                                         /* target */ this,
  758                                         /* type */   kIOPMRequestTypeAddPowerChild3 );
  759 
  760                 if (!requests[0] || !requests[1] || !requests[2])
  761                         break;
  762 
  763                 requests[0]->setParentRequest( requests[1] );
  764                 requests[1]->setParentRequest( requests[2] );
  765 
  766                 connection->init();
  767                 connection->start(this);
  768                 connection->setAwaitingAck(false);
  769                 connection->setReadyFlag(false);
  770 
  771                 attachToChild( connection, gIOPowerPlane );
  772                 connection->attachToChild( child, gIOPowerPlane );
  773 
  774                 // connection needs to be released
  775                 requests[0]->fArg0 = connection;
  776                 requests[1]->fArg0 = connection;
  777                 requests[2]->fArg0 = connection;
  778 
  779                 submitPMRequest( requests, 3 );
  780                 return kIOReturnSuccess;
  781         }
  782         while (false);
  783 
  784         if (connection)  connection->release();
  785         if (requests[0]) releasePMRequest(requests[0]);
  786         if (requests[1]) releasePMRequest(requests[1]);
  787         if (requests[2]) releasePMRequest(requests[2]);
  788 
  789         // silent failure, to prevent platform drivers from adding the child
  790         // to the root domain.
  791         return IOPMNoErr;
  792 }
  793 
  794 //*********************************************************************************
  795 // [private] addPowerChild1
  796 //
  797 // Called on the power parent.
  798 //*********************************************************************************
  799 
  800 void IOService::addPowerChild1 ( IOPMRequest * request )
  801 {
  802         unsigned long tempDesire = 0;
  803 
  804         // Make us temporary usable before adding the child.
  805 
  806         PM_ASSERT_IN_GATE();
  807     OUR_PMLog( kPMLogMakeUsable, kPMLogMakeUsable, fDeviceDesire );
  808 
  809         if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState)
  810         {
  811                 tempDesire = fNumberOfPowerStates - 1;
  812         }
  813 
  814         if (tempDesire && (fWeAreRoot || (fMaxCapability >= tempDesire)))
  815         {
  816                 computeDesiredState( tempDesire );
  817                 changeState();
  818         }
  819 }
  820 
  821 //*********************************************************************************
  822 // [private] addPowerChild2
  823 //
  824 // Called on the joining child. Blocked behind addPowerChild1.
  825 //*********************************************************************************
  826 
  827 void IOService::addPowerChild2 ( IOPMRequest * request )
  828 {
  829         IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
  830         IOService *         parent;
  831         IOPMPowerFlags          powerFlags;
  832         bool                            knowsState;
  833         unsigned long           powerState;
  834         unsigned long           tempDesire;
  835 
  836         PM_ASSERT_IN_GATE();
  837         parent = (IOService *) connection->getParentEntry(gIOPowerPlane);
  838 
  839         if (!parent || !inPlane(gIOPowerPlane))
  840         {
  841                 PM_DEBUG("[%s] addPowerChild2 not in power plane\n", getName());
  842                 return;
  843         }
  844 
  845         // Parent will be waiting for us to complete this stage, safe to
  846         // directly access parent's vars.
  847 
  848         knowsState = (parent->fPowerStates) && (parent->fParentsKnowState);
  849         powerState = parent->fCurrentPowerState;
  850 
  851         if (knowsState)
  852                 powerFlags = parent->fPowerStates[powerState].outputPowerCharacter;
  853         else
  854                 powerFlags = 0;
  855 
  856         // Set our power parent.
  857 
  858     OUR_PMLog(kPMLogSetParent, knowsState, powerFlags);
  859 
  860         setParentInfo( powerFlags, connection, knowsState );
  861 
  862         connection->setReadyFlag(true);
  863 
  864     if ( fControllingDriver && fParentsKnowState )
  865     {
  866         fMaxCapability = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
  867         // initially change into the state we are already in
  868         tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
  869         computeDesiredState(tempDesire);
  870         fPreviousRequest = 0xffffffff;
  871         changeState();
  872     }
  873 }
  874 
  875 //*********************************************************************************
  876 // [private] addPowerChild3
  877 //
  878 // Called on the parent. Blocked behind addPowerChild2.
  879 //*********************************************************************************
  880 
  881 void IOService::addPowerChild3 ( IOPMRequest * request )
  882 {
  883         IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
  884         IOService *         child;
  885         unsigned int            i;
  886 
  887         PM_ASSERT_IN_GATE();
  888         child = (IOService *) connection->getChildEntry(gIOPowerPlane);
  889 
  890         if (child && inPlane(gIOPowerPlane))
  891         {
  892                 if (child->getProperty("IOPMStrictTreeOrder"))
  893                 {
  894                         PM_DEBUG("[%s] strict ordering enforced\n", getName());
  895                         fStrictTreeOrder = true;
  896                 }
  897 
  898                 for (i = 0; i <= kMaxType; i++)
  899                 {
  900                         if ( fAggressivenessValid[i] )
  901                         {
  902                                 child->setAggressiveness(i, fAggressivenessValue[i]);
  903                         }
  904                 }
  905         }
  906         else
  907         {
  908                 PM_DEBUG("[%s] addPowerChild3 not in power plane\n", getName());
  909         }
  910 
  911         connection->release();
  912 }
  913 
  914 //*********************************************************************************
  915 // [public virtual deprecated] setPowerParent
  916 //
  917 // Power Management is informing us who our parent is.
  918 // If we have a controlling driver, find out, given our newly-informed
  919 // power domain state, what state it would be in, and then tell it
  920 // to assume that state.
  921 //*********************************************************************************
  922 
  923 IOReturn IOService::setPowerParent (
  924         IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags powerFlags )
  925 {
  926         return kIOReturnUnsupported;
  927 }
  928 
  929 //*********************************************************************************
  930 // [public virtual] removePowerChild
  931 //
  932 // Called on a parent whose child is being removed by PMstop().
  933 //*********************************************************************************
  934 
  935 IOReturn IOService::removePowerChild ( IOPowerConnection * theNub )
  936 {
  937     IORegistryEntry *   theChild;
  938 
  939         PM_ASSERT_IN_GATE();
  940     OUR_PMLog( kPMLogRemoveChild, 0, 0 );
  941 
  942     theNub->retain();
  943     
  944     // detach nub from child
  945     theChild = theNub->copyChildEntry(gIOPowerPlane);                   
  946     if ( theChild )
  947     {
  948         theNub->detachFromChild(theChild, gIOPowerPlane);
  949         theChild->release();
  950     }
  951     // detach from the nub
  952     detachFromChild(theNub, gIOPowerPlane);
  953 
  954     // Are we awaiting an ack from this child?
  955     if ( theNub->getAwaitingAck() )
  956         {
  957                 // yes, pretend we got one
  958                 theNub->setAwaitingAck(false);
  959                 if (fHeadNotePendingAcks != 0 )
  960                 {
  961                         // that's one fewer ack to worry about
  962                         fHeadNotePendingAcks--;
  963 
  964                         // is that the last?
  965                         if ( fHeadNotePendingAcks == 0 )
  966                         {
  967                                 stop_ack_timer();
  968                         }
  969                 }
  970         }
  971 
  972         theNub->release();
  973 
  974         // Schedule a request to re-scan child desires and clamp bits.
  975         if (!fWillAdjustPowerState)
  976         {
  977                 IOPMRequest * request;
  978 
  979                 request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
  980                 if (request)
  981                 {
  982                         submitPMRequest( request );
  983                         fWillAdjustPowerState = true;
  984                 }
  985         }
  986 
  987     return IOPMNoErr;
  988 }
  989 
  990 //*********************************************************************************
  991 // [public virtual] registerPowerDriver
  992 //
  993 // A driver has called us volunteering to control power to our device.
  994 //*********************************************************************************
  995 
  996 IOReturn IOService::registerPowerDriver (
  997         IOService *                     powerDriver,
  998         IOPMPowerState *        powerStates,
  999         unsigned long           numberOfStates )
 1000 {
 1001         IOPMRequest *    request;
 1002         IOPMPowerState * powerStatesCopy = 0;
 1003 
 1004     if (!initialized)
 1005                 return IOPMNotYetInitialized;
 1006 
 1007         // Validate arguments.
 1008         if (!powerStates || (numberOfStates < 2))
 1009         {
 1010                 OUR_PMLog(kPMLogControllingDriverErr5, numberOfStates, 0);
 1011                 return kIOReturnBadArgument;
 1012         }
 1013 
 1014         if (!powerDriver)
 1015         {
 1016                 OUR_PMLog(kPMLogControllingDriverErr4, 0, 0);
 1017                 return kIOReturnBadArgument;
 1018         }
 1019 
 1020         if (powerStates[0].version != kIOPMPowerStateVersion1)
 1021         {
 1022                 OUR_PMLog(kPMLogControllingDriverErr1, powerStates[0].version, 0);
 1023                 return kIOReturnBadArgument;
 1024         }
 1025 
 1026         do {
 1027                 // Make a copy of the supplied power state array.
 1028                 powerStatesCopy = IONew(IOPMPowerState, numberOfStates);
 1029                 if (!powerStatesCopy)
 1030                         break;
 1031 
 1032                 bcopy( powerStates, powerStatesCopy,
 1033                         sizeof(IOPMPowerState) * numberOfStates );
 1034 
 1035                 request = acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver );
 1036                 if (!request)
 1037                         break;
 1038 
 1039                 powerDriver->retain();
 1040                 request->fArg0 = (void *) powerDriver;
 1041                 request->fArg1 = (void *) powerStatesCopy;
 1042                 request->fArg2 = (void *) numberOfStates;
 1043 
 1044                 submitPMRequest( request );
 1045                 return kIOReturnSuccess;
 1046         }
 1047         while (false);
 1048 
 1049         if (powerStatesCopy)
 1050                 IODelete(powerStatesCopy, IOPMPowerState, numberOfStates);
 1051         return kIOReturnNoMemory;
 1052 }
 1053 
 1054 //*********************************************************************************
 1055 // [private] handleRegisterPowerDriver
 1056 //*********************************************************************************
 1057 
 1058 void IOService::handleRegisterPowerDriver ( IOPMRequest * request )
 1059 {
 1060         IOService *                     powerDriver    = (IOService *)      request->fArg0;
 1061         IOPMPowerState *        powerStates    = (IOPMPowerState *) request->fArg1;
 1062         unsigned long           numberOfStates = (unsigned long)    request->fArg2;
 1063     unsigned long               i;
 1064         IOService *                     root;
 1065 
 1066         PM_ASSERT_IN_GATE();
 1067         assert(powerStates);
 1068         assert(powerDriver);
 1069         assert(numberOfStates > 1);
 1070 
 1071     if ( !fNumberOfPowerStates )
 1072     {
 1073                 OUR_PMLog(kPMLogControllingDriver,
 1074                         (unsigned long) numberOfStates,
 1075                         (unsigned long) powerStates[0].version);
 1076 
 1077         fPowerStates            = powerStates;
 1078                 fNumberOfPowerStates    = numberOfStates;
 1079                 fControllingDriver      = powerDriver;
 1080         fCurrentCapabilityFlags = fPowerStates[0].capabilityFlags;
 1081 
 1082                 // make a mask of all the character bits we know about
 1083                 fOutputPowerCharacterFlags = 0;
 1084                 for ( i = 0; i < numberOfStates; i++ ) {
 1085                         fOutputPowerCharacterFlags |= fPowerStates[i].outputPowerCharacter;
 1086                 }
 1087 
 1088                 // Register powerDriver as interested, unless already done.
 1089                 // We don't want to register the default implementation since
 1090                 // it does nothing. One ramification of not always registering
 1091                 // is the one fewer retain count held.
 1092 
 1093                 root = getPlatform()->getProvider();
 1094                 assert(root);
 1095                 if (!root ||
 1096                         ((OSMemberFunctionCast(void (*)(void),
 1097                                 root, &IOService::powerStateDidChangeTo)) !=
 1098                         ((OSMemberFunctionCast(void (*)(void),
 1099                                 this, &IOService::powerStateDidChangeTo)))) ||
 1100                         ((OSMemberFunctionCast(void (*)(void),
 1101                                 root, &IOService::powerStateWillChangeTo)) !=
 1102                         ((OSMemberFunctionCast(void (*)(void),
 1103                                 this, &IOService::powerStateWillChangeTo)))))
 1104                 {               
 1105                         if (fInterestedDrivers->findItem(powerDriver) == NULL)
 1106                         {
 1107                                 PM_LOCK();
 1108                                 fInterestedDrivers->appendNewInformee(powerDriver);
 1109                                 PM_UNLOCK();
 1110                         }
 1111                 }
 1112 
 1113                 if ( fNeedToBecomeUsable ) {
 1114                         fNeedToBecomeUsable = false;
 1115                         fDeviceDesire = fNumberOfPowerStates - 1;
 1116                 }
 1117 
 1118                 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
 1119                 {
 1120                         unsigned long tempDesire;
 1121                         fMaxCapability = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
 1122                         // initially change into the state we are already in
 1123                         tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
 1124                         computeDesiredState(tempDesire);
 1125                         changeState();
 1126                 }
 1127         }
 1128         else
 1129         {
 1130                 OUR_PMLog(kPMLogControllingDriverErr2, numberOfStates, 0);
 1131         IODelete(powerStates, IOPMPowerState, numberOfStates);
 1132         }
 1133 
 1134         powerDriver->release();
 1135 }
 1136 
 1137 //*********************************************************************************
 1138 // [public virtual] registerInterestedDriver
 1139 //
 1140 // Add the caller to our list of interested drivers and return our current
 1141 // power state.  If we don't have a power-controlling driver yet, we will
 1142 // call this interested driver again later when we do get a driver and find
 1143 // out what the current power state of the device is.
 1144 //*********************************************************************************
 1145 
 1146 IOPMPowerFlags IOService::registerInterestedDriver ( IOService * driver )
 1147 {
 1148         IOPMRequest *   request;
 1149         bool                    signal;
 1150 
 1151         if (!initialized || !fInterestedDrivers)
 1152                 return IOPMNotPowerManaged;
 1153 
 1154         PM_LOCK();
 1155         signal = (!fInsertInterestSet && !fRemoveInterestSet);
 1156         if (fInsertInterestSet == NULL)
 1157                 fInsertInterestSet = OSSet::withCapacity(4);
 1158         if (fInsertInterestSet)
 1159                 fInsertInterestSet->setObject(driver);
 1160         PM_UNLOCK();
 1161 
 1162         if (signal)
 1163         {
 1164                 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
 1165                 if (request)
 1166                         submitPMRequest( request );
 1167         }
 1168 
 1169         // This return value cannot be trusted, but return a value
 1170         // for those clients that care.
 1171 
 1172     OUR_PMLog(kPMLogInterestedDriver, kIOPMDeviceUsable, 2);
 1173     return kIOPMDeviceUsable;   
 1174 }
 1175 
 1176 //*********************************************************************************
 1177 // [public virtual] deRegisterInterestedDriver
 1178 //*********************************************************************************
 1179 
 1180 IOReturn IOService::deRegisterInterestedDriver ( IOService * driver )
 1181 {
 1182         IOPMinformeeList *      list;
 1183     IOPMinformee *              item;
 1184         IOPMRequest *           request;
 1185         bool                            signal;
 1186 
 1187         if (!initialized || !fInterestedDrivers)
 1188                 return IOPMNotPowerManaged;
 1189 
 1190         PM_LOCK();
 1191         signal = (!fRemoveInterestSet && !fInsertInterestSet);
 1192         if (fRemoveInterestSet == NULL)
 1193                 fRemoveInterestSet = OSSet::withCapacity(4);
 1194         if (fRemoveInterestSet)
 1195         {
 1196                 fRemoveInterestSet->setObject(driver);
 1197 
 1198                 list = fInterestedDrivers;
 1199                 item = list->findItem(driver);
 1200                 if (item && item->active)
 1201                 {
 1202                         item->active = false;
 1203                 }
 1204                 if (fDriverCallBusy)
 1205             PM_DEBUG("%s::deRegisterInterestedDriver() driver call busy\n", getName());
 1206         }
 1207         PM_UNLOCK();
 1208 
 1209         if (signal)
 1210         {
 1211                 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
 1212                 if (request)
 1213                         submitPMRequest( request );
 1214         }
 1215 
 1216         return IOPMNoErr;
 1217 }
 1218 
 1219 //*********************************************************************************
 1220 // [private] handleInterestChanged
 1221 //
 1222 // Handle interest added or removed.
 1223 //*********************************************************************************
 1224 
 1225 void IOService::handleInterestChanged( IOPMRequest * request )
 1226 {
 1227         IOService *                     driver;
 1228     IOPMinformee *              informee;
 1229         IOPMinformeeList *      list = fInterestedDrivers;
 1230 
 1231         PM_LOCK();
 1232 
 1233         if (fInsertInterestSet)
 1234         {
 1235                 while ((driver = (IOService *) fInsertInterestSet->getAnyObject()))
 1236                 {
 1237                         if ((list->findItem(driver) == NULL) &&
 1238                                 (!fRemoveInterestSet ||
 1239                                  !fRemoveInterestSet->containsObject(driver)))
 1240                         {
 1241                                 informee = list->appendNewInformee(driver);
 1242                         }
 1243                         fInsertInterestSet->removeObject(driver);
 1244                 }
 1245                 fInsertInterestSet->release();
 1246                 fInsertInterestSet = 0;
 1247         }
 1248 
 1249         if (fRemoveInterestSet)
 1250         {
 1251                 while ((driver = (IOService *) fRemoveInterestSet->getAnyObject()))
 1252                 {
 1253                         informee = list->findItem(driver);
 1254                         if (informee)
 1255                         {
 1256                                 if (fHeadNotePendingAcks && informee->timer)
 1257                                 {
 1258                                         informee->timer = 0;
 1259                                         fHeadNotePendingAcks--;
 1260                                 }
 1261                                 list->removeFromList(driver);
 1262                         }
 1263                         fRemoveInterestSet->removeObject(driver);
 1264                 }
 1265                 fRemoveInterestSet->release();
 1266                 fRemoveInterestSet = 0;
 1267         }
 1268 
 1269         PM_UNLOCK();
 1270 }
 1271 
 1272 //*********************************************************************************
 1273 // [public virtual] acknowledgePowerChange
 1274 //
 1275 // After we notified one of the interested drivers or a power-domain child
 1276 // of an impending change in power, it has called to say it is now
 1277 // prepared for the change.  If this object is the last to
 1278 // acknowledge this change, we take whatever action we have been waiting
 1279 // for.
 1280 // That may include acknowledging to our parent.  In this case, we do it
 1281 // last of all to insure that this doesn't cause the parent to call us some-
 1282 // where else and alter data we are relying on here (like the very existance
 1283 // of a "current change note".)
 1284 //*********************************************************************************
 1285 
 1286 IOReturn IOService::acknowledgePowerChange ( IOService * whichObject )
 1287 {
 1288         IOPMRequest * request;
 1289 
 1290     if (!initialized)
 1291                 return IOPMNotYetInitialized;
 1292         if (!whichObject)
 1293                 return kIOReturnBadArgument;
 1294 
 1295         request = acquirePMRequest( this, kIOPMRequestTypeAckPowerChange );
 1296         if (!request)
 1297     {
 1298         PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__);
 1299                 return kIOReturnNoMemory;
 1300     }
 1301 
 1302         whichObject->retain();
 1303         request->fArg0 = whichObject;
 1304 
 1305         submitPMRequest( request );
 1306     return IOPMNoErr;
 1307 }
 1308 
 1309 //*********************************************************************************
 1310 // [private] handleAcknowledgePowerChange
 1311 //*********************************************************************************
 1312 
 1313 bool IOService::handleAcknowledgePowerChange ( IOPMRequest * request )
 1314 {
 1315     IOPMinformee *              informee;
 1316     unsigned long               childPower = kIOPMUnknown;
 1317     IOService *                 theChild;
 1318         IOService *                     whichObject;
 1319         bool                            all_acked  = false;
 1320 
 1321         PM_ASSERT_IN_GATE();
 1322         whichObject = (IOService *) request->fArg0;
 1323         assert(whichObject);
 1324 
 1325     // one of our interested drivers?
 1326         informee = fInterestedDrivers->findItem( whichObject );
 1327     if ( informee == NULL )
 1328     {
 1329         if ( !isChild(whichObject, gIOPowerPlane) )
 1330         {
 1331                         OUR_PMLog(kPMLogAcknowledgeErr1, 0, 0);
 1332                         goto no_err;
 1333         } else {
 1334             OUR_PMLog(kPMLogChildAcknowledge, fHeadNotePendingAcks, 0);
 1335         }
 1336     } else {
 1337         OUR_PMLog(kPMLogDriverAcknowledge, fHeadNotePendingAcks, 0);
 1338     }
 1339 
 1340     if ( fHeadNotePendingAcks != 0 )
 1341     {
 1342         assert(fPowerStates != NULL);
 1343 
 1344          // yes, make sure we're expecting acks
 1345         if ( informee != NULL )
 1346         {
 1347             // it's an interested driver
 1348             // make sure we're expecting this ack
 1349             if ( informee->timer != 0 )
 1350             {
 1351 #if LOG_SETPOWER_TIMES
 1352                 if (informee->timer > 0)
 1353                 {
 1354                     uint64_t nsec = computeTimeDeltaNS(&informee->startTime);
 1355                     if (nsec > LOG_SETPOWER_TIMES)
 1356                         PM_DEBUG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) async took %d ms\n",
 1357                             informee->whatObject->getName(),
 1358                             (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
 1359                             informee->whatObject,
 1360                             fName, fCurrentPowerState, fHeadNoteState, NS_TO_MS(nsec));
 1361                 }
 1362 #endif
 1363                 // mark it acked
 1364                 informee->timer = 0;
 1365                 // that's one fewer to worry about
 1366                 fHeadNotePendingAcks--;
 1367             } else {
 1368                 // this driver has already acked
 1369                 OUR_PMLog(kPMLogAcknowledgeErr2, 0, 0);
 1370             }
 1371         } else {
 1372             // it's a child
 1373             // make sure we're expecting this ack
 1374             if ( ((IOPowerConnection *)whichObject)->getAwaitingAck() )
 1375             {
 1376                 // that's one fewer to worry about
 1377                 fHeadNotePendingAcks--;
 1378                 ((IOPowerConnection *)whichObject)->setAwaitingAck(false);
 1379                 theChild = (IOService *)whichObject->copyChildEntry(gIOPowerPlane);
 1380                 if ( theChild )
 1381                 {
 1382                     childPower = theChild->currentPowerConsumption();
 1383                     theChild->release();
 1384                 }
 1385                 if ( childPower == kIOPMUnknown )
 1386                 {
 1387                     fPowerStates[fHeadNoteState].staticPower = kIOPMUnknown;
 1388                 } else {
 1389                     if ( fPowerStates[fHeadNoteState].staticPower != kIOPMUnknown )
 1390                     {
 1391                         fPowerStates[fHeadNoteState].staticPower += childPower;
 1392                     }
 1393                 }
 1394             }
 1395             }
 1396 
 1397                 if ( fHeadNotePendingAcks == 0 ) {
 1398                         // yes, stop the timer
 1399                         stop_ack_timer();
 1400                         // and now we can continue
 1401                         all_acked = true;
 1402                 }
 1403     } else {
 1404         OUR_PMLog(kPMLogAcknowledgeErr3, 0, 0); // not expecting anybody to ack
 1405     }
 1406 
 1407 no_err:
 1408         if (whichObject)
 1409                 whichObject->release();
 1410 
 1411     return all_acked;
 1412 }
 1413 
 1414 //*********************************************************************************
 1415 // [public virtual] acknowledgeSetPowerState
 1416 //
 1417 // After we instructed our controlling driver to change power states,
 1418 // it has called to say it has finished doing so.
 1419 // We continue to process the power state change.
 1420 //*********************************************************************************
 1421 
 1422 IOReturn IOService::acknowledgeSetPowerState ( void )
 1423 {
 1424         IOPMRequest * request;
 1425 
 1426     if (!initialized)
 1427                 return IOPMNotYetInitialized;
 1428 
 1429         request = acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState );
 1430         if (!request)
 1431         {
 1432         PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__);
 1433                 return kIOReturnNoMemory;
 1434         }
 1435 
 1436         submitPMRequest( request );
 1437         return kIOReturnSuccess;
 1438 }
 1439 
 1440 //*********************************************************************************
 1441 // [private] adjustPowerState
 1442 //
 1443 // Child has signaled a change - child changed it's desire, new child added,
 1444 // existing child removed. Adjust our power state accordingly.
 1445 //*********************************************************************************
 1446 
 1447 void IOService::adjustPowerState( void )
 1448 {
 1449         PM_ASSERT_IN_GATE();
 1450         if (inPlane(gIOPowerPlane))
 1451         {
 1452                 rebuildChildClampBits();
 1453                 computeDesiredState();
 1454                 if ( fControllingDriver && fParentsKnowState )
 1455                         changeState();
 1456         }
 1457         else
 1458         {
 1459                 PM_DEBUG("[%s] %s: not in power tree\n", getName(), __FUNCTION__);
 1460                 return;
 1461         }
 1462         fWillAdjustPowerState = false;
 1463 }
 1464 
 1465 //*********************************************************************************
 1466 // [public deprecated] powerDomainWillChangeTo
 1467 //
 1468 // Called by the power-hierarchy parent notifying of a new power state
 1469 // in the power domain.
 1470 // We enqueue a parent power-change to our queue of power changes.
 1471 // This may or may not cause us to change power, depending on what
 1472 // kind of change is occuring in the domain.
 1473 //*********************************************************************************
 1474 
 1475 IOReturn IOService::powerDomainWillChangeTo (
 1476         IOPMPowerFlags          newPowerFlags,
 1477         IOPowerConnection *     whichParent )
 1478 {
 1479         assert(false);
 1480         return kIOReturnUnsupported;
 1481 }
 1482 
 1483 //*********************************************************************************
 1484 // [private] handlePowerDomainWillChangeTo
 1485 //*********************************************************************************
 1486 
 1487 void IOService::handlePowerDomainWillChangeTo ( IOPMRequest * request )
 1488 {
 1489         IOPMPowerFlags          newPowerFlags = (IOPMPowerFlags)      request->fArg0;
 1490         IOPowerConnection *     whichParent   = (IOPowerConnection *) request->fArg1;
 1491         bool                            powerWillDrop = (bool)                request->fArg2;
 1492     OSIterator *                iter;
 1493     OSObject *                  next;
 1494     IOPowerConnection * connection;
 1495     unsigned long               newPowerState;
 1496     IOPMPowerFlags              combinedPowerFlags;
 1497         bool                            savedParentsKnowState;
 1498         IOReturn                        result = IOPMAckImplied;
 1499 
 1500         PM_ASSERT_IN_GATE();
 1501     OUR_PMLog(kPMLogWillChange, newPowerFlags, 0);
 1502 
 1503         if (!inPlane(gIOPowerPlane))
 1504         {
 1505                 PM_DEBUG("[%s] %s: not in power tree\n", getName(), __FUNCTION__);
 1506                 return;
 1507         }
 1508 
 1509         savedParentsKnowState = fParentsKnowState;
 1510 
 1511     // Combine parents' power flags to determine our maximum state
 1512         // within the new power domain
 1513         combinedPowerFlags = 0;
 1514 
 1515     iter = getParentIterator(gIOPowerPlane);
 1516     if ( iter )
 1517     {
 1518         while ( (next = iter->getNextObject()) )
 1519         {
 1520             if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
 1521             {
 1522                 if ( connection == whichParent )
 1523                     combinedPowerFlags |= newPowerFlags;
 1524                 else
 1525                     combinedPowerFlags |= connection->parentCurrentPowerFlags();
 1526             }
 1527         }
 1528         iter->release();
 1529     }
 1530 
 1531     if  ( fControllingDriver )
 1532     {
 1533                 newPowerState = fControllingDriver->maxCapabilityForDomainState(
 1534                                                         combinedPowerFlags);
 1535 
 1536                 result = enqueuePowerChange(
 1537                  /* flags        */     IOPMParentInitiated | IOPMDomainWillChange,
 1538                  /* power state  */     newPowerState,
 1539                                  /* domain state */     combinedPowerFlags,
 1540                                  /* connection   */     whichParent,
 1541                                  /* parent state */     newPowerFlags);
 1542         }
 1543 
 1544         // If parent is dropping power, immediately update the parent's
 1545         // capability flags. Any future merging of parent(s) combined
 1546         // power flags should account for this power drop.
 1547 
 1548         if (powerWillDrop)
 1549         {
 1550                 setParentInfo(newPowerFlags, whichParent, true);
 1551         }
 1552 
 1553         // Parent is expecting an ACK from us. If we did not embark on a state
 1554         // transition, when enqueuePowerChang() returns IOPMAckImplied. We are
 1555         // still required to issue an ACK to our parent.
 1556 
 1557         if (IOPMAckImplied == result)
 1558         {
 1559                 IOService * parent;
 1560                 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
 1561                 assert(parent);
 1562                 if ( parent )
 1563                 {
 1564                         parent->acknowledgePowerChange( whichParent );
 1565                         parent->release();
 1566                 }
 1567         }
 1568 
 1569         // If the parent registers it's power driver late, then this is the
 1570         // first opportunity to tell our parent about our desire. 
 1571 
 1572         if (!savedParentsKnowState && fParentsKnowState)
 1573         {
 1574                 PM_TRACE("[%s] powerDomainWillChangeTo: parentsKnowState = true\n",
 1575                         getName());
 1576                 ask_parent( fDesiredPowerState );
 1577         }
 1578 }
 1579 
 1580 //*********************************************************************************
 1581 // [public deprecated] powerDomainDidChangeTo
 1582 //
 1583 // Called by the power-hierarchy parent after the power state of the power domain
 1584 // has settled at a new level.
 1585 // We enqueue a parent power-change to our queue of power changes.
 1586 // This may or may not cause us to change power, depending on what
 1587 // kind of change is occuring in the domain.
 1588 //*********************************************************************************
 1589 
 1590 IOReturn IOService::powerDomainDidChangeTo (
 1591         IOPMPowerFlags          newPowerFlags,
 1592         IOPowerConnection *     whichParent )
 1593 {
 1594         assert(false);
 1595         return kIOReturnUnsupported;
 1596 }
 1597 
 1598 //*********************************************************************************
 1599 // [private] handlePowerDomainDidChangeTo
 1600 //*********************************************************************************
 1601 
 1602 void IOService::handlePowerDomainDidChangeTo ( IOPMRequest * request )
 1603 {
 1604         IOPMPowerFlags          newPowerFlags = (IOPMPowerFlags)      request->fArg0;
 1605         IOPowerConnection *     whichParent   = (IOPowerConnection *) request->fArg1;
 1606     unsigned long               newPowerState;
 1607         bool                            savedParentsKnowState;
 1608         IOReturn                        result = IOPMAckImplied;
 1609 
 1610         PM_ASSERT_IN_GATE();
 1611     OUR_PMLog(kPMLogDidChange, newPowerFlags, 0);
 1612 
 1613         if (!inPlane(gIOPowerPlane))
 1614         {
 1615                 PM_DEBUG("[%s] %s: not in power tree\n", getName(), __FUNCTION__);
 1616                 return;
 1617         }
 1618 
 1619         savedParentsKnowState = fParentsKnowState;
 1620 
 1621     setParentInfo(newPowerFlags, whichParent, true);
 1622 
 1623     if ( fControllingDriver )
 1624         {
 1625                 newPowerState = fControllingDriver->maxCapabilityForDomainState(
 1626                                                         fParentsCurrentPowerFlags);
 1627 
 1628                 result = enqueuePowerChange(
 1629                                  /* flags        */     IOPMParentInitiated | IOPMDomainDidChange,
 1630                  /* power state  */     newPowerState,
 1631                                  /* domain state */     fParentsCurrentPowerFlags,
 1632                                  /* connection   */     whichParent,
 1633                                  /* parent state */     0);
 1634         }
 1635 
 1636         // Parent is expecting an ACK from us. If we did not embark on a state
 1637         // transition, when enqueuePowerChang() returns IOPMAckImplied. We are
 1638         // still required to issue an ACK to our parent.
 1639 
 1640         if (IOPMAckImplied == result)
 1641         {
 1642                 IOService * parent;
 1643                 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
 1644                 assert(parent);
 1645                 if ( parent )
 1646                 {
 1647                         parent->acknowledgePowerChange( whichParent );
 1648                         parent->release();
 1649                 }
 1650         }
 1651 
 1652         // If the parent registers it's power driver late, then this is the
 1653         // first opportunity to tell our parent about our desire. 
 1654 
 1655         if (!savedParentsKnowState && fParentsKnowState)
 1656         {
 1657                 PM_TRACE("[%s] powerDomainDidChangeTo: parentsKnowState = true\n",
 1658                         getName());
 1659                 ask_parent( fDesiredPowerState );
 1660         }
 1661 }
 1662 
 1663 //*********************************************************************************
 1664 // [private] setParentInfo
 1665 //
 1666 // Set our connection data for one specific parent, and then combine all the parent
 1667 // data together.
 1668 //*********************************************************************************
 1669  
 1670 void IOService::setParentInfo (
 1671         IOPMPowerFlags          newPowerFlags,
 1672         IOPowerConnection * whichParent,
 1673         bool                            knowsState )
 1674 {
 1675     OSIterator *                iter;
 1676     OSObject *                  next;
 1677     IOPowerConnection * conn;
 1678 
 1679         PM_ASSERT_IN_GATE();
 1680 
 1681     // set our connection data
 1682     whichParent->setParentCurrentPowerFlags(newPowerFlags);
 1683     whichParent->setParentKnowsState(knowsState);
 1684     
 1685     // recompute our parent info
 1686     fParentsCurrentPowerFlags = 0;
 1687     fParentsKnowState = true;
 1688 
 1689     iter = getParentIterator(gIOPowerPlane);
 1690     if ( iter )
 1691     {
 1692         while ( (next = iter->getNextObject()) )
 1693         {
 1694             if ( (conn = OSDynamicCast(IOPowerConnection, next)) )
 1695             {
 1696                 fParentsKnowState &= conn->parentKnowsState();
 1697                 fParentsCurrentPowerFlags |= conn->parentCurrentPowerFlags();
 1698             }
 1699         }
 1700         iter->release();
 1701     }
 1702 }
 1703 
 1704 //*********************************************************************************
 1705 // [private] rebuildChildClampBits
 1706 //
 1707 // The ChildClamp bits (kIOPMChildClamp & kIOPMChildClamp2) in our capabilityFlags
 1708 // indicate that one of our children (or grandchildren or great-grandchildren ...)
 1709 // doesn't support idle or system sleep in its current state. Since we don't track
 1710 // the origin of each bit, every time any child changes state we have to clear
 1711 // these bits and rebuild them.
 1712 //*********************************************************************************
 1713 
 1714 void IOService::rebuildChildClampBits ( void )
 1715 {
 1716     unsigned long               i;
 1717     OSIterator *                iter;
 1718     OSObject *                  next;
 1719     IOPowerConnection * connection;
 1720         unsigned long           powerState;
 1721 
 1722     // A child's desires has changed. We need to rebuild the child-clamp bits in
 1723         // our power state array. Start by clearing the bits in each power state.
 1724     
 1725     for ( i = 0; i < fNumberOfPowerStates; i++ )
 1726     {
 1727         fPowerStates[i].capabilityFlags &= ~(kIOPMChildClamp | kIOPMChildClamp2);
 1728     }
 1729 
 1730     // Loop through the children. When we encounter the calling child, save the
 1731         // computed state as this child's desire. And set the ChildClamp bits in any
 1732     // of our states that some child has clamp on.
 1733 
 1734     iter = getChildIterator(gIOPowerPlane);
 1735     if ( iter )
 1736     {
 1737         while ( (next = iter->getNextObject()) )
 1738         {
 1739             if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
 1740             {
 1741                                 if (connection->getReadyFlag() == false)
 1742                                 {
 1743                                         PM_CONNECT("[%s] %s: connection not ready\n",
 1744                                                 getName(), __FUNCTION__);
 1745                                         continue;
 1746                                 }
 1747 
 1748                                 powerState = connection->getDesiredDomainState();
 1749                 if (powerState < fNumberOfPowerStates)
 1750                 {
 1751                     if ( connection->getPreventIdleSleepFlag() )
 1752                         fPowerStates[powerState].capabilityFlags |= kIOPMChildClamp;
 1753                     if ( connection->getPreventSystemSleepFlag() )
 1754                         fPowerStates[powerState].capabilityFlags |= kIOPMChildClamp2;
 1755                 }
 1756             }
 1757         }
 1758         iter->release();
 1759     }
 1760 }
 1761 
 1762 //*********************************************************************************
 1763 // [public virtual] requestPowerDomainState
 1764 //
 1765 // The child of a power domain calls it parent here to request power of a certain
 1766 // character.
 1767 //*********************************************************************************
 1768 
 1769 IOReturn IOService::requestPowerDomainState (
 1770         IOPMPowerFlags          desiredState,
 1771         IOPowerConnection *     whichChild,
 1772         unsigned long           specification )
 1773 {
 1774     unsigned long               i;
 1775     unsigned long               computedState;
 1776     unsigned long               theDesiredState;
 1777         IOService *                     child;
 1778 
 1779     if (!initialized)
 1780                 return IOPMNotYetInitialized;
 1781 
 1782         if (gIOPMWorkLoop->onThread() == false)
 1783         {
 1784                 PM_DEBUG("[%s] called requestPowerDomainState\n", getName());
 1785                 return kIOReturnSuccess;
 1786         }
 1787 
 1788         theDesiredState = desiredState & ~(kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
 1789 
 1790     OUR_PMLog(kPMLogRequestDomain, desiredState, specification);
 1791 
 1792         if (!isChild(whichChild, gIOPowerPlane))
 1793                 return kIOReturnNotAttached;
 1794 
 1795     if (fControllingDriver == NULL || !fPowerStates)
 1796         return IOPMNotYetInitialized;
 1797 
 1798         child = (IOService *) whichChild->getChildEntry(gIOPowerPlane);
 1799         assert(child);
 1800 
 1801     switch (specification) {
 1802         case IOPMLowestState:
 1803             i = 0;
 1804             while ( i < fNumberOfPowerStates )
 1805             {
 1806                 if ( ( fPowerStates[i].outputPowerCharacter & theDesiredState) ==
 1807                                          (theDesiredState & fOutputPowerCharacterFlags) )
 1808                 {
 1809                     break;
 1810                 }
 1811                 i++;
 1812             }
 1813             if ( i >= fNumberOfPowerStates )
 1814             {
 1815                 return IOPMNoSuchState;
 1816             }
 1817             break;
 1818 
 1819         case IOPMNextLowerState:
 1820             i = fCurrentPowerState - 1;
 1821             while ( (int) i >= 0 )
 1822             {
 1823                 if ( ( fPowerStates[i].outputPowerCharacter & theDesiredState) ==
 1824                                          (theDesiredState & fOutputPowerCharacterFlags) )
 1825                 {
 1826                     break;
 1827                 }
 1828                 i--;
 1829             }
 1830             if ( (int) i < 0 )
 1831             {
 1832                 return IOPMNoSuchState;
 1833             }
 1834             break;
 1835 
 1836         case IOPMHighestState:
 1837             i = fNumberOfPowerStates;
 1838             while ( (int) i >= 0 )
 1839             {
 1840                 i--;
 1841                 if ( ( fPowerStates[i].outputPowerCharacter & theDesiredState) ==
 1842                                          (theDesiredState & fOutputPowerCharacterFlags) )
 1843                 {
 1844                     break;
 1845                 }
 1846             }
 1847             if ( (int) i < 0 )
 1848             {
 1849                 return IOPMNoSuchState;
 1850             }
 1851             break;
 1852 
 1853         case IOPMNextHigherState:
 1854             i = fCurrentPowerState + 1;
 1855             while ( i < fNumberOfPowerStates )
 1856             {
 1857                 if ( ( fPowerStates[i].outputPowerCharacter & theDesiredState) ==
 1858                                          (theDesiredState & fOutputPowerCharacterFlags) )
 1859                 {
 1860                     break;
 1861                 }
 1862                 i++;
 1863             }
 1864             if ( i == fNumberOfPowerStates )
 1865             {
 1866                 return IOPMNoSuchState;
 1867             }
 1868             break;
 1869 
 1870         default:
 1871             return IOPMBadSpecification;
 1872     }
 1873 
 1874     computedState = i;
 1875 
 1876         // Clamp removed on the initial power request from a new child.
 1877 
 1878         if (fClampOn && !whichChild->childHasRequestedPower())
 1879         {
 1880                 PM_TRACE("[%s] %p power clamp removed (child = %p)\n",
 1881                         getName(), this, whichChild);
 1882                 fClampOn = false;
 1883                 fDeviceDesire = 0;
 1884         }
 1885 
 1886         // Record the child's desires on the connection.
 1887 
 1888         whichChild->setDesiredDomainState( computedState );
 1889         whichChild->setPreventIdleSleepFlag( desiredState & kIOPMPreventIdleSleep );
 1890         whichChild->setPreventSystemSleepFlag( desiredState & kIOPMPreventSystemSleep );
 1891         whichChild->setChildHasRequestedPower();
 1892 
 1893         if (whichChild->getReadyFlag() == false)
 1894                 return IOPMNoErr;
 1895 
 1896         // Issue a ping for us to re-evaluate all children desires and
 1897         // possibly change power state.
 1898 
 1899         if (!fWillAdjustPowerState && !fDeviceOverrides)
 1900         {
 1901                 IOPMRequest * childRequest;
 1902 
 1903                 childRequest = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
 1904                 if (childRequest)
 1905                 {
 1906                         submitPMRequest( childRequest );
 1907                         fWillAdjustPowerState = true;
 1908                 }
 1909         }
 1910 
 1911         return IOPMNoErr;
 1912 }
 1913 
 1914 //*********************************************************************************
 1915 // [public virtual] temporaryPowerClampOn
 1916 //
 1917 // A power domain wants to clamp its power on till it has children which
 1918 // will thendetermine the power domain state.
 1919 //
 1920 // We enter the highest state until addPowerChild is called.
 1921 //*********************************************************************************
 1922 
 1923 IOReturn IOService::temporaryPowerClampOn ( void )
 1924 {
 1925         IOPMRequest * request;
 1926 
 1927     if (!initialized)
 1928                 return IOPMNotYetInitialized;
 1929 
 1930         request = acquirePMRequest( this, kIOPMRequestTypeTemporaryPowerClamp );
 1931         if (!request)
 1932                 return kIOReturnNoMemory;
 1933 
 1934         submitPMRequest( request );
 1935     return IOPMNoErr;
 1936 }
 1937 
 1938 //*********************************************************************************
 1939 // [public virtual] makeUsable
 1940 //
 1941 // Some client of our device is asking that we become usable.  Although
 1942 // this has not come from a subclassed device object, treat it exactly
 1943 // as if it had.  In this way, subsequent requests for lower power from
 1944 // a subclassed device object will pre-empt this request.
 1945 //
 1946 // We treat this as a subclass object request to switch to the
 1947 // highest power state.
 1948 //*********************************************************************************
 1949 
 1950 IOReturn IOService::makeUsable ( void )
 1951 {
 1952         IOPMRequest * request;
 1953 
 1954     if (!initialized)
 1955                 return IOPMNotYetInitialized;
 1956 
 1957     OUR_PMLog(kPMLogMakeUsable, 0, 0);
 1958 
 1959         request = acquirePMRequest( this, kIOPMRequestTypeMakeUsable );
 1960         if (!request)
 1961                 return kIOReturnNoMemory;
 1962 
 1963         submitPMRequest( request );
 1964     return IOPMNoErr;
 1965 }
 1966 
 1967 //*********************************************************************************
 1968 // [private] handleMakeUsable
 1969 //
 1970 // Handle a request to become usable.
 1971 //*********************************************************************************
 1972 
 1973 void IOService::handleMakeUsable ( IOPMRequest * request )
 1974 {
 1975         PM_ASSERT_IN_GATE();
 1976     if ( fControllingDriver )
 1977     {
 1978                 fDeviceDesire = fNumberOfPowerStates - 1;
 1979                 computeDesiredState();
 1980                 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
 1981                 {
 1982                         changeState();
 1983                 }
 1984         }
 1985         else
 1986         {
 1987         fNeedToBecomeUsable = true;
 1988     }
 1989 }
 1990 
 1991 //*********************************************************************************
 1992 // [public virtual] currentCapability
 1993 //*********************************************************************************
 1994 
 1995 IOPMPowerFlags IOService::currentCapability ( void )
 1996 {
 1997         if (!initialized)
 1998                 return IOPMNotPowerManaged;
 1999 
 2000     return fCurrentCapabilityFlags;
 2001 }
 2002 
 2003 //*********************************************************************************
 2004 // [public virtual] changePowerStateTo
 2005 //
 2006 // For some reason, our power-controlling driver has decided it needs to change
 2007 // power state.  We enqueue the power change so that appropriate parties
 2008 // will be notified, and then we will instruct the driver to make the change.
 2009 //*********************************************************************************
 2010 
 2011 IOReturn IOService::changePowerStateTo ( unsigned long ordinal )
 2012 {
 2013         IOPMRequest * request;
 2014 
 2015         if (!initialized)
 2016                 return IOPMNotYetInitialized;
 2017 
 2018     OUR_PMLog(kPMLogChangeStateTo, ordinal, 0);
 2019 
 2020         request = acquirePMRequest( this, kIOPMRequestTypeChangePowerStateTo );
 2021         if (!request)
 2022                 return kIOReturnNoMemory;
 2023 
 2024         request->fArg0 = (void *) ordinal;
 2025         request->fArg1 = (void *) false;
 2026 
 2027         // Avoid needless downwards power transitions by clamping power in
 2028         // computeDesiredState() until the delayed request is processed.
 2029 
 2030         if (gIOPMWorkLoop->inGate())
 2031         {
 2032                 fTempClampPowerState = max(fTempClampPowerState, ordinal);
 2033                 fTempClampCount++;
 2034                 request->fArg1 = (void *) true;
 2035         }
 2036 
 2037         submitPMRequest( request );
 2038     return IOPMNoErr;
 2039 }
 2040 
 2041 //*********************************************************************************
 2042 // [private] handleChangePowerStateTo
 2043 //*********************************************************************************
 2044 
 2045 void IOService::handleChangePowerStateTo ( IOPMRequest * request )
 2046 {
 2047         unsigned long ordinal = (unsigned long) request->fArg0;
 2048 
 2049         PM_ASSERT_IN_GATE();
 2050         if (request->fArg1)
 2051         {
 2052                 assert(fTempClampCount != 0);
 2053                 if (fTempClampCount)
 2054                         fTempClampCount--;
 2055                 if (!fTempClampCount)
 2056                         fTempClampPowerState = 0;
 2057         }
 2058 
 2059         if ( fControllingDriver && (ordinal < fNumberOfPowerStates))
 2060     {
 2061                 fDriverDesire = ordinal;
 2062                 computeDesiredState();
 2063                 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
 2064                 {
 2065                         changeState();
 2066                 }
 2067         }
 2068 }
 2069 
 2070 //*********************************************************************************
 2071 // [public virtual] changePowerStateToPriv
 2072 //
 2073 // For some reason, a subclassed device object has decided it needs to change
 2074 // power state.  We enqueue the power change so that appropriate parties
 2075 // will be notified, and then we will instruct the driver to make the change.
 2076 //*********************************************************************************
 2077 
 2078 IOReturn IOService::changePowerStateToPriv ( unsigned long ordinal )
 2079 {
 2080         IOPMRequest * request;
 2081 
 2082         if (!initialized)
 2083                 return IOPMNotYetInitialized;
 2084 
 2085         request = acquirePMRequest( this, kIOPMRequestTypeChangePowerStateToPriv );
 2086         if (!request)
 2087                 return kIOReturnNoMemory;
 2088 
 2089         request->fArg0 = (void *) ordinal;
 2090         request->fArg1 = (void *) false;
 2091 
 2092         // Avoid needless downwards power transitions by clamping power in
 2093         // computeDesiredState() until the delayed request is processed.
 2094 
 2095         if (gIOPMWorkLoop->inGate())
 2096         {
 2097                 fTempClampPowerState = max(fTempClampPowerState, ordinal);
 2098                 fTempClampCount++;
 2099                 request->fArg1 = (void *) true;
 2100         }
 2101 
 2102         submitPMRequest( request );
 2103     return IOPMNoErr;
 2104 }
 2105 
 2106 //*********************************************************************************
 2107 // [private] handleChangePowerStateToPriv
 2108 //*********************************************************************************
 2109 
 2110 void IOService::handleChangePowerStateToPriv ( IOPMRequest * request )
 2111 {
 2112         unsigned long ordinal = (unsigned long) request->fArg0;
 2113 
 2114         PM_ASSERT_IN_GATE();
 2115     OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
 2116         if (request->fArg1)
 2117         {
 2118                 assert(fTempClampCount != 0);
 2119                 if (fTempClampCount)
 2120                         fTempClampCount--;
 2121                 if (!fTempClampCount)
 2122                         fTempClampPowerState = 0;
 2123         }
 2124 
 2125         if ( fControllingDriver && (ordinal < fNumberOfPowerStates))
 2126         {
 2127                 fDeviceDesire = ordinal;
 2128                 computeDesiredState();
 2129                 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
 2130                 {
 2131                         changeState();
 2132                 }
 2133         }
 2134 }
 2135 
 2136 //*********************************************************************************
 2137 // [private] computeDesiredState
 2138 //*********************************************************************************
 2139 
 2140 void IOService::computeDesiredState ( unsigned long tempDesire )
 2141 {
 2142     OSIterator *                iter;
 2143     OSObject *                  next;
 2144     IOPowerConnection * connection;
 2145     unsigned long               newDesiredState = 0;
 2146         unsigned long           childDesire = 0;
 2147         unsigned long           deviceDesire;
 2148 
 2149         if (tempDesire)
 2150                 deviceDesire = tempDesire;
 2151         else
 2152                 deviceDesire = fDeviceDesire;
 2153 
 2154         // If clamp is on, always override deviceDesire to max.
 2155 
 2156         if (fClampOn && fNumberOfPowerStates)
 2157                 deviceDesire = fNumberOfPowerStates - 1;
 2158 
 2159     // Compute the maximum  of our children's desires,
 2160         // our controlling driver's desire, and the subclass device's desire.
 2161 
 2162     if ( !fDeviceOverrides )
 2163     {
 2164         iter = getChildIterator(gIOPowerPlane);
 2165         if ( iter )
 2166         {
 2167             while ( (next = iter->getNextObject()) )
 2168             {
 2169                 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
 2170                 {
 2171                                         if (connection->getReadyFlag() == false)
 2172                                         {
 2173                                                 PM_CONNECT("[%s] %s: connection not ready\n",
 2174                                                         getName(), __FUNCTION__);
 2175                                                 continue;
 2176                                         }
 2177         
 2178                     if (connection->getDesiredDomainState() > childDesire)
 2179                         childDesire = connection->getDesiredDomainState();
 2180                 }
 2181             }
 2182             iter->release();
 2183         }
 2184 
 2185         fChildrenDesire = childDesire;
 2186                 newDesiredState = max(childDesire, fDriverDesire);
 2187     }
 2188 
 2189         newDesiredState = max(deviceDesire, newDesiredState);
 2190         if (fTempClampCount && (fTempClampPowerState < fNumberOfPowerStates))
 2191                 newDesiredState = max(fTempClampPowerState, newDesiredState);
 2192 
 2193     fDesiredPowerState = newDesiredState;
 2194     
 2195     // Limit check against number of power states.
 2196 
 2197     if (fNumberOfPowerStates == 0)
 2198         fDesiredPowerState = 0;
 2199     else if (fDesiredPowerState >= fNumberOfPowerStates)
 2200         fDesiredPowerState = fNumberOfPowerStates - 1;
 2201 
 2202         // Restart idle timer if stopped and deviceDesire has increased.
 2203 
 2204         if (fDeviceDesire && fActivityTimerStopped)
 2205         {
 2206                 fActivityTimerStopped = false;
 2207                 start_PM_idle_timer();
 2208         }
 2209 
 2210         // Invalidate cached tickle power state when desires change, and not
 2211         // due to a tickle request.  This invalidation must occur before the
 2212         // power state change to minimize races.  We want to err on the side
 2213         // of servicing more activity tickles rather than dropping one when
 2214         // the device is in a low power state.
 2215 
 2216         if (fPMRequest && (fPMRequest->getType() != kIOPMRequestTypeActivityTickle) &&
 2217                 (fActivityTicklePowerState != -1))
 2218         {
 2219                 IOLockLock(fActivityLock);
 2220                 fActivityTicklePowerState = -1;
 2221                 IOLockUnlock(fActivityLock);
 2222         }
 2223 
 2224         PM_TRACE("   NewState %ld, Child %ld, Driver %ld, Device %ld, Clamp %d (%ld)\n",
 2225                 fDesiredPowerState, childDesire, fDriverDesire, deviceDesire,
 2226                 fClampOn, fTempClampCount ? fTempClampPowerState : 0);
 2227 }
 2228 
 2229 //*********************************************************************************
 2230 // [private] changeState
 2231 //
 2232 // A subclass object, our controlling driver, or a power domain child
 2233 // has asked for a different power state.  Here we compute what new
 2234 // state we should enter and enqueue the change (or start it).
 2235 //*********************************************************************************
 2236 
 2237 IOReturn IOService::changeState ( void )
 2238 {
 2239         IOReturn result;
 2240 
 2241         PM_ASSERT_IN_GATE();
 2242         assert(inPlane(gIOPowerPlane));
 2243         assert(fParentsKnowState);
 2244         assert(fControllingDriver);
 2245 
 2246         result = enqueuePowerChange(
 2247                          /* flags        */     IOPMWeInitiated,
 2248                          /* power state  */     fDesiredPowerState,
 2249                          /* domain state */     0,
 2250                          /* connection   */     0,
 2251                          /* parent state */     0);
 2252 
 2253         return result;
 2254 }
 2255 
 2256 //*********************************************************************************
 2257 // [public virtual] currentPowerConsumption
 2258 //
 2259 //*********************************************************************************
 2260 
 2261 unsigned long IOService::currentPowerConsumption ( void )
 2262 {
 2263     if (!initialized)
 2264         return kIOPMUnknown;
 2265 
 2266     return fCurrentPowerConsumption;
 2267 }
 2268 
 2269 //*********************************************************************************
 2270 // [public virtual] getPMworkloop
 2271 //*********************************************************************************
 2272 
 2273 IOWorkLoop * IOService::getPMworkloop ( void )
 2274 {
 2275         return gIOPMWorkLoop;
 2276 }
 2277 
 2278 //*********************************************************************************
 2279 // [public virtual] activityTickle
 2280 //
 2281 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
 2282 // flag to be set, and the device state checked.  If the device has been
 2283 // powered down, it is powered up again.
 2284 // The tickle with parameter kIOPMSubclassPolicy is ignored here and
 2285 // should be intercepted by a subclass.
 2286 //*********************************************************************************
 2287 
 2288 bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber )
 2289 {
 2290         IOPMRequest *   request;
 2291         bool                    noPowerChange = true;
 2292 
 2293     if ( initialized && stateNumber && (type == kIOPMSuperclassPolicy1) )
 2294         {
 2295         IOLockLock(fActivityLock);
 2296 
 2297                 // Record device activity for the idle timer handler.
 2298 
 2299         fDeviceActive = true;
 2300         clock_get_uptime(&fDeviceActiveTimestamp);
 2301 
 2302                 // Record the last tickle power state.
 2303                 // This helps to filter out redundant tickles as
 2304                 // this function may be called from the data path.
 2305 
 2306                 if (fActivityTicklePowerState < (long)stateNumber)
 2307                 {
 2308                         fActivityTicklePowerState = stateNumber;
 2309                         noPowerChange = false;
 2310 
 2311                         request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
 2312                         if (request)
 2313                         {
 2314                                 request->fArg0 = (void *) stateNumber;  // power state
 2315                                 request->fArg1 = (void *) true;                 // power rise
 2316                                 submitPMRequest(request);
 2317                         }
 2318                 }
 2319 
 2320                 IOLockUnlock(fActivityLock);
 2321         }
 2322 
 2323         // Returns false if the activityTickle might cause a transition to a
 2324         // higher powered state, true otherwise.
 2325 
 2326     return noPowerChange;
 2327 }
 2328 
 2329 //*********************************************************************************
 2330 // [public virtual] setIdleTimerPeriod
 2331 //
 2332 // A subclass policy-maker is going to use our standard idleness
 2333 // detection service.  Make a command queue and an idle timer and
 2334 // connect them to the power management workloop.  Finally,
 2335 // start the timer.
 2336 //*********************************************************************************
 2337 
 2338 IOReturn IOService::setIdleTimerPeriod ( unsigned long period )
 2339 {
 2340         IOWorkLoop * wl = getPMworkloop();
 2341 
 2342     if (!initialized || !wl)
 2343                 return IOPMNotYetInitialized;
 2344 
 2345     OUR_PMLog(PMsetIdleTimerPeriod, period, 0);
 2346 
 2347     fIdleTimerPeriod = period;
 2348 
 2349     if ( period > 0 )
 2350     {
 2351         // make the timer event
 2352         if ( fIdleTimerEventSource == NULL )
 2353         {
 2354                         IOTimerEventSource * timerSrc;
 2355 
 2356                         timerSrc = IOTimerEventSource::timerEventSource(
 2357                                 this, PM_idle_timer_expired);
 2358                         
 2359             if (timerSrc && (wl->addEventSource(timerSrc) != kIOReturnSuccess))
 2360                         {
 2361                                 timerSrc->release();
 2362                                 timerSrc = 0;
 2363                         }
 2364 
 2365             fIdleTimerEventSource = timerSrc;
 2366         }
 2367 
 2368         start_PM_idle_timer();
 2369     }
 2370     return IOPMNoErr;
 2371 }
 2372 
 2373 //******************************************************************************
 2374 // [public virtual] nextIdleTimeout
 2375 //
 2376 // Returns how many "seconds from now" the device should idle into its
 2377 // next lowest power state.
 2378 //******************************************************************************
 2379 
 2380 SInt32 IOService::nextIdleTimeout(
 2381     AbsoluteTime currentTime,
 2382     AbsoluteTime lastActivity, 
 2383     unsigned int powerState)
 2384 {
 2385     AbsoluteTime                        delta;
 2386     UInt64                              delta_ns;
 2387     SInt32                              delta_secs;
 2388     SInt32                              delay_secs;
 2389 
 2390     // Calculate time difference using funky macro from clock.h.
 2391     delta = currentTime;
 2392     SUB_ABSOLUTETIME(&delta, &lastActivity);
 2393     
 2394     // Figure it in seconds.
 2395     absolutetime_to_nanoseconds(delta, &delta_ns);
 2396     delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
 2397 
 2398     // Be paranoid about delta somehow exceeding timer period.
 2399     if (delta_secs < (int) fIdleTimerPeriod )
 2400         delay_secs = (int) fIdleTimerPeriod - delta_secs;
 2401     else
 2402         delay_secs = (int) fIdleTimerPeriod;
 2403     
 2404     return (SInt32)delay_secs;
 2405 }
 2406 
 2407 //******************************************************************************
 2408 // [public virtual] start_PM_idle_timer
 2409 //
 2410 // The parameter is a pointer to us.  Use it to call our timeout method.
 2411 //******************************************************************************
 2412 
 2413 void IOService::start_PM_idle_timer ( void )
 2414 {
 2415     static const int                    maxTimeout = 100000;
 2416     static const int                    minTimeout = 1;
 2417     AbsoluteTime                        uptime;
 2418     SInt32                              idle_in = 0;
 2419 
 2420         if (!initialized || !fIdleTimerEventSource)
 2421                 return;
 2422 
 2423     IOLockLock(fActivityLock);
 2424 
 2425     clock_get_uptime(&uptime);
 2426     
 2427     // Subclasses may modify idle sleep algorithm
 2428     idle_in = nextIdleTimeout(uptime, fDeviceActiveTimestamp, fCurrentPowerState);
 2429 
 2430     // Check for out-of range responses
 2431     if (idle_in > maxTimeout)
 2432     {
 2433         // use standard implementation
 2434         idle_in = IOService::nextIdleTimeout(uptime,
 2435                         fDeviceActiveTimestamp,
 2436                         fCurrentPowerState);
 2437     } else if (idle_in < minTimeout) {
 2438         idle_in = fIdleTimerPeriod;
 2439     }
 2440 
 2441     IOLockUnlock(fActivityLock);
 2442 
 2443         fIdleTimerEventSource->setTimeout(idle_in, NSEC_PER_SEC);
 2444 }
 2445 
 2446 //*********************************************************************************
 2447 // [private] PM_idle_timer_expired
 2448 //
 2449 // The parameter is a pointer to us.  Use it to call our timeout method.
 2450 //*********************************************************************************
 2451 
 2452 void PM_idle_timer_expired ( OSObject * ourSelves, IOTimerEventSource * )
 2453 {
 2454     ((IOService *)ourSelves)->PM_idle_timer_expiration();
 2455 }
 2456 
 2457 //*********************************************************************************
 2458 // [public virtual] PM_idle_timer_expiration
 2459 //
 2460 // The idle timer has expired.  If there has been activity since the last
 2461 // expiration, just restart the timer and return.  If there has not been
 2462 // activity, switch to the next lower power state and restart the timer.
 2463 //*********************************************************************************
 2464 
 2465 void IOService::PM_idle_timer_expiration ( void )
 2466 {
 2467         IOPMRequest *   request;
 2468         bool                    restartTimer = true;
 2469 
 2470     if ( !initialized || !fIdleTimerPeriod )
 2471         return;
 2472 
 2473         IOLockLock(fActivityLock);
 2474 
 2475         // Check for device activity (tickles) over last timer period.
 2476 
 2477         if (fDeviceActive)
 2478         {
 2479                 // Device was active - do not drop power, restart timer.
 2480                 fDeviceActive = false;
 2481         }
 2482         else
 2483         {
 2484                 // No device activity - drop power state by one level.
 2485                 // Decrement the cached tickle power state when possible.
 2486                 // This value may be (-1) before activityTickle() is called,
 2487                 // but the power drop request must be issued regardless.
 2488 
 2489                 if (fActivityTicklePowerState > 0)
 2490                 {
 2491                         fActivityTicklePowerState--;
 2492                 }
 2493 
 2494                 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
 2495                 if (request)
 2496                 {
 2497                         request->fArg0 = (void *) 0;            // power state (irrelevant)
 2498                         request->fArg1 = (void *) false;        // power drop
 2499                         submitPMRequest( request );
 2500 
 2501                         // Do not restart timer until after the tickle request has been
 2502                         // processed.
 2503 
 2504                         restartTimer = false;
 2505                 }
 2506     }
 2507 
 2508         IOLockUnlock(fActivityLock);
 2509 
 2510         if (restartTimer)
 2511                 start_PM_idle_timer();
 2512 }
 2513 
 2514 //*********************************************************************************
 2515 // [public virtual] command_received
 2516 //
 2517 //*********************************************************************************
 2518 
 2519 void IOService::command_received ( void *statePtr , void *, void * , void * )
 2520 {
 2521 }
 2522 
 2523 //*********************************************************************************
 2524 // [public virtual] setAggressiveness
 2525 //
 2526 // Pass on the input parameters to all power domain children. All those which are
 2527 // power domains will pass it on to their children, etc.
 2528 //*********************************************************************************
 2529 
 2530 IOReturn IOService::setAggressiveness ( unsigned long type, unsigned long newLevel )
 2531 {
 2532     OSIterator *                iter;
 2533     OSObject *                  next;
 2534     IOPowerConnection * connection;
 2535     IOService *                 child;
 2536 
 2537     if (!initialized)
 2538                 return IOPMNotYetInitialized;
 2539 
 2540     if (getPMRootDomain() == this)
 2541         OUR_PMLog(kPMLogSetAggressiveness, type, newLevel);
 2542 
 2543     if ( type <= kMaxType )
 2544     {
 2545         fAggressivenessValue[type] = newLevel;
 2546         fAggressivenessValid[type]  = true;
 2547     }
 2548 
 2549     iter = getChildIterator(gIOPowerPlane);
 2550     if ( iter )
 2551     {
 2552         while ( (next = iter->getNextObject()) )
 2553         {
 2554             if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
 2555             {
 2556                                 if (connection->getReadyFlag() == false)
 2557                                 {
 2558                                         PM_CONNECT("[%s] %s: connection not ready\n",
 2559                                                 getName(), __FUNCTION__);
 2560                                         continue;
 2561                                 }
 2562 
 2563                 child = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
 2564                 if ( child )
 2565                 {
 2566                     child->setAggressiveness(type, newLevel);
 2567                     child->release();
 2568                 }
 2569             }
 2570         }
 2571         iter->release();
 2572     }
 2573 
 2574     return IOPMNoErr;
 2575 }
 2576 
 2577 //*********************************************************************************
 2578 // [public virtual] getAggressiveness
 2579 //
 2580 // Called by the user client.
 2581 //*********************************************************************************
 2582 
 2583 IOReturn IOService::getAggressiveness ( unsigned long type, unsigned long * currentLevel )
 2584 {
 2585     if ( !initialized || (type > kMaxType) )
 2586         return kIOReturnBadArgument;
 2587 
 2588     if ( !fAggressivenessValid[type] )
 2589         return kIOReturnInvalid;
 2590  
 2591     *currentLevel = fAggressivenessValue[type];
 2592 
 2593     return kIOReturnSuccess;
 2594 }
 2595 
 2596 //*********************************************************************************
 2597 // [public] getPowerState
 2598 //
 2599 //*********************************************************************************
 2600 
 2601 UInt32 IOService::getPowerState ( void )
 2602 {
 2603     if (!initialized)
 2604         return 0;
 2605 
 2606     return fCurrentPowerState;
 2607 }
 2608 
 2609 //*********************************************************************************
 2610 // [public virtual] systemWake
 2611 //
 2612 // Pass this to all power domain children. All those which are
 2613 // power domains will pass it on to their children, etc.
 2614 //*********************************************************************************
 2615 
 2616 IOReturn IOService::systemWake ( void )
 2617 {
 2618     OSIterator *                iter;
 2619     OSObject *                  next;
 2620     IOPowerConnection * connection;
 2621     IOService *                 theChild;
 2622 
 2623     OUR_PMLog(kPMLogSystemWake, 0, 0);
 2624 
 2625     iter = getChildIterator(gIOPowerPlane);
 2626     if ( iter )
 2627     {
 2628         while ( (next = iter->getNextObject()) )
 2629         {
 2630             if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
 2631             {
 2632                                 if (connection->getReadyFlag() == false)
 2633                                 {
 2634                                         PM_CONNECT("[%s] %s: connection not ready\n",
 2635                                                 getName(), __FUNCTION__);
 2636                                         continue;
 2637                                 }
 2638 
 2639                 theChild = (IOService *)connection->copyChildEntry(gIOPowerPlane);
 2640                 if ( theChild )
 2641                 {
 2642                         theChild->systemWake();
 2643                     theChild->release();
 2644                 }
 2645             }
 2646         }
 2647         iter->release();
 2648     }
 2649 
 2650     if ( fControllingDriver != NULL )
 2651     {
 2652         if ( fControllingDriver->didYouWakeSystem() )
 2653         {
 2654             makeUsable();
 2655         }
 2656     }
 2657 
 2658     return IOPMNoErr;
 2659 }
 2660 
 2661 //*********************************************************************************
 2662 // [public virtual] temperatureCriticalForZone
 2663 //*********************************************************************************
 2664 
 2665 IOReturn IOService::temperatureCriticalForZone ( IOService * whichZone )
 2666 {
 2667     IOService * theParent;
 2668     IOService * theNub;
 2669     
 2670     OUR_PMLog(kPMLogCriticalTemp, 0, 0);
 2671 
 2672     if ( inPlane(gIOPowerPlane) && !fWeAreRoot )
 2673     {
 2674         theNub = (IOService *)copyParentEntry(gIOPowerPlane);
 2675         if ( theNub )
 2676         {
 2677             theParent = (IOService *)theNub->copyParentEntry(gIOPowerPlane);
 2678             theNub->release();
 2679             if ( theParent )
 2680             {
 2681                 theParent->temperatureCriticalForZone(whichZone);
 2682                 theParent->release();
 2683             }
 2684         }
 2685     }
 2686     return IOPMNoErr;
 2687 }
 2688 
 2689 //*********************************************************************************
 2690 // [public] powerOverrideOnPriv
 2691 //*********************************************************************************
 2692 
 2693 IOReturn IOService::powerOverrideOnPriv ( void )
 2694 {
 2695         IOPMRequest * request;
 2696 
 2697     if (!initialized)
 2698                 return IOPMNotYetInitialized;
 2699 
 2700         if (gIOPMWorkLoop->inGate())
 2701         {
 2702                 fDeviceOverrides = true;
 2703                 return IOPMNoErr;
 2704         }
 2705 
 2706         request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv );
 2707         if (!request)
 2708                 return kIOReturnNoMemory;
 2709 
 2710         submitPMRequest( request );
 2711     return IOPMNoErr;
 2712 }
 2713 
 2714 //*********************************************************************************
 2715 // [public] powerOverrideOffPriv
 2716 //*********************************************************************************
 2717 
 2718 IOReturn IOService::powerOverrideOffPriv ( void )
 2719 {
 2720         IOPMRequest * request;
 2721 
 2722     if (!initialized)
 2723                 return IOPMNotYetInitialized;
 2724 
 2725         if (gIOPMWorkLoop->inGate())
 2726         {
 2727                 fDeviceOverrides = false;
 2728                 return IOPMNoErr;
 2729         }
 2730 
 2731         request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv );
 2732         if (!request)
 2733                 return kIOReturnNoMemory;
 2734 
 2735         submitPMRequest( request );
 2736     return IOPMNoErr;
 2737 }
 2738 
 2739 //*********************************************************************************
 2740 // [private] handlePowerOverrideChanged
 2741 //*********************************************************************************
 2742 
 2743 void IOService::handlePowerOverrideChanged ( IOPMRequest * request )
 2744 {
 2745         PM_ASSERT_IN_GATE();
 2746         if (request->getType() == kIOPMRequestTypePowerOverrideOnPriv)
 2747         {
 2748                 OUR_PMLog(kPMLogOverrideOn, 0, 0);
 2749                 fDeviceOverrides = true;
 2750     }
 2751         else
 2752         {
 2753                 OUR_PMLog(kPMLogOverrideOff, 0, 0);
 2754                 fDeviceOverrides = false;
 2755         }
 2756 
 2757         if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState)
 2758         {
 2759                 computeDesiredState();
 2760                 changeState();
 2761         }
 2762 }
 2763 
 2764 //*********************************************************************************
 2765 // [private] enqueuePowerChange
 2766 //*********************************************************************************
 2767 
 2768 IOReturn IOService::enqueuePowerChange ( 
 2769     unsigned long               flags,  
 2770     unsigned long               whatStateOrdinal, 
 2771     unsigned long               domainState, 
 2772     IOPowerConnection * whichParent, 
 2773     unsigned long               singleParentState )
 2774 {
 2775         changeNoteItem          changeNote;
 2776         IOPMPowerState *        powerStatePtr;
 2777 
 2778         PM_ASSERT_IN_GATE();
 2779         assert( fMachineState == kIOPM_Finished );
 2780     assert( whatStateOrdinal < fNumberOfPowerStates );
 2781 
 2782     if (whatStateOrdinal >= fNumberOfPowerStates)
 2783         return IOPMAckImplied;
 2784 
 2785         powerStatePtr = &fPowerStates[whatStateOrdinal];
 2786 
 2787     // Initialize the change note
 2788     changeNote.flags                 = flags;
 2789     changeNote.newStateNumber        = whatStateOrdinal;
 2790     changeNote.outputPowerCharacter  = powerStatePtr->outputPowerCharacter;
 2791     changeNote.inputPowerRequirement = powerStatePtr->inputPowerRequirement;
 2792     changeNote.capabilityFlags       = powerStatePtr->capabilityFlags;
 2793     changeNote.parent                = NULL;
 2794 
 2795     if (flags & IOPMParentInitiated )
 2796     {
 2797         changeNote.domainState       = domainState;
 2798         changeNote.parent            = whichParent;
 2799         changeNote.singleParentState = singleParentState;
 2800     }
 2801 
 2802         if (flags & IOPMWeInitiated )
 2803         {
 2804                 start_our_change(&changeNote);
 2805                 return 0;
 2806         }
 2807         else
 2808         {
 2809                 return start_parent_change(&changeNote);
 2810         }
 2811 }
 2812 
 2813 //*********************************************************************************
 2814 // [private] notifyInterestedDrivers
 2815 //*********************************************************************************
 2816 
 2817 bool IOService::notifyInterestedDrivers ( void )
 2818 {
 2819         IOPMinformee *          informee;
 2820         IOPMinformeeList *      list = fInterestedDrivers;
 2821         DriverCallParam *       param;
 2822         IOItemCount                     count;
 2823 
 2824         PM_ASSERT_IN_GATE();
 2825         assert( fDriverCallBusy == false );
 2826         assert( fDriverCallParamCount == 0 );
 2827         assert( fHeadNotePendingAcks == 0 );
 2828 
 2829         count = list->numberOfItems();
 2830         if (!count)
 2831                 goto done;      // no interested drivers
 2832 
 2833         // Allocate an array of interested drivers and their return values
 2834         // for the callout thread. Everything else is still "owned" by the
 2835         // PM work loop, which can run to process acknowledgePowerChange()
 2836         // responses.
 2837 
 2838         param = (DriverCallParam *) fDriverCallParamPtr;
 2839         if (count > fDriverCallParamSlots)
 2840         {
 2841                 if (fDriverCallParamSlots)
 2842                 {
 2843                         assert(fDriverCallParamPtr);
 2844                         IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
 2845                         fDriverCallParamPtr = 0;
 2846                         fDriverCallParamSlots = 0;
 2847                 }
 2848 
 2849                 param = IONew(DriverCallParam, count);
 2850                 if (!param)
 2851                         goto done;      // no memory
 2852 
 2853                 fDriverCallParamPtr   = (void *) param;
 2854                 fDriverCallParamSlots = count;
 2855         }
 2856 
 2857         informee = list->firstInList();
 2858         assert(informee);
 2859         for (IOItemCount i = 0; i < count; i++)
 2860         {
 2861                 informee->timer = -1;
 2862                 param[i].Target = informee;
 2863                 informee->retain();
 2864         informee = list->nextInList( informee );
 2865         }
 2866 
 2867         fDriverCallParamCount = count;
 2868         fHeadNotePendingAcks = count;
 2869 
 2870         // Machine state will be blocked pending callout thread completion.
 2871 
 2872         PM_LOCK();
 2873         fDriverCallBusy = true;
 2874         PM_UNLOCK();
 2875         thread_call_enter( fDriverCallEntry );
 2876         return true;
 2877 
 2878 done:
 2879         // no interested drivers or did not schedule callout thread due to error.
 2880         return false;
 2881 }
 2882 
 2883 //*********************************************************************************
 2884 // [private] notifyInterestedDriversDone
 2885 //*********************************************************************************
 2886 
 2887 void IOService::notifyInterestedDriversDone ( void )
 2888 {
 2889         IOPMinformee *          informee;
 2890         IOItemCount                     count;
 2891         DriverCallParam *       param;
 2892         IOReturn                        result;
 2893 
 2894         PM_ASSERT_IN_GATE();
 2895         param = (DriverCallParam *) fDriverCallParamPtr;
 2896         count = fDriverCallParamCount;
 2897 
 2898         assert( fDriverCallBusy == false );
 2899         assert( fMachineState == kIOPM_DriverThreadCallDone );
 2900 
 2901         if (param && count)
 2902         {
 2903                 for (IOItemCount i = 0; i < count; i++, param++)
 2904                 {
 2905                         informee = (IOPMinformee *) param->Target;
 2906                         result   = param->Result;
 2907 
 2908                         if ((result == IOPMAckImplied) || (result < 0))
 2909                         {
 2910                                 // child return IOPMAckImplied
 2911                                 informee->timer = 0;
 2912                                 fHeadNotePendingAcks--;
 2913                         }
 2914                         else if (informee->timer)
 2915                         {
 2916                 assert(informee->timer == -1);
 2917 
 2918                 // Driver has not acked, and has returned a positive result.
 2919                 // Enforce a minimum permissible timeout value.
 2920                 // Make the min value large enough so timeout is less likely
 2921                 // to occur if a driver misinterpreted that the return value
 2922                 // should be in microsecond units.  And make it large enough
 2923                 // to be noticeable if a driver neglects to ack.
 2924 
 2925                 if (result < kMinAckTimeoutTicks)
 2926                     result = kMinAckTimeoutTicks;
 2927 
 2928                 informee->timer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
 2929                         }
 2930                         // else, child has already acked or driver has removed interest,
 2931             // and head_note_pendingAcks decremented.
 2932                         // informee may have been removed from the interested drivers list,
 2933             // thus the informee must be retained across the callout.
 2934 
 2935                         informee->release();
 2936                 }
 2937 
 2938                 fDriverCallParamCount = 0;
 2939 
 2940                 if ( fHeadNotePendingAcks )
 2941                 {
 2942                         OUR_PMLog(kPMLogStartAckTimer, 0, 0);
 2943                         start_ack_timer();
 2944                 }
 2945         }
 2946 
 2947         // Hop back to original machine state path (from notifyAll)
 2948         fMachineState = fNextMachineState;
 2949 
 2950         notifyChildren();
 2951 }
 2952 
 2953 //*********************************************************************************
 2954 // [private] notifyChildren
 2955 //*********************************************************************************
 2956 
 2957 void IOService::notifyChildren ( void )
 2958 {
 2959     OSIterator *                iter;
 2960     OSObject *                  next;
 2961     IOPowerConnection * connection;
 2962         OSArray *                       children = 0;
 2963 
 2964         if (fStrictTreeOrder)
 2965                 children = OSArray::withCapacity(8);
 2966 
 2967     // Sum child power consumption in notifyChild()
 2968     fPowerStates[fHeadNoteState].staticPower = 0;
 2969 
 2970     iter = getChildIterator(gIOPowerPlane);
 2971     if ( iter )
 2972     {
 2973         while ((next = iter->getNextObject()))
 2974         {
 2975             if ((connection = OSDynamicCast(IOPowerConnection, next)))
 2976             {
 2977                                 if (connection->getReadyFlag() == false)
 2978                                 {
 2979                                         PM_CONNECT("[%s] %s: connection not ready\n",
 2980                                                 getName(), __FUNCTION__);
 2981                                         continue;
 2982                                 }
 2983 
 2984                                 if (children)
 2985                                         children->setObject( connection );
 2986                                 else
 2987                                         notifyChild( connection,
 2988                                                 fDriverCallReason == kDriverCallInformPreChange );
 2989                         }
 2990         }
 2991         iter->release();
 2992     }
 2993 
 2994         if (children)
 2995         {
 2996                 if (children->getCount() == 0)
 2997                 {
 2998                         children->release();
 2999                         children = 0;
 3000                 }
 3001                 else
 3002                 {
 3003                         assert(fNotifyChildArray == 0);
 3004                         fNotifyChildArray = children;
 3005                         fNextMachineState = fMachineState;
 3006                         fMachineState     = kIOPM_NotifyChildrenDone;
 3007                 }               
 3008         }
 3009 }
 3010 
 3011 //*********************************************************************************
 3012 // [private] notifyChildrenDone
 3013 //*********************************************************************************
 3014 
 3015 void IOService::notifyChildrenDone ( void )
 3016 {
 3017         PM_ASSERT_IN_GATE();
 3018         assert(fNotifyChildArray);
 3019         assert(fMachineState == kIOPM_NotifyChildrenDone);
 3020 
 3021         // Interested drivers have all acked (if any), ack timer stopped.
 3022         // Notify one child, wait for it's ack, then repeat for next child.
 3023         // This is a workaround for some drivers with multiple instances at
 3024         // the same branch in the power tree, but the driver is slow to power
 3025         // up unless the tree ordering is observed. Problem observed only on
 3026         // system wake, not on system sleep.
 3027         //
 3028         // We have the ability to power off in reverse child index order.
 3029         // That works nicely on some machines, but not on all HW configs.
 3030 
 3031         if (fNotifyChildArray->getCount())
 3032         {
 3033                 IOPowerConnection *     connection;
 3034                 connection = (IOPowerConnection *) fNotifyChildArray->getObject(0);
 3035                 fNotifyChildArray->removeObject(0);
 3036                 notifyChild( connection, fDriverCallReason == kDriverCallInformPreChange );
 3037         }
 3038         else
 3039         {
 3040                 fNotifyChildArray->release();
 3041                 fNotifyChildArray = 0;
 3042                 fMachineState = fNextMachineState;
 3043         }
 3044 }
 3045 
 3046 //*********************************************************************************
 3047 // [private] notifyAll
 3048 //*********************************************************************************
 3049 
 3050 IOReturn IOService::notifyAll ( bool is_prechange )
 3051 {
 3052         // Save the next machine_state to be restored by notifyInterestedDriversDone()
 3053 
 3054         PM_ASSERT_IN_GATE();
 3055         fNextMachineState = fMachineState;
 3056         fMachineState     = kIOPM_DriverThreadCallDone;
 3057         fDriverCallReason = is_prechange ?
 3058                                                 kDriverCallInformPreChange : kDriverCallInformPostChange;
 3059 
 3060         if (!notifyInterestedDrivers())
 3061                 notifyInterestedDriversDone();
 3062 
 3063         return IOPMWillAckLater;
 3064 }
 3065 
 3066 //*********************************************************************************
 3067 // [private, static] pmDriverCallout
 3068 //
 3069 // Thread call context
 3070 //*********************************************************************************
 3071 
 3072 IOReturn IOService::actionDriverCalloutDone (
 3073         OSObject * target,
 3074         void * arg0, void * arg1,
 3075         void * arg2, void * arg3 )
 3076 {
 3077         IOServicePM * pwrMgt = (IOServicePM *) arg0;
 3078 
 3079         PM_LOCK();
 3080         fDriverCallBusy = false;
 3081         PM_UNLOCK();
 3082 
 3083         if (gIOPMReplyQueue)
 3084                 gIOPMReplyQueue->signalWorkAvailable();
 3085 
 3086         return kIOReturnSuccess;
 3087 }
 3088 
 3089 void IOService::pmDriverCallout ( IOService * from )
 3090 {
 3091         assert(from);
 3092         switch (from->fDriverCallReason)
 3093         {
 3094                 case kDriverCallSetPowerState:
 3095                         from->driverSetPowerState();
 3096                         break;
 3097 
 3098                 case kDriverCallInformPreChange:
 3099                 case kDriverCallInformPostChange:
 3100                         from->driverInformPowerChange();
 3101                         break;
 3102 
 3103                 default:
 3104                         IOPanic("IOService::pmDriverCallout bad machine state");
 3105         }
 3106 
 3107         gIOPMWorkLoop->runAction(actionDriverCalloutDone,
 3108                 /* target */ from,
 3109                 /* arg0   */ (void *) from->pwrMgt );
 3110 }
 3111 
 3112 //*********************************************************************************
 3113 // [private] driverSetPowerState
 3114 //
 3115 // Thread call context
 3116 //*********************************************************************************
 3117 
 3118 void IOService::driverSetPowerState ( void )
 3119 {
 3120         IOService *                     driver;
 3121         unsigned long           powerState;
 3122         DriverCallParam *       param;
 3123         IOReturn                        result;
 3124     AbsoluteTime        end;
 3125 
 3126         assert( fDriverCallBusy );
 3127         param = (DriverCallParam *) fDriverCallParamPtr;
 3128         assert( param );
 3129         assert( fDriverCallParamCount == 1 );
 3130 
 3131         driver = fControllingDriver;
 3132         powerState = fHeadNoteState;
 3133 
 3134         if (!fWillPMStop)
 3135         {
 3136                 OUR_PMLog(          kPMLogProgramHardware, (UInt32) this, powerState);
 3137         clock_get_uptime(&fDriverCallStartTime);
 3138                 result = driver->setPowerState( powerState, this );
 3139         clock_get_uptime(&end);
 3140                 OUR_PMLog((UInt32) -kPMLogProgramHardware, (UInt32) this, (UInt32) result);
 3141 
 3142 #if LOG_SETPOWER_TIMES
 3143         if ((result == IOPMAckImplied) || (result < 0))
 3144         {
 3145             uint64_t    nsec;
 3146 
 3147             SUB_ABSOLUTETIME(&end, &fDriverCallStartTime);
 3148             absolutetime_to_nanoseconds(end, &nsec);
 3149             if (nsec > LOG_SETPOWER_TIMES)
 3150                 PM_DEBUG("%s::setPowerState(%p, %lu -> %lu) took %d ms\n",
 3151                     fName, this, fCurrentPowerState, powerState, NS_TO_MS(nsec));
 3152         }
 3153 #endif
 3154         }
 3155         else
 3156                 result = kIOPMAckImplied;
 3157 
 3158         param->Result = result;
 3159 }
 3160 
 3161 //*********************************************************************************
 3162 // [private] driverInformPowerChange
 3163 //
 3164 // Thread call context
 3165 //*********************************************************************************
 3166 
 3167 void IOService::driverInformPowerChange ( void )
 3168 {
 3169         IOItemCount                     count;
 3170         IOPMinformee *          informee;
 3171         IOService *                     driver;
 3172         IOReturn                        result;
 3173         IOPMPowerFlags          powerFlags;
 3174         unsigned long           powerState;
 3175         DriverCallParam *       param;
 3176     AbsoluteTime        end;
 3177 
 3178         assert( fDriverCallBusy );
 3179         param = (DriverCallParam *) fDriverCallParamPtr;
 3180         count = fDriverCallParamCount;
 3181         assert( count && param );
 3182 
 3183         powerFlags = fHeadNoteCapabilityFlags;
 3184         powerState = fHeadNoteState;
 3185 
 3186         for (IOItemCount i = 0; i < count; i++)
 3187         {
 3188                 informee = (IOPMinformee *) param->Target;
 3189                 driver   = informee->whatObject;
 3190 
 3191                 if (!fWillPMStop && informee->active)
 3192                 {
 3193                         if (fDriverCallReason == kDriverCallInformPreChange)
 3194                         {
 3195                                 OUR_PMLog(kPMLogInformDriverPreChange, (UInt32) this, powerState);
 3196                 clock_get_uptime(&informee->startTime);
 3197                                 result = driver->powerStateWillChangeTo(powerFlags, powerState, this);
 3198                 clock_get_uptime(&end);
 3199                                 OUR_PMLog((UInt32)-kPMLogInformDriverPreChange, (UInt32) this, result);
 3200                         }
 3201                         else
 3202                         {
 3203                                 OUR_PMLog(kPMLogInformDriverPostChange, (UInt32) this, powerState);
 3204                 clock_get_uptime(&informee->startTime);
 3205                                 result = driver->powerStateDidChangeTo(powerFlags, powerState, this);
 3206                 clock_get_uptime(&end);
 3207                                 OUR_PMLog((UInt32)-kPMLogInformDriverPostChange, (UInt32) this, result);
 3208                         }
 3209 
 3210 #if LOG_SETPOWER_TIMES
 3211             if ((result == IOPMAckImplied) || (result < 0))
 3212             {
 3213                 uint64_t nsec;
 3214 
 3215                 SUB_ABSOLUTETIME(&end, &informee->startTime);
 3216                 absolutetime_to_nanoseconds(end, &nsec);
 3217                 if (nsec > LOG_SETPOWER_TIMES)
 3218                     PM_DEBUG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) took %d ms\n",
 3219                         driver->getName(),
 3220                         (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
 3221                         driver, fName, fCurrentPowerState, powerState, NS_TO_MS(nsec));
 3222             }
 3223 #endif
 3224                 }
 3225                 else
 3226                         result = kIOPMAckImplied;
 3227 
 3228                 param->Result = result;
 3229                 param++;
 3230         }
 3231 }
 3232 
 3233 //*********************************************************************************
 3234 // [private] notifyChild
 3235 //
 3236 // Notify a power domain child of an upcoming power change.
 3237 // If the object acknowledges the current change, we return TRUE.
 3238 //*********************************************************************************
 3239 
 3240 bool IOService::notifyChild ( IOPowerConnection * theNub, bool is_prechange )
 3241 {
 3242     IOReturn            k = IOPMAckImplied;
 3243     unsigned long       childPower;
 3244     IOService *         theChild;
 3245         IOPMRequest *   childRequest;
 3246         int                             requestType;
 3247 
 3248         PM_ASSERT_IN_GATE();
 3249     theChild = (IOService *)(theNub->copyChildEntry(gIOPowerPlane));
 3250     if (!theChild)
 3251     {
 3252                 assert(false);
 3253         return true;
 3254     }
 3255 
 3256     // Unless the child handles the notification immediately and returns
 3257     // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
 3258         fHeadNotePendingAcks++;
 3259     theNub->setAwaitingAck(true);
 3260     
 3261         requestType = is_prechange ?
 3262                 kIOPMRequestTypePowerDomainWillChange :
 3263                 kIOPMRequestTypePowerDomainDidChange;
 3264 
 3265         childRequest = acquirePMRequest( theChild, requestType );
 3266         if (childRequest)
 3267         {
 3268                 childRequest->fArg0 = (void *) fHeadNoteOutputFlags;
 3269                 childRequest->fArg1 = (void *) theNub;
 3270                 childRequest->fArg2 = (void *) (fHeadNoteState < fCurrentPowerState);
 3271                 theChild->submitPMRequest( childRequest );
 3272                 k = IOPMWillAckLater;
 3273         }
 3274         else
 3275         {
 3276                 k = IOPMAckImplied;
 3277                 fHeadNotePendingAcks--;  
 3278                 theNub->setAwaitingAck(false);
 3279         childPower = theChild->currentPowerConsumption();
 3280         if ( childPower == kIOPMUnknown )
 3281         {
 3282             fPowerStates[fHeadNoteState].staticPower = kIOPMUnknown;
 3283         } else {
 3284             if ( fPowerStates[fHeadNoteState].staticPower != kIOPMUnknown )
 3285             {
 3286                 fPowerStates[fHeadNoteState].staticPower += childPower;
 3287             }
 3288         }
 3289     }
 3290 
 3291     theChild->release();
 3292         return (k == IOPMAckImplied);
 3293 }
 3294 
 3295 //*********************************************************************************
 3296 // [private] OurChangeTellClientsPowerDown
 3297 //
 3298 // All registered applications and kernel clients have positively acknowledged our
 3299 // intention of lowering power.  Here we notify them all that we will definitely
 3300 // lower the power.  If we don't have to wait for any of them to acknowledge, we
 3301 // carry on by notifying interested drivers.  Otherwise, we do wait.
 3302 //*********************************************************************************
 3303 
 3304 void IOService::OurChangeTellClientsPowerDown ( void )
 3305 {
 3306     fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
 3307     tellChangeDown1(fHeadNoteState);
 3308 }
 3309 
 3310 //*********************************************************************************
 3311 // [private] OurChangeTellPriorityClientsPowerDown
 3312 //
 3313 // All registered applications and kernel clients have positively acknowledged our
 3314 // intention of lowering power.  Here we notify "priority" clients that we are
 3315 // lowering power.  If we don't have to wait for any of them to acknowledge, we
 3316 // carry on by notifying interested drivers.  Otherwise, we do wait.
 3317 //*********************************************************************************
 3318 
 3319 void IOService::OurChangeTellPriorityClientsPowerDown ( void )
 3320 {
 3321     fMachineState = kIOPM_OurChangeNotifyInterestedDriversWillChange;
 3322     tellChangeDown2(fHeadNoteState);
 3323 }
 3324 
 3325 //*********************************************************************************
 3326 // [private] OurChangeNotifyInterestedDriversWillChange
 3327 //
 3328 // All registered applications and kernel clients have acknowledged our notification
 3329 // that we are lowering power.  Here we notify interested drivers.  If we don't have
 3330 // to wait for any of them to acknowledge, we instruct our power driver to make the
 3331 // change. Otherwise, we do wait.
 3332 //*********************************************************************************
 3333 
 3334 void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
 3335 {
 3336     fMachineState = kIOPM_OurChangeSetPowerState;
 3337     notifyAll( true );
 3338 }
 3339 
 3340 //*********************************************************************************
 3341 // [private] OurChangeSetPowerState
 3342 //
 3343 // All interested drivers have acknowledged our pre-change notification of a power
 3344 // change we initiated.  Here we instruct our controlling driver to make
 3345 // the change to the hardware.  If it does so, we continue processing
 3346 // (waiting for settle and notifying interested parties post-change.)
 3347 // If it doesn't, we have to wait for it to acknowledge and then continue.
 3348 //*********************************************************************************
 3349 
 3350 void IOService::OurChangeSetPowerState ( void )
 3351 {
 3352     fNextMachineState = kIOPM_OurChangeWaitForPowerSettle;
 3353         fMachineState     = kIOPM_DriverThreadCallDone;
 3354         fDriverCallReason = kDriverCallSetPowerState;
 3355 
 3356         if (notifyControllingDriver() == false)
 3357                 notifyControllingDriverDone();
 3358 }
 3359 
 3360 //*********************************************************************************
 3361 // [private] OurChangeWaitForPowerSettle
 3362 //
 3363 // Our controlling driver has changed power state on the hardware
 3364 // during a power change we initiated.  Here we see if we need to wait
 3365 // for power to settle before continuing.  If not, we continue processing
 3366 // (notifying interested parties post-change).  If so, we wait and
 3367 // continue later.
 3368 //*********************************************************************************
 3369 
 3370 void IOService::OurChangeWaitForPowerSettle ( void )
 3371 {
 3372         fMachineState = kIOPM_OurChangeNotifyInterestedDriversDidChange;
 3373     fSettleTimeUS = compute_settle_time();
 3374     if ( fSettleTimeUS )
 3375     {
 3376                 startSettleTimer(fSettleTimeUS);
 3377         }
 3378 }
 3379 
 3380 //*********************************************************************************
 3381 // [private] OurChangeNotifyInterestedDriversDidChange
 3382 //
 3383 // Power has settled on a power change we initiated.  Here we notify
 3384 // all our interested parties post-change.  If they all acknowledge, we're
 3385 // done with this change note, and we can start on the next one.
 3386 // Otherwise we have to wait for acknowledgements and finish up later.
 3387 //*********************************************************************************
 3388 
 3389 void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
 3390 {
 3391     fMachineState = kIOPM_OurChangeFinish;
 3392     notifyAll(false);
 3393 }
 3394 
 3395 //*********************************************************************************
 3396 // [private] OurChangeFinish
 3397 //
 3398 // Power has settled on a power change we initiated, and
 3399 // all our interested parties have acknowledged.  We're
 3400 // done with this change note, and we can start on the next one.
 3401 //*********************************************************************************
 3402 
 3403 void IOService::OurChangeFinish ( void )
 3404 {
 3405     all_done();
 3406 }
 3407 
 3408 //*********************************************************************************
 3409 // [private] ParentDownTellPriorityClientsPowerDown
 3410 //
 3411 // All applications and kernel clients have been notified of a power lowering
 3412 // initiated by the parent and we had to wait for responses.  Here
 3413 // we notify any priority clients.  If they all ack, we continue with the power change.
 3414 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
 3415 //*********************************************************************************
 3416 
 3417 void IOService::ParentDownTellPriorityClientsPowerDown ( void )
 3418 {
 3419     fMachineState = kIOPM_ParentDownNotifyInterestedDriversWillChange;
 3420         tellChangeDown2(fHeadNoteState);
 3421 }
 3422 
 3423 //*********************************************************************************
 3424 // [private] ParentDownNotifyInterestedDriversWillChange
 3425 //
 3426 // All applications and kernel clients have been notified of a power lowering
 3427 // initiated by the parent and we had to wait for their responses.  Here we notify
 3428 // any interested drivers and power domain children.  If they all ack, we continue
 3429 // with the power change.
 3430 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
 3431 //*********************************************************************************
 3432 
 3433 void IOService::ParentDownNotifyInterestedDriversWillChange ( void )
 3434 {
 3435     fMachineState = kIOPM_ParentDownSetPowerState;
 3436         notifyAll( true );
 3437 }
 3438 
 3439 //*********************************************************************************
 3440 // [private] ParentDownSetPowerState
 3441 //
 3442 // We had to wait for it, but all parties have acknowledged our pre-change
 3443 // notification of a power lowering initiated by the parent.
 3444 // Here we instruct our controlling driver
 3445 // to put the hardware in the state it needs to be in when the domain is
 3446 // lowered.  If it does so, we continue processing
 3447 // (waiting for settle and acknowledging the parent.)
 3448 // If it doesn't, we have to wait for it to acknowledge and then continue.
 3449 //*********************************************************************************
 3450 
 3451 void IOService::ParentDownSetPowerState ( void )
 3452 {
 3453         fNextMachineState = kIOPM_ParentDownWaitForPowerSettle;
 3454         fMachineState     = kIOPM_DriverThreadCallDone;
 3455         fDriverCallReason = kDriverCallSetPowerState;
 3456 
 3457         if (notifyControllingDriver() == false)
 3458                 notifyControllingDriverDone();
 3459 }
 3460 
 3461 //*********************************************************************************
 3462 // [private] ParentDownWaitForPowerSettle
 3463 //
 3464 // Our controlling driver has changed power state on the hardware
 3465 // during a power change initiated by our parent.  We have had to wait
 3466 // for acknowledgement from interested parties, or we have had to wait
 3467 // for the controlling driver to change the state.  Here we see if we need
 3468 // to wait for power to settle before continuing.  If not, we continue
 3469 // processing (acknowledging our preparedness to the parent).
 3470 // If so, we wait and continue later.
 3471 //*********************************************************************************
 3472 
 3473 void IOService::ParentDownWaitForPowerSettle ( void )
 3474 {
 3475         fMachineState = kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange;
 3476     fSettleTimeUS = compute_settle_time();
 3477     if ( fSettleTimeUS )
 3478     {
 3479        startSettleTimer(fSettleTimeUS);
 3480         }
 3481 }
 3482 
 3483 //*********************************************************************************
 3484 // [private] ParentDownNotifyDidChangeAndAcknowledgeChange
 3485 //
 3486 // Power has settled on a power change initiated by our parent.  Here we
 3487 // notify interested parties.
 3488 //*********************************************************************************
 3489 
 3490 void IOService::ParentDownNotifyDidChangeAndAcknowledgeChange ( void )
 3491 {
 3492     fMachineState = kIOPM_ParentDownAcknowledgeChange;
 3493         notifyAll(false);       
 3494 }
 3495 
 3496 //*********************************************************************************
 3497 // [private] ParentDownAcknowledgeChange
 3498 //
 3499 // We had to wait for it, but all parties have acknowledged our post-change
 3500 // notification of a power  lowering initiated by the parent.
 3501 // Here we acknowledge the parent.
 3502 // We are done with this change note, and we can start on the next one.
 3503 //*********************************************************************************
 3504 
 3505 void IOService::ParentDownAcknowledgeChange ( void )
 3506 {
 3507     IORegistryEntry *   nub;
 3508     IOService *                 parent;
 3509 
 3510     nub = fHeadNoteParent;
 3511     nub->retain();
 3512     all_done();
 3513     parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
 3514     if ( parent )
 3515     {
 3516         parent->acknowledgePowerChange((IOService *)nub);
 3517         parent->release();
 3518     }
 3519     nub->release();
 3520 }
 3521 
 3522 //*********************************************************************************
 3523 // [private] ParentUpSetPowerState
 3524 //
 3525 // Our parent has informed us via powerStateDidChange that it has
 3526 // raised the power in our power domain, and we have had to wait
 3527 // for some interested party to acknowledge our notification.
 3528 //   Here we instruct our controlling
 3529 // driver to program the hardware to take advantage of the higher domain
 3530 // power.  If it does so, we continue processing
 3531 // (waiting for settle and notifying interested parties post-change.)
 3532 // If it doesn't, we have to wait for it to acknowledge and then continue.
 3533 //*********************************************************************************
 3534 
 3535 void IOService::ParentUpSetPowerState ( void )
 3536 {
 3537         fNextMachineState = kIOPM_ParentUpWaitForSettleTime;
 3538         fMachineState     = kIOPM_DriverThreadCallDone;
 3539         fDriverCallReason = kDriverCallSetPowerState;
 3540 
 3541         if (notifyControllingDriver() == false)
 3542                 notifyControllingDriverDone();
 3543 }
 3544 
 3545 //*********************************************************************************
 3546 // [private] ParentUpWaitForSettleTime
 3547 //
 3548 // Our controlling driver has changed power state on the hardware
 3549 // during a power raise initiated by the parent, but we had to wait for it.
 3550 // Here we see if we need to wait for power to settle before continuing.
 3551 // If not, we continue processing  (notifying interested parties post-change).
 3552 // If so, we wait and continue later.
 3553 //*********************************************************************************
 3554 
 3555 void IOService::ParentUpWaitForSettleTime ( void )
 3556 {
 3557         fMachineState = kIOPM_ParentUpNotifyInterestedDriversDidChange;
 3558     fSettleTimeUS = compute_settle_time();
 3559     if ( fSettleTimeUS )
 3560     {
 3561         startSettleTimer(fSettleTimeUS);
 3562     }
 3563 }
 3564 
 3565 //*********************************************************************************
 3566 // [private] ParentUpNotifyInterestedDriversDidChange
 3567 //
 3568 // Power has settled on a power raise initiated by the parent.
 3569 // Here we notify all our interested parties post-change.  If they all acknowledge,
 3570 // we're done with this change note, and we can start on the next one.
 3571 // Otherwise we have to wait for acknowledgements and finish up later.
 3572 //*********************************************************************************
 3573 
 3574 void IOService::ParentUpNotifyInterestedDriversDidChange ( void )
 3575 {
 3576     fMachineState = kIOPM_ParentUpAcknowledgePowerChange;
 3577         notifyAll(false);       
 3578 }
 3579 
 3580 //*********************************************************************************
 3581 // [private] ParentUpAcknowledgePowerChange
 3582 //
 3583 // All parties have acknowledged our post-change notification of a power
 3584 // raising initiated by the parent.  Here we acknowledge the parent.
 3585 // We are done with this change note, and we can start on the next one.
 3586 //*********************************************************************************
 3587 
 3588 void IOService::ParentUpAcknowledgePowerChange ( void )
 3589 {
 3590     IORegistryEntry *   nub;
 3591     IOService *                 parent;
 3592 
 3593     nub = fHeadNoteParent;
 3594     nub->retain();
 3595     all_done();
 3596     parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
 3597     if ( parent )
 3598     {
 3599         parent->acknowledgePowerChange((IOService *)nub);
 3600         parent->release();
 3601     }
 3602     nub->release();
 3603 }
 3604 
 3605 //*********************************************************************************
 3606 // [private] all_done
 3607 //
 3608 // A power change is complete, and the used post-change note is at
 3609 // the head of the queue.  Remove it and set myCurrentState to the result
 3610 // of the change.  Start up the next change in queue.
 3611 //*********************************************************************************
 3612 
 3613 void IOService::all_done ( void )
 3614 {
 3615     unsigned long       previous_state;
 3616 
 3617     fMachineState = kIOPM_Finished;
 3618 
 3619     // our power change
 3620     if ( fHeadNoteFlags & IOPMWeInitiated )
 3621     {
 3622         // could our driver switch to the new state?
 3623         if ( !( fHeadNoteFlags & IOPMNotDone) )
 3624         {
 3625                         // we changed, tell our parent
 3626                         if ( !fWeAreRoot )
 3627                         {
 3628                                 ask_parent(fHeadNoteState);
 3629                         }
 3630 
 3631             // yes, did power raise?
 3632             if ( fCurrentPowerState < fHeadNoteState )
 3633             {
 3634                 // yes, inform clients and apps
 3635                 tellChangeUp (fHeadNoteState);
 3636             }
 3637             previous_state = fCurrentPowerState;
 3638             // either way
 3639             fCurrentPowerState = fHeadNoteState;
 3640 #if PM_VARS_SUPPORT
 3641                         fPMVars->myCurrentState = fCurrentPowerState;
 3642 #endif
 3643             OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, 0);
 3644 
 3645             // inform subclass policy-maker
 3646             if (!fWillPMStop && fParentsKnowState)
 3647                 powerChangeDone(previous_state);
 3648             else
 3649                 PM_DEBUG("%s::powerChangeDone() skipped\n", getName());
 3650         }
 3651     }
 3652 
 3653     // parent's power change
 3654     if ( fHeadNoteFlags & IOPMParentInitiated)
 3655     {
 3656         if (((fHeadNoteFlags & IOPMDomainWillChange) && (fCurrentPowerState >= fHeadNoteState)) ||
 3657                         ((fHeadNoteFlags & IOPMDomainDidChange) && (fCurrentPowerState < fHeadNoteState)))
 3658         {
 3659             // did power raise?
 3660             if ( fCurrentPowerState < fHeadNoteState )
 3661             {
 3662                 // yes, inform clients and apps
 3663                 tellChangeUp (fHeadNoteState);
 3664             }
 3665             // either way
 3666             previous_state = fCurrentPowerState;
 3667             fCurrentPowerState = fHeadNoteState;
 3668 #if PM_VARS_SUPPORT
 3669                         fPMVars->myCurrentState = fCurrentPowerState;
 3670 #endif
 3671             fMaxCapability = fControllingDriver->maxCapabilityForDomainState(fHeadNoteDomainState);
 3672 
 3673             OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, 0);
 3674 
 3675             // inform subclass policy-maker
 3676             if (!fWillPMStop && fParentsKnowState)
 3677                 powerChangeDone(previous_state);
 3678             else
 3679                 PM_DEBUG("%s::powerChangeDone() skipped\n", getName());
 3680         }
 3681     }
 3682 
 3683     if (fCurrentPowerState < fNumberOfPowerStates)
 3684     {
 3685         const IOPMPowerState * powerStatePtr = &fPowerStates[fCurrentPowerState];
 3686 
 3687         fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
 3688         if (fCurrentCapabilityFlags & kIOPMStaticPowerValid)
 3689             fCurrentPowerConsumption = powerStatePtr->staticPower;
 3690     }
 3691 }
 3692 
 3693 //*********************************************************************************
 3694 // [public] settleTimerExpired
 3695 //
 3696 // Power has settled after our last change.  Notify interested parties that
 3697 // there is a new power state.
 3698 //*********************************************************************************
 3699 
 3700 void IOService::settleTimerExpired ( void )
 3701 {
 3702         fSettleTimeUS = 0;
 3703 }
 3704 
 3705 //*********************************************************************************
 3706 // [private] compute_settle_time
 3707 //
 3708 // Compute the power-settling delay in microseconds for the
 3709 // change from myCurrentState to head_note_state.
 3710 //*********************************************************************************
 3711 
 3712 unsigned long IOService::compute_settle_time ( void )
 3713 {
 3714     unsigned long       totalTime;
 3715     unsigned long       i;
 3716 
 3717         PM_ASSERT_IN_GATE();
 3718 
 3719     // compute total time to attain the new state
 3720     totalTime = 0;
 3721     i = fCurrentPowerState;
 3722 
 3723     // we're lowering power
 3724     if ( fHeadNoteState < fCurrentPowerState )
 3725     {
 3726         while ( i > fHeadNoteState )
 3727         {
 3728             totalTime +=  fPowerStates[i].settleDownTime;
 3729             i--;
 3730         }
 3731     }
 3732 
 3733     // we're raising power
 3734     if ( fHeadNoteState > fCurrentPowerState )
 3735     {
 3736         while ( i < fHeadNoteState )
 3737         {
 3738             totalTime +=  fPowerStates[i+1].settleUpTime;
 3739             i++;
 3740         }
 3741     }
 3742 
 3743     return totalTime;
 3744 }
 3745 
 3746 //*********************************************************************************
 3747 // [private] startSettleTimer
 3748 //
 3749 // Enter a power-settling delay in microseconds and start a timer for that delay.
 3750 //*********************************************************************************
 3751 
 3752 IOReturn IOService::startSettleTimer ( unsigned long delay )
 3753 {
 3754     AbsoluteTime        deadline;
 3755         boolean_t               pending;
 3756 
 3757         retain();
 3758     clock_interval_to_deadline(delay, kMicrosecondScale, &deadline);
 3759     pending = thread_call_enter_delayed(fSettleTimer, deadline);
 3760         if (pending) release();
 3761 
 3762     return IOPMNoErr;
 3763 }
 3764 
 3765 //*********************************************************************************
 3766 // [public] ackTimerTick
 3767 //
 3768 // The acknowledgement timeout periodic timer has ticked.
 3769 // If we are awaiting acks for a power change notification,
 3770 // we decrement the timer word of each interested driver which hasn't acked.
 3771 // If a timer word becomes zero, we pretend the driver aknowledged.
 3772 // If we are waiting for the controlling driver to change the power
 3773 // state of the hardware, we decrement its timer word, and if it becomes
 3774 // zero, we pretend the driver acknowledged.
 3775 //
 3776 // Returns true if the timer tick made it possible to advance to the next
 3777 // machine state, false otherwise.
 3778 //*********************************************************************************
 3779 
 3780 void IOService::ack_timer_ticked ( void )
 3781 {
 3782         assert(false);
 3783 }
 3784 
 3785 bool IOService::ackTimerTick( void )
 3786 {
 3787     IOPMinformee *              nextObject;
 3788         bool                            done = false;
 3789 
 3790         PM_ASSERT_IN_GATE();
 3791     switch (fMachineState) {
 3792         case kIOPM_OurChangeWaitForPowerSettle:
 3793         case kIOPM_ParentDownWaitForPowerSettle:
 3794         case kIOPM_ParentUpWaitForSettleTime:
 3795             // are we waiting for controlling driver to acknowledge?
 3796             if ( fDriverTimer > 0 )
 3797             {
 3798                 // yes, decrement timer tick
 3799                 fDriverTimer--;
 3800                 if ( fDriverTimer == 0 )
 3801                 {
 3802                     // controlling driver is tardy
 3803                     uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
 3804                     OUR_PMLog(kPMLogCtrlDriverTardy, 0, 0);
 3805                     setProperty(kIOPMTardyAckSPSKey, kOSBooleanTrue);
 3806                     PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
 3807                         fName, this, fCurrentPowerState, fHeadNoteState, NS_TO_MS(nsec));
 3808 
 3809                     if (gIOKitDebug & kIOLogDebugPower)
 3810                     {
 3811                         panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
 3812                             fName, this, fCurrentPowerState, fHeadNoteState, NS_TO_MS(nsec));
 3813                     }
 3814                     else
 3815                                         {
 3816                                                 // Unblock state machine and pretend driver has acked.
 3817                                                 done = true;
 3818                                         }
 3819                 } else {
 3820                     // still waiting, set timer again
 3821                     start_ack_timer();
 3822                 }
 3823             }
 3824             break;
 3825 
 3826         case kIOPM_OurChangeSetPowerState:
 3827         case kIOPM_OurChangeFinish:
 3828         case kIOPM_ParentDownSetPowerState:
 3829         case kIOPM_ParentDownAcknowledgeChange:
 3830         case kIOPM_ParentUpSetPowerState:
 3831         case kIOPM_ParentUpAcknowledgePowerChange:
 3832                 case kIOPM_NotifyChildrenDone:
 3833             // are we waiting for interested parties to acknowledge?
 3834             if ( fHeadNotePendingAcks != 0 )
 3835             {
 3836                 // yes, go through the list of interested drivers
 3837                 nextObject = fInterestedDrivers->firstInList();
 3838                 // and check each one
 3839                 while (  nextObject != NULL )
 3840                 {
 3841                     if ( nextObject->timer > 0 )
 3842                     {
 3843                         nextObject->timer--;
 3844                         // this one should have acked by now
 3845                         if ( nextObject->timer == 0 )
 3846                         {
 3847                             uint64_t nsec = computeTimeDeltaNS(&nextObject->startTime);
 3848                             OUR_PMLog(kPMLogIntDriverTardy, 0, 0);
 3849                             nextObject->whatObject->setProperty(kIOPMTardyAckPSCKey, kOSBooleanTrue);
 3850                             PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
 3851                                 nextObject->whatObject->getName(),
 3852                                 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
 3853                                 nextObject->whatObject, fName, fCurrentPowerState, fHeadNoteState,
 3854                                 NS_TO_MS(nsec));
 3855 
 3856                             // Pretend driver has acked.
 3857                             fHeadNotePendingAcks--;
 3858                         }
 3859                     }
 3860                     nextObject = fInterestedDrivers->nextInList(nextObject);
 3861                 }
 3862 
 3863                 // is that the last?
 3864                 if ( fHeadNotePendingAcks == 0 )
 3865                 {
 3866                     // yes, we can continue
 3867                                         done = true;
 3868                 } else {
 3869                     // no, set timer again
 3870                     start_ack_timer();
 3871                 }
 3872             }
 3873             break;
 3874 
 3875         case kIOPM_ParentDownTellPriorityClientsPowerDown:
 3876         case kIOPM_ParentDownNotifyInterestedDriversWillChange:
 3877         case kIOPM_OurChangeTellClientsPowerDown:
 3878         case kIOPM_OurChangeTellPriorityClientsPowerDown:
 3879         case kIOPM_OurChangeNotifyInterestedDriversWillChange:
 3880                         // apps didn't respond in time
 3881             cleanClientResponses(true);
 3882             OUR_PMLog(kPMLogClientTardy, 0, 1);
 3883                         if (fMachineState == kIOPM_OurChangeTellClientsPowerDown)
 3884                         {
 3885                                 // tardy equates to veto
 3886                                 fDoNotPowerDown = true;
 3887                         }
 3888                         done = true;
 3889             break;
 3890 
 3891         default:
 3892             PM_TRACE("[%s] unexpected ack timer tick (state = %ld)\n",
 3893                                 getName(), fMachineState);
 3894             break;
 3895     }
 3896         return done;
 3897 }
 3898 
 3899 //*********************************************************************************
 3900 // [private] start_ack_timer
 3901 //*********************************************************************************
 3902 
 3903 void IOService::start_ack_timer ( void )
 3904 {
 3905         start_ack_timer( ACK_TIMER_PERIOD, kNanosecondScale );
 3906 }
 3907 
 3908 void IOService::start_ack_timer ( UInt32 interval, UInt32 scale )
 3909 {
 3910     AbsoluteTime        deadline;
 3911         boolean_t               pending;
 3912 
 3913     clock_interval_to_deadline(interval, scale, &deadline);
 3914 
 3915         retain();
 3916     pending = thread_call_enter_delayed(fAckTimer, deadline);
 3917         if (pending) release();
 3918 }
 3919 
 3920 //*********************************************************************************
 3921 // [private] stop_ack_timer
 3922 //*********************************************************************************
 3923 
 3924 void IOService::stop_ack_timer ( void )
 3925 {
 3926         boolean_t               pending;
 3927 
 3928     pending = thread_call_cancel(fAckTimer);
 3929         if (pending) release();
 3930 }
 3931 
 3932 //*********************************************************************************
 3933 // [static] settleTimerExpired
 3934 //
 3935 // Inside PM work loop's gate.
 3936 //*********************************************************************************
 3937 
 3938 IOReturn
 3939 IOService::actionAckTimerExpired (
 3940         OSObject * target,
 3941         void * arg0, void * arg1,
 3942         void * arg2, void * arg3 )
 3943 {
 3944         IOService * me = (IOService *) target;
 3945         bool            done;
 3946 
 3947         // done will be true if the timer tick unblocks the machine state,
 3948         // otherwise no need to signal the work loop.
 3949 
 3950         done = me->ackTimerTick();
 3951         if (done && gIOPMReplyQueue)
 3952                 gIOPMReplyQueue->signalWorkAvailable();
 3953 
 3954         return kIOReturnSuccess;
 3955 }
 3956 
 3957 //*********************************************************************************
 3958 // ack_timer_expired
 3959 //
 3960 // Thread call function. Holds a retain while the callout is in flight.
 3961 //*********************************************************************************
 3962 
 3963 void
 3964 IOService::ack_timer_expired ( thread_call_param_t arg0, thread_call_param_t arg1 )
 3965 {
 3966         IOService * me = (IOService *) arg0;
 3967 
 3968         if (gIOPMWorkLoop)
 3969         {
 3970                 gIOPMWorkLoop->runAction(&actionAckTimerExpired, me);
 3971         }
 3972         me->release();
 3973 }
 3974 
 3975 //*********************************************************************************
 3976 // settleTimerExpired
 3977 //
 3978 // Inside PM work loop's gate.
 3979 //*********************************************************************************
 3980 
 3981 static IOReturn
 3982 settleTimerExpired (
 3983         OSObject * target,
 3984         void * arg0, void * arg1,
 3985         void * arg2, void * arg3 )
 3986 {
 3987         IOService * me = (IOService *) target;
 3988         me->settleTimerExpired();
 3989         return kIOReturnSuccess;
 3990 }
 3991 
 3992 //*********************************************************************************
 3993 // settle_timer_expired
 3994 //
 3995 // Thread call function. Holds a retain while the callout is in flight.
 3996 //*********************************************************************************
 3997 
 3998 static void
 3999 settle_timer_expired ( thread_call_param_t arg0, thread_call_param_t arg1 )
 4000 {
 4001         IOService * me = (IOService *) arg0;
 4002 
 4003         if (gIOPMWorkLoop && gIOPMReplyQueue)
 4004         {
 4005                 gIOPMWorkLoop->runAction(settleTimerExpired, me);
 4006                 gIOPMReplyQueue->signalWorkAvailable();
 4007         }
 4008         me->release();
 4009 }
 4010 
 4011 //*********************************************************************************
 4012 // [private] start_parent_change
 4013 //
 4014 // Here we begin the processing of a power change initiated by our parent.
 4015 //*********************************************************************************
 4016 
 4017 IOReturn IOService::start_parent_change ( const changeNoteItem * changeNote )
 4018 {
 4019     fHeadNoteFlags           = changeNote->flags;
 4020     fHeadNoteState           = changeNote->newStateNumber;
 4021     fHeadNoteOutputFlags     = changeNote->outputPowerCharacter;
 4022     fHeadNoteDomainState     = changeNote->domainState;
 4023     fHeadNoteParent          = changeNote->parent;
 4024     fHeadNoteCapabilityFlags = changeNote->capabilityFlags;
 4025 
 4026         PM_ASSERT_IN_GATE();
 4027     OUR_PMLog( kPMLogStartParentChange, fHeadNoteState, fCurrentPowerState );
 4028 
 4029     // Power domain is lowering power
 4030     if ( fHeadNoteState < fCurrentPowerState )
 4031     {
 4032                 setParentInfo(
 4033                         changeNote->singleParentState,
 4034                         fHeadNoteParent, true );
 4035 
 4036         // tell apps and kernel clients
 4037         fInitialChange = false;
 4038         fMachineState = kIOPM_ParentDownTellPriorityClientsPowerDown;
 4039                 tellChangeDown1(fHeadNoteState);
 4040         return IOPMWillAckLater;
 4041     }
 4042 
 4043     // Power domain is raising power
 4044     if ( fHeadNoteState > fCurrentPowerState )
 4045     {
 4046                 IOPMPowerState * powerStatePtr;
 4047 
 4048         if ( fDesiredPowerState > fCurrentPowerState )
 4049         {
 4050             if ( fDesiredPowerState < fHeadNoteState )
 4051             {
 4052                 // We power up, but not all the way
 4053                 fHeadNoteState = fDesiredPowerState;
 4054                                 powerStatePtr = &fPowerStates[fHeadNoteState];
 4055                 fHeadNoteOutputFlags = powerStatePtr->outputPowerCharacter;
 4056                 fHeadNoteCapabilityFlags = powerStatePtr->capabilityFlags;
 4057                 OUR_PMLog(kPMLogAmendParentChange, fHeadNoteState, 0);
 4058              }
 4059         } else {
 4060             // We don't need to change
 4061             fHeadNoteState = fCurrentPowerState;
 4062                         powerStatePtr = &fPowerStates[fHeadNoteState];
 4063             fHeadNoteOutputFlags = powerStatePtr->outputPowerCharacter;
 4064             fHeadNoteCapabilityFlags = powerStatePtr->capabilityFlags;
 4065             OUR_PMLog(kPMLogAmendParentChange, fHeadNoteState, 0);
 4066         }
 4067     }
 4068 
 4069         if ((fHeadNoteState > fCurrentPowerState) &&
 4070                 (fHeadNoteFlags & IOPMDomainDidChange))
 4071         {
 4072         // Parent did change up - start our change up
 4073         fInitialChange = false;
 4074         fMachineState = kIOPM_ParentUpSetPowerState;
 4075                 notifyAll( true );
 4076         return IOPMWillAckLater;
 4077     }
 4078 
 4079     all_done();
 4080     return IOPMAckImplied;
 4081 }
 4082 
 4083 //*********************************************************************************
 4084 // [private] start_our_change
 4085 //
 4086 // Here we begin the processing of a power change initiated by us.
 4087 //*********************************************************************************
 4088 
 4089 void IOService::start_our_change ( const changeNoteItem * changeNote )
 4090 {
 4091     fHeadNoteFlags           = changeNote->flags;
 4092     fHeadNoteState           = changeNote->newStateNumber;
 4093     fHeadNoteOutputFlags     = changeNote->outputPowerCharacter;
 4094     fHeadNoteCapabilityFlags = changeNote->capabilityFlags;
 4095 
 4096         PM_ASSERT_IN_GATE();
 4097 
 4098     OUR_PMLog( kPMLogStartDeviceChange, fHeadNoteState, fCurrentPowerState );
 4099 
 4100     // can our driver switch to the new state?
 4101     if (( fHeadNoteCapabilityFlags & IOPMNotAttainable ) ||
 4102                 ((fMaxCapability < fHeadNoteState) && (!fWeAreRoot)))
 4103     {
 4104         // mark the change note un-actioned
 4105         fHeadNoteFlags |= IOPMNotDone;
 4106 
 4107         // no, ask the parent to do it then
 4108         if ( !fWeAreRoot )
 4109         {
 4110             ask_parent(fHeadNoteState);
 4111         }
 4112         all_done();
 4113         return;
 4114     }
 4115 
 4116     if ( !fInitialChange )
 4117     {
 4118         if ( fHeadNoteState == fCurrentPowerState )
 4119         {
 4120             // we initiated a null change; forget it
 4121             all_done();
 4122             return;
 4123         }
 4124     }
 4125     fInitialChange = false;
 4126 
 4127     // dropping power?
 4128     if ( fHeadNoteState < fCurrentPowerState )
 4129     {
 4130         // yes, in case we have to wait for acks
 4131         fMachineState = kIOPM_OurChangeTellClientsPowerDown;
 4132         fDoNotPowerDown = false;
 4133 
 4134         // ask apps and kernel clients if we can drop power
 4135         fOutOfBandParameter = kNotifyApps;
 4136                 askChangeDown(fHeadNoteState);
 4137     } else {
 4138         // in case they don't all ack
 4139         fMachineState = kIOPM_OurChangeSetPowerState;
 4140         // notify interested drivers and children
 4141         notifyAll(true);
 4142     }
 4143 }
 4144 
 4145 //*********************************************************************************
 4146 // [private] ask_parent
 4147 //
 4148 // Call the power domain parent to ask for a higher power state in the domain
 4149 // or to suggest a lower power state.
 4150 //*********************************************************************************
 4151 
 4152 IOReturn IOService::ask_parent ( unsigned long requestedState )
 4153 {
 4154     OSIterator *                        iter;
 4155     OSObject *                          next;
 4156     IOPowerConnection *         connection;
 4157     IOService *                         parent;
 4158         const IOPMPowerState *  powerStatePtr;
 4159     unsigned long                       ourRequest;
 4160 
 4161         PM_ASSERT_IN_GATE();
 4162     if (requestedState >= fNumberOfPowerStates)
 4163         return IOPMNoErr;
 4164 
 4165         powerStatePtr = &fPowerStates[requestedState];
 4166         ourRequest    = powerStatePtr->inputPowerRequirement;
 4167 
 4168     if ( powerStatePtr->capabilityFlags & (kIOPMChildClamp | kIOPMPreventIdleSleep) )
 4169     {
 4170         ourRequest |= kIOPMPreventIdleSleep;
 4171     }
 4172     if ( powerStatePtr->capabilityFlags & (kIOPMChildClamp2 | kIOPMPreventSystemSleep) )
 4173     {
 4174         ourRequest |= kIOPMPreventSystemSleep;
 4175     }
 4176 
 4177     // is this a new desire?
 4178     if ( fPreviousRequest == ourRequest )
 4179     {   
 4180         // no, the parent knows already, just return
 4181         return IOPMNoErr;
 4182     }
 4183 
 4184     if ( fWeAreRoot )
 4185     {
 4186         return IOPMNoErr;
 4187     }
 4188     fPreviousRequest = ourRequest;
 4189 
 4190     iter = getParentIterator(gIOPowerPlane);
 4191     if ( iter )
 4192     {
 4193         while ( (next = iter->getNextObject()) )
 4194         {
 4195             if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
 4196             {
 4197                 parent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
 4198                 if ( parent ) {
 4199                     if ( parent->requestPowerDomainState(
 4200                                                 ourRequest, connection, IOPMLowestState) != IOPMNoErr )
 4201                     {
 4202                         OUR_PMLog(kPMLogRequestDenied, fPreviousRequest, 0);
 4203                     }
 4204                     parent->release();
 4205                 }
 4206             }
 4207         }
 4208         iter->release();
 4209     }
 4210 
 4211     return IOPMNoErr;
 4212 }
 4213 
 4214 //*********************************************************************************
 4215 // [private] notifyControllingDriver
 4216 //*********************************************************************************
 4217 
 4218 bool IOService::notifyControllingDriver ( void )
 4219 {
 4220         DriverCallParam *       param;
 4221         unsigned long           powerState;
 4222 
 4223         PM_ASSERT_IN_GATE();
 4224         assert( fDriverCallBusy == false );
 4225         assert( fDriverCallParamCount == 0  );
 4226         assert( fControllingDriver );
 4227 
 4228         powerState = fHeadNoteState;
 4229     if (fPowerStates[powerState].capabilityFlags & IOPMNotAttainable )
 4230         return false;   // state not attainable
 4231 
 4232         param = (DriverCallParam *) fDriverCallParamPtr;
 4233         if (!param)
 4234         {
 4235                 param = IONew(DriverCallParam, 1);
 4236                 if (!param)
 4237                         return false;   // no memory
 4238 
 4239                 fDriverCallParamPtr   = (void *) param;
 4240                 fDriverCallParamSlots = 1;
 4241         }
 4242 
 4243         param->Target = fControllingDriver;
 4244         fDriverCallParamCount = 1;
 4245 
 4246         fDriverTimer = -1;
 4247 
 4248         // Machine state for this object will stall waiting for a reply
 4249         // from the callout thread.
 4250 
 4251         PM_LOCK();
 4252         fDriverCallBusy = true;
 4253         PM_UNLOCK();
 4254         thread_call_enter( fDriverCallEntry );
 4255         return true;
 4256 }
 4257 
 4258 //*********************************************************************************
 4259 // [private] notifyControllingDriverDone
 4260 //*********************************************************************************
 4261 
 4262 void IOService::notifyControllingDriverDone( void )
 4263 {
 4264         DriverCallParam *       param;
 4265         IOReturn                        result;
 4266 
 4267         PM_ASSERT_IN_GATE();
 4268         param = (DriverCallParam *) fDriverCallParamPtr;
 4269 
 4270         assert( fDriverCallBusy == false );
 4271         assert( fMachineState == kIOPM_DriverThreadCallDone );
 4272 
 4273         if (param)
 4274         {
 4275                 assert(fDriverCallParamCount == 1);
 4276                 
 4277                 // the return value from setPowerState()
 4278                 result = param->Result;
 4279 
 4280                 if ((result == IOPMAckImplied) || (result < 0))
 4281                 {
 4282                         // child return IOPMAckImplied
 4283                         fDriverTimer = 0;
 4284                 }
 4285                 else if (fDriverTimer)
 4286                 {
 4287                         assert(fDriverTimer == -1);
 4288 
 4289             // Driver has not acked, and has returned a positive result.
 4290             // Enforce a minimum permissible timeout value.
 4291             // Make the min value large enough so timeout is less likely
 4292             // to occur if a driver misinterpreted that the return value
 4293             // should be in microsecond units.  And make it large enough
 4294             // to be noticeable if a driver neglects to ack.
 4295 
 4296             if (result < kMinAckTimeoutTicks)
 4297                 result = kMinAckTimeoutTicks;
 4298 
 4299             fDriverTimer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
 4300                 }
 4301                 // else, child has already acked and driver_timer reset to 0.
 4302 
 4303                 fDriverCallParamCount = 0;
 4304 
 4305                 if ( fDriverTimer )
 4306                 {
 4307                         OUR_PMLog(kPMLogStartAckTimer, 0, 0);
 4308                         start_ack_timer();
 4309                 }
 4310         }
 4311 
 4312         // Hop back to original machine state path.
 4313         fMachineState = fNextMachineState;
 4314 }
 4315 
 4316 //*********************************************************************************
 4317 // [public virtual] askChangeDown
 4318 //
 4319 // Ask registered applications and kernel clients if we can change to a lower
 4320 // power state.
 4321 //
 4322 // Subclass can override this to send a different message type.  Parameter is
 4323 // the destination state number.
 4324 //
 4325 // Return true if we don't have to wait for acknowledgements
 4326 //*********************************************************************************
 4327 
 4328 bool IOService::askChangeDown ( unsigned long stateNum )
 4329 {
 4330     return tellClientsWithResponse( kIOMessageCanDevicePowerOff );
 4331 }
 4332 
 4333 //*********************************************************************************
 4334 // [public] tellChangeDown1
 4335 //
 4336 // Notify registered applications and kernel clients that we are definitely
 4337 // dropping power.
 4338 //
 4339 // Return true if we don't have to wait for acknowledgements
 4340 //*********************************************************************************
 4341 
 4342 bool IOService::tellChangeDown1 ( unsigned long stateNum )
 4343 {
 4344     fOutOfBandParameter = kNotifyApps;
 4345     return tellChangeDown(stateNum);
 4346 }
 4347 
 4348 //*********************************************************************************
 4349 // [public] tellChangeDown2
 4350 //
 4351 // Notify priority clients that we are definitely dropping power.
 4352 //
 4353 // Return true if we don't have to wait for acknowledgements
 4354 //*********************************************************************************
 4355 
 4356 bool IOService::tellChangeDown2 ( unsigned long stateNum )
 4357 {
 4358     fOutOfBandParameter = kNotifyPriority;
 4359     return tellChangeDown(stateNum);
 4360 }
 4361 
 4362 //*********************************************************************************
 4363 // [public virtual] tellChangeDown
 4364 //
 4365 // Notify registered applications and kernel clients that we are definitely
 4366 // dropping power.
 4367 //
 4368 // Subclass can override this to send a different message type.  Parameter is
 4369 // the destination state number.
 4370 //
 4371 // Return true if we don't have to wait for acknowledgements
 4372 //*********************************************************************************
 4373 
 4374 bool IOService::tellChangeDown ( unsigned long stateNum )
 4375 {
 4376     return tellClientsWithResponse( kIOMessageDeviceWillPowerOff );
 4377 }
 4378 
 4379 //*********************************************************************************
 4380 // cleanClientResponses
 4381 //
 4382 //*********************************************************************************
 4383 
 4384 static void logAppTimeouts ( OSObject * object, void * context)
 4385 {
 4386     struct context  *theContext = (struct context *)context;
 4387     OSObject        *flag;
 4388 
 4389     if( !OSDynamicCast( IOService, object) ) {
 4390         flag = theContext->responseFlags->getObject(theContext->counter);
 4391         if (kOSBooleanTrue != flag)
 4392         {
 4393             OSString * clientID = 0;
 4394             theContext->us->messageClient(theContext->msgType, object, &clientID);
 4395             PM_ERROR(theContext->errorLog, clientID ? clientID->getCStringNoCopy() : "");
 4396             if (clientID)
 4397                 clientID->release();
 4398         }
 4399         theContext->counter += 1;
 4400     }
 4401 }
 4402 
 4403 void IOService::cleanClientResponses ( bool logErrors )
 4404 {
 4405     struct context theContext;
 4406 
 4407     if (logErrors && fResponseArray) {
 4408         theContext.responseFlags    = fResponseArray;
 4409         theContext.serialNumber     = fSerialNumber;
 4410         theContext.counter          = 0;
 4411         theContext.msgType          = kIOMessageCopyClientID;
 4412         theContext.us               = this;
 4413         theContext.maxTimeRequested = 0;
 4414         theContext.stateNumber      = fHeadNoteState;
 4415         theContext.stateFlags       = fHeadNoteCapabilityFlags;
 4416         theContext.errorLog         = "PM notification timeout (%s)\n";
 4417 
 4418         switch ( fOutOfBandParameter ) {
 4419             case kNotifyApps:
 4420                 applyToInterested(gIOAppPowerStateInterest, logAppTimeouts, (void *) &theContext);
 4421             case kNotifyPriority:
 4422             default:
 4423                 break;
 4424         }
 4425     }
 4426 
 4427     if (fResponseArray) 
 4428     {
 4429         // get rid of this stuff
 4430         fResponseArray->release();
 4431         fResponseArray = NULL;
 4432     }
 4433 
 4434     return;
 4435 }
 4436 
 4437 //*********************************************************************************
 4438 // [public] tellClientsWithResponse
 4439 //
 4440 // Notify registered applications and kernel clients that we are definitely
 4441 // dropping power.
 4442 //
 4443 // Return true if we don't have to wait for acknowledgements
 4444 //*********************************************************************************
 4445 
 4446 bool IOService::tellClientsWithResponse ( int messageType )
 4447 {
 4448     struct context      theContext;
 4449 
 4450         PM_ASSERT_IN_GATE();
 4451 
 4452     fResponseArray = OSArray::withCapacity( 1 );
 4453     fSerialNumber += 1;
 4454     
 4455     theContext.responseFlags = fResponseArray;
 4456     theContext.serialNumber = fSerialNumber;
 4457     theContext.counter = 0;
 4458     theContext.msgType = messageType;
 4459     theContext.us = this;
 4460     theContext.maxTimeRequested = 0;
 4461     theContext.stateNumber = fHeadNoteState;
 4462     theContext.stateFlags = fHeadNoteCapabilityFlags;
 4463 
 4464     switch ( fOutOfBandParameter ) {
 4465         case kNotifyApps:
 4466             applyToInterested(gIOAppPowerStateInterest,
 4467                                 pmTellAppWithResponse, (void *)&theContext);
 4468             applyToInterested(gIOGeneralInterest,
 4469                                 pmTellClientWithResponse, (void *)&theContext);
 4470             break;
 4471         case kNotifyPriority:
 4472             applyToInterested(gIOPriorityPowerStateInterest,
 4473                                 pmTellClientWithResponse, (void *)&theContext);
 4474             break;
 4475     }
 4476     
 4477     // do we have to wait for somebody?
 4478     if ( !checkForDone() )
 4479     {
 4480         OUR_PMLog(kPMLogStartAckTimer,theContext.maxTimeRequested, 0);
 4481                 start_ack_timer( theContext.maxTimeRequested / 1000, kMillisecondScale );       
 4482         return false;
 4483     }
 4484 
 4485     // everybody responded
 4486     fResponseArray->release();
 4487     fResponseArray = NULL;
 4488     // cleanClientResponses(false);
 4489     
 4490     return true;
 4491 }
 4492 
 4493 //*********************************************************************************
 4494 // [static private] pmTellAppWithResponse
 4495 //
 4496 // We send a message to an application, and we expect a response, so we compute a
 4497 // cookie we can identify the response with.
 4498 //*********************************************************************************
 4499 
 4500 void IOService::pmTellAppWithResponse ( OSObject * object, void * context )
 4501 {
 4502     struct context *    theContext = (struct context *) context;
 4503     IOServicePM *               pwrMgt = theContext->us->pwrMgt;
 4504     AbsoluteTime        now;
 4505 
 4506     if( OSDynamicCast( IOService, object) )
 4507     {
 4508                 // Automatically 'ack' in kernel clients
 4509         theContext->responseFlags->setObject(theContext->counter, kOSBooleanTrue);
 4510 
 4511                 const char *who = ((IOService *) object)->getName();
 4512                 fPlatform->PMLog(who,
 4513                         kPMLogClientAcknowledge, theContext->msgType, * (UInt32 *) object);
 4514     } else {
 4515         UInt32 refcon = ((theContext->serialNumber & 0xFFFF)<<16)
 4516                           + (theContext->counter & 0xFFFF);
 4517                 OUR_PMLog(kPMLogAppNotify, theContext->msgType, refcon);
 4518 
 4519 #if LOG_APP_RESPONSE_TIMES
 4520         OSNumber * num;
 4521         clock_get_uptime(&now);
 4522         num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
 4523         if (num)
 4524         {
 4525             theContext->responseFlags->setObject(theContext->counter, num);
 4526             num->release();
 4527         }
 4528         else
 4529 #endif
 4530         theContext->responseFlags->setObject(theContext->counter, kOSBooleanFalse);
 4531 
 4532         theContext->us->messageClient(theContext->msgType, object, (void *)refcon);
 4533         if ( theContext->maxTimeRequested < k30seconds )
 4534         {
 4535             theContext->maxTimeRequested = k30seconds;
 4536         }
 4537 
 4538         theContext->counter += 1;
 4539     }
 4540 }
 4541 
 4542 //*********************************************************************************
 4543 // [static private] pmTellClientWithResponse
 4544 //
 4545 // We send a message to an in-kernel client, and we expect a response, so we compute a
 4546 // cookie we can identify the response with.
 4547 // If it doesn't understand the notification (it is not power-management savvy)
 4548 // we won't wait for it to prepare for sleep.  If it tells us via a return code
 4549 // in the passed struct that it is currently ready, we won't wait for it to prepare.
 4550 // If it tells us via the return code in the struct that it does need time, we will chill.
 4551 //*********************************************************************************
 4552 
 4553 void IOService::pmTellClientWithResponse ( OSObject * object, void * context )
 4554 {
 4555     struct context                          *theContext = (struct context *)context;
 4556     IOPowerStateChangeNotification          notify;
 4557     UInt32                                  refcon;
 4558     IOReturn                                retCode;
 4559     OSObject                                *theFlag;
 4560 
 4561     refcon = ((theContext->serialNumber & 0xFFFF)<<16) + (theContext->counter & 0xFFFF);
 4562     theContext->responseFlags->setObject(theContext->counter, kOSBooleanFalse);
 4563 
 4564     IOServicePM * pwrMgt = theContext->us->pwrMgt;
 4565     if (gIOKitDebug & kIOLogPower) {
 4566                 OUR_PMLog(kPMLogClientNotify, refcon, (UInt32) theContext->msgType);
 4567                 if (OSDynamicCast(IOService, object)) {
 4568                         const char *who = ((IOService *) object)->getName();
 4569                         fPlatform->PMLog(who,
 4570                                 kPMLogClientNotify, * (UInt32 *) object, (UInt32) object);
 4571                 } else if (OSDynamicCast(_IOServiceInterestNotifier, object)) {
 4572                         _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
 4573                         OUR_PMLog(kPMLogClientNotify, (UInt32) n->handler, 0);
 4574                 }
 4575     }
 4576 
 4577     notify.powerRef = (void *)refcon;
 4578     notify.returnValue = 0;
 4579     notify.stateNumber = theContext->stateNumber;
 4580     notify.stateFlags = theContext->stateFlags;
 4581     retCode = theContext->us->messageClient(theContext->msgType,object,(void *)&notify);
 4582     if ( retCode == kIOReturnSuccess )
 4583     {
 4584         if ( notify.returnValue == 0 )
 4585         {
 4586             // client doesn't want time to respond
 4587             theContext->responseFlags->replaceObject(theContext->counter, kOSBooleanTrue);
 4588                         OUR_PMLog(kPMLogClientAcknowledge, refcon, (UInt32) object);
 4589         } else {
 4590             // it does want time, and it hasn't responded yet
 4591             theFlag = theContext->responseFlags->getObject(theContext->counter);
 4592             if ( kOSBooleanTrue != theFlag ) 
 4593             {
 4594                 // so note its time requirement
 4595                 if ( theContext->maxTimeRequested < notify.returnValue ) 
 4596                 {
 4597                     theContext->maxTimeRequested = notify.returnValue;
 4598                 }
 4599             }
 4600         }
 4601     } else {
 4602                 OUR_PMLog(kPMLogClientAcknowledge, refcon, 0);
 4603         // not a client of ours
 4604         // so we won't be waiting for response
 4605         theContext->responseFlags->replaceObject(theContext->counter, kOSBooleanTrue);
 4606     }
 4607     theContext->counter += 1;
 4608 }
 4609 
 4610 //*********************************************************************************
 4611 // [public virtual] tellNoChangeDown
 4612 //
 4613 // Notify registered applications and kernel clients that we are not
 4614 // dropping power.
 4615 //
 4616 // Subclass can override this to send a different message type.  Parameter is
 4617 // the aborted destination state number.
 4618 //*********************************************************************************
 4619 
 4620 void IOService::tellNoChangeDown ( unsigned long )
 4621 {
 4622     return tellClients( kIOMessageDeviceWillNotPowerOff );
 4623 }
 4624 
 4625 //*********************************************************************************
 4626 // [public virtual] tellChangeUp
 4627 //
 4628 // Notify registered applications and kernel clients that we are raising power.
 4629 //
 4630 // Subclass can override this to send a different message type.  Parameter is
 4631 // the aborted destination state number.
 4632 //*********************************************************************************
 4633 
 4634 void IOService::tellChangeUp ( unsigned long )
 4635 {
 4636     return tellClients( kIOMessageDeviceHasPoweredOn );
 4637 }
 4638 
 4639 //*********************************************************************************
 4640 // [public] tellClients
 4641 //
 4642 // Notify registered applications and kernel clients of something.
 4643 //*********************************************************************************
 4644 
 4645 void IOService::tellClients ( int messageType )
 4646 {
 4647     struct context theContext;
 4648 
 4649     theContext.msgType = messageType;
 4650     theContext.us = this;
 4651     theContext.stateNumber = fHeadNoteState;
 4652     theContext.stateFlags = fHeadNoteCapabilityFlags;
 4653 
 4654     applyToInterested(gIOPriorityPowerStateInterest,tellClient,(void *)&theContext);
 4655     applyToInterested(gIOAppPowerStateInterest,tellClient, (void *)&theContext);
 4656     applyToInterested(gIOGeneralInterest,tellClient, (void *)&theContext);
 4657 }
 4658 
 4659 //*********************************************************************************
 4660 // [global] tellClient
 4661 //
 4662 // Notify a registered application or kernel client of something.
 4663 //*********************************************************************************
 4664 
 4665 void tellClient ( OSObject * object, void * context )
 4666 {
 4667     struct context *                            theContext = (struct context *) context;
 4668     IOPowerStateChangeNotification      notify;
 4669 
 4670     notify.powerRef     = (void *) 0;
 4671     notify.returnValue  = 0;
 4672     notify.stateNumber  = theContext->stateNumber;
 4673     notify.stateFlags   = theContext->stateFlags;
 4674 
 4675     theContext->us->messageClient(theContext->msgType, object, &notify);
 4676 }
 4677 
 4678 //*********************************************************************************
 4679 // [private] checkForDone
 4680 //*********************************************************************************
 4681 
 4682 bool IOService::checkForDone ( void )
 4683 {
 4684     int                 i = 0;
 4685     OSObject *  theFlag;
 4686 
 4687     if ( fResponseArray == NULL )
 4688     {
 4689         return true;
 4690     }
 4691     
 4692     for ( i = 0; ; i++ )
 4693     {
 4694         theFlag = fResponseArray->getObject(i);
 4695         if ( theFlag == NULL )
 4696         {
 4697             break;
 4698         }
 4699         if ( kOSBooleanTrue != theFlag ) 
 4700         {
 4701             return false;
 4702         }
 4703     }
 4704     return true;
 4705 }
 4706 
 4707 //*********************************************************************************
 4708 // [public] responseValid
 4709 //*********************************************************************************
 4710 
 4711 bool IOService::responseValid ( unsigned long x, int pid )
 4712 {
 4713     UInt16                      serialComponent;
 4714     UInt16                      ordinalComponent;
 4715     OSObject *          theFlag;
 4716     unsigned long       refcon = (unsigned long) x;
 4717 
 4718     serialComponent  = (refcon >> 16) & 0xFFFF;
 4719     ordinalComponent = (refcon & 0xFFFF);
 4720 
 4721     if ( serialComponent != fSerialNumber )
 4722     {
 4723         return false;
 4724     }
 4725     
 4726     if ( fResponseArray == NULL )
 4727     {
 4728         return false;
 4729     }
 4730     
 4731     theFlag = fResponseArray->getObject(ordinalComponent);
 4732     
 4733     if ( theFlag == 0 )
 4734     {
 4735         return false;
 4736     }
 4737 
 4738     OSNumber * num;
 4739     if ((num = OSDynamicCast(OSNumber, theFlag)))
 4740     {
 4741 #if LOG_APP_RESPONSE_TIMES
 4742         AbsoluteTime    now;
 4743         AbsoluteTime    start;
 4744         uint64_t        nsec;
 4745 
 4746         clock_get_uptime(&now);
 4747         AbsoluteTime_to_scalar(&start) = num->unsigned64BitValue();
 4748         SUB_ABSOLUTETIME(&now, &start);
 4749         absolutetime_to_nanoseconds(now, &nsec);
 4750 
 4751         // > 100 ms
 4752         if (nsec > LOG_APP_RESPONSE_TIMES)
 4753         {
 4754             OSString * name = IOCopyLogNameForPID(pid);
 4755             PM_DEBUG("PM response took %d ms (%s)\n", NS_TO_MS(nsec),
 4756                 name ? name->getCStringNoCopy() : "");
 4757             if (name)
 4758             name->release();
 4759         }
 4760 #endif
 4761         theFlag = kOSBooleanFalse;
 4762     }
 4763 
 4764     if ( kOSBooleanFalse == theFlag ) 
 4765     {
 4766         fResponseArray->replaceObject(ordinalComponent, kOSBooleanTrue);
 4767     }
 4768     
 4769     return true;
 4770 }
 4771 
 4772 //*********************************************************************************
 4773 // [public virtual] allowPowerChange
 4774 //
 4775 // Our power state is about to lower, and we have notified applications
 4776 // and kernel clients, and one of them has acknowledged.  If this is the last to do
 4777 // so, and all acknowledgements are positive, we continue with the power change.
 4778 //
 4779 // We serialize this processing with timer expiration with a command gate on the
 4780 // power management workloop, which the timer expiration is command gated to as well.
 4781 //*********************************************************************************
 4782 
 4783 IOReturn IOService::allowPowerChange ( unsigned long refcon )
 4784 {
 4785         IOPMRequest * request;
 4786 
 4787     if ( !initialized )
 4788     {
 4789         // we're unloading
 4790         return kIOReturnSuccess;
 4791     }
 4792 
 4793         request = acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange );
 4794         if (!request)
 4795         {
 4796         PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__);
 4797                 return kIOReturnNoMemory;
 4798         }
 4799 
 4800         request->fArg0 = (void *) refcon;
 4801         request->fArg1 = (void *) proc_selfpid();
 4802         submitPMRequest( request );
 4803 
 4804         return kIOReturnSuccess;
 4805 }
 4806 
 4807 IOReturn serializedAllowPowerChange ( OSObject *owner, void * refcon, void *, void *, void *)
 4808 {
 4809         // [deprecated] public
 4810         return kIOReturnUnsupported;
 4811 }
 4812 
 4813 IOReturn IOService::serializedAllowPowerChange2 ( unsigned long refcon )
 4814 {
 4815         // [deprecated] public
 4816         return kIOReturnUnsupported;
 4817 }
 4818 
 4819 //*********************************************************************************
 4820 // [public virtual] cancelPowerChange
 4821 //
 4822 // Our power state is about to lower, and we have notified applications
 4823 // and kernel clients, and one of them has vetoed the change.  If this is the last
 4824 // client to respond, we abandon the power change.
 4825 //
 4826 // We serialize this processing with timer expiration with a command gate on the
 4827 // power management workloop, which the timer expiration is command gated to as well.
 4828 //*********************************************************************************
 4829 
 4830 IOReturn IOService::cancelPowerChange ( unsigned long refcon )
 4831 {
 4832         IOPMRequest * request;
 4833 
 4834     if ( !initialized )
 4835     {
 4836         // we're unloading
 4837         return kIOReturnSuccess;
 4838     }
 4839 
 4840         request = acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange );
 4841         if (!request)
 4842         {
 4843         PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__);
 4844                 return kIOReturnNoMemory;
 4845         }
 4846 
 4847         request->fArg0 = (void *) refcon;
 4848         request->fArg1 = (void *) proc_selfpid();
 4849         submitPMRequest( request );
 4850 
 4851         return kIOReturnSuccess;
 4852 }
 4853 
 4854 IOReturn serializedCancelPowerChange ( OSObject *owner, void * refcon, void *, void *, void *)
 4855 {
 4856         // [deprecated] public
 4857         return kIOReturnUnsupported;
 4858 }
 4859 
 4860 IOReturn IOService::serializedCancelPowerChange2 ( unsigned long refcon )
 4861 {
 4862         // [deprecated] public
 4863         return kIOReturnUnsupported;
 4864 }
 4865 
 4866 #if 0
 4867 //*********************************************************************************
 4868 // c_PM_clamp_Timer_Expired (C Func)
 4869 //
 4870 // Called when our clamp timer expires...we will call the object method.
 4871 //*********************************************************************************
 4872 
 4873 static void c_PM_Clamp_Timer_Expired ( OSObject * client, IOTimerEventSource * )
 4874 {
 4875     if (client)
 4876         ((IOService *)client)->PM_Clamp_Timer_Expired ();
 4877 }
 4878 #endif
 4879 
 4880 //*********************************************************************************
 4881 // PM_Clamp_Timer_Expired
 4882 //
 4883 // called when clamp timer expires...set power state to 0.
 4884 //*********************************************************************************
 4885 
 4886 void IOService::PM_Clamp_Timer_Expired ( void )
 4887 {
 4888 #if 0
 4889     if ( ! initialized )
 4890     {
 4891         // we're unloading
 4892         return;
 4893     }
 4894 
 4895   changePowerStateToPriv (0);
 4896 #endif
 4897 }
 4898 
 4899 //*********************************************************************************
 4900 // clampPowerOn
 4901 //
 4902 // Set to highest available power state for a minimum of duration milliseconds
 4903 //*********************************************************************************
 4904 
 4905 #define kFiveMinutesInNanoSeconds (300 * NSEC_PER_SEC)
 4906 
 4907 void IOService::clampPowerOn ( unsigned long duration )
 4908 {
 4909 #if 0
 4910   changePowerStateToPriv (fNumberOfPowerStates-1);
 4911 
 4912   if (  pwrMgt->clampTimerEventSrc == NULL ) {
 4913     pwrMgt->clampTimerEventSrc = IOTimerEventSource::timerEventSource(this,
 4914                                                     c_PM_Clamp_Timer_Expired);
 4915 
 4916     IOWorkLoop * workLoop = getPMworkloop ();
 4917 
 4918     if ( !pwrMgt->clampTimerEventSrc || !workLoop ||
 4919        ( workLoop->addEventSource(  pwrMgt->clampTimerEventSrc) != kIOReturnSuccess) ) {
 4920 
 4921     }
 4922   }
 4923 
 4924    pwrMgt->clampTimerEventSrc->setTimeout(300*USEC_PER_SEC, USEC_PER_SEC);
 4925 #endif
 4926 }
 4927 
 4928 //*********************************************************************************
 4929 // [public virtual] setPowerState
 4930 //
 4931 // Does nothing here.  This should be implemented in a subclass driver.
 4932 //*********************************************************************************
 4933 
 4934 IOReturn IOService::setPowerState (
 4935         unsigned long powerStateOrdinal, IOService * whatDevice )
 4936 {
 4937     return IOPMNoErr;
 4938 }
 4939 
 4940 //*********************************************************************************
 4941 // [public virtual] maxCapabilityForDomainState
 4942 //
 4943 // Finds the highest power state in the array whose input power
 4944 // requirement is equal to the input parameter.  Where a more intelligent
 4945 // decision is possible, override this in the subclassed driver.
 4946 //*********************************************************************************
 4947 
 4948 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
 4949 {
 4950    int i;
 4951 
 4952    if (fNumberOfPowerStates == 0 )
 4953    {
 4954        return 0;
 4955    }
 4956    for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
 4957    {
 4958        if ( (domainState & fPowerStates[i].inputPowerRequirement) ==
 4959                         fPowerStates[i].inputPowerRequirement )
 4960        {
 4961            return i;
 4962        }
 4963    }
 4964    return 0;
 4965 }
 4966 
 4967 //*********************************************************************************
 4968 // [public virtual] initialPowerStateForDomainState
 4969 //
 4970 // Finds the highest power state in the array whose input power
 4971 // requirement is equal to the input parameter.  Where a more intelligent
 4972 // decision is possible, override this in the subclassed driver.
 4973 //*********************************************************************************
 4974 
 4975 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState )
 4976 {
 4977     int i;
 4978 
 4979     if (fNumberOfPowerStates == 0 )
 4980     {
 4981         return 0;
 4982     }
 4983     for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
 4984     {
 4985         if ( (domainState & fPowerStates[i].inputPowerRequirement) ==
 4986                         fPowerStates[i].inputPowerRequirement )
 4987         {
 4988             return i;
 4989         }
 4990     }
 4991     return 0;
 4992 }
 4993 
 4994 //*********************************************************************************
 4995 // [public virtual] powerStateForDomainState
 4996 //
 4997 // Finds the highest power state in the array whose input power
 4998 // requirement is equal to the input parameter.  Where a more intelligent
 4999 // decision is possible, override this in the subclassed driver.
 5000 //*********************************************************************************
 5001 
 5002 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState )
 5003 {
 5004     int i;
 5005 
 5006     if (fNumberOfPowerStates == 0 )
 5007     {
 5008         return 0;
 5009     }
 5010     for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
 5011     {
 5012         if ( (domainState & fPowerStates[i].inputPowerRequirement) ==
 5013                         fPowerStates[i].inputPowerRequirement )
 5014         {
 5015             return i;
 5016         }
 5017     }
 5018     return 0;
 5019 }
 5020 
 5021 //*********************************************************************************
 5022 // [public virtual] didYouWakeSystem
 5023 //
 5024 // Does nothing here.  This should be implemented in a subclass driver.
 5025 //*********************************************************************************
 5026 
 5027 bool IOService::didYouWakeSystem  ( void )
 5028 {
 5029     return false;
 5030 }
 5031 
 5032 //*********************************************************************************
 5033 // [public virtual] powerStateWillChangeTo
 5034 //
 5035 // Does nothing here.  This should be implemented in a subclass driver.
 5036 //*********************************************************************************
 5037 
 5038 IOReturn IOService::powerStateWillChangeTo ( IOPMPowerFlags, unsigned long, IOService * )
 5039 {
 5040     return kIOPMAckImplied;
 5041 }
 5042 
 5043 //*********************************************************************************
 5044 // [public virtual] powerStateDidChangeTo
 5045 //
 5046 // Does nothing here.  This should be implemented in a subclass driver.
 5047 //*********************************************************************************
 5048 
 5049 IOReturn IOService::powerStateDidChangeTo ( IOPMPowerFlags, unsigned long, IOService * )
 5050 {
 5051     return kIOPMAckImplied;
 5052 }
 5053 
 5054 //*********************************************************************************
 5055 // [public virtual] powerChangeDone
 5056 //
 5057 // Called from PM work loop thread.
 5058 // Does nothing here.  This should be implemented in a subclass policy-maker.
 5059 //*********************************************************************************
 5060 
 5061 void IOService::powerChangeDone ( unsigned long )
 5062 {
 5063 }
 5064 
 5065 //*********************************************************************************
 5066 // [public virtual] newTemperature
 5067 //
 5068 // Does nothing here.  This should be implemented in a subclass driver.
 5069 //*********************************************************************************
 5070 
 5071 IOReturn IOService::newTemperature ( long currentTemp, IOService * whichZone )
 5072 {
 5073     return IOPMNoErr;
 5074 }
 5075 
 5076 //*********************************************************************************
 5077 // [public virtual] systemWillShutdown
 5078 //
 5079 // System shutdown and restart notification.
 5080 //*********************************************************************************
 5081 
 5082 void IOService::systemWillShutdown( IOOptionBits specifier )
 5083 {
 5084         IOPMrootDomain * rootDomain = IOService::getPMRootDomain();
 5085         if (rootDomain)
 5086                 rootDomain->acknowledgeSystemWillShutdown( this );
 5087 }
 5088 
 5089 //*********************************************************************************
 5090 // [private static] acquirePMRequest
 5091 //*********************************************************************************
 5092 
 5093 IOPMRequest *
 5094 IOService::acquirePMRequest( IOService * target, IOOptionBits requestType )
 5095 {
 5096         IOPMRequest * request;
 5097 
 5098         assert(target);
 5099 
 5100         request = IOPMRequest::create();
 5101         if (request)
 5102         {
 5103                 request->init( target, requestType );
 5104         }
 5105         return request;
 5106 }
 5107 
 5108 //*********************************************************************************
 5109 // [private static] releasePMRequest
 5110 //*********************************************************************************
 5111 
 5112 void IOService::releasePMRequest( IOPMRequest * request )
 5113 {
 5114         if (request)
 5115         {
 5116                 request->reset();
 5117                 request->release();
 5118         }
 5119 }
 5120 
 5121 //*********************************************************************************
 5122 // [private] submitPMRequest
 5123 //*********************************************************************************
 5124 
 5125 void IOService::submitPMRequest( IOPMRequest * request )
 5126 {
 5127         assert( request );
 5128         assert( gIOPMReplyQueue );
 5129         assert( gIOPMRequestQueue );
 5130 
 5131         PM_TRACE("[+ %02lx] %p [%p %s] %p %p %p\n",
 5132                 request->getType(), request,
 5133                 request->getTarget(), request->getTarget()->getName(),
 5134                 request->fArg0, request->fArg1, request->fArg2);
 5135 
 5136         if (request->isReply())
 5137                 gIOPMReplyQueue->queuePMRequest( request );
 5138         else
 5139                 gIOPMRequestQueue->queuePMRequest( request );
 5140 }
 5141 
 5142 void IOService::submitPMRequest( IOPMRequest ** requests, IOItemCount count )
 5143 {
 5144         assert( requests );
 5145         assert( count > 0 );
 5146         assert( gIOPMRequestQueue );
 5147 
 5148         for (IOItemCount i = 0; i < count; i++)
 5149         {
 5150                 IOPMRequest * req = requests[i];
 5151                 PM_TRACE("[+ %02lx] %p [%p %s] %p %p %p\n",
 5152                         req->getType(), req,
 5153                         req->getTarget(), req->getTarget()->getName(),
 5154                         req->fArg0, req->fArg1, req->fArg2);
 5155         }
 5156 
 5157         gIOPMRequestQueue->queuePMRequestChain( requests, count );
 5158 }
 5159 
 5160 //*********************************************************************************
 5161 // [private] servicePMRequestQueue
 5162 //*********************************************************************************
 5163 
 5164 bool IOService::servicePMRequestQueue(
 5165         IOPMRequest *           request,
 5166         IOPMRequestQueue *      queue )
 5167 {
 5168         // Calling PM methods without PMinit() is not allowed, fail the requests.
 5169 
 5170         if (!initialized)
 5171         {
 5172                 PM_DEBUG("[%s] %s: PM not initialized\n", getName(), __FUNCTION__);
 5173                 goto done;
 5174         }
 5175 
 5176         // Create an IOPMWorkQueue on demand, when the initial PM request is
 5177         // received.
 5178 
 5179         if (!fPMWorkQueue)
 5180         {
 5181                 // Allocate and attach an IOPMWorkQueue on demand to avoid taking
 5182                 // the work loop lock in PMinit(), which may deadlock with certain
 5183                 // drivers / families.
 5184 
 5185                 fPMWorkQueue = IOPMWorkQueue::create(
 5186                         /* target */    this,
 5187                         /* Work */              OSMemberFunctionCast(IOPMWorkQueue::Action, this,
 5188                                                                 &IOService::servicePMRequest),
 5189                         /* Done */              OSMemberFunctionCast(IOPMWorkQueue::Action, this,
 5190                                                                 &IOService::retirePMRequest)
 5191                         );
 5192 
 5193                 if (fPMWorkQueue &&
 5194                         (gIOPMWorkLoop->addEventSource(fPMWorkQueue) != kIOReturnSuccess))
 5195                 {
 5196                         PM_ERROR("[%s] %s: addEventSource failed\n",
 5197                                 getName(), __FUNCTION__);
 5198                         fPMWorkQueue->release();
 5199                         fPMWorkQueue = 0;
 5200                 }
 5201 
 5202                 if (!fPMWorkQueue)
 5203                 {
 5204                         PM_ERROR("[%s] %s: not ready (type %02lx)\n",
 5205                                 getName(), __FUNCTION__, request->getType());
 5206                         goto done;
 5207                 }
 5208         }
 5209 
 5210         fPMWorkQueue->queuePMRequest(request);
 5211         return false;   // do not signal more
 5212 
 5213 done:
 5214         gIOPMFreeQueue->queuePMRequest( request );
 5215         return false;   // do not signal more
 5216 }
 5217 
 5218 //*********************************************************************************
 5219 // [private] servicePMFreeQueue
 5220 //
 5221 // Called by IOPMFreeQueue to recycle a completed request.
 5222 //*********************************************************************************
 5223 
 5224 bool IOService::servicePMFreeQueue(
 5225         IOPMRequest *           request,
 5226         IOPMRequestQueue *      queue )
 5227 {
 5228         bool more = request->hasParentRequest();
 5229         releasePMRequest( request );
 5230         return more;
 5231 }
 5232 
 5233 //*********************************************************************************
 5234 // [private] retirePMRequest
 5235 //
 5236 // Called by IOPMWorkQueue to retire a completed request.
 5237 //*********************************************************************************
 5238 
 5239 bool IOService::retirePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
 5240 {
 5241         assert(request && queue);
 5242 
 5243         PM_TRACE("[- %02lx] %p [%p %s] State %ld, Busy %ld\n",
 5244                 request->getType(), request, this, getName(),
 5245                 fMachineState, gIOPMBusyCount);
 5246 
 5247         // Catch requests created by PM_idle_timer_expiration().
 5248 
 5249         if ((request->getType() == kIOPMRequestTypeActivityTickle) &&
 5250                 (request->fArg1 == (void *) false))
 5251         {
 5252                 // Idle timer power drop request completed.
 5253                 // Restart the idle timer if deviceDesire can go lower, otherwise set
 5254                 // a flag so we know to restart idle timer when deviceDesire goes up.
 5255 
 5256                 if (fDeviceDesire > 0)
 5257                         start_PM_idle_timer();
 5258                 else
 5259                         fActivityTimerStopped = true;
 5260         }
 5261 
 5262         gIOPMFreeQueue->queuePMRequest( request );
 5263         return true;
 5264 }
 5265 
 5266 //*********************************************************************************
 5267 // [private] isPMBlocked
 5268 //
 5269 // Check if machine state transition is blocked.
 5270 //*********************************************************************************
 5271 
 5272 bool IOService::isPMBlocked ( IOPMRequest * request, int count )
 5273 {
 5274         int     reason = 0;
 5275 
 5276         do {
 5277                 if (kIOPM_Finished == fMachineState)
 5278                         break;
 5279 
 5280                 if (kIOPM_DriverThreadCallDone == fMachineState)
 5281                 {
 5282             // 5 = kDriverCallInformPreChange
 5283             // 6 = kDriverCallInformPostChange
 5284             // 7 = kDriverCallSetPowerState
 5285                         if (fDriverCallBusy) reason = 5 + fDriverCallReason;
 5286                         break;
 5287                 }
 5288 
 5289                 // Waiting on driver's setPowerState() timeout.
 5290                 if (fDriverTimer)
 5291                 {
 5292                         reason = 1; break;
 5293                 }
 5294 
 5295                 // Child or interested driver acks pending.
 5296                 if (fHeadNotePendingAcks)
 5297                 {
 5298                         reason = 2; break;
 5299                 }
 5300 
 5301                 // Waiting on apps or priority power interest clients.
 5302                 if (fResponseArray)
 5303                 {
 5304                         reason = 3; break;
 5305                 }
 5306 
 5307                 // Waiting on settle timer expiration.
 5308                 if (fSettleTimeUS)
 5309                 {
 5310                         reason = 4; break;
 5311                 }
 5312         } while (false);
 5313 
 5314         fWaitReason = reason;
 5315 
 5316         if (reason)
 5317         {
 5318                 if (count)
 5319                 {
 5320                         PM_TRACE("[B %02lx] %p [%p %s] State %ld, Reason %d\n",
 5321                                 request->getType(), request, this, getName(),
 5322                                 fMachineState, reason);
 5323                 }
 5324 
 5325                 return true;
 5326         }
 5327 
 5328         return false;
 5329 }
 5330 
 5331 //*********************************************************************************
 5332 // [private] servicePMRequest
 5333 //
 5334 // Service a request from our work queue.
 5335 //*********************************************************************************
 5336 
 5337 bool IOService::servicePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
 5338 {
 5339         bool    done = false;
 5340         int             loop = 0;
 5341 
 5342         assert(request && queue);
 5343 
 5344         while (isPMBlocked(request, loop++) == false)
 5345         {
 5346                 PM_TRACE("[W %02lx] %p [%p %s] State %ld\n",
 5347                         request->getType(), request, this, getName(), fMachineState);
 5348 
 5349                 fPMRequest = request;
 5350 
 5351                 // Every PM machine states must be handled in one of the cases below.
 5352 
 5353                 switch ( fMachineState )
 5354                 {
 5355                         case kIOPM_Finished:
 5356                                 executePMRequest( request );
 5357                                 break;
 5358 
 5359                         case kIOPM_OurChangeTellClientsPowerDown:
 5360                                 // our change, was it vetoed?
 5361                                 if (fDesiredPowerState > fHeadNoteState)
 5362                                 {
 5363                                         PM_DEBUG("%s: idle cancel\n", fName);
 5364                                         fDoNotPowerDown = true;
 5365                                 }
 5366                                 if (!fDoNotPowerDown)
 5367                                 {
 5368                                         // no, we can continue
 5369                                         OurChangeTellClientsPowerDown();
 5370                                 }
 5371                                 else
 5372                                 {
 5373                                         // yes, rescind the warning
 5374                                         tellNoChangeDown(fHeadNoteState);
 5375                                         // mark the change note un-actioned
 5376                                         fHeadNoteFlags |= IOPMNotDone;
 5377                                         // and we're done
 5378                                         all_done();
 5379                                 }
 5380                                 break;
 5381 
 5382                         case kIOPM_OurChangeTellPriorityClientsPowerDown:
 5383                                 OurChangeTellPriorityClientsPowerDown();  
 5384                                 break;
 5385 
 5386                         case kIOPM_OurChangeNotifyInterestedDriversWillChange:
 5387                                 OurChangeNotifyInterestedDriversWillChange();
 5388                                 break;
 5389 
 5390                         case kIOPM_OurChangeSetPowerState:
 5391                                 OurChangeSetPowerState();
 5392                                 break;
 5393 
 5394                         case kIOPM_OurChangeWaitForPowerSettle:
 5395                                 OurChangeWaitForPowerSettle();
 5396                                 break;
 5397 
 5398                         case kIOPM_OurChangeNotifyInterestedDriversDidChange:
 5399                                 OurChangeNotifyInterestedDriversDidChange();
 5400                                 break;
 5401 
 5402                         case kIOPM_OurChangeFinish:
 5403                                 OurChangeFinish();
 5404                                 break;
 5405 
 5406                         case kIOPM_ParentDownTellPriorityClientsPowerDown:
 5407                                 ParentDownTellPriorityClientsPowerDown();
 5408                                 break;
 5409 
 5410                         case kIOPM_ParentDownNotifyInterestedDriversWillChange:
 5411                                 ParentDownNotifyInterestedDriversWillChange();
 5412                                 break;
 5413 
 5414                         case kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange:
 5415                                 ParentDownNotifyDidChangeAndAcknowledgeChange();
 5416                                 break;
 5417 
 5418                         case kIOPM_ParentDownSetPowerState:
 5419                                 ParentDownSetPowerState();      
 5420                                 break;
 5421 
 5422                         case kIOPM_ParentDownWaitForPowerSettle:
 5423                                 ParentDownWaitForPowerSettle();
 5424                                 break;
 5425 
 5426                         case kIOPM_ParentDownAcknowledgeChange:
 5427                                 ParentDownAcknowledgeChange();
 5428                                 break;
 5429 
 5430                         case kIOPM_ParentUpSetPowerState:
 5431                                 ParentUpSetPowerState();
 5432                                 break;
 5433 
 5434                         case kIOPM_ParentUpWaitForSettleTime:
 5435                                 ParentUpWaitForSettleTime();
 5436                                 break;
 5437 
 5438                         case kIOPM_ParentUpNotifyInterestedDriversDidChange:
 5439                                 ParentUpNotifyInterestedDriversDidChange();
 5440                                 break;
 5441 
 5442                         case kIOPM_ParentUpAcknowledgePowerChange:
 5443                                 ParentUpAcknowledgePowerChange();
 5444                                 break;
 5445 
 5446                         case kIOPM_DriverThreadCallDone:
 5447                                 if (fDriverCallReason == kDriverCallSetPowerState)
 5448                                         notifyControllingDriverDone();
 5449                                 else
 5450                                         notifyInterestedDriversDone();
 5451                                 break;
 5452 
 5453                         case kIOPM_NotifyChildrenDone:
 5454                                 notifyChildrenDone();
 5455                                 break;
 5456 
 5457                         default:
 5458                                 IOPanic("servicePMWorkQueue: unknown machine state");
 5459                 }
 5460 
 5461                 fPMRequest = 0;
 5462 
 5463                 if (fMachineState == kIOPM_Finished)
 5464                 {
 5465                         //PM_TRACE("[%s] PM   End: Request %p (type %02lx)\n",
 5466                         //      getName(), request, request->getType());
 5467                         done = true;
 5468                         break;
 5469                 }
 5470         }
 5471 
 5472         return done;
 5473 }
 5474 
 5475 //*********************************************************************************
 5476 // [private] executePMRequest
 5477 //*********************************************************************************
 5478 
 5479 void IOService::executePMRequest( IOPMRequest * request )
 5480 {
 5481         assert( kIOPM_Finished == fMachineState );
 5482 
 5483         switch (request->getType())
 5484         {
 5485                 case kIOPMRequestTypePMStop:
 5486                         handlePMstop( request );
 5487                         break;
 5488 
 5489                 case kIOPMRequestTypeAddPowerChild1:
 5490                         addPowerChild1( request );
 5491                         break;
 5492 
 5493                 case kIOPMRequestTypeAddPowerChild2:
 5494                         addPowerChild2( request );
 5495                         break;
 5496 
 5497                 case kIOPMRequestTypeAddPowerChild3:
 5498                         addPowerChild3( request );
 5499                         break;
 5500 
 5501                 case kIOPMRequestTypeRegisterPowerDriver:
 5502                         handleRegisterPowerDriver( request );
 5503                         break;
 5504 
 5505                 case kIOPMRequestTypeAdjustPowerState:
 5506                         adjustPowerState();
 5507                         break;
 5508 
 5509                 case kIOPMRequestTypeMakeUsable:
 5510                         handleMakeUsable( request );
 5511                         break;
 5512 
 5513                 case kIOPMRequestTypeTemporaryPowerClamp:
 5514                         fClampOn = true;
 5515                         handleMakeUsable( request );
 5516                         break;
 5517 
 5518                 case kIOPMRequestTypePowerDomainWillChange:
 5519                         handlePowerDomainWillChangeTo( request );
 5520                         break;
 5521 
 5522                 case kIOPMRequestTypePowerDomainDidChange:
 5523                         handlePowerDomainDidChangeTo( request );
 5524                         break;
 5525 
 5526                 case kIOPMRequestTypeChangePowerStateTo:
 5527                         handleChangePowerStateTo( request );
 5528                         break;
 5529 
 5530                 case kIOPMRequestTypeChangePowerStateToPriv:
 5531                         handleChangePowerStateToPriv( request );
 5532                         break;
 5533 
 5534                 case kIOPMRequestTypePowerOverrideOnPriv:
 5535                 case kIOPMRequestTypePowerOverrideOffPriv:
 5536                         handlePowerOverrideChanged( request );
 5537                         break;
 5538 
 5539                 case kIOPMRequestTypeActivityTickle:
 5540                         if (request)
 5541                         {
 5542                                 bool setDeviceDesire = false;
 5543 
 5544                                 if (request->fArg1)
 5545                                 {
 5546                                         // power rise
 5547                                         if (fDeviceDesire < (unsigned long) request->fArg0)
 5548                                                 setDeviceDesire = true;
 5549                                 }
 5550                                 else if (fDeviceDesire)
 5551                                 {
 5552                                         // power drop and deviceDesire is not zero
 5553                                         request->fArg0 = (void *) (fDeviceDesire - 1);
 5554                                         setDeviceDesire = true;
 5555                                 }
 5556 
 5557                                 if (setDeviceDesire)
 5558                                 {
 5559                                         // handleChangePowerStateToPriv() does not check the
 5560                                         // request type, as long as the args are appropriate
 5561                                         // for kIOPMRequestTypeChangePowerStateToPriv.
 5562 
 5563                                         request->fArg1 = (void *) false;
 5564                                         handleChangePowerStateToPriv( request );
 5565                                 }
 5566                         }
 5567                         break;
 5568 
 5569                 default:
 5570                         IOPanic("executePMRequest: unknown request type");
 5571         }
 5572 }
 5573 
 5574 //*********************************************************************************
 5575 // [private] servicePMReplyQueue
 5576 //*********************************************************************************
 5577 
 5578 bool IOService::servicePMReplyQueue( IOPMRequest * request, IOPMRequestQueue * queue )
 5579 {
 5580         bool more = false;
 5581 
 5582         assert( request && queue );
 5583         assert( request->isReply() );
 5584 
 5585         PM_TRACE("[A %02lx] %p [%p %s] State %ld\n",
 5586                 request->getType(), request, this, getName(), fMachineState);
 5587 
 5588         switch ( request->getType() )
 5589         {
 5590                 case kIOPMRequestTypeAllowPowerChange:
 5591                 case kIOPMRequestTypeCancelPowerChange:
 5592                         // Check if we are expecting this response.
 5593                         if (responseValid((unsigned long) request->fArg0, (int) request->fArg1))
 5594                         {
 5595                                 if (kIOPMRequestTypeCancelPowerChange == request->getType())
 5596                                         fDoNotPowerDown = true;
 5597 
 5598                                 if (checkForDone())
 5599                                 {
 5600                                         stop_ack_timer();
 5601                                         if ( fResponseArray )
 5602                                         {
 5603                                                 fResponseArray->release();
 5604                                                 fResponseArray = NULL;
 5605                                         }
 5606                                         more = true;
 5607                                 }
 5608                         }
 5609                         break;
 5610 
 5611                 case kIOPMRequestTypeAckPowerChange:
 5612                         more = handleAcknowledgePowerChange( request );
 5613                         break;
 5614 
 5615                 case kIOPMRequestTypeAckSetPowerState:
 5616                         if (fDriverTimer == -1)
 5617                         {
 5618                                 // driver acked while setPowerState() call is in-flight.
 5619                                 // take this ack, return value from setPowerState() is irrelevant.
 5620                                 OUR_PMLog(kPMLogDriverAcknowledgeSet,
 5621                                         (UInt32) this, fDriverTimer);
 5622                                 fDriverTimer = 0;
 5623                         }
 5624                         else if (fDriverTimer > 0)
 5625                         {
 5626                                 // expected ack, stop the timer
 5627                                 stop_ack_timer();
 5628 
 5629 #if LOG_SETPOWER_TIMES
 5630                 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
 5631                 if (nsec > LOG_SETPOWER_TIMES)
 5632                     PM_DEBUG("%s::setPowerState(%p, %lu -> %lu) async took %d ms\n",
 5633                         fName, this, fCurrentPowerState, fHeadNoteState, NS_TO_MS(nsec));
 5634 #endif
 5635                                 OUR_PMLog(kPMLogDriverAcknowledgeSet, (UInt32) this, fDriverTimer);
 5636                                 fDriverTimer = 0;
 5637                                 more = true;
 5638                         }
 5639                         else
 5640                         {
 5641                                 // unexpected ack
 5642                                 OUR_PMLog(kPMLogAcknowledgeErr4, (UInt32) this, 0);
 5643                         }
 5644                         break;
 5645 
 5646                 case kIOPMRequestTypeInterestChanged:
 5647                         handleInterestChanged( request );
 5648                         more = true;
 5649                         break;
 5650 
 5651                 default:
 5652                         IOPanic("servicePMReplyQueue: unknown reply type");
 5653         }
 5654 
 5655         releasePMRequest( request );
 5656         return more;
 5657 }
 5658 
 5659 //*********************************************************************************
 5660 // IOPMRequest Class
 5661 //
 5662 // Requests from PM clients, and also used for inter-object messaging within PM.
 5663 //*********************************************************************************
 5664 
 5665 OSDefineMetaClassAndStructors( IOPMRequest, IOCommand );
 5666 
 5667 IOPMRequest * IOPMRequest::create( void )
 5668 {
 5669         IOPMRequest * me = OSTypeAlloc(IOPMRequest);
 5670         if (me && !me->init(0, kIOPMRequestTypeInvalid))
 5671         {
 5672                 me->release();
 5673                 me = 0;
 5674         }
 5675         return me;
 5676 }
 5677 
 5678 bool IOPMRequest::init( IOService * target, IOOptionBits type )
 5679 {
 5680         if (!IOCommand::init())
 5681                 return false;
 5682 
 5683         fType       = type;
 5684         fTarget     = target;
 5685         fParent     = 0;
 5686         fChildCount = 0;
 5687         fArg0 = fArg1 = fArg2 = 0;
 5688 
 5689         if (fTarget)
 5690                 fTarget->retain();
 5691 
 5692         return true;
 5693 }
 5694 
 5695 void IOPMRequest::reset( void )
 5696 {
 5697         assert( fChildCount == 0 );
 5698 
 5699         fType = kIOPMRequestTypeInvalid;
 5700 
 5701         if (fParent)
 5702         {
 5703                 fParent->fChildCount--;
 5704                 fParent = 0;
 5705         }
 5706 
 5707         if (fTarget)
 5708         {
 5709                 fTarget->release();
 5710                 fTarget = 0;
 5711         }
 5712 }
 5713 
 5714 //*********************************************************************************
 5715 // IOPMRequestQueue Class
 5716 //
 5717 // Global queues. As PM-aware drivers load and unload, their IOPMWorkQueue's are
 5718 // created and deallocated. IOPMRequestQueue are created once and never released.
 5719 //*********************************************************************************
 5720 
 5721 OSDefineMetaClassAndStructors( IOPMRequestQueue, IOEventSource );
 5722 
 5723 IOPMRequestQueue * IOPMRequestQueue::create( IOService * inOwner, Action inAction )
 5724 {
 5725         IOPMRequestQueue * me = OSTypeAlloc(IOPMRequestQueue);
 5726         if (me && !me->init(inOwner, inAction))
 5727         {
 5728                 me->release();
 5729                 me = 0;
 5730         }
 5731         return me;
 5732 }
 5733 
 5734 bool IOPMRequestQueue::init( IOService * inOwner, Action inAction )
 5735 {
 5736         if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction))
 5737         return false;
 5738 
 5739         queue_init(&fQueue);
 5740         fLock = IOLockAlloc();
 5741         return (fLock != 0);
 5742 }
 5743 
 5744 void IOPMRequestQueue::free( void )
 5745 {
 5746         if (fLock)
 5747         {
 5748                 IOLockFree(fLock);
 5749                 fLock = 0;
 5750         }
 5751         return IOEventSource::free();
 5752 }
 5753 
 5754 void IOPMRequestQueue::queuePMRequest( IOPMRequest * request )
 5755 {
 5756         assert(request);
 5757         IOLockLock(fLock);
 5758         queue_enter(&fQueue, request, IOPMRequest *, fCommandChain);
 5759         IOLockUnlock(fLock);
 5760         if (workLoop) signalWorkAvailable();
 5761 }
 5762 
 5763 void
 5764 IOPMRequestQueue::queuePMRequestChain( IOPMRequest ** requests, IOItemCount count )
 5765 {
 5766         IOPMRequest * next;
 5767 
 5768         assert(requests && count);
 5769         IOLockLock(fLock);
 5770         while (count--)
 5771         {
 5772                 next = *requests;
 5773                 requests++;
 5774                 queue_enter(&fQueue, next, IOPMRequest *, fCommandChain);
 5775         }
 5776         IOLockUnlock(fLock);
 5777         if (workLoop) signalWorkAvailable();
 5778 }
 5779 
 5780 bool IOPMRequestQueue::checkForWork( void )
 5781 {
 5782     Action                      dqAction = (Action) action;
 5783         IOPMRequest *   request;
 5784         IOService *             target;
 5785         bool                    more = false;
 5786 
 5787         IOLockLock( fLock );
 5788 
 5789         while (!queue_empty(&fQueue))
 5790         {
 5791                 queue_remove_first( &fQueue, request, IOPMRequest *, fCommandChain );           
 5792                 IOLockUnlock( fLock );
 5793                 target = request->getTarget();
 5794                 assert(target);
 5795                 more |= (*dqAction)( target, request, this );
 5796                 IOLockLock( fLock );
 5797         }
 5798 
 5799         IOLockUnlock( fLock );
 5800         return more;
 5801 }
 5802 
 5803 void IOPMRequestQueue::signalWorkAvailable( void )
 5804 {
 5805         IOEventSource::signalWorkAvailable();
 5806 }
 5807 
 5808 //*********************************************************************************
 5809 // IOPMWorkQueue Class
 5810 //
 5811 // Every object in the power plane that has handled a PM request, will have an
 5812 // instance of IOPMWorkQueue allocated for it.
 5813 //*********************************************************************************
 5814 
 5815 OSDefineMetaClassAndStructors( IOPMWorkQueue, IOEventSource );
 5816 
 5817 IOPMWorkQueue *
 5818 IOPMWorkQueue::create( IOService * inOwner, Action work, Action retire )
 5819 {
 5820         IOPMWorkQueue * me = OSTypeAlloc(IOPMWorkQueue);
 5821         if (me && !me->init(inOwner, work, retire))
 5822         {
 5823                 me->release();
 5824                 me = 0;
 5825         }
 5826         return me;
 5827 }
 5828 
 5829 bool IOPMWorkQueue::init( IOService * inOwner, Action work, Action retire )
 5830 {
 5831         if (!work || !retire ||
 5832                 !IOEventSource::init(inOwner, (IOEventSourceAction)0))
 5833                 return false;
 5834 
 5835         queue_init(&fWorkQueue);
 5836 
 5837         fWorkAction   = work;
 5838         fRetireAction = retire;
 5839 
 5840         return true;
 5841 }
 5842 
 5843 void IOPMWorkQueue::queuePMRequest( IOPMRequest * request )
 5844 {
 5845         assert( request );
 5846         assert( onThread() );
 5847 
 5848         gIOPMBusyCount++;
 5849         queue_enter(&fWorkQueue, request, IOPMRequest *, fCommandChain);
 5850         checkForWork();
 5851 }
 5852 
 5853 bool IOPMWorkQueue::checkForWork( void )
 5854 {
 5855         IOPMRequest *   request;
 5856         IOService *             target = (IOService *) owner;
 5857         bool                    done;
 5858 
 5859         while (!queue_empty(&fWorkQueue))
 5860         {
 5861                 request = (IOPMRequest *) queue_first(&fWorkQueue);
 5862                 assert(request->getTarget() == target);
 5863                 if (request->hasChildRequest()) break;
 5864                 done = (*fWorkAction)( target, request, this );
 5865                 if (!done) break;
 5866 
 5867                 assert(gIOPMBusyCount > 0);
 5868                 if (gIOPMBusyCount) gIOPMBusyCount--;
 5869                 queue_remove_first(&fWorkQueue, request, IOPMRequest *, fCommandChain);
 5870                 (*fRetireAction)( target, request, this );
 5871         }
 5872 
 5873         return false;
 5874 }
 5875 
 5876 OSDefineMetaClassAndStructors(IOServicePM, OSObject)
 5877 
 5878 //*********************************************************************************
 5879 // serialize
 5880 //
 5881 // Serialize IOServicePM for debugging.
 5882 //*********************************************************************************
 5883 
 5884 static void
 5885 setPMProperty( OSDictionary * dict, const char * key, unsigned long value )
 5886 {
 5887     OSNumber * num = OSNumber::withNumber(value, sizeof(value) * 8);
 5888     if (num)
 5889     {
 5890         dict->setObject(key, num);
 5891         num->release();
 5892     }
 5893 }
 5894 
 5895 bool IOServicePM::serialize( OSSerialize * s ) const
 5896 {
 5897         OSDictionary *  dict;
 5898         bool                    ok = false;
 5899 
 5900         dict = OSDictionary::withCapacity(8);
 5901         if (dict)
 5902         {
 5903         setPMProperty( dict, "CurrentPowerState", CurrentPowerState );
 5904         if (DesiredPowerState != CurrentPowerState)
 5905             setPMProperty( dict, "DesiredPowerState", DesiredPowerState );
 5906         if (kIOPM_Finished != MachineState)
 5907             setPMProperty( dict, "MachineState", MachineState );
 5908         if (ChildrenDesire)
 5909             setPMProperty( dict, "ChildrenPowerState", ChildrenDesire );
 5910         if (DeviceDesire)
 5911             setPMProperty( dict, "DeviceChangePowerState", DeviceDesire );
 5912         if (DriverDesire)
 5913             setPMProperty( dict, "DriverChangePowerState", DriverDesire );
 5914         if (DeviceOverrides)
 5915             dict->setObject( "PowerOverrideOn", kOSBooleanTrue );
 5916 
 5917                 ok = dict->serialize(s);
 5918                 dict->release();
 5919         }
 5920 
 5921         return ok;
 5922 }

Cache object: fff00687e6b563d6f4e0de87fae943ab


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.