Annotation of XNU/iokit/Kernel/IOServicePM.cpp, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: #include <IOKit/IOService.h>
                     23: #include <IOKit/IOLib.h>
                     24: #include <IOKit/IOCommandQueue.h>
                     25: #include <IOKit/IOTimerEventSource.h>
                     26: #include <IOKit/IOWorkLoop.h>
                     27: #include <IOKit/IOPlatformExpert.h>
                     28: #include <IOKit/assert.h>
                     29: #include "IOKit/pwr_mgt/IOPMpmChild.h"
                     30: #include "IOKit/pwr_mgt/IOPMinformeeList.h"
                     31: #include "IOKit/pwr_mgt/IOPMchangeNoteList.h"
                     32: #include "IOKit/pwr_mgt/IOPMlog.h"
                     33: 
                     34: static void ack_timer_expired(thread_call_param_t, thread_call_param_t);
                     35: static void settle_timer_expired(thread_call_param_t, thread_call_param_t);
                     36: void PMreceiveCmd ( OSObject *,  void *, void *, void *, void * );
                     37: static void PM_idle_timer_expired(OSObject *, IOTimerEventSource *);
                     38: 
                     39: extern const IORegistryPlane * gIOPowerPlane;
                     40: 
                     41: 
                     42: // and there's 1000 nanosecons in a microsecond:
                     43: #define ns_per_us 1000
                     44: 
                     45: 
                     46: // The current change note is processed by a state machine.
                     47: // Inputs are acks from interested parties, ack from the controlling driver,
                     48: // ack timeouts, settle timeout, and powerStateDidChange from the parent.
                     49: // These are the states:
                     50: 
                     51: #define IOPMour_prechange_1            1
                     52: #define IOPMour_prechange_2            2
                     53: #define IOPMour_prechange_3            3
                     54: #define IOPMour_prechange_4            4
                     55: #define IOPMparent_prechange_down_3    5
                     56: #define IOPMparent_prechange_down_4    6
                     57: #define IOPMparent_prechange_down_5    7
                     58: #define IOPMparent_postchange_down_1   8
                     59: #define IOPMparent_postchange_down_2   9
                     60: #define IOPMparent_prechange_up_1      10
                     61: #define IOPMparent_postchange_up_1     11
                     62: #define IOPMparent_postchange_up_4     12
                     63: #define IOPMparent_postchange_up_5     13
                     64: #define IOPMparent_postchange_up_6     14
                     65: #define IOPMparent_postchange_null     15
                     66: #define IOPMfinished                   16
                     67: 
                     68: /*
                     69:  There are two different kinds of power state changes.  One is initiated by a subclassed device object which has either
                     70:  decided to change power state, or its controlling driver has suggested it, or some other driver wants to use the
                     71:  idle device and has asked it to become usable.  The second kind of power state change is initiated by the power
                     72:  domain parent.  The two are handled slightly differently.
                     73: 
                     74: There is a queue of so-called change notifications, or change notes for short.  Usually the queue is empty, and when
                     75:  it isn't, usually there is one change note in it, but since it's possible to have more than one power state change pending
                     76:  at one time, a queue is implemented.  Example:  the subclass device decides it's idle and initiates a change to a lower
                     77:  power state.  This causes interested parties to be notified, but they don't all acknowledge right away.  This causes the
                     78:  change note to sit in the queue until all the acks are received.  During this time, the device decides it isn't idle anymore and
                     79:  wants to raise power back up again.  This change can't be started, however, because the previous one isn't complete yet,
                     80:  so the second one waits in the queue.  During this time, the parent decides to lower or raise the power state of the entire
                     81:  power domain and notifies the device, and that notification goes into the queue, too, and can't be actioned until the
                     82:  others are.
                     83: 
                     84:  This is how a power change initiated by the subclass device is handled:
                     85:  First, all interested parties are notified of the change via their powerStateWillChangeTo method.  If they all don't
                     86:  acknowledge via return code, then we have to wait.  If they do, or when they finally all acknowledge via our
                     87:  acknowledgePowerChange method, then we can continue.  We call the controlling driver, instructing it to change to
                     88:  the new state.  Then we wait for power to settle.  If there is no settling-time, or after it has passed, we notify
                     89:  interested parties again, this time via their powerStateDidChangeTo methods.  When they have all acked, we're done.
                     90:  If we lowered power and don't need the power domain to be in its current power state, we suggest to the parent that
                     91:  it lower the power domain state.
                     92: 
                     93:  This is how a change to a lower power domain state initiated by the parent is handled:
                     94:  First, we figure out what power state we will be in when the new domain state is reached.  Then all interested parties are
                     95:  notified that we are moving to that new state.  When they have acknowledged, we call the controlling driver to assume
                     96:  that state and we wait for power to settle.  Then we acknowledge our preparedness to our parent.  When all its interested
                     97:  parties have acknowledged, it lowers power and then notifies its interested parties again.  When we get this call, we notify
                     98:  our interested parties that the power state has changed, and when they have all acknowledged, we're done.
                     99: 
                    100:  This is how a change to a higher power domain state initiated by the parent is handled:
                    101:  We figure out what power state we will be in when the new domain state is reached.  If it is different from our current
                    102:  state we notify all our interested parties.  When they have all acknowledged, we acknowledge the parent.  When all the
                    103:  parent's interested parties have acknowledged, it raises power in the domain and waits for power to settle.  Then it
                    104:  notifies everyone that the new state has been reached.  When we get this call, we call the controlling driver, instructing it
                    105:  to assume the new state, and wait for power to settle.  Then we notify our interested parties.  When they all acknowledge
                    106:  we are done.
                    107: 
                    108:  In either of the two cases above, it is possible that we will not be changing state even though the domain is.  Examples:
                    109:  A change to a lower domain state may not affect us because we are already in a low enough state, and
                    110:  We will not take advantage of a change to a higher domain state, because we have no need of the higher power.
                    111:  In such a case, there is nothing to do but acknowledge the parent.  So when the parent calls our powerDomainWillChange
                    112:  method, and we decide that we will not be changing state, we merely acknowledge the parent, via return code, and wait.
                    113:  When the parent subsequently calls powerStateDidChange, we acknowledge again via return code, and the change is complete.
                    114: 
                    115:  Power state changes are processed in a state machine, and since there are four varieties of power state changes, there are
                    116:  four major paths through the state machine:
                    117: 
                    118:  The fourth is nearly trivial.  In this path, the parent is changing the domain state, but we are not changing the device state.
                    119:  The change starts when the parent calls powerDomainWillChange.  All we do is acknowledge the parent and enter the "IOPMparent_postchange" state.  We wait there until the parent calls powerStateDidChange.  Then we acknowledge the parent
                    120:  again, and we're done.
                    121: 
                    122:  The first is fairly simple.  It starts when a power domain child calls requestDomainState and we decide to change power states
                    123:  to accomodate the child, or if our power-controlling driver calls changeStateTo, or if some other driver which is using our
                    124:  device calls makeUsable, or if a subclassed object calls changeStateToPriv.  These are all power changes initiated by us, not
                    125:  forced upon us by the parent.  We start by notifying interested parties.  If they all acknowledge via return code, we can go
                    126:  on to state "our_prechange_1".  Otherwise, we start the ack timer and wait for the stragglers to acknowlege by calling
                    127:  acknowledgePowerChange.  We move on to state "our_prechange_1" when all the stragglers have acknowledged,
                    128:  or when the ack timer expires on all those which didn't acknowledge.  In "our_prechange_1" we call the power-controlling
                    129:  driver to change the power state of the hardware.  If it returns saying it has done so, we go on to state "our_prechange_2".
                    130:  Otherwise, we have to wait for it, so we set the ack timer and wait.  When it calls acknowledgeSetPowerState, or when the
                    131:  ack timer expires, we go on.  In "our_prechange_2", we look in the power state array to see if there is any settle time required
                    132:  when changing from our current state to the new state.  If not, we go right away to "our_prechange_3".  Otherwise, we
                    133:  set the settle timer and wait.  When it expires, we move on.  In "our_prechange_3" state, we notify all our interested parties
                    134:  via their powerStateDidChange methods that we have finished changing power state.  If they all acknowledge via return
                    135:  code, we move on to "our_prechange_4".  Otherwise we set the ack timer and wait.  When they have all acknowledged, or
                    136:  when the ack timer has expired for those that didn't, we move on to "our_prechange_4", where we remove the used
                    137:  change note from the head of the queue and start the next one if one exists.
                    138: 
                    139:  Parent-initiated changes are more complex in the state machine.  First, power going up and power going down are handled
                    140:  differently, so they have different paths throught the state machine.  Second, we can acknowledge the parent's notification
                    141:  in two different ways, so each of the parent paths is really two.
                    142: 
                    143:  When the parent calls our powerDomainWillChange method, notifying us that it will lower power in the domain, we decide
                    144:  what state that will put our device in.  Then we embark on the state machine path "IOPMparent_prechange_down_1"
                    145:  and "IOPMparent_prechange_down_2", in which we notify interested parties of the upcoming change,
                    146:  instruct our driver to make the change, and check for settle time.  If we get to the end of this path without
                    147:  stalling due to an interested party which didn't acknowledge via return code, due to the controlling driver not able to change
                    148:  state right away, or due to a non-zero settling time, then we return IOPMAckImplied to the parent and enter
                    149:  "IOPMparent_postchange_down_1".  If we do stall in any of those states, we return IOPMWillAckLater to the parent
                    150:  and enter the parallel path "IOPMparent_prechange_down_4", "IOPMparent_prechange_down_5", and "IOPMparent_prechange_down_3", where we continue with the same processing, except that at the end we
                    151:  acknowledge the parent explicitly via acknowledgePowerChange and enter "IOPMparent_postchange_down_1".
                    152:  In "IOPMparent_postchange_down_1" we wait for the parent to lower power in the domain.  When it calls us at
                    153:  powerStateDidChange, we notify all our interested parties of the new power state.  If they all acknowledge via return
                    154:  code, we return to the parent, also acknowledging via return code.  Otherwise we enter "parent_postchange_down_2",
                    155:  waiting for acknowledgements.  When they all arrive, or when the acknowledgement timer expires for all stragglers, we
                    156:  explicitly acknowledge the parent via acknowledgePowerChange.  In either case, we are done, and we remove the used
                    157:  change note from the head of the queue and start on the next one.
                    158: 
                    159:  The case of the parent raising power in the domain is handled similarly in that there are parallel paths, one for no-stall
                    160:  that ends in implicit acknowleging the parent, and one that has stalled at least once that ends in explicit acknowledging
                    161:  the parent.  This case is different, though in that our device changes state in the second half, after the parent calls
                    162:  powerStateDidChange rather than before, as in the power-lowering case.
                    163: 
                    164:  As usual, we start by notifying our interested parties.  If they all acknowledge via return code, we acknowledge the parent
                    165:  via return code and enter "IOPMparent_postchange_up_1".  If they don't, we wait in "parent_prechange_up_1" for them to
                    166:  acknowledge or for the ack timer to expire on the stragglers.  Then we acknowledge the parent via acknowledgePowerChange
                    167:  and enter "IOPMparent_postchange_up_1", waiting for the parent to raise power and notify us.  When the parent calls us
                    168:  at powerStateDidChange, we instruct the power-controlling driver to change to the new higher state, we check for any
                    169:  necessary settling time in "IOPMparent_postchange_up_2", and we notify all interested parties that power has changed
                    170:  in "IOPMparent_postchange_up_3".  If none of these operations stall, we acknowledge the parent via return code, release
                    171:  the change note, and start the next, if there is one.  If one of them does stall, we enter the parallel path
                    172:  "IOPMparent_postchange_up_4", "IOPMparent_postchange_up_5", and "IOPMparent_postchange_up_6", which ends with
                    173:  our explicit acknowledgement to the parent.
                    174: 
                    175: */
                    176: 
                    177: 
                    178: const char priv_key[ ] = "Power Management private data";
                    179: const char prot_key[ ] = "Power Management protected data";
                    180: 
                    181: 
                    182: void IOService::PMinit ( void )
                    183: {
                    184:     if ( ! initialized ) {
                    185: 
                    186:         pm_vars =  new IOPMprot;                                       // make space for our variables
                    187:         priv = new IOPMpriv;
                    188:         pm_vars->init();
                    189:         priv->init();
                    190:         
                    191:         setProperty(prot_key, (OSObject *) pm_vars);                   // add these to the properties
                    192:         setProperty(priv_key, (OSObject *) priv);
                    193: 
                    194:         initialized = true;
                    195:         priv->owner = this;
                    196:         pm_vars->theNumberOfPowerStates = 0;                           // then initialize them
                    197:         pm_vars->myParent = NULL;
                    198:         priv->we_are_root = false;
                    199:         pm_vars->theControllingDriver = NULL;
                    200:         priv->our_lock = IOLockAlloc();
                    201:         priv->interestedDrivers = new IOPMinformeeList;
                    202:         priv->interestedDrivers->initialize();
                    203:         priv->children = new IOPMinformeeList;
                    204:         priv->children->initialize();
                    205:         priv->numberOfInformees = 0;
                    206:         priv->changeList = new IOPMchangeNoteList;
                    207:         priv->changeList->initialize();
                    208:         pm_vars->aggressiveness = 0;
                    209:         pm_vars->myCurrentState =  0;
                    210:         priv->imminentState = 0;
                    211:         priv->askingFor = 0;
                    212:         priv->ourDesiredPowerState = 0;
                    213:         pm_vars->parentCurrentPowerFlags = 0;
                    214:         pm_vars->maxCapability = 0;
                    215:         priv->driverDesire = 0;
                    216:         priv->deviceDesire = 0;
                    217:         priv->initial_change = true;
                    218:         priv->need_to_become_usable = false;
                    219:         priv->previousRequest = 0;
                    220:         priv->device_overrides = false;
                    221:         priv->machine_state = IOPMfinished;
                    222:         pm_vars->commandQueue = NULL;
                    223:         priv->timerEventSrc = NULL;
                    224:         pm_vars->PMworkloop = NULL;
                    225:         priv->activityLock = NULL;
                    226:         pm_vars->ourName = getName();
                    227:         pm_vars->thePlatform = getPlatform();
                    228:         assert( pm_vars->thePlatform != 0 );
                    229:     }
                    230: }
                    231: 
                    232: 
                    233: //*********************************************************************************
                    234: // PMstop
                    235: //
                    236: // Free up the data created in PMinit.
                    237: //*********************************************************************************
                    238: void IOService::PMstop ( void )
                    239: {
                    240:     initialized = false;
                    241: 
                    242:     removeProperty(prot_key);          // remove the properties
                    243:     removeProperty(priv_key);
                    244:     priv->interestedDrivers->release();                // remove lists
                    245:     priv->children->release();
                    246:     priv->changeList->release();
                    247:     pm_vars->release();                        // remove the instance variables
                    248:     priv->release();
                    249:     pm_vars = NULL;
                    250:     priv = NULL;
                    251: }
                    252: 
                    253: 
                    254: //*********************************************************************************
                    255: // joinPMtree
                    256: //
                    257: // A policy-maker calls its nub here when initializing, to be attached into
                    258: // the power management hierarchy.  The default function is to call the
                    259: // platform expert, which knows how to do it.  This method is overridden
                    260: // by a nub subclass which may either know how to do it, or may need
                    261: // to take other action.
                    262: //
                    263: // This may be the only "power management" method used in a nub,
                    264: // meaning it may not be initialized for power management.
                    265: //*********************************************************************************
                    266: void IOService::joinPMtree ( IOService * driver )
                    267: {
                    268:     IOPlatformExpert * thePlatform;
                    269: 
                    270:     thePlatform = getPlatform();
                    271:     assert(thePlatform != 0 );
                    272:     thePlatform->PMRegisterDevice(this,driver);
                    273: }
                    274: 
                    275: 
                    276: //*********************************************************************************
                    277: // youAreRoot
                    278: //
                    279: // Power Managment is informing us that we are the root power domain.
                    280: // The only difference between us and any other power domain is that
                    281: // we have no parent and therefore never call it.
                    282: //*********************************************************************************
                    283: IOReturn IOService::youAreRoot ( void )
                    284: {
                    285:     priv-> we_are_root = true;
                    286:     pm_vars->myParent = (IOService *)1;                // we won't use this, but keep it non-NULL
                    287:     return IOPMNoErr;
                    288: }
                    289: 
                    290: 
                    291: //*********************************************************************************
                    292: // setParent
                    293: //
                    294: // Power Management is informing us who our parent is.
                    295: // If we have a controlling driver, find out, given our newly-informed
                    296: // power domain state, what state it would be in, and then tell it
                    297: // to assume that state.
                    298: //*********************************************************************************
                    299: IOReturn IOService::setParent ( IOService * theParent, IOPMPowerFlags currentState )
                    300: {
                    301:     unsigned long tempDesire;
                    302: 
                    303:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSetParent,(unsigned long)currentState,0);
                    304: 
                    305:     attachToParent( theParent, gIOPowerPlane);
                    306:     pm_vars->myParent = theParent;
                    307:     pm_vars->parentCurrentPowerFlags = currentState;
                    308:     if ( pm_vars->theControllingDriver != NULL ) {
                    309:         pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(pm_vars->parentCurrentPowerFlags);
                    310:         tempDesire = priv->deviceDesire;                       // initially change into the state we are already in
                    311:         priv->deviceDesire = pm_vars->theControllingDriver->initialPowerStateForDomainState(pm_vars->parentCurrentPowerFlags);
                    312:         changeState();
                    313:         priv->deviceDesire = tempDesire;                       // put this back like before
                    314:     }
                    315:    return IOPMNoErr;
                    316: }
                    317: 
                    318: 
                    319: //*********************************************************************************
                    320: // addChild
                    321: //
                    322: // Power Management is informing us who our children are.
                    323: //*********************************************************************************
                    324: IOReturn IOService::addChild ( IOService * theChild )
                    325: {
                    326:     IOPMinformee * newChild;
                    327:     IOPMPowerFlags capability;
                    328: 
                    329:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAddChild,0,0);
                    330: 
                    331:     theChild->retain();
                    332:     
                    333:     newChild = new IOPMpmChild;
                    334:     newChild->initialize(theChild);                            // make a new child
                    335:     priv->children->addToList(newChild);                       // add it to list of children
                    336:     priv->numberOfInformees = priv->children->numberOfItems() +  priv->interestedDrivers->numberOfItems();
                    337:     if ( pm_vars->theControllingDriver == NULL ) {             // tell it the current state of the power domain
                    338:         capability = 0;
                    339:     }
                    340:     else {
                    341:         capability =  pm_vars->thePowerStates[pm_vars->myCurrentState].outputPowerCharacter;
                    342:     }
                    343:     theChild->setParent(this,capability);
                    344:     theChild->setAggressiveness (kPMGeneralAggressiveness,pm_vars->aggressiveness);    // tell it the current aggressiveness
                    345:     add_to_active_change(newChild, true);                      // catch it up if change is in progress
                    346:     return IOPMNoErr;
                    347: }
                    348: 
                    349: 
                    350: //*********************************************************************************
                    351: // removeChild
                    352: //
                    353: //*********************************************************************************
                    354: IOReturn IOService::removeChild ( IOService * theChild )
                    355: {
                    356:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRemoveChild,0,0);
                    357: 
                    358:     priv->children->removeFromList(theChild);    // remove the departing child
                    359:     priv->numberOfInformees = priv->children->numberOfItems() +  priv->interestedDrivers->numberOfItems();
                    360:     
                    361:     if ( (pm_vars->theControllingDriver == NULL) ||    // if not fully initialized
                    362:          (pm_vars->myParent == NULL) ) {
                    363:         return IOPMNoErr;                              // we can do no more
                    364:     }
                    365: 
                    366:     changeState();                                     // change state if we can now tolerate lower power
                    367: 
                    368:     return IOPMNoErr;
                    369: }
                    370: 
                    371: 
                    372: //*********************************************************************************
                    373: // registerControllingDriver
                    374: //
                    375: // A driver has called us volunteering to control power to our device.
                    376: // If the power state array it provides is richer than the one we already
                    377: // know about (supplied by an earlier volunteer), then accept the offer.
                    378: // Notify all interested parties of our power state, which we now know.
                    379: //*********************************************************************************
                    380: 
                    381: IOReturn IOService::registerControllingDriver ( IOService * controllingDriver, IOPMPowerState* powerStates, unsigned long numberOfStates  )
                    382: {
                    383:     unsigned long i;
                    384:     unsigned long tempDesire;
                    385: 
                    386:     if ( (numberOfStates > pm_vars->theNumberOfPowerStates) && (numberOfStates > 1) ) {
                    387:         if (  priv->changeList->currentChange() == -1 ) {
                    388:             if ( controllingDriver != NULL ) {
                    389:                 if ( numberOfStates <= IOPMMaxPowerStates ) {
                    390:                     switch ( powerStates[0].version  ) {
                    391:                         case 1:
                    392:                             pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriver,
                    393:                                                                     (unsigned long)numberOfStates, (unsigned long)powerStates[0].version);
                    394:                             for ( i = 0; i < numberOfStates; i++ ) {
                    395:                                 pm_vars->thePowerStates[i] = powerStates[i];
                    396:                             }
                    397:                                 break;
                    398:                         case 2:
                    399:                             pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriver,
                    400:                                                                     (unsigned long) numberOfStates,(unsigned long) powerStates[0].version);
                    401:                             for ( i = 0; i < numberOfStates; i++ ) {
                    402:                                 pm_vars->thePowerStates[i].version = powerStates[i].version;
                    403:                                 pm_vars->thePowerStates[i].capabilityFlags = powerStates[i].capabilityFlags;
                    404:                                 pm_vars->thePowerStates[i].outputPowerCharacter = powerStates[i].outputPowerCharacter;
                    405:                                 pm_vars->thePowerStates[i].inputPowerRequirement = powerStates[i].inputPowerRequirement;
                    406:                                 pm_vars->thePowerStates[i].staticPower = powerStates[i].staticPower;
                    407:                                 pm_vars->thePowerStates[i].unbudgetedPower = powerStates[i].unbudgetedPower;
                    408:                                 pm_vars->thePowerStates[i].powerToAttain = powerStates[i].powerToAttain;
                    409:                                 pm_vars->thePowerStates[i].timeToAttain = powerStates[i].timeToAttain;
                    410:                                 pm_vars->thePowerStates[i].settleUpTime = powerStates[i].settleUpTime;
                    411:                                 pm_vars->thePowerStates[i].timeToLower = powerStates[i].timeToLower;
                    412:                                 pm_vars->thePowerStates[i].settleDownTime = powerStates[i].settleDownTime;
                    413:                                 pm_vars->thePowerStates[i].powerDomainBudget = powerStates[i].powerDomainBudget;
                    414:                             }
                    415:                                 break;
                    416:                         default:
                    417:                             pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr1,
                    418:                                                                     (unsigned long)powerStates[0].version,0);
                    419:                             return IOPMNoErr;
                    420:                     }
                    421: 
                    422:                     pm_vars->theNumberOfPowerStates = numberOfStates;
                    423:                     pm_vars->theControllingDriver = controllingDriver;
                    424:                     if ( priv->interestedDrivers->findItem(controllingDriver) == NULL ) {      // register it as interested
                    425:                         registerInterestedDriver (controllingDriver );                         // unless already done
                    426:                     }
                    427:                     if ( priv->need_to_become_usable ) {
                    428:                         priv->need_to_become_usable = false;
                    429:                         priv->deviceDesire = pm_vars->theNumberOfPowerStates - 1;
                    430:                     }
                    431:                     if ( pm_vars->myParent != NULL ) {
                    432:                         pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(pm_vars->parentCurrentPowerFlags);
                    433:                         tempDesire = priv->deviceDesire;                       // initially change into the state we are already in
                    434:                         priv->deviceDesire = pm_vars->theControllingDriver->initialPowerStateForDomainState(pm_vars->parentCurrentPowerFlags);
                    435:                         changeState();
                    436:                         priv->deviceDesire = tempDesire;                       // put this back like before
                    437:                     }
                    438:                 }
                    439:                 else {
                    440:                     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr2,(unsigned long)numberOfStates,0);
                    441:                 }
                    442:             }
                    443:             else {
                    444:                 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr4,0,0);
                    445:             }
                    446:         }
                    447:     }
                    448:     else {
                    449:         pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr5,(unsigned long)numberOfStates,0);
                    450:     }
                    451:     return IOPMNoErr;
                    452: }
                    453: 
                    454: //*********************************************************************************
                    455: // registerInterestedDriver
                    456: //
                    457: // Add the caller to our list of interested drivers and return our current
                    458: // power state.  If we don't have a power-controlling driver yet, we will
                    459: // call this interested driver again later when we do get a driver and find
                    460: // out what the current power state of the device is.
                    461: //*********************************************************************************
                    462: 
                    463: IOPMPowerFlags IOService::registerInterestedDriver ( IOService * theDriver )
                    464: {
                    465:     IOPMinformee * newInformee;
                    466:     IOPMPowerFlags futureCapability;
                    467: 
                    468:     if (theDriver == NULL ) {
                    469:         return 0;                                                      // can't tell it a state yet
                    470:     }
                    471: 
                    472:     theDriver->retain();
                    473:     
                    474:     newInformee = new IOPMinformee;                            // make new driver node
                    475:     newInformee->initialize(theDriver);
                    476:     priv->interestedDrivers->addToList(newInformee);                   // add it to list of drivers
                    477:     priv->numberOfInformees = priv->children->numberOfItems() +  priv->interestedDrivers->numberOfItems();
                    478: 
                    479:     if ( (pm_vars->theControllingDriver == NULL) || (pm_vars->myParent == NULL) ) {
                    480:         pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,0,0);
                    481:         return 0;                                                      // can't tell it a state yet
                    482:     }
                    483: 
                    484:     switch (priv->machine_state) {                                     // can we notify new driver of a change in progress?
                    485:         case IOPMour_prechange_1:
                    486:         case IOPMour_prechange_4:
                    487:         case IOPMparent_prechange_down_4:
                    488:         case IOPMparent_postchange_down_2:
                    489:         case IOPMparent_prechange_up_1:
                    490:         case IOPMparent_postchange_up_6:
                    491:             futureCapability = priv->head_note_capabilityFlags;                        // yes, remember what we tell it
                    492:             pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,(unsigned long)futureCapability,0);
                    493:             add_to_active_change(newInformee,false);                           // notify it
                    494:             return futureCapability;                                           // and return the same thing
                    495:     }
                    496:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,
                    497:                                             (unsigned long) pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags,0);
                    498:     return  pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags;  // no, return current capability
                    499: }
                    500: 
                    501: 
                    502: //*********************************************************************************
                    503: // deRegisterInterestedDriver
                    504: //
                    505: //*********************************************************************************
                    506: IOReturn IOService::deRegisterInterestedDriver ( IOService * theDriver )
                    507: {
                    508:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRemoveDriver,0,0);
                    509: 
                    510:     priv->interestedDrivers->removeFromList(theDriver);                                  // remove the departing driver
                    511:     priv->numberOfInformees = priv->children->numberOfItems() +  priv->interestedDrivers->numberOfItems();
                    512: 
                    513:     theDriver->release();
                    514: 
                    515:     return IOPMNoErr;
                    516: }
                    517: 
                    518: 
                    519: //*********************************************************************************
                    520: // acknowledgePowerChange
                    521: //
                    522: // After we notified one of the interested drivers or a power-domain child
                    523: // of an impending change in power, it has called to say it is now
                    524: // prepared for the change.  If this object is the last to
                    525: // acknowledge this change, we take whatever action we have been waiting
                    526: // for.
                    527: // That may include acknowledging to our parent.  In this case, we do it
                    528: // last of all to insure that this doesn't cause the parent to call us some-
                    529: // where else and alter data we are relying on here (like the very existance
                    530: // of a "current change note".)
                    531: //*********************************************************************************
                    532: 
                    533: IOReturn IOService::acknowledgePowerChange ( IOService * whichObject )
                    534: {
                    535:    IOPMinformee *      ackingObject;
                    536: 
                    537:     ackingObject =  priv->interestedDrivers->findItem(whichObject);                    // one of our interested drivers?
                    538:    if ( ackingObject == NULL ) {
                    539:        ackingObject = priv->children->findItem(whichObject);                   // no, one of our children?
                    540:        if ( ackingObject == NULL ) {
                    541:            pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr1,0,0);
                    542:            return IOPMNoErr;                                                   // no, just return
                    543:        }
                    544:        else {
                    545:            pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChildAcknowledge,0,0);
                    546:        }
                    547:    }
                    548:    else {
                    549:        pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogDriverAcknowledge,0,0);
                    550:    }
                    551: 
                    552:    if (! acquire_lock() ) {
                    553:        return IOPMNoErr;
                    554:    }
                    555: 
                    556:    if (priv->head_note_pendingAcks != 0 ) {                                    // yes, make sure we're expecting acks
                    557:        if ( ackingObject->timer != 0 ) {                                               // make sure we're expecting this ack
                    558:            ackingObject->timer = 0;                                            // mark it acked
                    559:            priv->head_note_pendingAcks -= 1;                                   // that's one fewer to worry about
                    560:            if ( priv->head_note_pendingAcks == 0 ) {                                   // is that the last?
                    561:                stop_ack_timer();                                                       // yes, stop the timer
                    562:                IOUnlock(priv->our_lock);
                    563:                all_acked();                                                    // and now we can continue
                    564:                return IOPMNoErr;
                    565:            }
                    566:        }
                    567:        else {
                    568:            pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr2,0,0);     // this object has already acked
                    569:        }
                    570:    }
                    571:    else {
                    572:        pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr3,0,0); // not expecting anybody to ack
                    573:    }
                    574:    IOUnlock(priv->our_lock);
                    575:    return IOPMNoErr;
                    576: }
                    577: 
                    578: //*********************************************************************************
                    579: // acknowledgeSetPowerState
                    580: //
                    581: // After we instructed our controlling driver to change power states,
                    582: // it has called to say it has finished doing so.
                    583: // We continue to process the power state change.
                    584: //*********************************************************************************
                    585: 
                    586: IOReturn IOService::acknowledgeSetPowerState ( void )
                    587: {
                    588:     if (! acquire_lock() ) {
                    589:         return IOPMNoErr;
                    590:     }
                    591:     if ( priv->driver_timer == -1 ) {
                    592:         priv->driver_timer = 0;                                // driver is acking instead of using return code
                    593:     }
                    594:     else {
                    595:         if ( priv->driver_timer > 0 ) {                        // are we expecting this?
                    596:             stop_ack_timer();                          // yes, stop the timer
                    597:             priv->driver_timer = 0;
                    598:             IOUnlock(priv->our_lock);
                    599:             pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogDriverAcknowledgeSet,0,0);
                    600:             driver_acked();
                    601:             return IOPMNoErr;
                    602:         }
                    603:         else {
                    604:             pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr4,0,0);            // no
                    605:         }
                    606:     }
                    607:     IOUnlock(priv->our_lock);
                    608:     return IOPMNoErr;
                    609: }
                    610: 
                    611: 
                    612: //*********************************************************************************
                    613: // driver_acked
                    614: //
                    615: // Either the controlling driver has called acknowledgeSetPowerState
                    616: // or the acknowledgement timer has expired while waiting for that.
                    617: // We carry on processing the current change note.
                    618: //*********************************************************************************
                    619: 
                    620: void IOService::driver_acked ( void )
                    621: {
                    622:     switch (priv->machine_state) {
                    623:         case IOPMour_prechange_2:
                    624:             our_prechange_2();
                    625:             break;
                    626:         case IOPMparent_prechange_down_5:
                    627:             parent_prechange_down_5();
                    628:             break;
                    629:         case IOPMparent_postchange_up_4:
                    630:             parent_postchange_up_4();
                    631:             break;
                    632:     }
                    633: }
                    634: 
                    635: 
                    636: //*********************************************************************************
                    637: // powerDomainWillChangeTo
                    638: //
                    639: // Called by the power-hierarchy parent notifying of a new power state
                    640: // in the power domain.
                    641: // If power is going lower, we notify our interested parties that power
                    642: // will lower.  When they have all acked, we lower the state of our device
                    643: // to the state appropriate for the coming domain level.  Then we ack the parent.
                    644: // Later, when the domain has lowered, we notify everyone that power has dropped.
                    645: //
                    646: // If power is going higher and we will take advantage of this by raising our
                    647: // own power state, we notify our interested parties that power
                    648: // will raise.  When they have all acked, we ack the parent.  Later, when
                    649: // the domain has raised, we raise our power level.  When power has
                    650: // settled, we inform our interested parties.  When they have all acked,
                    651: // we ack the parent.
                    652: //*********************************************************************************
                    653: 
                    654: IOReturn IOService::powerDomainWillChangeTo ( IOPMPowerFlags newPowerStateFlags )
                    655: {
                    656:    unsigned long       newStateNumber;
                    657: 
                    658:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogWillChange,(unsigned long)newPowerStateFlags,0);
                    659: 
                    660:     if ( pm_vars->myParent == NULL ) {
                    661:         return IOPMAckImplied;                                         // somebody goofed
                    662:     }
                    663: 
                    664:     if  ( pm_vars->theControllingDriver == NULL ) {
                    665:         pm_vars->parentCurrentPowerFlags = newPowerStateFlags;         // we can't take any action except note the change
                    666:         return IOPMAckImplied;
                    667:     }
                    668:     newStateNumber = pm_vars->theControllingDriver->maxCapabilityForDomainState(newPowerStateFlags);
                    669:     return enqueuePowerChange(IOPMParentInitiated, newStateNumber,newPowerStateFlags); // tell interested parties about it
                    670: }
                    671: 
                    672: 
                    673: //*********************************************************************************
                    674: // powerDomainDidChangeTo
                    675: //
                    676: // Called by the power-hierarchy parent after the power state of the power domain
                    677: // has settled at a new level.  We must notify our interested drivers and children.
                    678: // If they all acknowledge immediately, so do we.  Otherwise, we'll acknowledge
                    679: // when the last of them does.
                    680: //*********************************************************************************
                    681: 
                    682: IOReturn IOService::powerDomainDidChangeTo ( IOPMPowerFlags newPowerStateFlags )
                    683: {
                    684: 
                    685:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogDidChange,(unsigned long)newPowerStateFlags,0);
                    686: 
                    687:     if ( (pm_vars->myParent == NULL) || (pm_vars->theControllingDriver == NULL) ) {
                    688:         return IOPMAckImplied;                                 // somebody goofed
                    689:     }
                    690: 
                    691:     switch (priv->machine_state) {
                    692:         case IOPMparent_postchange_down_1:
                    693:             return parent_postchange_down_1();                         // life-style 2 continues
                    694:         case IOPMparent_postchange_up_1:
                    695:             return parent_postchange_up_1();                           // life-style 3 continues
                    696:         case IOPMparent_postchange_null:
                    697:             all_done();
                    698:             return IOPMAckImplied;                                     // life-style 4 done
                    699:     }
                    700: 
                    701:     return IOPMAckImplied;                                     // something wrong
                    702: }
                    703: 
                    704: 
                    705: //*********************************************************************************
                    706: // requestDomainState
                    707: //
                    708: //
                    709: //*********************************************************************************
                    710: IOReturn IOService::requestDomainState ( IOPMPowerFlags desiredState, IOService* whichChild, unsigned long specification )
                    711: {
                    712:     unsigned long      i;
                    713:     IOPMinformee *     nextChild;
                    714: 
                    715:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRequestDomain,
                    716:                                 (unsigned long)desiredState,(unsigned long)specification);
                    717: 
                    718:     if ( pm_vars->theControllingDriver == NULL) {
                    719:         return IOPMNotYetInitialized;
                    720:     }
                    721: 
                    722:     switch (specification) {
                    723:         case IOPMLowestState:
                    724:             i = 0;
                    725:             while ( i < pm_vars->theNumberOfPowerStates ) {
                    726:                 if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & desiredState) == desiredState ) {
                    727:                     break;
                    728:                 }
                    729:                 i++;
                    730:             }
                    731:                 if ( i >= pm_vars->theNumberOfPowerStates ) {
                    732:                 return IOPMNoSuchState;
                    733:            }
                    734:             break;
                    735: 
                    736:         case IOPMNextLowerState:
                    737:             i = pm_vars->myCurrentState - 1;
                    738:             while ( i >= 0 ) {
                    739:                 if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & desiredState) == desiredState ) {
                    740:                     break;
                    741:                 }
                    742:                 i--;
                    743:             }
                    744:             if ( i < 0 ) {
                    745:                 return IOPMNoSuchState;
                    746:             }
                    747:             break;
                    748: 
                    749:         case IOPMHighestState:
                    750:             i = pm_vars->theNumberOfPowerStates;
                    751:             while ( i >= 0 ) {
                    752:                 i--;
                    753:                 if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & desiredState) == desiredState ) {
                    754:                     break;
                    755:                 }
                    756:             }
                    757:             if ( i < 0 ) {
                    758:                 return IOPMNoSuchState;
                    759:             }
                    760:             break;
                    761: 
                    762:         case IOPMNextHigherState:
                    763:             i = pm_vars->myCurrentState + 1;
                    764:             while ( i < pm_vars->theNumberOfPowerStates ) {
                    765:                 if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & desiredState) == desiredState ) {
                    766:                     break;
                    767:                 }
                    768:             i++;
                    769:             }
                    770:                 if ( i == pm_vars->theNumberOfPowerStates ) {
                    771:                 return IOPMNoSuchState;
                    772:             }
                    773:             break;
                    774: 
                    775:         default:
                    776:             return IOPMBadSpecification;
                    777:     }
                    778: 
                    779: // Now loop through the children.  When we encounter the calling child, save
                    780: // the new state as this child's desire.  Then, compute a new maximum
                    781: // of everybody's desires.
                    782: 
                    783:     nextChild = priv->children->firstInList();
                    784: 
                    785:    if ( nextChild == NULL ) {                  // we're not a power domain
                    786:        return IOPMNoErr;
                    787:    }
                    788: 
                    789:    while ( nextChild != NULL ) {
                    790:        if ( whichChild == (IOService*)nextChild->whatObject ) {
                    791:            ((IOPMpmChild *)nextChild)->desiredDomainState = i;
                    792:            break;
                    793:        }
                    794:        nextChild = priv->children->nextInList(nextChild);
                    795:    }
                    796: 
                    797:    if ( pm_vars->myParent != NULL ) {
                    798:        changeState();                                  // change state if all children can now tolerate lower power
                    799:    }
                    800: 
                    801:    return IOPMNoErr;
                    802: }
                    803: 
                    804: 
                    805: //*********************************************************************************
                    806: // makeUsable
                    807: //
                    808: // Some client of our device is asking that we become usable.  Although
                    809: // this has not come from a subclassed device object, treat it exactly
                    810: // as if it had.  In this way, subsequent requests for lower power from
                    811: // a subclassed device object will pre-empt this request.
                    812: //
                    813: // We treat this as a subclass object request to switch to the
                    814: // highest power state.
                    815: //*********************************************************************************
                    816: 
                    817: IOReturn IOService::makeUsable ( void )
                    818: {
                    819:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogMakeUsable,0,0);
                    820: 
                    821:     if ( pm_vars->theControllingDriver == NULL ) {
                    822:         priv->need_to_become_usable = true;
                    823:         return IOPMNoErr;
                    824:     }
                    825:     priv->deviceDesire = pm_vars->theNumberOfPowerStates - 1;
                    826:     if ( pm_vars->myParent == NULL  ) {
                    827:         return IOPMNoErr;
                    828:     }
                    829:    return changeState();
                    830: }
                    831: 
                    832: 
                    833: //*********************************************************************************
                    834: // currentCapability
                    835: //
                    836: //*********************************************************************************
                    837: 
                    838: IOPMPowerFlags IOService::currentCapability ( void )
                    839: {
                    840:     if ( pm_vars->theControllingDriver == NULL ) {
                    841:         return 0;
                    842:     }
                    843:     else {
                    844:         return   pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags;
                    845:     }
                    846: }
                    847: 
                    848: 
                    849: //*********************************************************************************
                    850: // changeStateTo
                    851: //
                    852: // For some reason, our power-controlling driver has decided it needs to change
                    853: // power state.  We enqueue the power change so that appropriate parties
                    854: // will be notified, and then we will instruct the driver to make the change.
                    855: //*********************************************************************************
                    856: 
                    857: IOReturn IOService::changeStateTo ( unsigned long ordinal )
                    858: {
                    859:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeStateTo,ordinal,0);
                    860: 
                    861:     if ( ordinal >= pm_vars->theNumberOfPowerStates ) {
                    862:         return IOPMParameterError;
                    863:     }
                    864:     priv->driverDesire = ordinal;
                    865:     if ( pm_vars->myParent == NULL ) {
                    866:         return IOPMNoErr;
                    867:     }
                    868:     return changeState();
                    869: }
                    870: 
                    871: //*********************************************************************************
                    872: // changeStateToPriv
                    873: //
                    874: // For some reason, a subclassed device object has decided it needs to change
                    875: // power state.  We enqueue the power change so that appropriate parties
                    876: // will be notified, and then we will instruct the driver to make the change.
                    877: //*********************************************************************************
                    878: 
                    879: IOReturn IOService::changeStateToPriv ( unsigned long ordinal )
                    880: {
                    881:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeStateToPriv,ordinal,0);
                    882: 
                    883:     if ( pm_vars->theControllingDriver == NULL) {
                    884:         return IOPMNotYetInitialized;
                    885:     }
                    886:     if ( ordinal >= pm_vars->theNumberOfPowerStates ) {
                    887:         return IOPMParameterError;
                    888:     }
                    889:     priv->deviceDesire = ordinal;
                    890:     if ( pm_vars->myParent == NULL ) {
                    891:         return IOPMNoErr;
                    892:     }
                    893:     return changeState();
                    894: }
                    895: 
                    896: 
                    897: //*********************************************************************************
                    898: // changeState
                    899: //
                    900: // A subclass object, our controlling driver, or a power domain child
                    901: // has asked for a different power state.  Here we compute what new
                    902: // state we should enter and enqueue the change (or start it).
                    903: //*********************************************************************************
                    904: 
                    905: IOReturn IOService::changeState ( void )
                    906: {
                    907:     unsigned long      newDesiredState = 0;
                    908:     IOPMinformee * nextChild;
                    909: 
                    910:     // Compute the maximum  of our children's desires, our controlling driver's desire, and the subclass device's desire.
                    911: 
                    912:     if ( !  priv->device_overrides ) {
                    913:         nextChild = priv->children->firstInList();
                    914: 
                    915:         while ( nextChild != NULL ) {
                    916:             if ( (( IOPMpmChild *)nextChild)->desiredDomainState > newDesiredState ) {
                    917:                 newDesiredState =(( IOPMpmChild *)nextChild)->desiredDomainState;
                    918:             }
                    919:             nextChild = priv->children->nextInList(nextChild);
                    920:         }
                    921:         if (  priv->driverDesire > newDesiredState ) {
                    922:             newDesiredState =  priv->driverDesire;
                    923:         }
                    924:     }
                    925: 
                    926:     if ( priv->deviceDesire > newDesiredState ) {
                    927:         newDesiredState = priv->deviceDesire;
                    928:     }
                    929: 
                    930:     priv->ourDesiredPowerState = newDesiredState;
                    931: 
                    932:     return enqueuePowerChange(IOPMWeInitiated,newDesiredState,0);
                    933: }
                    934: 
                    935: 
                    936: //*********************************************************************************
                    937: // currentPowerConsumption
                    938: //
                    939: //*********************************************************************************
                    940: 
                    941: unsigned long IOService::currentPowerConsumption ( void )
                    942: {
                    943:     if ( pm_vars->theControllingDriver == NULL ) {
                    944:         return 0;
                    945:     }
                    946:     else {
                    947:         return  pm_vars->thePowerStates[pm_vars->myCurrentState].staticPower;
                    948:     }
                    949: }
                    950: 
                    951: //*********************************************************************************
                    952: // activityTickle
                    953: //
                    954: // The activity tickle with parameter kIOPMSubclassPolicyis not handled
                    955: // here and should have been intercepted by the subclass.
                    956: // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
                    957: // flag to be set, and the device state checked.  If the device has been
                    958: // powered down, it is powered up again.
                    959: //*********************************************************************************
                    960: 
                    961: bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber=0 )
                    962: {
                    963:     if ( type == kIOPMSuperclassPolicy1 ) {
                    964:         if ( (priv->activityLock == NULL) ||
                    965:              (pm_vars->theControllingDriver == NULL) ||
                    966:              ( pm_vars->commandQueue == NULL) ) {
                    967:             return true;
                    968:         }
                    969:         IOTakeLock(priv->activityLock);
                    970:         priv->device_active = true;
                    971:         if ( pm_vars->myCurrentState >= stateNumber) {
                    972:             IOUnlock(priv->activityLock);
                    973:             return true;
                    974:         }
                    975:         IOUnlock(priv->activityLock);                          // send a message on the command queue
                    976:         pm_vars->commandQueue->enqueueCommand(true, (void *)kPMunIdleDevice, (void *)stateNumber);
                    977:         return false;
                    978:     }
                    979:     return true;
                    980: }
                    981: 
                    982: //*********************************************************************************
                    983: // getPMworkloop
                    984: //
                    985: // A child is calling to get a pointer to the Power Management workloop.
                    986: // We got it or get it from our parent.
                    987: //*********************************************************************************
                    988: 
                    989: IOWorkLoop * IOService::getPMworkloop ( void )
                    990: {
                    991:     if ( pm_vars->myParent == NULL ) {
                    992:         return NULL;
                    993:     }
                    994:     if ( pm_vars->PMworkloop == NULL ) {
                    995:         pm_vars->PMworkloop =  pm_vars->myParent->getPMworkloop();
                    996:     }
                    997:     return  pm_vars->PMworkloop;
                    998: }
                    999: 
                   1000: 
                   1001: //*********************************************************************************
                   1002: // setIdleTimerPeriod
                   1003: //
                   1004: // A subclass policy-maker is going to use our standard idleness
                   1005: // detection service.  Make a command queue and an idle timer and
                   1006: // connect them to the power management workloop.  Finally,
                   1007: // start the timer.
                   1008: //*********************************************************************************
                   1009: 
                   1010: IOReturn  IOService::setIdleTimerPeriod ( unsigned long period )
                   1011: {
                   1012:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMsetIdleTimerPeriod,period, 0);
                   1013: 
                   1014:     priv->idle_timer_period = period;
                   1015: 
                   1016:     if ( period > 0 ) {
                   1017:         if ( getPMworkloop() == NULL ) {
                   1018:             return kIOReturnError;
                   1019:         }
                   1020: 
                   1021:         if (pm_vars->commandQueue == NULL ) {          // make the command queue
                   1022:             pm_vars->commandQueue = IOCommandQueue::commandQueue(this, PMreceiveCmd);
                   1023:             if (!  pm_vars->commandQueue ||
                   1024:                 (  pm_vars->PMworkloop->addEventSource( pm_vars->commandQueue) != kIOReturnSuccess) ) {
                   1025:                 return kIOReturnError;
                   1026:             }
                   1027:         }
                   1028:                                                         // make the timer event
                   1029:         if (  priv->timerEventSrc == NULL ) {
                   1030:             priv->timerEventSrc = IOTimerEventSource::timerEventSource(this,
                   1031:                                                     PM_idle_timer_expired);
                   1032:             if ( !  priv->timerEventSrc ||
                   1033:                  ( pm_vars->PMworkloop->addEventSource(  priv->timerEventSrc) != kIOReturnSuccess) ) {
                   1034:                 return kIOReturnError;
                   1035:             }
                   1036:         }
                   1037: 
                   1038:         if ( priv->activityLock == NULL ) {
                   1039:             priv->activityLock = IOLockAlloc();
                   1040:         }
                   1041: 
                   1042:         start_PM_idle_timer();
                   1043:     }
                   1044:     return IOPMNoErr;
                   1045: }
                   1046: 
                   1047: 
                   1048: //*********************************************************************************
                   1049: // start_PM_idle_timer
                   1050: //
                   1051: // The parameter is a pointer to us.  Use it to call our timeout method.
                   1052: //*********************************************************************************
                   1053: void IOService::start_PM_idle_timer ( void )
                   1054: {
                   1055:     priv->timerEventSrc->setTimeout(priv->idle_timer_period, NSEC_PER_SEC);
                   1056: }
                   1057: 
                   1058: 
                   1059: //*********************************************************************************
                   1060: // PM_idle_timer_expired
                   1061: //
                   1062: // The parameter is a pointer to us.  Use it to call our timeout method.
                   1063: //*********************************************************************************
                   1064: 
                   1065: void PM_idle_timer_expired(OSObject * ourSelves, IOTimerEventSource *)
                   1066: {
                   1067:    ((IOService *)ourSelves)->PM_idle_timer_expiration();
                   1068: }
                   1069: 
                   1070: 
                   1071: //*********************************************************************************
                   1072: // PM_idle_timer_expiration
                   1073: //
                   1074: // The idle timer has expired.  If there has been activity since the last
                   1075: // expiration, just restart the timer and return.  If there has not been
                   1076: // activity, switch to the next lower power state and restart the timer.
                   1077: //*********************************************************************************
                   1078: 
                   1079: void IOService::PM_idle_timer_expiration ( void )
                   1080: {
                   1081:     if (  priv->idle_timer_period > 0 ) {
                   1082:         IOTakeLock(priv->activityLock);
                   1083:         if ( priv->device_active ) {
                   1084:             priv->device_active = false;
                   1085:             IOUnlock(priv->activityLock);
                   1086:             start_PM_idle_timer();
                   1087:             return;
                   1088:         }
                   1089:         if (pm_vars->myCurrentState > 0 ) {
                   1090:             IOUnlock(priv->activityLock);
                   1091:             priv->askingFor = pm_vars->myCurrentState - 1;
                   1092:             changeStateToPriv(pm_vars->myCurrentState - 1);
                   1093:             start_PM_idle_timer();
                   1094:             return;
                   1095:         }
                   1096:         IOUnlock(priv->activityLock);
                   1097:         start_PM_idle_timer();
                   1098:     }
                   1099: }
                   1100: 
                   1101: 
                   1102: 
                   1103: // **********************************************************************************
                   1104: // PMreceiveCmd
                   1105: //
                   1106: //
                   1107: //
                   1108: // **********************************************************************************
                   1109: void PMreceiveCmd ( OSObject * theDriver,  void * command, void * param1, void * param2, void *param3 )
                   1110: {
                   1111:    ((IOService *)theDriver)->command_received(command,param1,param2,param3);
                   1112: }
                   1113: 
                   1114: 
                   1115: // **********************************************************************************
                   1116: // command_received
                   1117: //
                   1118: // We have received a command from ourselves on the command queue.
                   1119: // This is to prevent races with timer-expiration code.
                   1120: // **********************************************************************************
                   1121: void IOService::command_received ( void * command, void *stateNumber , void * , void *)
                   1122: {
                   1123:     if ( command == (void *)kPMunIdleDevice ) {
                   1124:         if ((pm_vars->myCurrentState < (unsigned long)stateNumber) &&
                   1125:             (priv->imminentState < (unsigned long)stateNumber ) &&
                   1126:             ((unsigned long)stateNumber > priv->askingFor) ) {
                   1127:             priv->askingFor = (unsigned long)stateNumber;
                   1128:             changeStateToPriv((unsigned long)stateNumber);
                   1129:         }
                   1130:     }
                   1131: }
                   1132: 
                   1133: 
                   1134: //*********************************************************************************
                   1135: // setAggressiveness
                   1136: //
                   1137: // Pass on the input parameters to all power domain children. All those which are
                   1138: // power domains will pass it on to their children, etc.
                   1139: //*********************************************************************************
                   1140: 
                   1141: IOReturn IOService::setAggressiveness ( unsigned long type, unsigned long newLevel )
                   1142: {
                   1143:     IOPMinformee * nextChild;
                   1144: 
                   1145:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSetAggressiveness,type, newLevel);
                   1146: 
                   1147:     if ( type == kPMGeneralAggressiveness ) {
                   1148:         pm_vars->aggressiveness = newLevel;
                   1149:     }
                   1150: 
                   1151:     nextChild = priv->children->firstInList();
                   1152: 
                   1153:     while (  nextChild != NULL ) {
                   1154:         nextChild->whatObject->setAggressiveness(type, newLevel);
                   1155:         nextChild = priv->children->nextInList(nextChild);
                   1156:     }
                   1157: 
                   1158:     return IOPMNoErr;
                   1159: }
                   1160: 
                   1161: 
                   1162: //*********************************************************************************
                   1163: // systemWake
                   1164: //
                   1165: // Pass this to all power domain children. All those which are
                   1166: // power domains will pass it on to their children, etc.
                   1167: //*********************************************************************************
                   1168: 
                   1169: IOReturn IOService::systemWake ( void )
                   1170: {
                   1171:     IOPMinformee * nextChild;
                   1172: 
                   1173:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSystemWake,0, 0);
                   1174: 
                   1175:     nextChild = priv->children->firstInList();
                   1176: 
                   1177:     while (  nextChild != NULL ) {
                   1178:         nextChild->whatObject->systemWake();
                   1179:         nextChild = priv->children->nextInList(nextChild);
                   1180:     }
                   1181: 
                   1182:     return IOPMNoErr;
                   1183: }
                   1184: 
                   1185: 
                   1186: //*********************************************************************************
                   1187: // temperatureCriticalForZone
                   1188: //
                   1189: //*********************************************************************************
                   1190: 
                   1191: IOReturn IOService::temperatureCriticalForZone ( IOService * whichZone )
                   1192: {
                   1193:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCriticalTemp,0,0);
                   1194: 
                   1195:     if ( (pm_vars->myParent != NULL) &&
                   1196:          ( !  priv->we_are_root) ) {
                   1197:         pm_vars->myParent->temperatureCriticalForZone(whichZone);
                   1198:     }
                   1199:     return IOPMNoErr;
                   1200: }
                   1201: 
                   1202: 
                   1203: //*********************************************************************************
                   1204: // overrideOnPriv
                   1205: //
                   1206: //*********************************************************************************
                   1207: 
                   1208: 
                   1209: IOReturn IOService::overrideOnPriv ( void )
                   1210: {
                   1211:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogOverrideOn,0,0);
                   1212: 
                   1213:     priv->device_overrides = true;     // turn on the override
                   1214:     return changeState();              // change state if that changed something
                   1215: }
                   1216: 
                   1217: 
                   1218: //*********************************************************************************
                   1219: // overrideOffPriv
                   1220: //
                   1221: //*********************************************************************************
                   1222: IOReturn IOService::overrideOffPriv ( void )
                   1223: {
                   1224:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogOverrideOff,0,0);
                   1225: 
                   1226:     priv->device_overrides = false;    // turn off the override
                   1227:     return changeState();              // change state if that changed something
                   1228: }
                   1229: 
                   1230: 
                   1231: //*********************************************************************************
                   1232: // enqueuePowerChange
                   1233: //
                   1234: // Allocate a new state change notification, initialize it with fields from the
                   1235: // caller, and add it to the tail of the list of pending power changes.
                   1236: //
                   1237: // If it is early enough in the list, and almost all the time it is the only one in
                   1238: // the list, start the power change.
                   1239: //
                   1240: // In rare instances, this change will preempt the previous change in the list.
                   1241: // If the previous change is un-actioned in any way (because we are still
                   1242: // processing an even earlier power change), and if both the previous change
                   1243: // in the list and this change are initiated by us (not the parent), then we
                   1244: // needn't perform the previous change, so we collapse the list a little.
                   1245: //*********************************************************************************
                   1246: 
                   1247: IOReturn IOService::enqueuePowerChange ( unsigned long flags,  unsigned long whatStateOrdinal, unsigned long domainState )
                   1248: {
                   1249:     long       newNote;
                   1250:     long       previousNote;
                   1251: 
                   1252: // Create and initialize the new change note
                   1253: 
                   1254:     newNote = priv->changeList->createChangeNote();
                   1255:     if ( newNote == -1 ) {
                   1256:         pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogEnqueueErr,0,0);
                   1257:         return IOPMAckImplied;                 // uh-oh, our list is full
                   1258:     }
                   1259: 
                   1260:     priv->changeList->changeNote[newNote].newStateNumber = whatStateOrdinal;
                   1261:     priv->changeList->changeNote[newNote].outputPowerCharacter =  pm_vars->thePowerStates[whatStateOrdinal].outputPowerCharacter;
                   1262:     priv->changeList->changeNote[newNote].inputPowerRequirement =  pm_vars->thePowerStates[whatStateOrdinal].inputPowerRequirement;
                   1263:     priv->changeList->changeNote[newNote].capabilityFlags =  pm_vars->thePowerStates[whatStateOrdinal].capabilityFlags;
                   1264:     priv->changeList->changeNote[newNote].flags = flags;
                   1265:     if (flags & IOPMParentInitiated ) {
                   1266:         priv->changeList->changeNote[newNote].domainState =  domainState;
                   1267:     }
                   1268: 
                   1269:     previousNote = priv->changeList->previousChangeNote(newNote);
                   1270: 
                   1271:     if ( previousNote == -1 ) {
                   1272: 
                   1273:         // Queue is empty, we can start this change.
                   1274: 
                   1275:         if (flags & IOPMWeInitiated ) {
                   1276:             start_our_change(newNote);
                   1277:             return 0;
                   1278:         }
                   1279:         else {
                   1280:             return start_parent_change(newNote);
                   1281:         }
                   1282:     }
                   1283: 
                   1284:     // The queue is not empty.  Try to collapse this new change and the previous one in queue into one change.
                   1285:     // This is possible only if both changes are initiated by us, and neither has been started yet.
                   1286:     // Do this more than once if possible.
                   1287: 
                   1288:     // (A change is started iff it is at the head of the queue)
                   1289: 
                   1290:     while ( (previousNote != priv->head_note) &&  (previousNote != -1) &&
                   1291:             (priv->changeList->changeNote[newNote].flags &  priv->changeList->changeNote[previousNote].flags &  IOPMWeInitiated)  ) {
                   1292:         priv->changeList->changeNote[previousNote].outputPowerCharacter = priv->changeList->changeNote[newNote].outputPowerCharacter;
                   1293:         priv->changeList->changeNote[previousNote].inputPowerRequirement = priv->changeList->changeNote[newNote].inputPowerRequirement;
                   1294:         priv->changeList->changeNote[previousNote].capabilityFlags =priv-> changeList->changeNote[newNote].capabilityFlags;
                   1295:         priv->changeList->changeNote[previousNote].newStateNumber = priv->changeList->changeNote[newNote].newStateNumber;
                   1296:         priv->changeList->releaseTailChangeNote();
                   1297:         newNote = previousNote;
                   1298:         previousNote = priv->changeList->previousChangeNote(newNote);
                   1299:         pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCollapseQueue,0,0);
                   1300:     }
                   1301:     return IOPMWillAckLater;                           // in any case, we can't start yet
                   1302: }
                   1303: 
                   1304: 
                   1305: //*********************************************************************************
                   1306: // notifyAll
                   1307: //
                   1308: // Notify all interested parties either that a change is impending or that the
                   1309: // previously-notified change is done and power has settled.
                   1310: // The parameter identifies whether this is the
                   1311: // pre-change notification or the post-change notification.
                   1312: //
                   1313: //*********************************************************************************
                   1314: 
                   1315: IOReturn IOService::notifyAll ( bool is_prechange )
                   1316: {
                   1317:     IOPMinformee *     nextObject;
                   1318:     bool               start_timer = false;
                   1319: 
                   1320:     // To prevent acknowledgePowerChange from finishing the change note and removing it from the queue if
                   1321:     // some driver calls it, we inflate the number of pending acks so it cannot become zero.  We'll fix it later.
                   1322: 
                   1323:     priv->head_note_pendingAcks = priv->numberOfInformees + 1;
                   1324: 
                   1325:     // OK, we will go through the lists of interested drivers and power domain children
                   1326:     // and notify each one of this change.
                   1327: 
                   1328:     nextObject =  priv->interestedDrivers->firstInList();              // notify interested drivers
                   1329:     while (  nextObject != NULL ) {
                   1330:         if (! notifyObject( nextObject, is_prechange, false) ) {
                   1331:             start_timer = true;
                   1332:         }
                   1333:         nextObject  =  priv->interestedDrivers->nextInList(nextObject);
                   1334:     }
                   1335:     if ( start_timer ) {                                       // start ack timer if any drivers didn't ack
                   1336:         pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
                   1337:         start_ack_timer();
                   1338:     }
                   1339: 
                   1340:     nextObject = priv->children->firstInList();                        // notify power domain children
                   1341:     while (  nextObject != NULL ) {
                   1342:         notifyObject(nextObject, is_prechange, true);
                   1343:         nextObject  = priv->children->nextInList(nextObject);
                   1344:     }
                   1345: 
                   1346:     priv->head_note_pendingAcks -= 1;                          // fix this
                   1347:     if (priv->head_note_pendingAcks == 0 ) {                   // is it all acked?
                   1348:         return IOPMAckImplied;                         // return ack to parent
                   1349:     }
                   1350:     return IOPMWillAckLater;
                   1351: }
                   1352: 
                   1353: 
                   1354: //*********************************************************************************
                   1355: // notifyObject
                   1356: //
                   1357: // Notify an interested driver or a power domain child of an upcoming
                   1358: // power change.
                   1359: //
                   1360: // If the object acknowledges the current change, we return TRUE.
                   1361: //*********************************************************************************
                   1362: 
                   1363: bool IOService::notifyObject ( IOPMinformee * nextObject, bool is_prechange, bool is_child )
                   1364: {
                   1365:     IOReturn k = IOPMAckImplied;
                   1366: 
                   1367:    nextObject->timer = -1;                                     // initialize this
                   1368: 
                   1369:    if ( is_prechange ) {
                   1370:        if ( is_child ) {
                   1371:            k =nextObject->whatObject->powerDomainWillChangeTo( priv->head_note_outputFlags);
                   1372:        }
                   1373:        else {
                   1374:            pm_vars->thePlatform->PMLog (pm_vars->ourName,PMlogInformDriverPreChange,
                   1375:                                    (unsigned long)priv->head_note_capabilityFlags,(unsigned long)priv->head_note_state);
                   1376:            k = nextObject->whatObject->powerStateWillChangeTo( priv->head_note_capabilityFlags,priv->head_note_state,this);
                   1377:        }
                   1378:    }
                   1379:    else {
                   1380:        if ( is_child ) {
                   1381:            k = nextObject->whatObject->powerDomainDidChangeTo(priv->head_note_outputFlags);
                   1382:        }
                   1383:        else {
                   1384:            pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInformDriverPostChange,
                   1385:                                   (unsigned long)priv->head_note_capabilityFlags,(unsigned long)priv->head_note_state);
                   1386:            k = nextObject->whatObject->powerStateDidChangeTo(priv->head_note_capabilityFlags,priv->head_note_state,this);
                   1387:        }
                   1388:    }
                   1389: 
                   1390:    if ( nextObject->timer == 0 ) {                             // did it ack behind our back?
                   1391:        return true;                                            // yes
                   1392:    }
                   1393:    if ( k ==IOPMAckImplied ) {                         // no, did the return code ack?
                   1394:        nextObject->timer = 0;                                  // yes
                   1395:        priv->head_note_pendingAcks -= 1;
                   1396:        return true;
                   1397:    }
                   1398:    if ( k < 0 ) {
                   1399:        nextObject->timer = 0;                                  // somebody goofed
                   1400:        priv-> head_note_pendingAcks -= 1;
                   1401:        return true;
                   1402:   }
                   1403:    nextObject->timer = (k * ns_per_us / ACK_TIMER_PERIOD) + 1; // no, it's a timer
                   1404:    return false;
                   1405: }
                   1406: 
                   1407: 
                   1408: //*********************************************************************************
                   1409: // our_prechange_1
                   1410: //
                   1411: // All parties have acknowledged our pre-change notification of a power
                   1412: // change we initiated.  Here we instruct our controlling driver to make
                   1413: // the change to the hardware.  If it does so, we continue processing
                   1414: // (waiting for settle and notifying interested parties post-change.)
                   1415: // If it doesn't, we have to wait for it to acknowledge and then continue.
                   1416: //*********************************************************************************
                   1417: 
                   1418: void IOService::our_prechange_1 ( void )
                   1419: {
                   1420:     if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) {
                   1421:         our_prechange_2();                                     // it's done, carry on
                   1422:     }
                   1423:     else {
                   1424:         priv->machine_state = IOPMour_prechange_2;             // it's not, wait for it
                   1425:         pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
                   1426:         start_ack_timer();
                   1427:     }
                   1428: }
                   1429: 
                   1430: 
                   1431: //*********************************************************************************
                   1432: // our_prechange_2
                   1433: //
                   1434: // Our controlling driver has changed power state on the hardware
                   1435: // during a power change we initiated.  Here we see if we need to wait
                   1436: // for power to settle before continuing.  If not, we continue processing
                   1437: // (notifying interested parties post-change).  If so, we wait and
                   1438: // continue later.
                   1439: //*********************************************************************************
                   1440: 
                   1441: void IOService::our_prechange_2 ( void )
                   1442: {
                   1443:     priv->settle_time = compute_settle_time();
                   1444:     if ( priv->settle_time == 0 ) {
                   1445:        our_prechange_3();
                   1446:     }
                   1447:     else {
                   1448:         priv->machine_state = IOPMour_prechange_3;
                   1449:         startSettleTimer(priv->settle_time);
                   1450:     }
                   1451: }
                   1452: 
                   1453: 
                   1454: //*********************************************************************************
                   1455: // our_prechange_3
                   1456: //
                   1457: // Power has settled on a power change we initiated.  Here we notify
                   1458: // all our interested parties post-change.  If they all acknowledge, we're
                   1459: // done with this change note, and we can start on the next one.
                   1460: // Otherwise we have to wait for acknowledgements and finish up later.
                   1461: //*********************************************************************************
                   1462: 
                   1463: void IOService::our_prechange_3 ( void )
                   1464: {
                   1465:     priv->machine_state = IOPMour_prechange_4;         // in case they don't all ack
                   1466:     if ( notifyAll(false) == IOPMAckImplied ) {
                   1467:         our_prechange_4();
                   1468:     }
                   1469: }
                   1470: 
                   1471: 
                   1472: //*********************************************************************************
                   1473: // our_prechange_4
                   1474: //
                   1475: // Power has settled on a power change we initiated, and
                   1476: // all our interested parties have acknowledged.  We're
                   1477: // done with this change note, and we can start on the next one.
                   1478: //*********************************************************************************
                   1479: 
                   1480: void IOService::our_prechange_4 ( void )
                   1481: {
                   1482:     all_done();
                   1483: }
                   1484: 
                   1485: 
                   1486: //*********************************************************************************
                   1487: // parent_prechange_down_1
                   1488: //
                   1489: // All parties have acknowledged our pre-change notification of a power
                   1490: // lowering initiated by the parent.  Here we instruct our controlling driver
                   1491: // to put the hardware in the state it needs to be in when the domain is
                   1492: // lowered.  If it does so, we continue processing
                   1493: // (waiting for settle and acknowledging the parent.)
                   1494: // If it doesn't, we have to wait for it to acknowledge and then continue.
                   1495: //*********************************************************************************
                   1496: 
                   1497: IOReturn IOService::parent_prechange_down_1 ( void )
                   1498: {
                   1499:     if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) {
                   1500:         return parent_prechange_down_2();                      // it's done, carry on
                   1501:     }
                   1502:     priv->machine_state = IOPMparent_prechange_down_5; // it's not, wait for it
                   1503:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
                   1504:     start_ack_timer();
                   1505:     return IOPMWillAckLater;
                   1506: }
                   1507: 
                   1508: 
                   1509: //*********************************************************************************
                   1510: // parent_prechange_down_4
                   1511: //
                   1512: // We had to wait for it, but all parties have acknowledged our pre-change
                   1513: // notification of a power lowering initiated by the parent.
                   1514: // Here we instruct our controlling driver
                   1515: // to put the hardware in the state it needs to be in when the domain is
                   1516: // lowered.  If it does so, we continue processing
                   1517: // (waiting for settle and acknowledging the parent.)
                   1518: // If it doesn't, we have to wait for it to acknowledge and then continue.
                   1519: //*********************************************************************************
                   1520: 
                   1521: void IOService::parent_prechange_down_4 ( void )
                   1522: {
                   1523:     if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) {
                   1524:         parent_prechange_down_5();                             // it's done, carry on
                   1525:     }
                   1526:     else {
                   1527:         priv-> machine_state = IOPMparent_prechange_down_5;    // it's not, wait for it
                   1528:         pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
                   1529:         start_ack_timer();
                   1530:     }
                   1531: }
                   1532: 
                   1533: 
                   1534: //*********************************************************************************
                   1535: // parent_prechange_down_2
                   1536: //
                   1537: // Our controlling driver has changed power state on the hardware
                   1538: // during a power change initiated by our parent.  Here we see if we need
                   1539: // to wait for power to settle before continuing.  If not, we continue
                   1540: // processing (acknowledging our preparedness to the parent).
                   1541: // If so, we wait and continue later.
                   1542: //*********************************************************************************
                   1543: 
                   1544: IOReturn IOService::parent_prechange_down_2 ( void )
                   1545: {
                   1546:     priv->settle_time = compute_settle_time();
                   1547:     if ( priv->settle_time == 0 ) {
                   1548:        priv->machine_state = IOPMparent_postchange_down_1;
                   1549:        return IOPMAckImplied;
                   1550:    }
                   1551:    else {
                   1552:        priv->machine_state = IOPMparent_prechange_down_3;
                   1553:        startSettleTimer(priv->settle_time);
                   1554:        return IOPMWillAckLater;
                   1555:    }
                   1556: }
                   1557: 
                   1558: 
                   1559: //*********************************************************************************
                   1560: // parent_prechange_down_5
                   1561: //
                   1562: // Our controlling driver has changed power state on the hardware
                   1563: // during a power change initiated by our parent.  We have had to wait
                   1564: // for acknowledgement from interested parties, or we have had to wait
                   1565: // for the controlling driver to change the state.  Here we see if we need
                   1566: // to wait for power to settle before continuing.  If not, we continue
                   1567: // processing (acknowledging our preparedness to the parent).
                   1568: // If so, we wait and continue later.
                   1569: //*********************************************************************************
                   1570: 
                   1571: void IOService::parent_prechange_down_5 ( void )
                   1572: {
                   1573:     priv->settle_time = compute_settle_time();
                   1574:     if ( priv->settle_time == 0 ) {
                   1575:       parent_prechange_down_3();
                   1576:    }
                   1577:    else {
                   1578:        priv->machine_state = IOPMparent_prechange_down_3;
                   1579:        startSettleTimer(priv->settle_time);
                   1580:    }
                   1581: }
                   1582: 
                   1583: 
                   1584: //*********************************************************************************
                   1585: // parent_prechange_down_3
                   1586: //
                   1587: // Power has settled on a power change initiated by our parent.  Here we
                   1588: // acknowledge the parent.  There is nothing more to do until the
                   1589: // parent lowers power in the domain and calls us at powerStateDidChange.
                   1590: //*********************************************************************************
                   1591: 
                   1592: void IOService::parent_prechange_down_3 ( void )
                   1593: {
                   1594:     priv->machine_state = IOPMparent_postchange_down_1;
                   1595:     pm_vars->myParent->acknowledgePowerChange(this);
                   1596: }
                   1597: 
                   1598: 
                   1599: //*********************************************************************************
                   1600: // parent_prechange_up_1
                   1601: //
                   1602: // All parties have acknowledged our pre-change notification of a power
                   1603: // raising initiated by the parent.  Here we acknowledge the parent.
                   1604: // There is nothing more to do until the parent raises power in the domain
                   1605: // and calls us at powerStateDidChange.
                   1606: //*********************************************************************************
                   1607: 
                   1608: void IOService::parent_prechange_up_1 ( void )
                   1609: {
                   1610:     priv->machine_state = IOPMparent_postchange_up_1;
                   1611:     pm_vars->myParent->acknowledgePowerChange(this);
                   1612: }
                   1613: 
                   1614: 
                   1615: //*********************************************************************************
                   1616: // parent_postchange_down_1
                   1617: //
                   1618: // Our parent is lowering power, and has called us at powerStateDidChange
                   1619: // to tell us the domain power has now settled in the new lower state.
                   1620: // We notify our interested parties.  When they have all acked, we're done
                   1621: //*********************************************************************************
                   1622: 
                   1623: IOReturn IOService::parent_postchange_down_1 ( void )
                   1624: {
                   1625:     priv->machine_state = IOPMparent_postchange_down_2;        // in case they don't all ack
                   1626:     if ( notifyAll(false) == IOPMAckImplied ) {
                   1627:         all_done();
                   1628:         return IOPMAckImplied;
                   1629:     }
                   1630:     return IOPMWillAckLater;                   // they didn't
                   1631: }
                   1632: 
                   1633: 
                   1634: //*********************************************************************************
                   1635: // parent_postchange_down_2
                   1636: //
                   1637: // We had to wait for it, but all parties have acknowledged our post-change
                   1638: // notification of a power  lowering initiated by the parent.
                   1639: // Here we acknowledge the parent.
                   1640: // We are done with this change note, and we can start on the next one.
                   1641: //*********************************************************************************
                   1642: 
                   1643: void IOService::parent_postchange_down_2 ( void )
                   1644: {
                   1645:     all_done();
                   1646:     pm_vars->myParent->acknowledgePowerChange(this);
                   1647: }
                   1648: 
                   1649: 
                   1650: //*********************************************************************************
                   1651: // parent_postchange_up_1
                   1652: //
                   1653: // Our parent has informed us via powerStateDidChange that it has
                   1654: // raised the power in our power domain.  Here we instruct our controlling
                   1655: // driver to program the hardware to take advantage of the higher domain
                   1656: // power.  If it does so, we continue processing
                   1657: // (waiting for settle and notifying interested parties post-change.)
                   1658: // If it doesn't, we have to wait for it to acknowledge and then continue.
                   1659: //*********************************************************************************
                   1660: 
                   1661: IOReturn IOService::parent_postchange_up_1 ( void )
                   1662: {
                   1663:     if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) {
                   1664:         return parent_postchange_up_2();                       // it did it, carry on
                   1665:     }
                   1666:     else {
                   1667:         priv->machine_state = IOPMparent_postchange_up_4;      // it didn't, wait for it
                   1668:         pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
                   1669:         start_ack_timer();
                   1670:         return IOPMWillAckLater;
                   1671:     }
                   1672: }
                   1673: 
                   1674: 
                   1675: //*********************************************************************************
                   1676: // parent_postchange_up_2
                   1677: //
                   1678: // Our controlling driver has changed power state on the hardware
                   1679: // during a power raise initiated by the parent.  Here we see if we need to wait
                   1680: // for power to settle before continuing.  If not, we continue processing
                   1681: // (notifying interested parties post-change).  If so, we wait and
                   1682: // continue later.
                   1683: //*********************************************************************************
                   1684: 
                   1685: IOReturn IOService::parent_postchange_up_2 ( void )
                   1686: {
                   1687:     priv->settle_time = compute_settle_time();
                   1688:     if ( priv->settle_time == 0 ) {
                   1689:       return parent_postchange_up_3();
                   1690:   }
                   1691:   else {
                   1692:       priv->machine_state = IOPMparent_postchange_up_5;
                   1693:       startSettleTimer(priv->settle_time);
                   1694:       return IOPMWillAckLater;
                   1695:   }
                   1696: }
                   1697: 
                   1698: 
                   1699: //*********************************************************************************
                   1700: // parent_postchange_up_4
                   1701: //
                   1702: // Our controlling driver has changed power state on the hardware
                   1703: // during a power raise initiated by the parent, but we had to wait for it.
                   1704: // Here we see if we need to wait for power to settle before continuing.
                   1705: // If not, we continue processing  (notifying interested parties post-change).
                   1706: // If so, we wait and continue later.
                   1707: //*********************************************************************************
                   1708: 
                   1709: void IOService::parent_postchange_up_4 ( void )
                   1710: {
                   1711:     priv->settle_time = compute_settle_time();
                   1712:     if ( priv->settle_time == 0 ) {
                   1713:      parent_postchange_up_5();
                   1714:   }
                   1715:   else {
                   1716:       priv->machine_state = IOPMparent_postchange_up_5;
                   1717:       startSettleTimer(priv->settle_time);
                   1718:   }
                   1719: }
                   1720: 
                   1721: 
                   1722: //*********************************************************************************
                   1723: // parent_postchange_up_3
                   1724: //
                   1725: // No power settling was required on a power raise initiated by the parent.
                   1726: // Here we notify all our interested parties post-change.  If they all acknowledge,
                   1727: // we're done with this change note, and we can start on the next one.
                   1728: // Otherwise we have to wait for acknowledgements and finish up later.
                   1729: //*********************************************************************************
                   1730: 
                   1731: IOReturn IOService::parent_postchange_up_3 ( void )
                   1732: {
                   1733:     priv->machine_state = IOPMparent_postchange_up_6;  // in case they don't all ack
                   1734:     if ( notifyAll(false) == IOPMAckImplied ) {
                   1735:         all_done();
                   1736:         return IOPMAckImplied;
                   1737:     }
                   1738:     return IOPMWillAckLater;                   // they didn't
                   1739: }
                   1740: 
                   1741: 
                   1742: //*********************************************************************************
                   1743: // parent_postchange_up_5
                   1744: //
                   1745: // Power has settled on a power raise initiated by the parent.
                   1746: // Here we notify all our interested parties post-change.  If they all acknowledge,
                   1747: // we're done with this change note, and we can start on the next one.
                   1748: // Otherwise we have to wait for acknowledgements and finish up later.
                   1749: //*********************************************************************************
                   1750: 
                   1751: void IOService::parent_postchange_up_5 ( void )
                   1752: {
                   1753:     priv->machine_state = IOPMparent_postchange_up_6;  // in case they don't all ack
                   1754:     if ( notifyAll(false) == IOPMAckImplied ) {
                   1755:         parent_postchange_up_6();
                   1756:     }
                   1757: }
                   1758: 
                   1759: 
                   1760: //*********************************************************************************
                   1761: // parent_postchange_up_6
                   1762: //
                   1763: // All parties have acknowledged our post-change notification of a power
                   1764: // raising initiated by the parent.  Here we acknowledge the parent.
                   1765: // We are done with this change note, and we can start on the next one.
                   1766: //*********************************************************************************
                   1767: 
                   1768: void IOService::parent_postchange_up_6 ( void )
                   1769: {
                   1770:     all_done();
                   1771:     pm_vars->myParent->acknowledgePowerChange(this);
                   1772: }
                   1773: 
                   1774: 
                   1775: //*********************************************************************************
                   1776: // all_done
                   1777: //
                   1778: // A power change is complete, and the used post-change note is at
                   1779: // the head of the queue.  Remove it and set myCurrentState to the result
                   1780: // of the change.  Start up the next change in queue.
                   1781: //*********************************************************************************
                   1782: 
                   1783: void IOService::all_done ( void )
                   1784: {
                   1785:     priv->machine_state = IOPMfinished;
                   1786: 
                   1787:     if ( priv->head_note_flags & IOPMWeInitiated ) {
                   1788:         if ( !( priv->head_note_flags & IOPMNotDone) ) {                               // could our driver switch to the new state?
                   1789:             pm_vars->myCurrentState = priv-> head_note_state;                  // yes
                   1790:             pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeDone,(unsigned long)pm_vars->myCurrentState,0);
                   1791:         }
                   1792:         else {                                                         // no
                   1793:             pm_vars->myCurrentState = pm_vars->theControllingDriver->powerStateForDomainState(pm_vars->parentCurrentPowerFlags);
                   1794:         }
                   1795:     }
                   1796:     if ( priv->head_note_flags & IOPMParentInitiated ) {
                   1797:         pm_vars->myCurrentState = priv->head_note_state;
                   1798:         pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(priv->head_note_domainState);
                   1799:         pm_vars->parentCurrentPowerFlags = priv->head_note_domainState;
                   1800:         pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeDone,(unsigned long)pm_vars->myCurrentState,0);
                   1801:     }
                   1802: 
                   1803:     priv->changeList->releaseHeadChangeNote();                                 // either way, we're done with this
                   1804: 
                   1805:     priv->head_note = priv->changeList->currentChange();                               // start next one in queue
                   1806:     if ( priv->head_note != -1 ) {
                   1807: 
                   1808:         if (priv->changeList->changeNote[priv->head_note].flags & IOPMWeInitiated ) {
                   1809:             start_our_change(priv->head_note);
                   1810:         }
                   1811:         else {
                   1812:             if ( start_parent_change(priv->head_note) == IOPMAckImplied ) {
                   1813:                 pm_vars->myParent->acknowledgePowerChange(this);
                   1814:             }
                   1815:         }
                   1816:     }
                   1817: }
                   1818: 
                   1819: 
                   1820: 
                   1821: //*********************************************************************************
                   1822: // all_acked
                   1823: //
                   1824: // A driver or child has acknowledged our notification of an upcoming power
                   1825: // change, and this acknowledgement is the last one pending
                   1826: // before we change power or after changing power.
                   1827: //
                   1828: //*********************************************************************************
                   1829: 
                   1830: void IOService::all_acked ( void )
                   1831: {
                   1832:     switch (priv->machine_state) {
                   1833:        case IOPMour_prechange_1:
                   1834:            our_prechange_1();
                   1835:            break;
                   1836:        case IOPMour_prechange_4:
                   1837:            our_prechange_4();
                   1838:            break;
                   1839:        case IOPMparent_prechange_down_4:
                   1840:            parent_prechange_down_4();  
                   1841:            break;
                   1842:        case IOPMparent_postchange_down_2:
                   1843:            parent_postchange_down_2();
                   1844:            break;
                   1845:        case IOPMparent_prechange_up_1:
                   1846:            parent_prechange_up_1();
                   1847:            break;
                   1848:        case IOPMparent_postchange_up_6:
                   1849:            parent_postchange_up_6();
                   1850:            break;
                   1851:    }
                   1852: }
                   1853: 
                   1854: 
                   1855: //*********************************************************************************
                   1856: // settleTimerExpired
                   1857: //
                   1858: // Power has settled after our last change.  Notify interested parties that
                   1859: // there is a new power state.
                   1860: //*********************************************************************************
                   1861: 
                   1862: void IOService::settleTimerExpired ( void )
                   1863: {
                   1864:     switch (priv->machine_state) {
                   1865:         case IOPMour_prechange_3:
                   1866:             our_prechange_3();
                   1867:             break;
                   1868:         case IOPMparent_prechange_down_3:
                   1869:             parent_prechange_down_3();
                   1870:             break;
                   1871:         case IOPMparent_postchange_up_5:
                   1872:             parent_postchange_up_5();
                   1873:             break;
                   1874:     }
                   1875: }
                   1876: 
                   1877: 
                   1878: //*********************************************************************************
                   1879: // compute_settle_time
                   1880: //
                   1881: // Compute the power-settling delay in microseconds for the
                   1882: // change from myCurrentState to head_note_state.
                   1883: //*********************************************************************************
                   1884: 
                   1885: unsigned long IOService::compute_settle_time ( void )
                   1886: {
                   1887:     unsigned long totalTime;
                   1888:     unsigned long i;
                   1889: 
                   1890:     totalTime = 0;                                             // compute total time to attain the new state
                   1891:     i = pm_vars->myCurrentState;
                   1892:     if ( priv->head_note_state < pm_vars->myCurrentState ) {   // we're lowering power
                   1893:         while ( i > priv->head_note_state ) {
                   1894:             totalTime +=  pm_vars->thePowerStates[i].settleDownTime;
                   1895:             i--;
                   1896:         }
                   1897:     }
                   1898: 
                   1899:     if ( priv->head_note_state > pm_vars->myCurrentState ) {   // we're raising power
                   1900:         while ( i < priv->head_note_state ) {
                   1901:             totalTime +=  pm_vars->thePowerStates[i+1].settleUpTime;
                   1902:             i++;
                   1903:         }
                   1904:     }
                   1905: 
                   1906:     return totalTime;
                   1907: }
                   1908: 
                   1909: 
                   1910: //*********************************************************************************
                   1911: // startSettleTimer
                   1912: //
                   1913: // Enter with a power-settling delay in microseconds and start a nano-second
                   1914: // timer for that delay.
                   1915: //*********************************************************************************
                   1916: 
                   1917: IOReturn IOService::startSettleTimer ( unsigned long delay )
                   1918: {
                   1919:     AbsoluteTime       deadline;
                   1920:     
                   1921:     clock_interval_to_deadline(delay, kMicrosecondScale, &deadline);
                   1922:     thread_call_func_delayed(settle_timer_expired, (void *)this, deadline);
                   1923:     return IOPMNoErr;
                   1924: }
                   1925: 
                   1926: //*********************************************************************************
                   1927: // ack_timer_ticked
                   1928: //
                   1929: // The acknowledgement timeout periodic timer has ticked.
                   1930: // If we are awaiting acks for a power change notification,
                   1931: // we decrement the timer word of each interested driver which hasn't acked.
                   1932: // If a timer word becomes zero, we pretend the driver aknowledged.
                   1933: // If we are waiting for the controlling driver to change the power
                   1934: // state of the hardware, we decrement its timer word, and if it becomes
                   1935: // zero, we pretend the driver acknowledged.
                   1936: //*********************************************************************************
                   1937: 
                   1938: void IOService::ack_timer_ticked ( void )
                   1939: {
                   1940:     IOPMinformee * nextObject;
                   1941: 
                   1942:     if (! acquire_lock() ) {
                   1943:         return;
                   1944:     }
                   1945: 
                   1946:     if ( priv->driver_timer != 0 ) {                                   // are we waiting for our driver to make its change?
                   1947:         priv->driver_timer -= 1;                                               // yes, tick once
                   1948:         if ( priv->driver_timer == 0 ) {                                       // it's tardy, we'll go on without it
                   1949:             IOUnlock(priv->our_lock);
                   1950:             pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCtrlDriverTardy,0,0);
                   1951:             driver_acked();
                   1952:         }
                   1953:         else {                                                 // still waiting, set timer again
                   1954:             start_ack_timer();
                   1955:             IOUnlock(priv->our_lock);
                   1956:         }
                   1957:         return;
                   1958:     }
                   1959: 
                   1960:     if (priv->head_note_pendingAcks != 0 ) {                           // are we waiting for interested parties to acknowledge?
                   1961:         nextObject =  priv->interestedDrivers->firstInList();          // yes, go through the list of interested drivers
                   1962:         while (  nextObject != NULL ) {                                        // and check each one
                   1963:             if ( nextObject->timer > 0 ) {
                   1964:                 nextObject->timer -= 1;
                   1965:                 if ( nextObject->timer == 0 ) {                                // this one should have acked by now
                   1966:                     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogIntDriverTardy,0,0);
                   1967:                     priv->head_note_pendingAcks -= 1;
                   1968:                 }
                   1969:             }
                   1970:             nextObject  =  priv->interestedDrivers->nextInList(nextObject);
                   1971:         }
                   1972:         if ( priv->head_note_pendingAcks == 0 ) {                      // is that the last?
                   1973:             IOUnlock(priv->our_lock);
                   1974:             all_acked();                                                       // yes, we can continue
                   1975:         }
                   1976:         else {                                                         // no, set timer again
                   1977:             start_ack_timer();
                   1978:             IOUnlock(priv->our_lock);
                   1979:         }
                   1980:         return;
                   1981:     }
                   1982:     IOUnlock(priv->our_lock);                                          // not waiting for acks
                   1983: }
                   1984: 
                   1985: 
                   1986: //*********************************************************************************
                   1987: // start_ack_timer
                   1988: //
                   1989: //*********************************************************************************
                   1990: 
                   1991: void IOService::start_ack_timer ( void )
                   1992: {
                   1993:     AbsoluteTime       deadline;
                   1994: 
                   1995:     clock_interval_to_deadline(ACK_TIMER_PERIOD, kNanosecondScale, &deadline);
                   1996:     thread_call_func_delayed(ack_timer_expired, (void *)this, deadline);
                   1997: }
                   1998: 
                   1999: 
                   2000: //*********************************************************************************
                   2001: // stop_ack_timer
                   2002: //
                   2003: //*********************************************************************************
                   2004: 
                   2005: void IOService::stop_ack_timer ( void )
                   2006: {
                   2007:     thread_call_func_cancel(ack_timer_expired, (void *)this, true);
                   2008: }
                   2009: 
                   2010: 
                   2011: //*********************************************************************************
                   2012: // c-language timer expiration functions
                   2013: //
                   2014: //*********************************************************************************
                   2015: 
                   2016: static void ack_timer_expired ( thread_call_param_t us, thread_call_param_t )
                   2017: {
                   2018:     ((IOService *)us)->ack_timer_ticked();
                   2019: }
                   2020: 
                   2021: 
                   2022: static void settle_timer_expired ( thread_call_param_t us, thread_call_param_t )
                   2023: {
                   2024:     ((IOService *)us)->settleTimerExpired();
                   2025: }
                   2026: 
                   2027: 
                   2028: //*********************************************************************************
                   2029: // add_to_active_change
                   2030: //
                   2031: // A child or interested driver has just registered with us.  If there is
                   2032: // currently a change in progress, get the new party involved: if we
                   2033: // have notified all parties and are waiting for acks, notify the new
                   2034: // party.
                   2035: //*********************************************************************************
                   2036: 
                   2037: IOReturn IOService::add_to_active_change ( IOPMinformee * newObject, bool is_child )
                   2038: {
                   2039:     if (! acquire_lock() ) {
                   2040:         return IOPMNoErr;
                   2041:     }
                   2042: 
                   2043:     switch (priv->machine_state) {
                   2044:         case IOPMour_prechange_1:
                   2045:             priv->head_note_pendingAcks += 1;
                   2046:             IOUnlock(priv->our_lock);
                   2047:             notifyObject(newObject, true, is_child);
                   2048:             return IOPMNoErr;
                   2049:         case IOPMour_prechange_4:
                   2050:             priv->head_note_pendingAcks += 1;
                   2051:             IOUnlock(priv->our_lock);
                   2052:             notifyObject(newObject, false, is_child);
                   2053:             return IOPMNoErr;
                   2054:         case IOPMparent_prechange_down_4:
                   2055:             priv->head_note_pendingAcks += 1;
                   2056:             IOUnlock(priv->our_lock);
                   2057:             notifyObject(newObject, true, is_child);
                   2058:             return IOPMNoErr;
                   2059:         case IOPMparent_postchange_down_2:
                   2060:             priv->head_note_pendingAcks += 1;
                   2061:             IOUnlock(priv->our_lock);
                   2062:             notifyObject(newObject, false, is_child);
                   2063:             return IOPMNoErr;
                   2064:         case IOPMparent_prechange_up_1:
                   2065:             priv->head_note_pendingAcks += 1;
                   2066:             IOUnlock(priv->our_lock);
                   2067:             notifyObject(newObject, true, is_child);
                   2068:             return IOPMNoErr;
                   2069:         case IOPMparent_postchange_up_6:
                   2070:             priv-> head_note_pendingAcks += 1;
                   2071:             IOUnlock(priv->our_lock);
                   2072:             notifyObject(newObject, false, is_child);
                   2073:             return IOPMNoErr;
                   2074:     }
                   2075:     IOUnlock(priv->our_lock);
                   2076:     return IOPMNoErr;
                   2077: }
                   2078: 
                   2079: 
                   2080: //*********************************************************************************
                   2081: // start_parent_change
                   2082: //
                   2083: // Here we begin the processing of a change note  initiated by our parent
                   2084: // which is at the head of the queue.
                   2085: //
                   2086: // It is possible for the change to be processed to completion and removed from the queue.
                   2087: // There are several possible interruptions to the processing, though, and they are:
                   2088: // we may have to wait for interested parties to acknowledge our pre-change notification,
                   2089: // changes initiated by the parent will wait in the middle for powerStateDidChange,
                   2090: // we may have to wait for our controlling driver to change the hardware power state,
                   2091: // there may be a settling time after changing the hardware power state,
                   2092: // we may have to wait for interested parties to acknowledge our post-change notification,
                   2093: // we may have to wait for the acknowledgement timer expiration to substitute for the
                   2094: // acknowledgement from a failing driver.
                   2095: // We identify which of the following three possible lives the note
                   2096: // will have and then start the life:
                   2097: // 2.  The parent initiated the change, and it is lowering power,
                   2098: // 3.  The parent initiated the change, and it is raising power,
                   2099: // 4.  The parent initiated the change, and the power state is not changing.
                   2100: //
                   2101: // In life-style 2, if all interested parties acknowledge our pre-change notification,
                   2102: // our controlling driver changes power states immediately without having to call us back later,
                   2103: // and there is no settling time required, we return IOPMAckImplied.
                   2104: // In life-style 3, if all interested parties acknowledge our pre-change notification, we return IOPMAckImplied.
                   2105: // In life-style 4, we always return IOPMAckImplied.
                   2106: // In any other case, we return IOPMWillAckLater.
                   2107: // If our caller is ultimately our powerDomainWillChange method, it will return our return code to the parent.
                   2108: // Otherwise, this new notification was dequeued from the queue after we finished a previous one.
                   2109: // In this case, an IOPMAckImplied return from here will cause the caller to explicitly acknowledge
                   2110: // the parent by calling its acknowledgePowerChange method.
                   2111: //*********************************************************************************
                   2112: 
                   2113: IOReturn IOService::start_parent_change ( unsigned long queue_head )
                   2114: {
                   2115:     priv->head_note = queue_head;
                   2116:     priv-> head_note_flags = priv-> changeList->changeNote[priv->head_note].flags;
                   2117:     priv-> head_note_state =  priv->changeList->changeNote[priv->head_note].newStateNumber;
                   2118:     priv-> head_note_outputFlags =  priv->changeList->changeNote[priv->head_note].outputPowerCharacter;
                   2119:     priv->head_note_domainState = priv->changeList->changeNote[priv->head_note].domainState;
                   2120:     priv->head_note_capabilityFlags =  priv->changeList->changeNote[priv->head_note].capabilityFlags;
                   2121: 
                   2122:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartParentChange,(unsigned long)priv->head_note_state,0);
                   2123: 
                   2124:     ask_parent( priv->ourDesiredPowerState);                   // if we need something and haven't told the parent, do so
                   2125: 
                   2126:     if ( priv->head_note_state < pm_vars->myCurrentState ) {
                   2127:        priv->initial_change = false;                           // life-style 2
                   2128:        priv->machine_state = IOPMparent_prechange_down_4;      // in case they don't all ack
                   2129:         if ( notifyAll(true) == IOPMAckImplied ) {
                   2130:             return parent_prechange_down_1();
                   2131:         }
                   2132:         return IOPMWillAckLater;                               // they didn't
                   2133:     }
                   2134: 
                   2135:     if ( priv->head_note_state > pm_vars->myCurrentState ) {   // if the parent is raising power, we may or may not
                   2136:         if ( priv->ourDesiredPowerState > pm_vars->myCurrentState ) {
                   2137:            if ( priv->ourDesiredPowerState < priv->head_note_state ) {
                   2138:                priv->head_note_state = priv->ourDesiredPowerState;     // we do, but not all the way
                   2139:                priv->head_note_outputFlags =   pm_vars->thePowerStates[priv->head_note_state].outputPowerCharacter;
                   2140:                priv->head_note_capabilityFlags =   pm_vars->thePowerStates[priv->head_note_state].capabilityFlags;
                   2141:                pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAmendParentChange,(unsigned long)priv->head_note_state,0);
                   2142:             }
                   2143:         }
                   2144:         else {
                   2145:             priv-> head_note_state = pm_vars->myCurrentState;  // we don't
                   2146:             priv->head_note_outputFlags =   pm_vars->thePowerStates[priv->head_note_state].outputPowerCharacter;
                   2147:             priv->head_note_capabilityFlags =   pm_vars->thePowerStates[priv->head_note_state].capabilityFlags;
                   2148:             pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAmendParentChange,(unsigned long)priv->head_note_state,0);
                   2149:         }
                   2150:     }
                   2151: 
                   2152:     if ( priv->head_note_state > pm_vars->myCurrentState ) {
                   2153:        priv->initial_change = false;                           // life-style 3
                   2154:        priv->machine_state = IOPMparent_prechange_up_1;                // in case they don't all ack
                   2155:        if (  notifyAll(true) == IOPMAckImplied ) {
                   2156:            priv->machine_state = IOPMparent_postchange_up_1;
                   2157:            return IOPMAckImplied;
                   2158:        }
                   2159:        return IOPMWillAckLater;                                // they didn't
                   2160:    }
                   2161: 
                   2162:     if ( priv->head_note_state == pm_vars->myCurrentState ) {
                   2163:         priv->machine_state = IOPMparent_postchange_null;              // life-style 4
                   2164:         return IOPMAckImplied;
                   2165:     }
                   2166: return IOPMAckImplied;                         // something wrong
                   2167: }
                   2168: 
                   2169: 
                   2170: //*********************************************************************************
                   2171: // start_our_change
                   2172: //
                   2173: // Here we begin the processing of a change note  initiated by us
                   2174: // which is at the head of the queue.
                   2175: //
                   2176: // It is possible for the change to be processed to completion and removed from the queue.
                   2177: // There are several possible interruptions to the processing, though, and they are:
                   2178: // we may have to wait for interested parties to acknowledge our pre-change notification,
                   2179: // changes initiated by the parent will wait in the middle for powerStateDidChange,
                   2180: // we may have to wait for our controlling driver to change the hardware power state,
                   2181: // there may be a settling time after changing the hardware power state,
                   2182: // we may have to wait for interested parties to acknowledge our post-change notification,
                   2183: // we may have to wait for the acknowledgement timer expiration to substitute for the
                   2184: // acknowledgement from a failing driver.
                   2185: //*********************************************************************************
                   2186: 
                   2187: void IOService::start_our_change ( unsigned long queue_head )
                   2188: {
                   2189:     priv->head_note = queue_head;
                   2190:     priv->head_note_flags =  priv->changeList->changeNote[priv->head_note].flags;
                   2191:     priv->head_note_state =  priv->changeList->changeNote[priv->head_note].newStateNumber;
                   2192:     priv->head_note_outputFlags =  priv->changeList->changeNote[priv->head_note].outputPowerCharacter;
                   2193:     priv->head_note_capabilityFlags =  priv->changeList->changeNote[priv->head_note].capabilityFlags;
                   2194: 
                   2195:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartDeviceChange,(unsigned long)priv->head_note_state,0);
                   2196: 
                   2197:     if ( !  priv->we_are_root ) {
                   2198:         ask_parent(priv->head_note_state);                     // if this changes our power requirement, tell the parent
                   2199:     }
                   2200: 
                   2201:     if ( priv->head_note_capabilityFlags & IOPMNotAttainable ) {       // can our driver switch to the new state?
                   2202:         priv-> head_note_flags |= IOPMNotDone;                 // no, mark the change note un-actioned
                   2203:         all_done();                                            // and we're done
                   2204:         return;                                                // let the parent make the change for us
                   2205:     }
                   2206:     if ( (pm_vars->maxCapability < priv->head_note_state) && (!  priv->we_are_root) ) {        // is there enough power in the domain?
                   2207:         priv->head_note_flags |= IOPMNotDone;                                          // no, mark the change note un-actioned
                   2208:         all_done();                                                                    // and we're done
                   2209:         return;                                                                        // till the parent raises power
                   2210:     }
                   2211: 
                   2212:     if ( !  priv->initial_change ) {
                   2213:         if ( priv->head_note_state == pm_vars->myCurrentState ) {
                   2214:             all_done();                                                // we initiated a null change; forget it
                   2215:             return;
                   2216:         }
                   2217:     }
                   2218:     priv->initial_change = false;
                   2219: 
                   2220:     priv->machine_state = IOPMour_prechange_1;         // in case they don't all ack
                   2221:     if ( notifyAll(true) == IOPMAckImplied ) {                 // in life-style 1
                   2222:         our_prechange_1();
                   2223:     }
                   2224: }
                   2225: 
                   2226: 
                   2227: //*********************************************************************************
                   2228: // ask_parent
                   2229: //
                   2230: // Call the power domain parent to ask for a higher power state in the domain
                   2231: // or to suggest a lower power state.
                   2232: //*********************************************************************************
                   2233: 
                   2234: IOReturn IOService::ask_parent ( unsigned long requestedState )
                   2235: {
                   2236:     unsigned long savedPreviousRequest;
                   2237:     IOReturn return_code;
                   2238: 
                   2239:     if ( priv->previousRequest ==  pm_vars->thePowerStates[requestedState].inputPowerRequirement ) {   // is this a new desire?
                   2240:         return IOPMNoErr;                                                      // no, the parent knows already, just return
                   2241:     }
                   2242: 
                   2243:     if (  priv->we_are_root ) {
                   2244:         return IOPMNoErr;
                   2245:     }
                   2246:     savedPreviousRequest = priv->previousRequest;                              // yes, remember our previous request for a second
                   2247:     priv->previousRequest =  pm_vars->thePowerStates[requestedState].inputPowerRequirement;
                   2248:     return_code = pm_vars->myParent->requestDomainState( priv->previousRequest,this,IOPMLowestState);
                   2249: 
                   2250:     if ( return_code != IOPMNoErr ) {                                  // if that was not ok with the parent,
                   2251: 
                   2252:         pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRequestDenied,(unsigned long)priv->previousRequest,0);
                   2253:         priv->previousRequest = savedPreviousRequest;                  // remember our previous desire
                   2254:     }
                   2255:     return return_code;
                   2256: }
                   2257: 
                   2258: 
                   2259: //*********************************************************************************
                   2260: // instruct_driver
                   2261: //
                   2262: // Call the controlling driver and have it change the power state of the
                   2263: // hardware.  If it returns IOPMAckImplied, the change is complete, and
                   2264: // we return IOPMAckImplied.  Otherwise, it will ack when the change
                   2265: // is done; we return IOPMWillAckLater.
                   2266: //*********************************************************************************
                   2267: 
                   2268: IOReturn IOService::instruct_driver ( unsigned long newState )
                   2269: {
                   2270:     IOReturn return_code;
                   2271: 
                   2272:     if (  pm_vars->thePowerStates[newState].capabilityFlags & IOPMNotAttainable ) {    // can our driver switch to the desired state?
                   2273:         return IOPMAckImplied;                                         // no, so don't try
                   2274:     }
                   2275:     priv->driver_timer = -1;
                   2276:     pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogProgramHardware,newState,0);
                   2277:     return_code = pm_vars->theControllingDriver->setPowerState(  newState,this );      // yes, instruct it
                   2278:     if ( return_code == IOPMAckImplied ) {                                     // it finished
                   2279:         priv->driver_timer = 0;
                   2280:         return IOPMAckImplied;
                   2281:     }
                   2282: 
                   2283:     if ( priv->driver_timer == 0 ) {                                           // it acked behind our back
                   2284:         return IOPMAckImplied;
                   2285:     }
                   2286: 
                   2287:     if ( return_code < 0 ) {                                                   // somebody goofed
                   2288:         return IOPMAckImplied;
                   2289:     }
                   2290: 
                   2291:     priv->driver_timer = (return_code / 1000) + 1;                                     // it didn't finish
                   2292:     return IOPMWillAckLater;
                   2293: }
                   2294: 
                   2295: 
                   2296: //*********************************************************************************
                   2297: // acquire_lock
                   2298: //
                   2299: // We are acquiring the lock we use to protect our queue head from
                   2300: // simutaneous access by a thread which calls acknowledgePowerStateChange
                   2301: // or acknowledgeSetPowerState and the ack timer expiration thread.
                   2302: // Return TRUE if we acquire the lock, and the queue head didn't change
                   2303: // while we were acquiring the lock (and maybe blocked).
                   2304: // If there is no queue head, or it changes while we are blocked,
                   2305: // return FALSE with the lock unlocked.
                   2306: //*********************************************************************************
                   2307: 
                   2308: bool IOService::acquire_lock ( void )
                   2309: {
                   2310:     long current_change_note;
                   2311: 
                   2312:     current_change_note = priv->head_note;
                   2313:     if ( current_change_note == -1 ) {
                   2314:         return FALSE;
                   2315:     }
                   2316: 
                   2317:     IOTakeLock(priv->our_lock);
                   2318:     if ( current_change_note == priv->head_note ) {
                   2319:         return TRUE;
                   2320:     }
                   2321:     else {                                     // we blocked and something changed radically
                   2322:         IOUnlock(priv->our_lock);              // so there's nothing to do any more
                   2323:         return FALSE;
                   2324:     }
                   2325: }
                   2326: 
                   2327: 
                   2328: //*********************************************************************************
                   2329: // foundDevice
                   2330: //
                   2331: // Does nothing here.  This should be implemented in a subclass driver.
                   2332: //*********************************************************************************
                   2333: #if BREAK
                   2334: IOReturn IOService::foundDevice ( IOService *  yourDevice )
                   2335: {
                   2336:     return IOPMNoErr;
                   2337: }
                   2338: #endif
                   2339: 
                   2340: //*********************************************************************************
                   2341: // setPowerState
                   2342: //
                   2343: // Does nothing here.  This should be implemented in a subclass driver.
                   2344: //*********************************************************************************
                   2345: 
                   2346: IOReturn IOService::setPowerState ( unsigned long powerStateOrdinal, IOService* whatDevice )
                   2347: {
                   2348:     return IOPMNoErr;
                   2349: }
                   2350: 
                   2351: 
                   2352: //*********************************************************************************
                   2353: // maxCapabilityForDomainState
                   2354: //
                   2355: // Finds the highest power state in the array whose input power
                   2356: // requirement is equal to the input parameter.  Where a more intelligent
                   2357: // decision is possible, override this in the subclassed driver.
                   2358: //*********************************************************************************
                   2359: 
                   2360: unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
                   2361: {
                   2362:    int i;
                   2363: 
                   2364:    if (pm_vars->theNumberOfPowerStates == 0 ) {
                   2365:        return 0;
                   2366:    }
                   2367:    for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- ) {
                   2368:        if (  pm_vars->thePowerStates[i].inputPowerRequirement == domainState ) {
                   2369:            return i;
                   2370:        }
                   2371:    }
                   2372:    return 0;
                   2373: }
                   2374: 
                   2375: 
                   2376: //*********************************************************************************
                   2377: // initialPowerStateForDomainState
                   2378: //
                   2379: // Finds the highest power state in the array whose input power
                   2380: // requirement is equal to the input parameter.  Where a more intelligent
                   2381: // decision is possible, override this in the subclassed driver.
                   2382: //*********************************************************************************
                   2383: 
                   2384: unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState )
                   2385: {
                   2386:   int i;
                   2387: 
                   2388:    if (pm_vars->theNumberOfPowerStates == 0 ) {
                   2389:       return 0;
                   2390:   }
                   2391:    for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- ) {
                   2392:       if ( pm_vars->thePowerStates[i].inputPowerRequirement == domainState ) {
                   2393:           return i;
                   2394:       }
                   2395:   }
                   2396:   return 0;
                   2397: }
                   2398: 
                   2399: 
                   2400: //*********************************************************************************
                   2401: // powerStateForDomainState
                   2402: //
                   2403: // Finds the highest power state in the array whose input power
                   2404: // requirement is equal to the input parameter.  Where a more intelligent
                   2405: // decision is possible, override this in the subclassed driver.
                   2406: //*********************************************************************************
                   2407: 
                   2408: unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState )
                   2409: {
                   2410:   int i;
                   2411: 
                   2412:    if (pm_vars->theNumberOfPowerStates == 0 ) {
                   2413:       return 0;
                   2414:   }
                   2415:    for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- ) {
                   2416:       if ( pm_vars->thePowerStates[i].inputPowerRequirement == domainState ) {
                   2417:           return i;
                   2418:       }
                   2419:   }
                   2420:   return 0;
                   2421: }
                   2422: 
                   2423: 
                   2424: //*********************************************************************************
                   2425: // powerStateWillChangeTo
                   2426: //
                   2427: // Does nothing here.  This should be implemented in a subclass driver.
                   2428: //*********************************************************************************
                   2429: 
                   2430: IOReturn IOService::powerStateWillChangeTo ( IOPMPowerFlags, unsigned long, IOService*)
                   2431: {
                   2432:     return 0;
                   2433: }
                   2434: 
                   2435: 
                   2436: //*********************************************************************************
                   2437: // powerStateDidChangeTo
                   2438: //
                   2439: // Does nothing here.  This should be implemented in a subclass driver.
                   2440: //*********************************************************************************
                   2441: 
                   2442: IOReturn IOService::powerStateDidChangeTo ( IOPMPowerFlags, unsigned long, IOService*)
                   2443: {
                   2444:     return 0;
                   2445: }
                   2446: 
                   2447: 
                   2448: //*********************************************************************************
                   2449: // newTemperature
                   2450: //
                   2451: // Does nothing here.  This should be implemented in a subclass driver.
                   2452: //*********************************************************************************
                   2453: 
                   2454: IOReturn IOService::newTemperature ( long currentTemp, IOService * whichZone )
                   2455: 
                   2456: {
                   2457:     return IOPMNoErr;
                   2458: }
                   2459: 
                   2460: 
                   2461: #undef super
                   2462: #define super OSObject
                   2463: 
                   2464: OSDefineMetaClassAndStructors(IOPMprot, OSObject)
                   2465: //*********************************************************************************
                   2466: // serialize
                   2467: //
                   2468: // Serialize protected instance variables for debug output.
                   2469: //*********************************************************************************
                   2470: bool IOPMprot::serialize(OSSerialize *s) const
                   2471: {
                   2472:     OSString * theOSString;
                   2473:     char * buffer;
                   2474:     char * ptr;
                   2475:     int i;
                   2476:     bool       rtn_code;
                   2477: 
                   2478:     buffer = ptr = IONew(char, 2000);
                   2479:     if(!buffer)
                   2480:         return false;
                   2481: 
                   2482:     ptr += sprintf(ptr,"{ theNumberOfPowerStates = %d, ",(unsigned int)theNumberOfPowerStates);
                   2483: 
                   2484:     if ( theNumberOfPowerStates != 0 ) {
                   2485:         ptr += sprintf(ptr,"version %d, ",(unsigned int)thePowerStates[0].version);
                   2486:     }
                   2487: 
                   2488:     if ( theNumberOfPowerStates != 0 ) {
                   2489:         for ( i = 0; i < (int)theNumberOfPowerStates; i++ ) {
                   2490:             ptr += sprintf(ptr,"power state %d = { ",i);
                   2491:             ptr += sprintf(ptr,"capabilityFlags %08x, ",(unsigned int)thePowerStates[i].capabilityFlags);
                   2492:             ptr += sprintf(ptr,"outputPowerCharacter %08x, ",(unsigned int)thePowerStates[i].outputPowerCharacter);
                   2493:             ptr += sprintf(ptr,"inputPowerRequirement %08x, ",(unsigned int)thePowerStates[i].inputPowerRequirement);
                   2494:             ptr += sprintf(ptr,"staticPower %d, ",(unsigned int)thePowerStates[i].staticPower);
                   2495:             ptr += sprintf(ptr,"unbudgetedPower %d, ",(unsigned int)thePowerStates[i].unbudgetedPower);
                   2496:             ptr += sprintf(ptr,"powerToAttain %d, ",(unsigned int)thePowerStates[i].powerToAttain);
                   2497:             ptr += sprintf(ptr,"timeToAttain %d, ",(unsigned int)thePowerStates[i].timeToAttain);
                   2498:             ptr += sprintf(ptr,"settleUpTime %d, ",(unsigned int)thePowerStates[i].settleUpTime);
                   2499:             ptr += sprintf(ptr,"timeToLower %d, ",(unsigned int)thePowerStates[i].timeToLower);
                   2500:             ptr += sprintf(ptr,"settleDownTime %d, ",(unsigned int)thePowerStates[i].settleDownTime);
                   2501:             ptr += sprintf(ptr,"powerDomainBudget %d }, ",(unsigned int)thePowerStates[i].powerDomainBudget);
                   2502:         }
                   2503:     }
                   2504: 
                   2505:     ptr += sprintf(ptr,"aggressiveness = %d, ",(unsigned int)aggressiveness);
                   2506:     ptr += sprintf(ptr,"myCurrentState = %d, ",(unsigned int)myCurrentState);
                   2507:     ptr += sprintf(ptr,"parentCurrentPowerFlags = %08x, ",(unsigned int)parentCurrentPowerFlags);
                   2508:     ptr += sprintf(ptr,"maxCapability = %d }",(unsigned int)maxCapability);
                   2509: 
                   2510:     theOSString = OSString::withCString(buffer);
                   2511:     rtn_code = theOSString->serialize(s);
                   2512:     theOSString->release();
                   2513:     IODelete(buffer, char, 2000);
                   2514: 
                   2515:     return rtn_code;
                   2516: }
                   2517: 
                   2518: 
                   2519: #undef super
                   2520: #define super OSObject
                   2521: 
                   2522: OSDefineMetaClassAndStructors(IOPMpriv, OSObject)
                   2523: //*********************************************************************************
                   2524: // serialize
                   2525: //
                   2526: // Serialize private instance variables for debug output.
                   2527: //*********************************************************************************
                   2528: bool IOPMpriv::serialize(OSSerialize *s) const
                   2529: {
                   2530:     OSString * theOSString;
                   2531:     char * buffer;
                   2532:     char * ptr;
                   2533:     IOPMinformee * nextObject;
                   2534:     bool       rtn_code;
                   2535: 
                   2536:     buffer = ptr = IONew(char, 2000);
                   2537:     if(!buffer)
                   2538:         return false;
                   2539: 
                   2540:     ptr += sprintf(ptr,"{ this object = %08x",(unsigned int)owner);
                   2541:     if ( we_are_root ) {
                   2542:         ptr += sprintf(ptr," (root)");
                   2543:     }
                   2544:     ptr += sprintf(ptr,", ");
                   2545: 
                   2546:     nextObject = interestedDrivers->firstInList();                     // display interested drivers
                   2547:     while (  nextObject != NULL ) {
                   2548:         ptr += sprintf(ptr,"interested driver = %08x, ",(unsigned int)nextObject->whatObject);
                   2549:         nextObject  =  interestedDrivers->nextInList(nextObject);
                   2550:     }
                   2551: 
                   2552:     nextObject =children->firstInList();                               // display power domain children
                   2553:     while (  nextObject != NULL ) {
                   2554:         ptr += sprintf(ptr,"child = %08x, ",(unsigned int)nextObject->whatObject);
                   2555:             nextObject  = children->nextInList(nextObject);
                   2556:     }
                   2557: 
                   2558:     ptr += sprintf(ptr,"numberOfInformees = %d, ",(unsigned int)numberOfInformees);
                   2559: 
                   2560:     if ( machine_state != IOPMfinished ) {
                   2561:         ptr += sprintf(ptr,"machine_state = %d, ",(unsigned int)machine_state);
                   2562:         ptr += sprintf(ptr,"driver_timer = %d, ",(unsigned int)driver_timer);
                   2563:         ptr += sprintf(ptr,"settle_time = %d, ",(unsigned int)settle_time);
                   2564:         ptr += sprintf(ptr,"head_note_flags = %08x, ",(unsigned int)head_note_flags);
                   2565:         ptr += sprintf(ptr,"head_note_state = %d, ",(unsigned int)head_note_state);
                   2566:         ptr += sprintf(ptr,"head_note_outputFlags = %08x, ",(unsigned int)head_note_outputFlags);
                   2567:         ptr += sprintf(ptr,"head_note_domainState = %08x, ",(unsigned int)head_note_domainState);
                   2568:         ptr += sprintf(ptr,"head_note_capabilityFlags = %08x, ",(unsigned int)head_note_capabilityFlags);
                   2569:         ptr += sprintf(ptr,"head_note_pendingAcks = %d, ",(unsigned int)head_note_pendingAcks);
                   2570:     }
                   2571: 
                   2572:     if ( device_overrides ) {
                   2573:         ptr += sprintf(ptr,"device overrides, ");
                   2574:     }
                   2575:     ptr += sprintf(ptr,"driverDesire = %d, ",(unsigned int)driverDesire);
                   2576:     ptr += sprintf(ptr,"deviceDesire = %d, ",(unsigned int)deviceDesire);
                   2577:     ptr += sprintf(ptr,"ourDesiredPowerState = %d, ",(unsigned int)ourDesiredPowerState);
                   2578:     ptr += sprintf(ptr,"previousRequest = %d }",(unsigned int)previousRequest);
                   2579: 
                   2580:     theOSString =  OSString::withCString(buffer);
                   2581:     rtn_code = theOSString->serialize(s);
                   2582:     theOSString->release();
                   2583:     IODelete(buffer, char, 2000);
                   2584: 
                   2585:     return rtn_code;
                   2586: }
                   2587: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.