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


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

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

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

    1 /*
    2  * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
    5  * 
    6  * This file contains Original Code and/or Modifications of Original Code
    7  * as defined in and that are subject to the Apple Public Source License
    8  * Version 2.0 (the 'License'). You may not use this file except in
    9  * compliance with the License. The rights granted to you under the License
   10  * may not be used to create, or enable the creation or redistribution of,
   11  * unlawful or unlicensed copies of an Apple operating system, or to
   12  * circumvent, violate, or enable the circumvention or violation of, any
   13  * terms of an Apple operating system software license agreement.
   14  * 
   15  * Please obtain a copy of the License at
   16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
   17  * 
   18  * The Original Code and all software distributed under the License are
   19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   23  * Please see the License for the specific language governing rights and
   24  * limitations under the License.
   25  * 
   26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
   27  */
   28 #include <IOKit/IOWorkLoop.h>
   29 #include <IOKit/IOCommandGate.h>
   30 #include <IOKit/IOTimerEventSource.h>
   31 #include <IOKit/IOPlatformExpert.h>
   32 #include <IOKit/IOKitDebug.h>
   33 #include <IOKit/IOTimeStamp.h>
   34 #include <IOKit/pwr_mgt/RootDomain.h>
   35 #include <IOKit/pwr_mgt/IOPMPrivate.h>
   36 #include <IOKit/IODeviceTreeSupport.h>
   37 #include <IOKit/IOMessage.h>
   38 #include <IOKit/IOReturn.h>
   39 #include "RootDomainUserClient.h"
   40 #include "IOKit/pwr_mgt/IOPowerConnection.h"
   41 #include "IOPMPowerStateQueue.h"
   42 #include <IOKit/IOCatalogue.h>
   43 #if HIBERNATION
   44 #include <IOKit/IOHibernatePrivate.h>
   45 #endif
   46 #include <sys/syslog.h>
   47 #include <sys/sysctl.h>
   48 #include <sys/time.h>
   49 #include "IOServicePrivate.h"   // _IOServiceInterestNotifier
   50 
   51 
   52 #if __i386__
   53 __BEGIN_DECLS
   54 #include "IOPMrootDomainInternal.h"
   55 __END_DECLS
   56 #endif
   57 
   58 
   59 //#define DEBUG   1
   60 #if DEBUG
   61 #define DEBUG_LOG(x...) do { kprintf(x); } while (0)
   62 #else
   63 #define DEBUG_LOG(x...)
   64 #endif
   65 #define HaltRestartLog(x...)  do { kprintf(x); } while (0)
   66 
   67 extern "C" {
   68 IOReturn OSMetaClassSystemSleepOrWake( UInt32 );
   69 }
   70 
   71 extern const IORegistryPlane * gIOPowerPlane;
   72 
   73 IOReturn broadcast_aggressiveness ( OSObject *, void *, void *, void *, void * );
   74 static void sleepTimerExpired(thread_call_param_t);
   75 static void wakeupClamshellTimerExpired ( thread_call_param_t us);
   76 static void notifySystemShutdown( IOService * root, unsigned long event );
   77 
   78 // "IOPMSetSleepSupported"  callPlatformFunction name
   79 static const OSSymbol *sleepSupportedPEFunction = NULL;
   80 
   81 #define kIOSleepSupportedKey  "IOSleepSupported"
   82 
   83 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
   84                            | kIOPMSupportedOnBatt \
   85                            | kIOPMSupportedOnUPS)
   86 
   87 #define number_of_power_states 5
   88 #define OFF_STATE 0
   89 #define RESTART_STATE 1
   90 #define SLEEP_STATE 2
   91 #define DOZE_STATE 3
   92 #define ON_STATE 4
   93 
   94 #define ON_POWER kIOPMPowerOn
   95 #define RESTART_POWER kIOPMRestart
   96 #define SLEEP_POWER kIOPMAuxPowerOn
   97 #define DOZE_POWER kIOPMDoze
   98 
   99 enum 
  100 {
  101     // not idle around autowake time, secs
  102     kAutoWakePreWindow  = 45,
  103     kAutoWakePostWindow = 15
  104 };
  105 
  106 
  107 #define kLocalEvalClamshellCommand        (1 << 15)
  108 
  109 static IOPMPowerState ourPowerStates[number_of_power_states] = {
  110     // state 0, off
  111     {1,0,                       0,              0,0,0,0,0,0,0,0,0},
  112     // state 1, restart
  113     {1,kIOPMRestartCapability,  kIOPMRestart,   RESTART_POWER,0,0,0,0,0,0,0,0}, 
  114     // state 2, sleep
  115     {1,kIOPMSleepCapability,    kIOPMSleep,     SLEEP_POWER,0,0,0,0,0,0,0,0},   
  116     // state 3, doze
  117     {1,kIOPMDoze,               kIOPMDoze,      DOZE_POWER,0,0,0,0,0,0,0,0},    
  118     // state 4, on
  119     {1,kIOPMPowerOn,            kIOPMPowerOn,   ON_POWER,0,0,0,0,0,0,0,0},      
  120 };
  121 
  122 static IOPMrootDomain * gRootDomain;
  123 static UInt32           gSleepOrShutdownPending = 0;
  124 
  125 struct timeval gIOLastSleepTime;
  126 struct timeval gIOLastWakeTime;
  127 
  128 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
  129 #define kCPUUnknownIndex    9999999
  130 enum {
  131     kInformAC = 0,
  132     kInformLid = 1,
  133     kInformableCount = 2
  134 };
  135 
  136 class PMSettingObject : public OSObject
  137 {
  138     OSDeclareDefaultStructors(PMSettingObject)
  139 private:
  140     IOPMrootDomain                  *parent;
  141     IOPMSettingControllerCallback   func;
  142     OSObject                        *target;
  143     uintptr_t                       refcon;
  144     uint32_t                        *publishedFeatureID;
  145     int                             releaseAtCount;
  146 public:
  147     static PMSettingObject *pmSettingObject(
  148                 IOPMrootDomain      *parent_arg,
  149                 IOPMSettingControllerCallback   handler_arg,
  150                 OSObject    *target_arg,
  151                 uintptr_t   refcon_arg,
  152                 uint32_t    supportedPowerSources,
  153                 const OSSymbol *settings[]);
  154 
  155     void setPMSetting(const OSSymbol *type, OSObject *obj);
  156 
  157     void taggedRelease(const void *tag, const int when) const;
  158     void free(void);
  159 };
  160 
  161 /*
  162  * Internal helper object for Shutdown/Restart notifications.
  163  */
  164 #define kPMHaltMaxWorkers   8
  165 #define kPMHaltTimeoutMS    100
  166 
  167 class PMHaltWorker : public OSObject
  168 {
  169     OSDeclareDefaultStructors( PMHaltWorker )
  170 
  171 public:
  172     IOService *  service;    // service being worked on
  173     AbsoluteTime startTime;  // time when work started
  174     int          depth;      // work on nubs at this PM-tree depth
  175     int          visits;     // number of nodes visited (debug)
  176     IOLock *     lock;
  177     bool         timeout;    // service took too long
  178 
  179     static  PMHaltWorker * worker( void );
  180     static  void main( void * arg );
  181     static  void work( PMHaltWorker * me );
  182     static  void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
  183     virtual void free( void );
  184 };
  185 
  186 OSDefineMetaClassAndStructors( PMHaltWorker, OSObject )
  187 
  188 
  189 #define super IOService
  190 OSDefineMetaClassAndStructors(IOPMrootDomain,IOService)
  191 
  192 extern "C"
  193 {
  194     IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
  195     {
  196         return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
  197     }
  198 
  199     IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
  200     {
  201         return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
  202     }
  203 
  204     IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
  205     {
  206         return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
  207     }
  208 
  209     IOReturn vetoSleepWakeNotification(void * PMrefcon)
  210     {
  211         return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
  212     }
  213     
  214     IOReturn rootDomainRestart ( void )
  215     {
  216         return gRootDomain->restartSystem();
  217     }
  218     
  219     IOReturn rootDomainShutdown ( void )
  220     {
  221         return gRootDomain->shutdownSystem();
  222     }
  223 
  224         void IOSystemShutdownNotification ( void )
  225     {
  226         IOCatalogue::disableExternalLinker();
  227         for ( int i = 0; i < 100; i++ )
  228         {
  229             if ( OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) ) break;
  230             IOSleep( 100 );
  231         }
  232     }
  233 
  234     int sync_internal(void);    
  235 }
  236 
  237 /*
  238 A device is always in the highest power state which satisfies its driver, its policy-maker, and any power domain
  239 children it has, but within the constraint of the power state provided by its parent.  The driver expresses its desire by
  240 calling changePowerStateTo(), the policy-maker expresses its desire by calling changePowerStateToPriv(), and the children
  241 express their desires by calling requestPowerDomainState().
  242 
  243 The Root Power Domain owns the policy for idle and demand sleep and doze for the system.  It is a power-managed IOService just
  244 like the others in the system.  It implements several power states which correspond to what we see as Sleep, Doze, etc.
  245 
  246 The sleep/doze policy is as follows:
  247 Sleep and Doze are prevented if the case is open so that nobody will think the machine is off and plug/unplug cards.
  248 Sleep and Doze are prevented if the sleep timeout slider in the preferences panel is at zero.
  249 The system cannot Sleep, but can Doze if some object in the tree is in a power state marked kIOPMPreventSystemSleep.
  250 
  251 These three conditions are enforced using the "driver clamp" by calling changePowerStateTo().  For example, if the case is
  252 opened, changePowerStateTo(ON_STATE) is called to hold the system on regardless of the desires of the children of the root or
  253 the state of the other clamp.
  254 
  255 Demand Sleep/Doze is initiated by pressing the front panel power button, closing the clamshell, or selecting the menu item.
  256 In this case the root's parent actually initiates the power state change so that the root has no choice and does not give
  257 applications the opportunity to veto the change.
  258 
  259 Idle Sleep/Doze occurs if no objects in the tree are in a state marked kIOPMPreventIdleSleep.  When this is true, the root's
  260 children are not holding the root on, so it sets the "policy-maker clamp" by calling changePowerStateToPriv(ON_STATE)
  261 to hold itself on until the sleep timer expires.  This timer is set for the difference between the sleep timeout slider and
  262 the larger of the display dim timeout slider and the disk spindown timeout slider in the Preferences panel.  For example, if
  263 the system is set to sleep after thirty idle minutes, and the display and disk are set to sleep after five idle minutes,
  264 when there is no longer an object in the tree holding the system out of Idle Sleep (via kIOPMPreventIdleSleep), the root
  265 sets its timer for 25 minutes (30 - 5).  When the timer expires, it releases its clamp and now nothing is holding it awake,
  266 so it falls asleep.
  267 
  268 Demand sleep is prevented when the system is booting.  When preferences are transmitted by the loginwindow at the end of
  269 boot, a flag is cleared, and this allows subsequent Demand Sleep.
  270 
  271 The system will not Sleep, but will Doze if some object calls setSleepSupported(kPCICantSleep) during a power change to the sleep state (this can be done by the PCI Aux Power Supply drivers, Slots99, MacRISC299, etc.).  This is not enforced with
  272 a clamp, but sets a flag which is noticed before actually sleeping the kernel.  If the flag is set, the root steps up
  273 one power state from Sleep to Doze, and any objects in the tree for which this is relevent will act appropriately (USB and
  274 ADB will turn on again so that they can wake the system out of Doze (keyboard/mouse activity will cause the Display Wrangler
  275 to be tickled)).
  276 */
  277 
  278 // **********************************************************************************
  279 
  280 IOPMrootDomain * IOPMrootDomain::construct( void )
  281 {
  282     IOPMrootDomain                          *root;
  283 
  284     root = new IOPMrootDomain;
  285     if( root)
  286         root->init();
  287 
  288     return( root );
  289 }
  290 
  291 // **********************************************************************************
  292 
  293 static void disk_sync_callout(thread_call_param_t p0, thread_call_param_t p1)
  294 {
  295     IOService       *rootDomain = (IOService *) p0;
  296     unsigned long   pmRef = (unsigned long) p1;
  297 
  298     DEBUG_LOG("disk_sync_callout: start\n");
  299 
  300 #if     HIBERNATION
  301     IOHibernateSystemSleep();
  302 #endif
  303     sync_internal();
  304     rootDomain->allowPowerChange(pmRef);
  305     DEBUG_LOG("disk_sync_callout: finish\n");
  306 }
  307 
  308 // **********************************************************************************
  309 
  310 static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime )
  311 {
  312         AbsoluteTime    endTime;
  313         UInt64                  nano = 0;
  314 
  315         clock_get_uptime(&endTime);
  316         if (CMP_ABSOLUTETIME(&endTime, startTime) > 0)
  317         {
  318                 SUB_ABSOLUTETIME(&endTime, startTime);
  319                 absolutetime_to_nanoseconds(endTime, &nano);
  320         }
  321 
  322         return (UInt32)(nano / 1000000ULL);
  323 }
  324 
  325 // **********************************************************************************
  326 // start
  327 //
  328 // We don't do much here.  The real initialization occurs when the platform
  329 // expert informs us we are the root.
  330 // **********************************************************************************
  331 
  332 #define kRootDomainSettingsCount        14
  333 
  334 static SYSCTL_STRUCT(_kern, OID_AUTO, sleeptime, 
  335                      CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN, 
  336                      &gIOLastSleepTime, timeval, "");
  337 
  338 static SYSCTL_STRUCT(_kern, OID_AUTO, waketime, 
  339                      CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN, 
  340                      &gIOLastWakeTime, timeval, "");
  341 
  342 static const OSSymbol * gIOPMSettingAutoWakeSecondsKey;
  343 
  344 bool IOPMrootDomain::start ( IOService * nub )
  345 {
  346     OSIterator      *psIterator;
  347     OSDictionary    *tmpDict;
  348 
  349     gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
  350 
  351     const OSSymbol  *settingsArr[kRootDomainSettingsCount] = 
  352         {
  353             OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
  354             gIOPMSettingAutoWakeSecondsKey,
  355             OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
  356             OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey),
  357             OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
  358             OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey),
  359             OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
  360             OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
  361             OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
  362             OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
  363             OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
  364             OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey),
  365             OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
  366             OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey)
  367         };
  368     
  369 
  370     pmPowerStateQueue = 0;
  371 
  372     _reserved = (ExpansionData *)IOMalloc(sizeof(ExpansionData));
  373     if(!_reserved) return false;
  374 
  375     super::start(nub);
  376 
  377     gRootDomain = this;
  378 
  379     PMinit();
  380     
  381     sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
  382     canSleep = true;
  383     setProperty(kIOSleepSupportedKey,true);
  384 
  385     userDisabledAllSleep = false;
  386     allowSleep = true;
  387     sleepIsSupported = true;
  388     systemBooting = true;
  389     sleepSlider = 0;
  390     idleSleepPending = false;
  391     wrangler = NULL;
  392     sleepASAP = false;
  393     clamshellIsClosed = false;
  394     clamshellExists = false;
  395     ignoringClamshell = true;
  396     ignoringClamshellDuringWakeup = false;
  397     acAdaptorConnect = true;
  398 
  399     idxPMCPUClamshell = kCPUUnknownIndex;
  400     idxPMCPULimitedPower = kCPUUnknownIndex;
  401         
  402     tmpDict = OSDictionary::withCapacity(1);
  403     setProperty(kRootDomainSupportedFeatures, tmpDict);
  404     tmpDict->release();
  405     
  406     settingsCallbacks = OSDictionary::withCapacity(1);
  407 
  408     // Create a list of the valid PM settings that we'll relay to
  409     // interested clients in setProperties() => setPMSetting()
  410     allowedPMSettings = OSArray::withObjects(
  411                     (const OSObject **)settingsArr,
  412                     kRootDomainSettingsCount,
  413                     0);
  414                     
  415     fPMSettingsDict = OSDictionary::withCapacity(5);
  416             
  417     pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(this);
  418     getPMworkloop()->addEventSource(pmPowerStateQueue);
  419     
  420     featuresDictLock = IOLockAlloc();
  421     settingsCtrlLock = IORecursiveLockAlloc();
  422     
  423     extraSleepTimer = thread_call_allocate(
  424                         (thread_call_func_t)sleepTimerExpired, 
  425                         (thread_call_param_t) this);
  426     clamshellWakeupIgnore = thread_call_allocate(
  427                         (thread_call_func_t)wakeupClamshellTimerExpired, 
  428                         (thread_call_param_t) this);
  429     diskSyncCalloutEntry = thread_call_allocate(
  430                         &disk_sync_callout, 
  431                         (thread_call_param_t) this);
  432 
  433     // create our parent
  434     patriarch = new IORootParent;
  435     patriarch->init();
  436     patriarch->attach(this);
  437     patriarch->start(this);
  438     patriarch->addPowerChild(this);
  439         
  440     registerPowerDriver(this,ourPowerStates,number_of_power_states);
  441 
  442     setPMRootDomain(this);
  443     // set a clamp until we sleep
  444     changePowerStateToPriv(ON_STATE);
  445 
  446     // install power change handler
  447     registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
  448 
  449 #if !NO_KERNEL_HID
  450     // Register for a notification when IODisplayWrangler is published
  451     _displayWranglerNotifier = addNotification( 
  452                 gIOPublishNotification, serviceMatching("IODisplayWrangler"), 
  453                 &displayWranglerPublished, this, 0);
  454 #endif
  455 
  456     // Battery location published - ApplePMU support only
  457     _batteryPublishNotifier = addNotification( 
  458                 gIOPublishNotification, serviceMatching("IOPMPowerSource"), 
  459                 &batteryPublished, this, this);
  460      
  461 
  462     const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
  463     setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
  464     ucClassName->release();
  465 
  466     // IOBacklightDisplay can take a long time to load at boot, or it may
  467     // not load at all if you're booting with clamshell closed. We publish
  468     // 'DisplayDims' here redundantly to get it published early and at all.
  469     psIterator = getMatchingServices( serviceMatching("IOPMPowerSource") );
  470     if( psIterator && psIterator->getNextObject() )
  471     {
  472         // There's at least one battery on the system, so we publish
  473         // 'DisplayDims' support for the LCD.
  474         publishFeature("DisplayDims");
  475     }
  476     if(psIterator) {
  477         psIterator->release();
  478     }
  479 
  480 
  481     sysctl_register_oid(&sysctl__kern_sleeptime);
  482     sysctl_register_oid(&sysctl__kern_waketime);
  483 
  484 #if     HIBERNATION
  485     IOHibernateSystemInit(this);
  486 #endif
  487 
  488     registerService();                                          // let clients find us
  489 
  490     return true;
  491 }
  492 
  493 // **********************************************************************************
  494 // setProperties
  495 //
  496 // Receive a setProperty call
  497 // The "System Boot" property means the system is completely booted.
  498 // **********************************************************************************
  499 IOReturn IOPMrootDomain::setProperties ( OSObject *props_obj)
  500 {
  501     IOReturn                        return_value = kIOReturnSuccess;
  502     OSDictionary                    *dict = OSDynamicCast(OSDictionary, props_obj);
  503     OSBoolean                       *b;
  504     OSNumber                        *n;
  505     OSString                        *str;
  506     OSSymbol                        *type;
  507     OSObject                        *obj;
  508     unsigned int                    i;
  509 
  510     const OSSymbol *boot_complete_string = 
  511                 OSSymbol::withCString("System Boot Complete");
  512     const OSSymbol *sys_shutdown_string = 
  513                 OSSymbol::withCString("System Shutdown");
  514     const OSSymbol *stall_halt_string = 
  515                 OSSymbol::withCString("StallSystemAtHalt");
  516     const OSSymbol *battery_warning_disabled_string = 
  517                 OSSymbol::withCString("BatteryWarningsDisabled");
  518     const OSSymbol *idle_seconds_string = 
  519                 OSSymbol::withCString("System Idle Seconds");
  520 #if     HIBERNATION
  521     const OSSymbol *hibernatemode_string = 
  522                 OSSymbol::withCString(kIOHibernateModeKey);
  523     const OSSymbol *hibernatefile_string = 
  524                 OSSymbol::withCString(kIOHibernateFileKey);
  525     const OSSymbol *hibernatefreeratio_string = 
  526                 OSSymbol::withCString(kIOHibernateFreeRatioKey);
  527     const OSSymbol *hibernatefreetime_string = 
  528                 OSSymbol::withCString(kIOHibernateFreeTimeKey);
  529 #endif
  530     const OSSymbol *sleepdisabled_string =
  531                 OSSymbol::withCString("SleepDisabled");
  532     
  533     if(!dict) 
  534     {
  535         return_value = kIOReturnBadArgument;
  536         goto exit;
  537     }
  538 
  539     if ((n = OSDynamicCast(OSNumber, dict->getObject(idle_seconds_string))))
  540     {
  541         setProperty(idle_seconds_string, n);
  542         idleSeconds = n->unsigned32BitValue();
  543     }
  544 
  545     if( systemBooting 
  546         && boot_complete_string 
  547         && dict->getObject(boot_complete_string)) 
  548     {
  549         systemBooting = false;
  550         adjustPowerState();
  551 
  552         // If lid is closed, re-send lid closed notification
  553         // now that booting is complete.
  554         if( clamshellIsClosed )
  555         {
  556             this->receivePowerNotification(kLocalEvalClamshellCommand);
  557         }
  558     }
  559     
  560     if( battery_warning_disabled_string
  561         && dict->getObject(battery_warning_disabled_string))
  562     {
  563         setProperty( battery_warning_disabled_string, 
  564                         dict->getObject(battery_warning_disabled_string));
  565     }
  566     
  567     if( sys_shutdown_string 
  568         && (b = OSDynamicCast(OSBoolean, dict->getObject(sys_shutdown_string)))) 
  569     {
  570     
  571         if(kOSBooleanTrue == b)
  572         {
  573             /* We set systemShutdown = true during shutdown
  574                to prevent sleep at unexpected times while loginwindow is trying
  575                to shutdown apps and while the OS is trying to transition to
  576                complete power of.
  577                
  578                Set to true during shutdown, as soon as loginwindow shows
  579                the "shutdown countdown dialog", through individual app
  580                termination, and through black screen kernel shutdown.
  581              */
  582              kprintf("systemShutdown true\n");
  583             systemShutdown = true;
  584         } else {
  585             /*
  586              A shutdown was initiated, but then the shutdown
  587              was cancelled, clearing systemShutdown to false here.
  588             */
  589             kprintf("systemShutdown false\n");
  590             systemShutdown = false;            
  591         }        
  592     }
  593     
  594     if( stall_halt_string
  595         && (b = OSDynamicCast(OSBoolean, dict->getObject(stall_halt_string))) ) 
  596     {
  597         setProperty(stall_halt_string, b);
  598     }
  599 
  600 #if     HIBERNATION
  601     if ( hibernatemode_string
  602     && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatemode_string))))
  603     {
  604         setProperty(hibernatemode_string, n);
  605     }
  606     if ( hibernatefreeratio_string
  607     && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreeratio_string))))
  608     {
  609         setProperty(hibernatefreeratio_string, n);
  610     }
  611     if ( hibernatefreetime_string
  612     && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreetime_string))))
  613     {
  614         setProperty(hibernatefreetime_string, n);
  615     }
  616     if ( hibernatefile_string
  617     && (str = OSDynamicCast(OSString, dict->getObject(hibernatefile_string))))
  618     {
  619         setProperty(hibernatefile_string, str);
  620     }
  621 #endif
  622     
  623     if( sleepdisabled_string
  624         && (b = OSDynamicCast(OSBoolean, dict->getObject(sleepdisabled_string))) )
  625     {
  626         setProperty(sleepdisabled_string, b);
  627         
  628         userDisabledAllSleep = (kOSBooleanTrue == b);
  629     }
  630 
  631     // Relay our allowed PM settings onto our registered PM clients
  632     for(i = 0; i < allowedPMSettings->getCount(); i++) {
  633 
  634         type = (OSSymbol *)allowedPMSettings->getObject(i);
  635         if(!type) continue;
  636 
  637         obj = dict->getObject(type);
  638         if(!obj) continue;
  639 
  640         if ((gIOPMSettingAutoWakeSecondsKey == type) && ((n = OSDynamicCast(OSNumber, obj))))
  641         {
  642             UInt32 rsecs = n->unsigned32BitValue();
  643             if (!rsecs)
  644                 autoWakeStart = autoWakeEnd = 0;
  645             else
  646             {
  647                 AbsoluteTime deadline;
  648                 clock_interval_to_deadline(rsecs + kAutoWakePostWindow, kSecondScale, &deadline);
  649                 autoWakeEnd = AbsoluteTime_to_scalar(&deadline);
  650                 if (rsecs > kAutoWakePreWindow)
  651                     rsecs -= kAutoWakePreWindow;
  652                 else
  653                     rsecs = 0;
  654                 clock_interval_to_deadline(rsecs, kSecondScale, &deadline);
  655                 autoWakeStart = AbsoluteTime_to_scalar(&deadline);
  656             }
  657         }
  658         
  659         return_value = setPMSetting(type, obj);
  660         
  661         if(kIOReturnSuccess != return_value) goto exit;
  662     }
  663 
  664 exit:
  665     if(sleepdisabled_string) sleepdisabled_string->release();
  666     if(boot_complete_string) boot_complete_string->release();
  667     if(stall_halt_string) stall_halt_string->release();
  668     if(idle_seconds_string) idle_seconds_string->release();
  669     return return_value;
  670 }
  671 
  672 
  673 //*********************************************************************************
  674 // youAreRoot
  675 //
  676 // Power Managment is informing us that we are the root power domain.
  677 // We know we are not the root however, since we have just instantiated a parent
  678 // for ourselves and made it the root.  We override this method so it will have
  679 // no effect
  680 //*********************************************************************************
  681 IOReturn IOPMrootDomain::youAreRoot ( void )
  682 {
  683     return IOPMNoErr;
  684 }
  685 
  686 // **********************************************************************************
  687 // command_received
  688 //
  689 // No longer used
  690 // **********************************************************************************
  691 void IOPMrootDomain::command_received ( void * w, void * x, void * y, void * z )
  692 {
  693     super::command_received(w,x,y,z);
  694 }
  695 
  696 
  697 // **********************************************************************************
  698 // broadcast_aggressiveness
  699 //
  700 // **********************************************************************************
  701 IOReturn broadcast_aggressiveness ( OSObject * root, void * x, void * y, void *, void * )
  702 {
  703     ((IOPMrootDomain *)root)->broadcast_it((unsigned long)x,(unsigned long)y);
  704     return IOPMNoErr;
  705 }
  706 
  707 
  708 // **********************************************************************************
  709 // broadcast_it
  710 //
  711 // We are behind the command gate to broadcast an aggressiveness factor.  We let the
  712 // superclass do it, but we need to snoop on factors that affect idle sleep.
  713 // **********************************************************************************
  714 void IOPMrootDomain::broadcast_it (unsigned long type, unsigned long value)
  715 {
  716     super::setAggressiveness(type,value);
  717 
  718     // Save user's spin down timer to restore after we replace it for idle sleep
  719     if( type == kPMMinutesToSpinDown ) user_spindown = value;
  720 
  721     // Use longestNonSleepSlider to calculate dimming adjust idle sleep timer
  722         if (getAggressiveness(kPMMinutesToDim, (unsigned long *)&longestNonSleepSlider)
  723                 != kIOReturnSuccess)
  724                 longestNonSleepSlider = 0;
  725 
  726     if ( type == kPMMinutesToSleep ) {
  727         DEBUG_LOG("PM idle time -> %ld secs (ena %d)\n", idleSeconds, (value != 0));
  728         if (0x7fffffff == value)
  729             value = idleSeconds;
  730 
  731         if ( (sleepSlider == 0) && (value != 0) ) {
  732             if (!wrangler)
  733             {
  734                 sleepASAP = false;
  735                 changePowerStateToPriv(ON_STATE);
  736                 if (idleSeconds)
  737                 {
  738                     AbsoluteTime deadline;
  739                     // stay awake for at least idleSeconds
  740                     clock_interval_to_deadline(idleSeconds, kSecondScale, &deadline);   
  741                     thread_call_enter_delayed(extraSleepTimer, deadline);
  742                     // this gets turned off when we sleep again
  743                     idleSleepPending = true;
  744                 }
  745             }
  746             else
  747             {
  748                 // If sleepASAP is already set, then calling adjustPowerState() here
  749                 // will put the system to sleep immediately which is bad.  Note that
  750                 // this aggressiveness change can occur without waking up the display
  751                 // by (dis)connecting the AC adapter. To get around this, the power
  752                 // clamp is restore to ON state then dropped after waiting for the
  753                 // sleep timer to expire.
  754 
  755                 if (sleepASAP)
  756                 {
  757                     AbsoluteTime deadline;
  758                     // stay awake for at least sleepSlider minutes
  759                     clock_interval_to_deadline(value * 60, kSecondScale, &deadline);    
  760                     thread_call_enter_delayed(extraSleepTimer, deadline);
  761                     // this gets turned off when we sleep again
  762                     idleSleepPending = true;
  763                     sleepASAP = false;
  764                 }
  765             }
  766         }
  767         sleepSlider = value;
  768         if ( sleepSlider == 0 ) {                       
  769             // idle sleep is now disabled
  770             adjustPowerState();
  771             // make sure we're powered
  772             patriarch->wakeSystem();
  773         }
  774     }
  775     if ( sleepSlider > longestNonSleepSlider ) {
  776         extraSleepDelay = sleepSlider - longestNonSleepSlider ;
  777     }
  778     else {
  779         extraSleepDelay = 0;
  780     }
  781 }
  782 
  783 
  784 // **********************************************************************************
  785 // sleepTimerExpired
  786 //
  787 // **********************************************************************************
  788 static void sleepTimerExpired ( thread_call_param_t us)
  789 {
  790     ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
  791     }
  792     
  793    
  794 static void wakeupClamshellTimerExpired ( thread_call_param_t us)
  795 {
  796     ((IOPMrootDomain *)us)->stopIgnoringClamshellEventsDuringWakeup();
  797 }
  798 
  799     
  800 // **********************************************************************************
  801 // handleSleepTimerExpiration
  802 //
  803 // The time between the sleep idle timeout and the next longest one has elapsed.
  804 // It's time to sleep.  Start that by removing the clamp that's holding us awake.
  805 // **********************************************************************************
  806 void IOPMrootDomain::handleSleepTimerExpiration ( void )
  807 {
  808     DEBUG_LOG("SleepTimerExpired\n");
  809 
  810     AbsoluteTime time;
  811 
  812     clock_get_uptime(&time);
  813     if ((AbsoluteTime_to_scalar(&time) > autoWakeStart) && (AbsoluteTime_to_scalar(&time) < autoWakeEnd))
  814     {
  815         thread_call_enter_delayed(extraSleepTimer, *((AbsoluteTime *) &autoWakeEnd));
  816         return;
  817     }
  818 
  819     // accelerate disk spin down if spin down timer is non-zero (zero = never spin down)  
  820     if(0 != user_spindown)
  821         setQuickSpinDownTimeout();
  822 
  823     sleepASAP = true;
  824     adjustPowerState();
  825 }
  826 
  827 
  828 void IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup(void)
  829 {
  830     // Allow clamshell-induced sleep now
  831     ignoringClamshellDuringWakeup = false;
  832 
  833     // Re-send clamshell event, in case it causes a sleep
  834     if(clamshellIsClosed) 
  835         this->receivePowerNotification( kLocalEvalClamshellCommand );
  836 }
  837 
  838 //*********************************************************************************
  839 // setAggressiveness
  840 //
  841 // Some aggressiveness factor has changed.  We broadcast it to the hierarchy while on
  842 // the Power Mangement workloop thread.  This enables objects in the
  843 // hierarchy to successfully alter their idle timers, which are all on the
  844 // same thread.
  845 //*********************************************************************************
  846 
  847 IOReturn IOPMrootDomain::setAggressiveness ( unsigned long type, unsigned long newLevel )
  848 {
  849     IOWorkLoop * pmWorkLoop = getPMworkloop();
  850     if (pmWorkLoop)
  851         pmWorkLoop->runAction(broadcast_aggressiveness,this,(void *)type,(void *)newLevel);
  852 
  853     return kIOReturnSuccess;
  854 }
  855 
  856 
  857 // **********************************************************************************
  858 // sleepSystem
  859 //
  860 // **********************************************************************************
  861 /* public */
  862 IOReturn IOPMrootDomain::sleepSystem ( void )
  863 {
  864     return sleepSystemOptions (NULL);
  865 }
  866 
  867 /* private */
  868 IOReturn IOPMrootDomain::sleepSystemOptions ( OSDictionary *options )
  869 {
  870         /* sleepSystem is a public function, and may be called by any kernel driver.
  871      * And that's bad - drivers should sleep the system by calling 
  872      * receivePowerNotification() instead. Drivers should not use sleepSystem.
  873      *
  874      * Note that user space app calls to IOPMSleepSystem() will also travel
  875      * this code path and thus be correctly identified as software sleeps.
  876      */
  877           
  878     if (options && options->getObject("OSSwitch")) 
  879     {
  880 
  881         // Log specific sleep cause for OS Switch hibernation
  882         return privateSleepSystem( kIOPMOSSwitchHibernationKey) ;
  883 
  884     } else {
  885 
  886         return privateSleepSystem( kIOPMSoftwareSleepKey);
  887 
  888     }
  889 }
  890 
  891 /* private */
  892 IOReturn IOPMrootDomain::privateSleepSystem ( const char *sleepReason )
  893 {
  894     // Record sleep cause in IORegistry
  895     if (sleepReason) {
  896         setProperty(kRootDomainSleepReasonKey, sleepReason);
  897     }
  898 
  899     if(systemShutdown) {
  900         kprintf("Preventing system sleep on grounds of systemShutdown.\n");
  901     }
  902     
  903     if( userDisabledAllSleep )
  904     {
  905         /* Prevent sleep of all kinds if directed to by user space */
  906         return kIOReturnNotPermitted;
  907     }
  908 
  909     if ( !systemBooting 
  910       && !systemShutdown 
  911       && allowSleep)
  912     {
  913         if ( !sleepIsSupported ) {
  914             setSleepSupported( kPCICantSleep );
  915             kprintf("Sleep prevented by kIOPMPreventSystemSleep flag\n");
  916         }
  917         patriarch->sleepSystem();
  918         return kIOReturnSuccess;
  919     } else {
  920         // Unable to sleep because system is in the process of booting or shutting down,
  921         // or sleep has otherwise been disallowed.
  922         return kIOReturnError;
  923     }
  924 }
  925 
  926 
  927 // **********************************************************************************
  928 // shutdownSystem
  929 //
  930 // **********************************************************************************
  931 IOReturn IOPMrootDomain::shutdownSystem ( void )
  932 {
  933     //patriarch->shutDownSystem();
  934     return kIOReturnUnsupported;
  935 }
  936 
  937 
  938 // **********************************************************************************
  939 // restartSystem
  940 //
  941 // **********************************************************************************
  942 IOReturn IOPMrootDomain::restartSystem ( void )
  943 {
  944     //patriarch->restartSystem();
  945     return kIOReturnUnsupported;
  946 }
  947 
  948 
  949 // **********************************************************************************
  950 // powerChangeDone
  951 //
  952 // This overrides powerChangeDone in IOService.
  953 //
  954 // Finder sleep and idle sleep move us from the ON state to the SLEEP_STATE.
  955 // In this case:
  956 // If we just finished going to the SLEEP_STATE, and the platform is capable of true sleep,
  957 // sleep the kernel.  Otherwise switch up to the DOZE_STATE which will keep almost
  958 // everything as off as it can get.
  959 //
  960 // **********************************************************************************
  961 void IOPMrootDomain::powerChangeDone ( unsigned long previousState )
  962 {
  963     OSNumber *          propertyPtr;
  964     unsigned short      theProperty;
  965     AbsoluteTime    deadline;
  966 
  967     DEBUG_LOG("PowerChangeDone: %ld -> %ld\n", previousState, getPowerState());
  968 
  969     switch ( getPowerState() ) {
  970         case SLEEP_STATE:
  971                         if ( previousState != ON_STATE )
  972                                 break;
  973 
  974             if ( canSleep && sleepIsSupported ) 
  975             {
  976                 // re-enable this timer for next sleep
  977                 idleSleepPending = false;                       
  978 
  979                 uint32_t secs, microsecs;
  980                 clock_get_calendar_microtime(&secs, &microsecs);
  981                 logtime(secs);
  982                 gIOLastSleepTime.tv_sec  = secs;
  983                 gIOLastSleepTime.tv_usec = microsecs;
  984 
  985 #if     HIBERNATION
  986                 IOLog("System %sSleep\n", gIOHibernateState ? "Safe" : "");
  987 
  988                 IOHibernateSystemHasSlept();
  989 #else
  990                 IOLog("System Sleep\n");
  991 #endif
  992 
  993                 getPlatform()->sleepKernel();
  994 
  995                 // The CPU(s) are off at this point. When they're awakened by CPU interrupt,
  996                 // code will resume execution here.
  997 
  998                 // Now we're waking...
  999 #if     HIBERNATION
 1000                 IOHibernateSystemWake();
 1001 #endif
 1002 
 1003                 // stay awake for at least 30 seconds
 1004                 clock_interval_to_deadline(30, kSecondScale, &deadline);        
 1005                 thread_call_enter_delayed(extraSleepTimer, deadline);
 1006                 // this gets turned off when we sleep again
 1007                 idleSleepPending = true;
 1008                 
 1009                 // Ignore closed clamshell during wakeup and for a few seconds
 1010                 // after wakeup is complete
 1011                 ignoringClamshellDuringWakeup = true;
 1012 
 1013                 // sleep transition complete
 1014                 gSleepOrShutdownPending = 0;
 1015 
 1016                 // trip the reset of the calendar clock
 1017                 clock_wakeup_calendar();
 1018 
 1019                 // get us some power
 1020                 patriarch->wakeSystem();
 1021                 
 1022                 // early stage wake notification
 1023                 tellClients(kIOMessageSystemWillPowerOn);
 1024 
 1025                 // tell the tree we're waking
 1026 #if     HIBERNATION
 1027                 IOLog("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
 1028 #endif
 1029                 systemWake();
 1030                 
 1031                 // Allow drivers to request extra processing time before clamshell
 1032                 // sleep if kIOREMSleepEnabledKey is present.
 1033                 // Ignore clamshell events for at least 5 seconds 
 1034                 if(getProperty(kIOREMSleepEnabledKey)) {
 1035                     // clamshellWakeupIgnore callout clears ignoreClamshellDuringWakeup bit   
 1036                     clock_interval_to_deadline(5, kSecondScale, &deadline);
 1037                     if(clamshellWakeupIgnore)  {
 1038                         thread_call_enter_delayed(clamshellWakeupIgnore, deadline);
 1039                     }
 1040                 } else ignoringClamshellDuringWakeup = false;
 1041                 
 1042                 // Find out what woke us
 1043                 propertyPtr = OSDynamicCast(OSNumber,getProperty("WakeEvent"));
 1044                 if ( propertyPtr ) {
 1045                     theProperty = propertyPtr->unsigned16BitValue();
 1046                     IOLog("Wake event %04x\n",theProperty);
 1047                     if ( (theProperty & 0x0008) ||      //lid
 1048                         (theProperty & 0x0800) ||       // front panel button
 1049                         (theProperty & 0x0020) ||       // external keyboard
 1050                         (theProperty & 0x0001) ) {      // internal keyboard
 1051                             // We've identified the wakeup event as UI driven
 1052                             reportUserInput();
 1053                     }
 1054                 } else {
 1055                     // Since we can't identify the wakeup event, treat it as UI activity
 1056                     reportUserInput();
 1057                 }
 1058                             
 1059                 // Wake for thirty seconds
 1060                 changePowerStateToPriv(ON_STATE);
 1061             } else {
 1062                 // allow us to step up a power state
 1063                 patriarch->sleepToDoze();
 1064 
 1065                 // ignore children's request for higher power during doze.
 1066                 powerOverrideOnPriv();
 1067                 changePowerStateToPriv(DOZE_STATE);
 1068             }
 1069             break;
 1070 
 1071         case DOZE_STATE:
 1072             if ( previousState != DOZE_STATE ) 
 1073             {
 1074                 IOLog("System Doze\n");
 1075             }
 1076             // re-enable this timer for next sleep
 1077             idleSleepPending = false;
 1078             gSleepOrShutdownPending = 0;
 1079             break;
 1080             
 1081         case RESTART_STATE:
 1082             IOLog("System Restart\n");
 1083             PEHaltRestart(kPERestartCPU);
 1084             break;
 1085             
 1086         case OFF_STATE:
 1087             IOLog("System Halt\n");
 1088             PEHaltRestart(kPEHaltCPU);
 1089             break;
 1090     }
 1091 }
 1092 
 1093 
 1094 // **********************************************************************************
 1095 // wakeFromDoze
 1096 //
 1097 // The Display Wrangler calls here when it switches to its highest state.  If the 
 1098 // system is currently dozing, allow it to wake by making sure the parent is
 1099 // providing power.
 1100 // **********************************************************************************
 1101 void IOPMrootDomain::wakeFromDoze( void )
 1102 {
 1103     if ( getPowerState() == DOZE_STATE ) 
 1104     {
 1105         // Reset sleep support till next sleep attempt.
 1106         // A machine's support of sleep vs. doze can change over the course of
 1107         // a running system, so we recalculate it before every sleep.
 1108         setSleepSupported(0);
 1109 
 1110         changePowerStateToPriv(ON_STATE);
 1111         powerOverrideOffPriv();
 1112 
 1113         // early wake notification
 1114         tellClients(kIOMessageSystemWillPowerOn);
 1115 
 1116         // allow us to wake if children so desire
 1117         patriarch->wakeSystem();
 1118     }
 1119 }
 1120 
 1121 
 1122 // *****************************************************************************
 1123 // publishFeature
 1124 //
 1125 // Adds a new feature to the supported features dictionary
 1126 // 
 1127 // 
 1128 // *****************************************************************************
 1129 void IOPMrootDomain::publishFeature( const char * feature )
 1130 {
 1131     publishFeature(feature, kIOPMSupportedOnAC 
 1132                                   | kIOPMSupportedOnBatt 
 1133                                   | kIOPMSupportedOnUPS,
 1134                             NULL);
 1135     return;
 1136 }
 1137 
 1138 
 1139 // *****************************************************************************
 1140 // publishFeature (with supported power source specified)
 1141 //
 1142 // Adds a new feature to the supported features dictionary
 1143 // 
 1144 // 
 1145 // *****************************************************************************
 1146 void IOPMrootDomain::publishFeature( 
 1147     const char *feature, 
 1148     uint32_t supportedWhere,
 1149     uint32_t *uniqueFeatureID)
 1150 {
 1151     static uint16_t     next_feature_id = 500;
 1152 
 1153     OSNumber            *new_feature_data = NULL;
 1154     OSNumber            *existing_feature = NULL;
 1155     OSArray             *existing_feature_arr = NULL;
 1156     OSObject            *osObj = NULL;
 1157     uint32_t            feature_value = 0;
 1158 
 1159     supportedWhere &= kRD_AllPowerSources; // mask off any craziness!
 1160 
 1161 //    kprintf("IOPMrootDomain::publishFeature [\"%s\":%0x01x]\n", feature, supportedWhere);
 1162 
 1163     if(!supportedWhere) {
 1164         // Feature isn't supported anywhere!
 1165         return;
 1166     }
 1167     
 1168     if(next_feature_id > 5000) {
 1169         // Far, far too many features!
 1170         return;
 1171     }
 1172 
 1173     if(featuresDictLock) IOLockLock(featuresDictLock);
 1174 
 1175     OSDictionary *features =
 1176         (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
 1177     
 1178     // Create new features dict if necessary
 1179     if ( features && OSDynamicCast(OSDictionary, features)) {
 1180         features = OSDictionary::withDictionary(features);
 1181     } else {
 1182         features = OSDictionary::withCapacity(1);
 1183     }
 1184     
 1185     // Create OSNumber to track new feature
 1186     
 1187     next_feature_id += 1;
 1188     if( uniqueFeatureID ) {
 1189         // We don't really mind if the calling kext didn't give us a place
 1190         // to stash their unique id. Many kexts don't plan to unload, and thus
 1191         // have no need to remove themselves later.
 1192         *uniqueFeatureID = next_feature_id;
 1193     }
 1194     
 1195     feature_value = supportedWhere + (next_feature_id << 16);
 1196     new_feature_data = OSNumber::withNumber(
 1197                                 (unsigned long long)feature_value, 32);
 1198 
 1199     // Does features object already exist?
 1200     if( (osObj = features->getObject(feature)) )
 1201     {
 1202         if(( existing_feature = OSDynamicCast(OSNumber, osObj) ))
 1203         {
 1204             // We need to create an OSArray to hold the now 2 elements.
 1205             existing_feature_arr = OSArray::withObjects(
 1206                             (const OSObject **)&existing_feature, 1, 2);
 1207             existing_feature_arr->setObject(new_feature_data);
 1208             features->setObject(feature, existing_feature_arr);
 1209         } else if(( existing_feature_arr = OSDynamicCast(OSArray, osObj) ))
 1210         {
 1211             // Add object to existing array
 1212             existing_feature_arr->setObject(new_feature_data);        
 1213         }
 1214     } else {
 1215         // The easy case: no previously existing features listed. We simply
 1216         // set the OSNumber at key 'feature' and we're on our way.
 1217         features->setObject(feature, new_feature_data);        
 1218     }
 1219     
 1220     new_feature_data->release();
 1221 
 1222     setProperty(kRootDomainSupportedFeatures, features);
 1223 
 1224     features->release();
 1225 
 1226     if(featuresDictLock) IOLockUnlock(featuresDictLock);    
 1227 
 1228     // Notify EnergySaver and all those in user space so they might
 1229     // re-populate their feature specific UI    
 1230     if(pmPowerStateQueue) {
 1231         pmPowerStateQueue->featureChangeOccurred( 
 1232                             kIOPMMessageFeatureChange, this);
 1233     }
 1234 }
 1235 
 1236 // *****************************************************************************
 1237 // removePublishedFeature
 1238 //
 1239 // Removes previously published feature
 1240 // 
 1241 // 
 1242 // *****************************************************************************
 1243 IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
 1244 {
 1245     IOReturn                ret = kIOReturnError;
 1246     uint32_t                feature_value = 0;
 1247     uint16_t                feature_id = 0;
 1248     bool                    madeAChange = false;
 1249     
 1250     OSSymbol                *dictKey = NULL;
 1251     OSCollectionIterator    *dictIterator = NULL;
 1252     OSArray                 *arrayMember  = NULL;
 1253     OSNumber                *numberMember = NULL;
 1254     OSObject                *osObj        = NULL;
 1255     OSNumber                *osNum        = NULL;
 1256 
 1257     if(featuresDictLock) IOLockLock(featuresDictLock);
 1258 
 1259     OSDictionary *features =
 1260         (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
 1261     
 1262     if ( features && OSDynamicCast(OSDictionary, features) )
 1263     {
 1264         // Any modifications to the dictionary are made to the copy to prevent
 1265         // races & crashes with userland clients. Dictionary updated
 1266         // automically later.
 1267         features = OSDictionary::withDictionary(features);
 1268     } else {
 1269         features = NULL;
 1270         ret = kIOReturnNotFound;
 1271         goto exit;
 1272     }
 1273     
 1274     // We iterate 'features' dictionary looking for an entry tagged
 1275     // with 'removeFeatureID'. If found, we remove it from our tracking
 1276     // structures and notify the OS via a general interest message.
 1277     
 1278     dictIterator = OSCollectionIterator::withCollection(features);
 1279     if(!dictIterator) {
 1280         goto exit;
 1281     }
 1282     
 1283     while( (dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject())) )
 1284     {
 1285         osObj = features->getObject(dictKey);
 1286         
 1287         // Each Feature is either tracked by an OSNumber
 1288         if( osObj && (numberMember = OSDynamicCast(OSNumber, osObj)) )
 1289         {
 1290             feature_value = numberMember->unsigned32BitValue();
 1291             feature_id = (uint16_t)(feature_value >> 16);
 1292 
 1293             if( feature_id == (uint16_t)removeFeatureID )
 1294             {
 1295                 // Remove this node
 1296                 features->removeObject(dictKey);
 1297                 madeAChange = true;
 1298                 break;
 1299             }
 1300         
 1301         // Or tracked by an OSArray of OSNumbers
 1302         } else if( osObj && (arrayMember = OSDynamicCast(OSArray, osObj)) )
 1303         {
 1304             unsigned int arrayCount = arrayMember->getCount();
 1305             
 1306             for(unsigned int i=0; i<arrayCount; i++)
 1307             {
 1308                 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
 1309                 if(!osNum) {
 1310                     continue;
 1311                 }
 1312                 
 1313                 feature_value = osNum->unsigned32BitValue();
 1314                 feature_id = (uint16_t)(feature_value >> 16);
 1315 
 1316                 if( feature_id == (uint16_t)removeFeatureID )
 1317                 {
 1318                     // Remove this node
 1319                     if( 1 == arrayCount ) {
 1320                         // If the array only contains one element, remove
 1321                         // the whole thing.
 1322                         features->removeObject(dictKey);
 1323                     } else {
 1324                         // Otherwise just remove the element in question.
 1325                         arrayMember->removeObject(i);                    
 1326                     }
 1327 
 1328                     madeAChange = true;
 1329                     break;
 1330                 }
 1331             }
 1332         }    
 1333     }
 1334     
 1335     
 1336     dictIterator->release();
 1337     
 1338     if( madeAChange )
 1339     {
 1340         ret = kIOReturnSuccess;    
 1341 
 1342         setProperty(kRootDomainSupportedFeatures, features);
 1343     
 1344         // Notify EnergySaver and all those in user space so they might
 1345         // re-populate their feature specific UI    
 1346         if(pmPowerStateQueue) {
 1347             pmPowerStateQueue->featureChangeOccurred( 
 1348                                 kIOPMMessageFeatureChange, this);
 1349         }
 1350     } else {
 1351         ret = kIOReturnNotFound;
 1352     }
 1353     
 1354 exit:
 1355     if(features)    features->release();
 1356     if(featuresDictLock) IOLockUnlock(featuresDictLock);    
 1357     return ret;
 1358 }
 1359 
 1360 
 1361 // **********************************************************************************
 1362 // unIdleDevice
 1363 //
 1364 // Enqueues unidle event to be performed later in a serialized context.
 1365 // 
 1366 // **********************************************************************************
 1367 void IOPMrootDomain::unIdleDevice( IOService *theDevice, unsigned long theState )
 1368 {
 1369     if(pmPowerStateQueue)
 1370         pmPowerStateQueue->unIdleOccurred(theDevice, theState);
 1371 }
 1372 
 1373 // **********************************************************************************
 1374 // announcePowerSourceChange
 1375 //
 1376 // Notifies "interested parties" that the batteries have changed state
 1377 // 
 1378 // **********************************************************************************
 1379 void IOPMrootDomain::announcePowerSourceChange( void )
 1380 {
 1381     IORegistryEntry *_batteryRegEntry = (IORegistryEntry *) getProperty("BatteryEntry");
 1382 
 1383     // (if possible) re-publish power source state under IOPMrootDomain;
 1384     // only do so if the battery controller publishes an IOResource 
 1385     // defining battery location. Called from ApplePMU battery driver.
 1386 
 1387     if(_batteryRegEntry)
 1388     {
 1389         OSArray             *batt_info;
 1390         batt_info = (OSArray *) _batteryRegEntry->getProperty(kIOBatteryInfoKey);
 1391         if(batt_info)
 1392             setProperty(kIOBatteryInfoKey, batt_info);
 1393     }
 1394 
 1395 }
 1396 
 1397 
 1398 // *****************************************************************************
 1399 // setPMSetting (private)
 1400 //
 1401 // Internal helper to relay PM settings changes from user space to individual
 1402 // drivers. Should be called only by IOPMrootDomain::setProperties.
 1403 // 
 1404 // *****************************************************************************
 1405 IOReturn     IOPMrootDomain::setPMSetting(
 1406     const OSSymbol *type, 
 1407     OSObject *obj)
 1408 {
 1409     OSArray             *arr = NULL;
 1410     PMSettingObject     *p_obj = NULL;
 1411     int                 count;
 1412     int                 i;
 1413 
 1414     if(NULL == type) return kIOReturnBadArgument;
 1415 
 1416     IORecursiveLockLock(settingsCtrlLock);
 1417     
 1418     fPMSettingsDict->setObject(type, obj);
 1419 
 1420     arr = (OSArray *)settingsCallbacks->getObject(type);
 1421     if(NULL == arr) goto exit;
 1422     count = arr->getCount();
 1423     for(i=0; i<count; i++) {
 1424         p_obj = (PMSettingObject *)OSDynamicCast(PMSettingObject, arr->getObject(i));
 1425         if(p_obj) p_obj->setPMSetting(type, obj);
 1426     }
 1427 
 1428 exit:
 1429     IORecursiveLockUnlock(settingsCtrlLock);
 1430     return kIOReturnSuccess;
 1431 }
 1432 
 1433 // *****************************************************************************
 1434 // copyPMSetting (public)
 1435 //
 1436 // Allows kexts to safely read setting values, without being subscribed to
 1437 // notifications.
 1438 // 
 1439 // *****************************************************************************
 1440 OSObject * IOPMrootDomain::copyPMSetting(
 1441     OSSymbol *whichSetting)
 1442 {
 1443     OSObject *obj = NULL;
 1444 
 1445     if(!whichSetting) return NULL;
 1446 
 1447     IORecursiveLockLock(settingsCtrlLock);
 1448     obj = fPMSettingsDict->getObject(whichSetting);
 1449     if(obj) {
 1450         obj->retain();
 1451     }
 1452     IORecursiveLockUnlock(settingsCtrlLock);
 1453     
 1454     return obj;
 1455 }
 1456 
 1457 // *****************************************************************************
 1458 // registerPMSettingController (public)
 1459 //
 1460 // direct wrapper to registerPMSettingController with uint32_t power source arg
 1461 // *****************************************************************************
 1462 IOReturn IOPMrootDomain::registerPMSettingController(
 1463     const OSSymbol *                settings[],
 1464     IOPMSettingControllerCallback   func,
 1465     OSObject                        *target,
 1466     uintptr_t                       refcon,
 1467     OSObject                        **handle)
 1468 {
 1469     return registerPMSettingController( 
 1470             settings,
 1471             (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS),
 1472             func, target, refcon, handle);
 1473 }
 1474 
 1475 // *****************************************************************************
 1476 // registerPMSettingController (public)
 1477 //
 1478 // Kexts may register for notifications when a particular setting is changed.
 1479 // A list of settings is available in IOPM.h.
 1480 // Arguments:
 1481 //  * settings - An OSArray containing OSSymbols. Caller should populate this
 1482 //          array with a list of settings caller wants notifications from.
 1483 //  * func - A C function callback of the type IOPMSettingControllerCallback
 1484 //  * target - caller may provide an OSObject *, which PM will pass as an 
 1485 //          target to calls to "func"
 1486 //  * refcon - caller may provide an void *, which PM will pass as an 
 1487 //          argument to calls to "func"
 1488 //  * handle - This is a return argument. We will populate this pointer upon
 1489 //          call success. Hold onto this and pass this argument to
 1490 //          IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
 1491 // Returns:
 1492 //      kIOReturnSuccess on success
 1493 // *****************************************************************************
 1494 IOReturn IOPMrootDomain::registerPMSettingController(
 1495     const OSSymbol *                settings[],
 1496     uint32_t                        supportedPowerSources,
 1497     IOPMSettingControllerCallback   func,
 1498     OSObject                        *target,
 1499     uintptr_t                       refcon,
 1500     OSObject                        **handle)
 1501 {
 1502     PMSettingObject     *pmso = NULL;
 1503     OSArray             *list = NULL;
 1504     IOReturn            ret = kIOReturnSuccess;
 1505     int                 i;
 1506 
 1507     if( NULL == settings ||
 1508         NULL == func ||
 1509         NULL == handle)
 1510     {
 1511         return kIOReturnBadArgument;
 1512     }
 1513 
 1514     pmso = PMSettingObject::pmSettingObject(
 1515                 (IOPMrootDomain *)this, func, target, 
 1516                 refcon, supportedPowerSources, settings);
 1517 
 1518     if(!pmso) {
 1519         ret = kIOReturnInternalError;
 1520         goto bail_no_unlock;
 1521     }
 1522 
 1523     IORecursiveLockLock(settingsCtrlLock);
 1524     for(i=0; settings[i]; i++) 
 1525     {
 1526         list = (OSArray *)settingsCallbacks->getObject(settings[i]);
 1527         if(!list) {
 1528             // New array of callbacks for this setting
 1529             list = OSArray::withCapacity(1);
 1530             settingsCallbacks->setObject(settings[i], list);
 1531             list->release();
 1532         }
 1533 
 1534         // Add caller to the callback list
 1535         list->setObject(pmso);
 1536     }
 1537 
 1538     IORecursiveLockUnlock(settingsCtrlLock);
 1539     
 1540     ret = kIOReturnSuccess;
 1541 
 1542     // Track this instance by its OSData ptr from now on  
 1543     *handle = pmso;
 1544 
 1545 bail_no_unlock:
 1546     if(kIOReturnSuccess != ret) 
 1547     {
 1548         // Error return case
 1549         if(pmso) pmso->release();
 1550         if(handle) *handle = NULL;
 1551     }
 1552     return ret;
 1553 }
 1554 
 1555 
 1556 //******************************************************************************
 1557 // sleepOnClamshellClosed
 1558 //
 1559 // contains the logic to determine if the system should sleep when the clamshell
 1560 // is closed.
 1561 //******************************************************************************
 1562 
 1563 bool IOPMrootDomain::shouldSleepOnClamshellClosed ( void )
 1564 {
 1565     return ( !ignoringClamshell 
 1566           && !ignoringClamshellDuringWakeup 
 1567           && !(desktopMode && acAdaptorConnect) );
 1568 }
 1569 
 1570 void IOPMrootDomain::sendClientClamshellNotification ( void )
 1571 {
 1572     /* Only broadcast clamshell alert if clamshell exists. */
 1573     if(!clamshellExists)
 1574         return;
 1575         
 1576     setProperty(kAppleClamshellStateKey, 
 1577                     clamshellIsClosed ? kOSBooleanTrue : kOSBooleanFalse);
 1578 
 1579     setProperty(kAppleClamshellCausesSleepKey, 
 1580        shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
 1581 
 1582 
 1583     /* Argument to message is a bitfiel of 
 1584      *      ( kClamshellStateBit | kClamshellSleepBit )
 1585      */
 1586     messageClients(kIOPMMessageClamshellStateChange,
 1587         (void *) ( (clamshellIsClosed ? kClamshellStateBit : 0)
 1588              | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)) );
 1589 }
 1590 
 1591 //******************************************************************************
 1592 // informCPUStateChange
 1593 //
 1594 // Call into PM CPU code so that CPU power savings may dynamically adjust for
 1595 // running on battery, with the lid closed, etc.
 1596 //
 1597 // informCPUStateChange is a no-op on non x86 systems
 1598 // only x86 has explicit support in the IntelCPUPowerManagement kext
 1599 //******************************************************************************
 1600 
 1601 void IOPMrootDomain::informCPUStateChange(
 1602     uint32_t type, 
 1603     uint32_t value )
 1604 {
 1605 #ifdef __i386__
 1606 
 1607     pmioctlVariableInfo_t varInfoStruct;                            
 1608     int                 pmCPUret = 0;
 1609     const char          *varNameStr = NULL;
 1610     int32_t             *varIndex   = NULL;
 1611 
 1612     if (kInformAC == type) {
 1613         varNameStr = kIOPMRootDomainBatPowerCString;
 1614         varIndex = &idxPMCPULimitedPower;
 1615     } else if (kInformLid == type) {
 1616         varNameStr = kIOPMRootDomainLidCloseCString;
 1617         varIndex = &idxPMCPUClamshell;
 1618     } else {
 1619         return;
 1620     }
 1621     
 1622     // Set the new value!
 1623     // pmCPUControl will assign us a new ID if one doesn't exist yet
 1624     bzero(&varInfoStruct, sizeof(pmioctlVariableInfo_t));
 1625     varInfoStruct.varID         = *varIndex;
 1626     varInfoStruct.varType       = vBool;
 1627     varInfoStruct.varInitValue  = value;
 1628     varInfoStruct.varCurValue   = value;
 1629     strncpy( (char *)varInfoStruct.varName,
 1630              (const char *)varNameStr,
 1631              strlen(varNameStr) + 1 );                 
 1632     
 1633     // Set!
 1634     pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct );
 1635 
 1636     // pmCPU only assigns numerical id's when a new varName is specified
 1637     if ((0 == pmCPUret)
 1638         && (*varIndex == kCPUUnknownIndex))
 1639     {
 1640         // pmCPUControl has assigned us a new variable ID. 
 1641         // Let's re-read the structure we just SET to learn that ID.
 1642         pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct );
 1643 
 1644         if (0 == pmCPUret) 
 1645         {        
 1646             // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
 1647             *varIndex = varInfoStruct.varID;
 1648         }
 1649     } 
 1650     
 1651     return;
 1652     
 1653 #endif __i386__
 1654 }
 1655 
 1656 
 1657 //******************************************************************************
 1658 // receivePowerNotification
 1659 //
 1660 // The power controller is notifying us of a hardware-related power management
 1661 // event that we must handle. This is a result of an 'environment' interrupt from
 1662 // the power mgt micro.
 1663 //******************************************************************************
 1664 
 1665 IOReturn IOPMrootDomain::receivePowerNotification (UInt32 msg)
 1666 {
 1667     bool        eval_clamshell = false;
 1668 
 1669     /*
 1670      * Local (IOPMrootDomain only) eval clamshell command
 1671      */
 1672     if (msg & kLocalEvalClamshellCommand)
 1673     {
 1674         eval_clamshell = true;
 1675     }
 1676 
 1677     /*
 1678      * Overtemp
 1679      */
 1680     if (msg & kIOPMOverTemp) 
 1681     {
 1682         IOLog("PowerManagement emergency overtemp signal. Going to sleep!");
 1683         
 1684         privateSleepSystem (kIOPMThermalEmergencySleepKey);
 1685     }
 1686 
 1687     /*
 1688      * PMU Processor Speed Change
 1689      */
 1690     if (msg & kIOPMProcessorSpeedChange) 
 1691     {
 1692         IOService *pmu = waitForService(serviceMatching("ApplePMU"));
 1693         pmu->callPlatformFunction("prepareForSleep", false, 0, 0, 0, 0);
 1694         getPlatform()->sleepKernel();
 1695         pmu->callPlatformFunction("recoverFromSleep", false, 0, 0, 0, 0);
 1696     }
 1697 
 1698     /*
 1699      * Sleep Now!
 1700      */
 1701     if (msg & kIOPMSleepNow) 
 1702     {
 1703         privateSleepSystem (kIOPMSoftwareSleepKey);
 1704     }
 1705     
 1706     /*
 1707      * Power Emergency
 1708      */
 1709     if (msg & kIOPMPowerEmergency) 
 1710     {
 1711         privateSleepSystem (kIOPMLowPowerSleepKey);
 1712     }
 1713 
 1714     
 1715     /*
 1716      * Clamshell OPEN
 1717      */
 1718     if (msg & kIOPMClamshellOpened) 
 1719     {
 1720         // Received clamshel open message from clamshell controlling driver
 1721         // Update our internal state and tell general interest clients
 1722         clamshellIsClosed = false;
 1723         clamshellExists = true;
 1724                 
 1725         // Tell PMCPU
 1726         informCPUStateChange(kInformLid, 0);
 1727 
 1728         // Tell general interest clients        
 1729         sendClientClamshellNotification();
 1730     } 
 1731 
 1732     /* 
 1733      * Clamshell CLOSED
 1734      * Send the clamshell interest notification since the lid is closing. 
 1735      */
 1736     if (msg & kIOPMClamshellClosed)
 1737     {
 1738         // Received clamshel open message from clamshell controlling driver
 1739         // Update our internal state and tell general interest clients
 1740         clamshellIsClosed = true;
 1741         clamshellExists = true;
 1742 
 1743         // Tell PMCPU
 1744         informCPUStateChange(kInformLid, 1);
 1745 
 1746         // Tell general interest clients
 1747         sendClientClamshellNotification();
 1748         
 1749         // And set eval_clamshell = so we can attempt 
 1750         eval_clamshell = true;
 1751     }
 1752 
 1753     /*
 1754      * Set Desktop mode (sent from graphics)
 1755      *
 1756      *  -> reevaluate lid state
 1757      */
 1758     if (msg & kIOPMSetDesktopMode) 
 1759     {
 1760         desktopMode = (0 != (msg & kIOPMSetValue));
 1761         msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
 1762 
 1763         sendClientClamshellNotification();
 1764 
 1765         // Re-evaluate the lid state
 1766         if( clamshellIsClosed )
 1767         {
 1768             eval_clamshell = true;
 1769         }
 1770     }
 1771     
 1772     /*
 1773      * AC Adaptor connected
 1774      *
 1775      *  -> reevaluate lid state
 1776      */
 1777     if (msg & kIOPMSetACAdaptorConnected) 
 1778     {
 1779         acAdaptorConnect = (0 != (msg & kIOPMSetValue));
 1780         msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
 1781 
 1782         // Tell PMCPU
 1783         informCPUStateChange(kInformAC, !acAdaptorConnect);
 1784 
 1785         sendClientClamshellNotification();
 1786 
 1787         // Re-evaluate the lid state
 1788         if( clamshellIsClosed )
 1789         {
 1790             eval_clamshell = true;
 1791         }
 1792 
 1793     }
 1794     
 1795     /*
 1796      * Enable Clamshell (external display disappear)
 1797      *
 1798      *  -> reevaluate lid state
 1799      */
 1800     if (msg & kIOPMEnableClamshell) 
 1801     {
 1802         // Re-evaluate the lid state
 1803         // System should sleep on external display disappearance
 1804         // in lid closed operation.
 1805         if( clamshellIsClosed && (true == ignoringClamshell) )        
 1806         {
 1807             eval_clamshell = true;
 1808         }
 1809 
 1810         ignoringClamshell = false;
 1811 
 1812         sendClientClamshellNotification();
 1813     }
 1814     
 1815     /*
 1816      * Disable Clamshell (external display appeared)
 1817      * We don't bother re-evaluating clamshell state. If the system is awake,
 1818      * the lid is probably open. 
 1819      */
 1820     if (msg & kIOPMDisableClamshell) 
 1821     {
 1822         ignoringClamshell = true;
 1823 
 1824         sendClientClamshellNotification();
 1825     }
 1826 
 1827     /*
 1828      * Evaluate clamshell and SLEEP if appropiate
 1829      */
 1830     if ( eval_clamshell && shouldSleepOnClamshellClosed() ) 
 1831     {
 1832 
 1833 
 1834         // SLEEP!
 1835         privateSleepSystem (kIOPMClamshellSleepKey);
 1836     }
 1837 
 1838     /*
 1839      * Power Button
 1840      */
 1841     if (msg & kIOPMPowerButton) 
 1842     {
 1843         // toggle state of sleep/wake
 1844         // are we dozing?
 1845         if ( getPowerState() == DOZE_STATE ) 
 1846         {
 1847             // yes, tell the tree we're waking 
 1848             systemWake();
 1849             // wake the Display Wrangler
 1850             reportUserInput();
 1851         }
 1852         else {
 1853             OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
 1854             // Check that power button sleep is enabled
 1855             if( pbs ) {
 1856                 if( kOSBooleanTrue != getProperty(pbs))
 1857                 privateSleepSystem (kIOPMPowerButtonSleepKey);
 1858             }
 1859         }
 1860     }
 1861 
 1862     /*
 1863      * Allow Sleep
 1864      *
 1865      */
 1866     if ( (msg & kIOPMAllowSleep) && !allowSleep ) 
 1867     {
 1868         allowSleep = true;
 1869         adjustPowerState();
 1870     }
 1871 
 1872     /*
 1873      * Prevent Sleep
 1874      *
 1875      */
 1876     if (msg & kIOPMPreventSleep) {
 1877         allowSleep = false;
 1878             // are we dozing?
 1879         if ( getPowerState() == DOZE_STATE ) {
 1880             // yes, tell the tree we're waking 
 1881             systemWake();
 1882             adjustPowerState();
 1883             // wake the Display Wrangler
 1884             reportUserInput();
 1885         } else {
 1886             adjustPowerState();
 1887             // make sure we have power to clamp
 1888             patriarch->wakeSystem();
 1889         }
 1890     }
 1891 
 1892    return 0;
 1893 }
 1894 
 1895 
 1896 //*********************************************************************************
 1897 // sleepSupported
 1898 //
 1899 //*********************************************************************************
 1900 
 1901 void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
 1902 {
 1903     if ( flags & kPCICantSleep ) 
 1904     {
 1905         canSleep = false;
 1906     } else {
 1907         canSleep = true;
 1908         platformSleepSupport = flags;
 1909     }
 1910 
 1911     setProperty(kIOSleepSupportedKey, canSleep);
 1912 
 1913 }
 1914 
 1915 //*********************************************************************************
 1916 // requestPowerDomainState
 1917 //
 1918 // The root domain intercepts this call to the superclass.
 1919 // Called on the PM work loop thread.
 1920 //
 1921 // If the clamp bit is not set in the desire, then the child doesn't need the power
 1922 // state it's requesting; it just wants it.  The root ignores desires but not needs.
 1923 // If the clamp bit is not set, the root takes it that the child can tolerate no
 1924 // power and interprets the request accordingly.  If all children can thus tolerate
 1925 // no power, we are on our way to idle sleep.
 1926 //*********************************************************************************
 1927 
 1928 IOReturn IOPMrootDomain::requestPowerDomainState (
 1929     IOPMPowerFlags      desiredState,
 1930     IOPowerConnection * whichChild,
 1931     unsigned long       specification )
 1932 {
 1933     OSIterator          *iter;
 1934     OSObject            *next;
 1935     IOPowerConnection   *connection;
 1936     unsigned long       powerRequestFlag = 0;
 1937     IOPMPowerFlags      editedDesire;
 1938 
 1939 #if DEBUG
 1940     IOService           *powerChild;
 1941     powerChild = (IOService *) whichChild->getChildEntry(gIOPowerPlane);
 1942 #endif
 1943 
 1944     DEBUG_LOG("RequestPowerDomainState: flags %lx, child %p [%s], spec %lx\n",
 1945         desiredState, powerChild, powerChild ? powerChild->getName() : "?",
 1946         specification);
 1947     
 1948     // Force the child's input power requirements to 0 unless the prevent
 1949     // idle-sleep flag is set. No input power flags map to our state 0.
 1950     // Our power clamp (deviceDesire) keeps the minimum power state at 2.
 1951 
 1952     if (desiredState & kIOPMPreventIdleSleep)
 1953         editedDesire = desiredState;
 1954     else
 1955         editedDesire = 0;
 1956 
 1957     // Recompute sleep supported flag (doze if not supported)
 1958     sleepIsSupported = true;
 1959 
 1960     iter = getChildIterator(gIOPowerPlane);
 1961     if ( iter ) 
 1962     {
 1963         while ( (next = iter->getNextObject()) ) 
 1964         {
 1965             if ( (connection = OSDynamicCast(IOPowerConnection, next)) ) 
 1966             {
 1967                 // Ignore child that are in the process of joining.
 1968                                 if (connection->getReadyFlag() == false)
 1969                                         continue;
 1970 
 1971                 // Is this connection attached to the child that called
 1972                 // requestPowerDomainState()?
 1973 
 1974                 if ( connection == whichChild ) 
 1975                 {
 1976                     // Yes, OR in the child's input power requirements.
 1977                     powerRequestFlag |= editedDesire;
 1978 
 1979                     if ( desiredState & kIOPMPreventSystemSleep )
 1980                         sleepIsSupported = false;
 1981                 }
 1982                 else
 1983                 {
 1984 #if DEBUG
 1985                     powerChild = (IOService *) connection->getChildEntry(gIOPowerPlane);
 1986 #endif
 1987                     DEBUG_LOG("  child %p, PState %ld, noIdle %d, noSleep %d, valid %d  %s\n",
 1988                         powerChild,
 1989                         connection->getDesiredDomainState(),
 1990                         connection->getPreventIdleSleepFlag(),
 1991                         connection->getPreventSystemSleepFlag(),
 1992                         connection->getReadyFlag(),
 1993                         powerChild ? powerChild->getName() : "?");
 1994 
 1995                     // No, OR in the child's desired power domain state.
 1996                     // Which is our power state desired by this child.
 1997                     powerRequestFlag |= connection->getDesiredDomainState();
 1998 
 1999                     if ( connection->getPreventSystemSleepFlag() )
 2000                         sleepIsSupported = false;
 2001                 }
 2002             }
 2003         }
 2004         iter->release();
 2005     }
 2006     
 2007     if ( !powerRequestFlag && !systemBooting ) 
 2008     {
 2009         if (!wrangler)
 2010         {
 2011             sleepASAP = false;
 2012             changePowerStateToPriv(ON_STATE);
 2013             if (idleSeconds)
 2014             {
 2015                 AbsoluteTime deadline;
 2016                 // stay awake for at least idleSeconds
 2017                 clock_interval_to_deadline(idleSeconds, kSecondScale, &deadline);       
 2018                 thread_call_enter_delayed(extraSleepTimer, deadline);
 2019                 // this gets turned off when we sleep again
 2020                 idleSleepPending = true;
 2021             }
 2022         }
 2023         else if (extraSleepDelay == 0)
 2024         {
 2025             sleepASAP = true;
 2026         }
 2027     }
 2028     
 2029     DEBUG_LOG("  sleepDelay %lx, mergedFlags %lx, sleepASAP %x, booting %x\n",
 2030         extraSleepDelay, powerRequestFlag, sleepASAP, systemBooting);
 2031 
 2032     // Drop our power clamp to SLEEP_STATE when all devices become idle.
 2033     // Needed when the system sleep and display sleep timeouts are the same.
 2034     // Otherwise, the extra sleep timer will also drop our power clamp.
 2035 
 2036     adjustPowerState();
 2037 
 2038     editedDesire |= (desiredState & kIOPMPreventSystemSleep);
 2039 
 2040     // If our power clamp has already dropped to SLEEP_STATE, and no child
 2041     // is keeping us at max power, then this will trigger idle sleep.
 2042 
 2043     return super::requestPowerDomainState(editedDesire, whichChild, specification);
 2044 }
 2045 
 2046 
 2047 //*********************************************************************************
 2048 // getSleepSupported
 2049 //
 2050 //*********************************************************************************
 2051 
 2052 IOOptionBits IOPMrootDomain::getSleepSupported( void )
 2053 {
 2054     return( platformSleepSupport );
 2055 }
 2056 
 2057 
 2058 //*********************************************************************************
 2059 // handlePlatformHaltRestart
 2060 //
 2061 //*********************************************************************************
 2062 
 2063 struct HaltRestartApplierContext {
 2064         IOPMrootDomain *        RootDomain;
 2065         unsigned long           PowerState;
 2066         IOPMPowerFlags          PowerFlags;
 2067         UInt32                          MessageType;
 2068         UInt32                          Counter;
 2069 };
 2070 
 2071 static void
 2072 platformHaltRestartApplier( OSObject * object, void * context )
 2073 {
 2074         IOPowerStateChangeNotification  notify;
 2075         HaltRestartApplierContext *             ctx;
 2076         AbsoluteTime                                    startTime;
 2077         UInt32                                                  deltaTime;
 2078 
 2079         ctx = (HaltRestartApplierContext *) context;
 2080         
 2081         memset(&notify, 0, sizeof(notify));
 2082     notify.powerRef    = (void *)ctx->Counter;
 2083     notify.returnValue = 0;
 2084     notify.stateNumber = ctx->PowerState;
 2085     notify.stateFlags  = ctx->PowerFlags;
 2086 
 2087         clock_get_uptime(&startTime);
 2088     ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)&notify );
 2089         deltaTime = computeDeltaTimeMS(&startTime);
 2090 
 2091         if ((deltaTime > kPMHaltTimeoutMS) || (gIOKitDebug & kIOLogDebugPower))
 2092         {
 2093                 _IOServiceInterestNotifier * notifier;
 2094                 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
 2095 
 2096                 // IOService children of IOPMrootDomain are not instrumented.
 2097                 // Only IORootParent currently falls under that group.
 2098 
 2099                 if (notifier)
 2100                 {
 2101                         HaltRestartLog("%s handler %p took %lu ms\n",
 2102                                 (ctx->MessageType == kIOMessageSystemWillPowerOff) ?
 2103                                         "PowerOff" : "Restart",
 2104                                 notifier->handler, deltaTime );
 2105                 }
 2106         }
 2107 
 2108         ctx->Counter++;
 2109 }
 2110 
 2111 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
 2112 {
 2113         HaltRestartApplierContext       ctx;
 2114         AbsoluteTime                            startTime;
 2115         UInt32                                          deltaTime;
 2116 
 2117         memset(&ctx, 0, sizeof(ctx));
 2118         ctx.RootDomain = this;
 2119 
 2120         clock_get_uptime(&startTime);
 2121         switch (pe_type)
 2122         {
 2123                 case kPEHaltCPU:
 2124                         ctx.PowerState  = OFF_STATE;
 2125                         ctx.MessageType = kIOMessageSystemWillPowerOff;
 2126                         break;
 2127                 
 2128                 case kPERestartCPU:
 2129                         ctx.PowerState  = RESTART_STATE;
 2130                         ctx.MessageType = kIOMessageSystemWillRestart;
 2131                         break;
 2132 
 2133                 default:
 2134                         return;
 2135         }
 2136 
 2137         // Notify legacy clients
 2138         applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &ctx);
 2139 
 2140         // Notify in power tree order
 2141         notifySystemShutdown(this, ctx.MessageType);
 2142 
 2143         deltaTime = computeDeltaTimeMS(&startTime);
 2144         HaltRestartLog("%s all drivers took %lu ms\n",
 2145                 (ctx.MessageType == kIOMessageSystemWillPowerOff) ?
 2146                         "PowerOff" : "Restart",
 2147                 deltaTime );
 2148 }
 2149 
 2150 
 2151 //*********************************************************************************
 2152 // tellChangeDown
 2153 //
 2154 // We override the superclass implementation so we can send a different message
 2155 // type to the client or application being notified.
 2156 //*********************************************************************************
 2157 
 2158 bool IOPMrootDomain::tellChangeDown ( unsigned long stateNum )
 2159 {
 2160     switch ( stateNum ) {
 2161         case DOZE_STATE:
 2162         case SLEEP_STATE:
 2163         
 2164             // Direct callout into OSMetaClass so it can disable kmod unloads
 2165             // during sleep/wake to prevent deadlocks.
 2166             OSMetaClassSystemSleepOrWake( kIOMessageSystemWillSleep );
 2167 
 2168             return super::tellClientsWithResponse(kIOMessageSystemWillSleep);
 2169     }
 2170     return super::tellChangeDown(stateNum);
 2171 }
 2172 
 2173 
 2174 //*********************************************************************************
 2175 // askChangeDown
 2176 //
 2177 // We override the superclass implementation so we can send a different message
 2178 // type to the client or application being notified.
 2179 //
 2180 // This must be idle sleep since we don't ask apps during any other power change.
 2181 //*********************************************************************************
 2182 
 2183 bool IOPMrootDomain::askChangeDown ( unsigned long )
 2184 {
 2185     return super::tellClientsWithResponse(kIOMessageCanSystemSleep);
 2186 }
 2187 
 2188 
 2189 //*********************************************************************************
 2190 // tellNoChangeDown
 2191 //
 2192 // Notify registered applications and kernel clients that we are not
 2193 // dropping power.
 2194 //
 2195 // We override the superclass implementation so we can send a different message
 2196 // type to the client or application being notified.
 2197 //
 2198 // This must be a vetoed idle sleep, since no other power change can be vetoed.
 2199 //*********************************************************************************
 2200 
 2201 void IOPMrootDomain::tellNoChangeDown ( unsigned long )
 2202 {
 2203     if (idleSeconds && !wrangler)
 2204     {
 2205         AbsoluteTime deadline;
 2206         sleepASAP = false;
 2207         // stay awake for at least idleSeconds
 2208         clock_interval_to_deadline(idleSeconds, kSecondScale, &deadline);       
 2209         thread_call_enter_delayed(extraSleepTimer, deadline);
 2210         // this gets turned off when we sleep again
 2211         idleSleepPending = true;
 2212     }
 2213     return tellClients(kIOMessageSystemWillNotSleep);
 2214 }
 2215 
 2216 
 2217 //*********************************************************************************
 2218 // tellChangeUp
 2219 //
 2220 // Notify registered applications and kernel clients that we are raising power.
 2221 //
 2222 // We override the superclass implementation so we can send a different message
 2223 // type to the client or application being notified.
 2224 //*********************************************************************************
 2225 
 2226 void IOPMrootDomain::tellChangeUp ( unsigned long stateNum)
 2227 {
 2228     if ( stateNum == ON_STATE ) 
 2229     {
 2230 #if     HIBERNATION
 2231         // Direct callout into OSMetaClass so it can disable kmod unloads
 2232         // during sleep/wake to prevent deadlocks.
 2233         OSMetaClassSystemSleepOrWake( kIOMessageSystemHasPoweredOn );
 2234 
 2235         IOHibernateSystemPostWake();
 2236 #endif
 2237         return tellClients(kIOMessageSystemHasPoweredOn);
 2238     }
 2239 }
 2240 
 2241 //*********************************************************************************
 2242 // reportUserInput
 2243 //
 2244 //*********************************************************************************
 2245 
 2246 void IOPMrootDomain::reportUserInput ( void )
 2247 {
 2248 #if !NO_KERNEL_HID
 2249     OSIterator * iter;
 2250 
 2251     if(!wrangler) 
 2252     {
 2253         iter = getMatchingServices(serviceMatching("IODisplayWrangler"));
 2254         if(iter) 
 2255         {
 2256             wrangler = (IOService *) iter->getNextObject();
 2257             iter->release();
 2258         }
 2259     }
 2260 
 2261     if(wrangler)
 2262         wrangler->activityTickle(0,0);
 2263 #endif
 2264 }
 2265 
 2266 //*********************************************************************************
 2267 // setQuickSpinDownTimeout
 2268 //
 2269 //*********************************************************************************
 2270 
 2271 void IOPMrootDomain::setQuickSpinDownTimeout ( void )
 2272 {
 2273     super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)1);
 2274 }
 2275 
 2276 //*********************************************************************************
 2277 // restoreUserSpinDownTimeout
 2278 //
 2279 //*********************************************************************************
 2280 
 2281 void IOPMrootDomain::restoreUserSpinDownTimeout ( void )
 2282 {
 2283     super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)user_spindown);
 2284 }
 2285 
 2286 //*********************************************************************************
 2287 // changePowerStateTo & changePowerStateToPriv
 2288 //
 2289 // Override of these methods for logging purposes.
 2290 //*********************************************************************************
 2291 
 2292 IOReturn IOPMrootDomain::changePowerStateTo ( unsigned long ordinal )
 2293 {
 2294     return super::changePowerStateTo(ordinal);
 2295 }
 2296 
 2297 IOReturn IOPMrootDomain::changePowerStateToPriv ( unsigned long ordinal )
 2298 {
 2299     IOReturn    ret;
 2300 
 2301     DEBUG_LOG("ChangePowerStateToPriv: power state %ld\n", ordinal);
 2302 
 2303         if ( (getPowerState() == DOZE_STATE) && (ordinal != ON_STATE) )
 2304         {
 2305                 return kIOReturnSuccess;
 2306         }
 2307 
 2308     if( (userDisabledAllSleep || systemBooting || systemShutdown) 
 2309         && (ordinal == SLEEP_STATE) )
 2310     {
 2311         DEBUG_LOG("  sleep denied: disableAllSleep %d, booting %d, shutdown %d\n",
 2312             userDisabledAllSleep, systemBooting, systemShutdown);
 2313         super::changePowerStateToPriv(ON_STATE);
 2314     }
 2315 
 2316     if( (SLEEP_STATE == ordinal) && sleepSupportedPEFunction )
 2317     {
 2318 
 2319         // Determine if the machine supports sleep, or must doze.
 2320         ret = getPlatform()->callPlatformFunction(
 2321                             sleepSupportedPEFunction, false,
 2322                             NULL, NULL, NULL, NULL);
 2323     
 2324         // If the machine only supports doze, the callPlatformFunction call
 2325         // boils down to IOPMrootDomain::setSleepSupported(kPCICantSleep), 
 2326         // otherwise nothing.
 2327     }
 2328 
 2329     return super::changePowerStateToPriv(ordinal);
 2330 }
 2331 
 2332 
 2333 //*********************************************************************************
 2334 // sysPowerDownHandler
 2335 //
 2336 // Receives a notification when the RootDomain changes state. 
 2337 //
 2338 // Allows us to take action on system sleep, power down, and restart after
 2339 // applications have received their power change notifications and replied,
 2340 // but before drivers have powered down. We perform a vfs sync on power down.
 2341 //*********************************************************************************
 2342 
 2343 IOReturn IOPMrootDomain::sysPowerDownHandler( void * target, void * refCon,
 2344                                     UInt32 messageType, IOService * service,
 2345                                     void * messageArgument, vm_size_t argSize )
 2346 {
 2347     IOReturn                             ret;
 2348     IOPowerStateChangeNotification      *params = (IOPowerStateChangeNotification *) messageArgument;
 2349     IOPMrootDomain                      *rootDomain = OSDynamicCast(IOPMrootDomain, service);
 2350 
 2351     if(!rootDomain)
 2352         return kIOReturnUnsupported;
 2353 
 2354     switch (messageType) {
 2355         case kIOMessageSystemWillSleep:
 2356             DEBUG_LOG("SystemWillSleep\n");
 2357 
 2358             // Interested applications have been notified of an impending power
 2359             // change and have acked (when applicable).
 2360             // This is our chance to save whatever state we can before powering
 2361             // down.
 2362             // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
 2363             // via callout
 2364 
 2365             // We will ack within 20 seconds
 2366             params->returnValue = 20 * 1000 * 1000;
 2367 #if     HIBERNATION
 2368             if (gIOHibernateState)
 2369                 params->returnValue += gIOHibernateFreeTime * 1000;     //add in time we could spend freeing pages
 2370 #endif
 2371 
 2372             if ( ! OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) )
 2373             {
 2374                 // Purposely delay the ack and hope that shutdown occurs quickly.
 2375                 // Another option is not to schedule the thread and wait for
 2376                 // ack timeout...
 2377                 AbsoluteTime deadline;
 2378                 clock_interval_to_deadline( 30, kSecondScale, &deadline );
 2379                 thread_call_enter1_delayed( rootDomain->diskSyncCalloutEntry, 
 2380                                             (thread_call_param_t)params->powerRef,
 2381                                             deadline );
 2382             }
 2383             else
 2384                 thread_call_enter1(rootDomain->diskSyncCalloutEntry, (thread_call_param_t)params->powerRef);
 2385             ret = kIOReturnSuccess;
 2386             break;
 2387 
 2388         case kIOMessageSystemWillPowerOff:
 2389         case kIOMessageSystemWillRestart:
 2390             ret = kIOReturnUnsupported;
 2391             break;
 2392 
 2393         default:
 2394             ret = kIOReturnUnsupported;
 2395             break;
 2396     }
 2397     return ret;
 2398 }
 2399                 
 2400 //*********************************************************************************
 2401 // displayWranglerNotification
 2402 //
 2403 // Receives a notification when the IODisplayWrangler changes state.
 2404 //
 2405 // Allows us to take action on display dim/undim.
 2406 //
 2407 // When the display sleeps we:
 2408 // - Start the idle sleep timer
 2409 // - set the quick spin down timeout
 2410 //
 2411 // On wake from display sleep:
 2412 // - Cancel the idle sleep timer
 2413 // - restore the user's chosen spindown timer from the "quick" spin down value
 2414 //*********************************************************************************
 2415 
 2416 IOReturn IOPMrootDomain::displayWranglerNotification(
 2417     void * target, void * refCon,
 2418     UInt32 messageType, IOService * service,
 2419     void * messageArgument, vm_size_t argSize )
 2420 {
 2421 #if !NO_KERNEL_HID
 2422     IOPMrootDomain *    rootDomain = OSDynamicCast(IOPMrootDomain, (IOService *)target);
 2423     AbsoluteTime        deadline;
 2424     static int          displayPowerState = 4;
 2425 
 2426     if (!rootDomain)
 2427         return kIOReturnUnsupported;
 2428 
 2429     switch (messageType) {
 2430        case kIOMessageDeviceWillPowerOff:
 2431             DEBUG_LOG("DisplayWranglerWillPowerOff: new p-state %d\n",
 2432                 displayPowerState - 1);
 2433 
 2434             // The display wrangler has dropped power because of idle display sleep
 2435             // or force system sleep. We will receive 4 messages before the display
 2436             // wrangler reaches its lowest state. Act only when going to state 2.
 2437             //
 2438             // 4->3 Display Dim
 2439             // 3->2 Display Sleep
 2440             // 2->1 Not visible to user
 2441             // 1->0 Not visible to user
 2442 
 2443             displayPowerState--;
 2444             if ( 2 != displayPowerState )
 2445                 return kIOReturnUnsupported;
 2446 
 2447             // We start a timer here if the System Sleep timer is greater than the
 2448             // Display Sleep timer. We kick off this timer when the display sleeps.
 2449             //
 2450             // Note that, although Display Dim timings may change adaptively accordingly
 2451             // to the user's activity patterns, Display Sleep _always_ occurs at the
 2452             // specified interval since last user activity.
 2453 
 2454             if ( rootDomain->extraSleepDelay )
 2455             {
 2456                 clock_interval_to_deadline(rootDomain->extraSleepDelay*60, kSecondScale, &deadline);
 2457                 thread_call_enter_delayed(rootDomain->extraSleepTimer, deadline);
 2458                 rootDomain->idleSleepPending = true;
 2459                 DEBUG_LOG("  sleep timer set to expire in %ld min\n",
 2460                     rootDomain->extraSleepDelay);
 2461             } else {
 2462                 // Accelerate disk spindown if system sleep and display sleep
 2463                 // sliders are set to the same value (e.g. both set to 5 min),
 2464                 // and display is about to go dark. Check that spin down timer
 2465                 // is non-zero (zero = never spin down) and system sleep is
 2466                 // not set to never sleep.
 2467 
 2468                 if ( (0 != rootDomain->user_spindown) && (0 != rootDomain->sleepSlider) )
 2469                 {
 2470                     DEBUG_LOG("  accelerate quick disk spindown, was %d min\n",
 2471                         rootDomain->user_spindown);
 2472                     rootDomain->setQuickSpinDownTimeout();
 2473                 }
 2474             }
 2475 
 2476             break;
 2477 
 2478         case kIOMessageDeviceHasPoweredOn:
 2479             DEBUG_LOG("DisplayWranglerHasPoweredOn: previous p-state %d\n",
 2480                 displayPowerState);
 2481 
 2482             // The display wrangler has powered on either because of user activity 
 2483             // or wake from sleep/doze.
 2484 
 2485             displayPowerState = 4;
 2486             rootDomain->adjustPowerState();
 2487 
 2488             // cancel any pending idle sleep timers
 2489             if (rootDomain->idleSleepPending) 
 2490             {
 2491                 DEBUG_LOG("  extra-sleep timer stopped\n");
 2492                 thread_call_cancel(rootDomain->extraSleepTimer);
 2493                 rootDomain->idleSleepPending = false;
 2494             }
 2495 
 2496             // Change the spindown value back to the user's selection from our
 2497             // accelerated setting.
 2498             if (0 != rootDomain->user_spindown)
 2499             {
 2500                 DEBUG_LOG("  restoring disk spindown to %d min\n",
 2501                     rootDomain->user_spindown);
 2502                 rootDomain->restoreUserSpinDownTimeout();
 2503             }
 2504 
 2505             break;
 2506 
 2507          default:
 2508              break;
 2509      }
 2510 #endif
 2511      return kIOReturnUnsupported;
 2512  }
 2513 
 2514 //*********************************************************************************
 2515 // displayWranglerPublished
 2516 //
 2517 // Receives a notification when the IODisplayWrangler is published.
 2518 // When it's published we install a power state change handler.
 2519 //
 2520 //*********************************************************************************
 2521 
 2522 bool IOPMrootDomain::displayWranglerPublished( 
 2523     void * target, 
 2524     void * refCon,
 2525     IOService * newService)
 2526 {
 2527 #if !NO_KERNEL_HID
 2528     IOPMrootDomain *rootDomain = 
 2529             OSDynamicCast(IOPMrootDomain, (IOService *)target);
 2530 
 2531     if(!rootDomain)
 2532         return false;
 2533 
 2534     rootDomain->wrangler = newService;
 2535     
 2536     // we found the display wrangler, now install a handler
 2537     if( !rootDomain->wrangler->registerInterest( gIOGeneralInterest, 
 2538                             &displayWranglerNotification, target, 0) ) 
 2539     {
 2540         return false;
 2541     }
 2542 #endif
 2543     return true;
 2544 }
 2545 
 2546 //*********************************************************************************
 2547 // batteryPublished
 2548 //
 2549 // Notification on battery class IOPowerSource appearance
 2550 //
 2551 //******************************************************************************
 2552 
 2553 bool IOPMrootDomain::batteryPublished( 
 2554     void * target, 
 2555     void * root_domain,
 2556     IOService * resourceService )
 2557 {    
 2558     // rdar://2936060&4435589    
 2559     // All laptops have dimmable LCD displays
 2560     // All laptops have batteries
 2561     // So if this machine has a battery, publish the fact that the backlight
 2562     // supports dimming.
 2563     ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims");
 2564 
 2565     return (true);
 2566 }
 2567 
 2568 //*********************************************************************************
 2569 // adjustPowerState
 2570 //
 2571 // Some condition that affects our wake/sleep/doze decision has changed.
 2572 //
 2573 // If the sleep slider is in the off position, we cannot sleep or doze.
 2574 // If the enclosure is open, we cannot sleep or doze.
 2575 // If the system is still booting, we cannot sleep or doze.
 2576 //
 2577 // In those circumstances, we prevent sleep and doze by holding power on with
 2578 // changePowerStateToPriv(ON).
 2579 //
 2580 // If the above conditions do not exist, and also the sleep timer has expired, we
 2581 // allow sleep or doze to occur with either changePowerStateToPriv(SLEEP) or
 2582 // changePowerStateToPriv(DOZE) depending on whether or not we already know the
 2583 // platform cannot sleep.
 2584 //
 2585 // In this case, sleep or doze will either occur immediately or at the next time
 2586 // that no children are holding the system out of idle sleep via the 
 2587 // kIOPMPreventIdleSleep flag in their power state arrays.
 2588 //*********************************************************************************
 2589 
 2590 void IOPMrootDomain::adjustPowerState( void )
 2591 {
 2592     if ( (sleepSlider == 0) 
 2593         || !allowSleep 
 2594         || systemBooting 
 2595         || systemShutdown
 2596         || userDisabledAllSleep )
 2597     {
 2598         DEBUG_LOG("AdjustPowerState %ld -> ON: slider %ld, allowSleep %d, "
 2599             "booting %d, shutdown %d, userDisabled %d\n",
 2600             getPowerState(), sleepSlider, allowSleep, systemBooting,
 2601             systemShutdown, userDisabledAllSleep);
 2602 
 2603         changePowerStateToPriv(ON_STATE);
 2604     } else {
 2605         if ( sleepASAP ) 
 2606         {
 2607             DEBUG_LOG("AdjustPowerState SLEEP\n");
 2608 
 2609             /* Convenient place to run any code at idle sleep time
 2610              * IOPMrootDomain initiates an  idle sleep here
 2611              *
 2612              * Set last sleep cause accordingly.
 2613              */
 2614             setProperty(kRootDomainSleepReasonKey, kIOPMIdleSleepKey);
 2615         
 2616             sleepASAP = false;
 2617             if ( !sleepIsSupported ) 
 2618             {
 2619                 setSleepSupported( kPCICantSleep );
 2620                 kprintf("Sleep prevented by kIOPMPreventSystemSleep flag\n");
 2621             }
 2622             changePowerStateToPriv(SLEEP_STATE);
 2623         }
 2624     }
 2625 }
 2626 
 2627 //*********************************************************************************
 2628 // PMHaltWorker Class
 2629 //
 2630 //*********************************************************************************
 2631 
 2632 static unsigned int             gPMHaltBusyCount;
 2633 static unsigned int             gPMHaltIdleCount;
 2634 static int                              gPMHaltDepth;
 2635 static unsigned long    gPMHaltEvent;
 2636 static IOLock *                 gPMHaltLock  = 0;
 2637 static OSArray *                gPMHaltArray = 0;
 2638 static const OSSymbol * gPMHaltClientAcknowledgeKey = 0;
 2639 
 2640 PMHaltWorker * PMHaltWorker::worker( void )
 2641 {
 2642         PMHaltWorker *  me;
 2643         IOThread                thread;
 2644 
 2645         do {
 2646                 me = OSTypeAlloc( PMHaltWorker );
 2647                 if (!me || !me->init())
 2648                         break;
 2649 
 2650                 me->lock = IOLockAlloc();
 2651                 if (!me->lock)
 2652                         break;
 2653 
 2654                 DEBUG_LOG("PMHaltWorker %p\n", me);
 2655                 me->retain();   // thread holds extra retain
 2656                 thread = IOCreateThread( &PMHaltWorker::main, me );
 2657                 if (!thread)
 2658                 {
 2659                         me->release();
 2660                         break;
 2661                 }
 2662                 return me;
 2663 
 2664         } while (false);
 2665 
 2666         if (me) me->release();
 2667         return 0;
 2668 }
 2669 
 2670 void PMHaltWorker::free( void )
 2671 {
 2672         DEBUG_LOG("PMHaltWorker free %p\n", this);
 2673         if (lock)
 2674         {
 2675                 IOLockFree(lock);
 2676                 lock = 0;
 2677         }
 2678         return OSObject::free();
 2679 }
 2680 
 2681 void PMHaltWorker::main( void * arg )
 2682 {
 2683         PMHaltWorker * me = (PMHaltWorker *) arg;
 2684 
 2685         IOLockLock( gPMHaltLock );
 2686         gPMHaltBusyCount++;
 2687         me->depth = gPMHaltDepth;
 2688         IOLockUnlock( gPMHaltLock );
 2689 
 2690         while (me->depth >= 0)
 2691         {
 2692                 PMHaltWorker::work( me );
 2693 
 2694                 IOLockLock( gPMHaltLock );
 2695                 if (++gPMHaltIdleCount >= gPMHaltBusyCount)
 2696                 {
 2697                         // This is the last thread to finish work on this level,
 2698                         // inform everyone to start working on next lower level.
 2699                         gPMHaltDepth--;
 2700                         me->depth = gPMHaltDepth;
 2701                         gPMHaltIdleCount = 0;
 2702                         thread_wakeup((event_t) &gPMHaltIdleCount);
 2703                 }
 2704                 else
 2705                 {
 2706                         // One or more threads are still working on this level,
 2707                         // this thread must wait.
 2708                         me->depth = gPMHaltDepth - 1;
 2709                         do {
 2710                                 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
 2711                         } while (me->depth != gPMHaltDepth);
 2712                 }
 2713                 IOLockUnlock( gPMHaltLock );
 2714         }
 2715 
 2716         // No more work to do, terminate thread
 2717         DEBUG_LOG("All done for worker: %p (visits = %u)\n", me, me->visits);
 2718         thread_wakeup( &gPMHaltDepth );
 2719         me->release();
 2720 }
 2721 
 2722 void PMHaltWorker::work( PMHaltWorker * me )
 2723 {
 2724         IOService *             service;
 2725         OSSet *                 inner;
 2726         AbsoluteTime    startTime;
 2727         UInt32                  deltaTime;
 2728         bool                    timeout;
 2729 
 2730         while (true)
 2731         {
 2732                 service = 0;
 2733                 timeout = false;
 2734 
 2735                 // Claim an unit of work from the shared pool
 2736                 IOLockLock( gPMHaltLock );
 2737                 inner = (OSSet *)gPMHaltArray->getObject(me->depth);
 2738                 if (inner)
 2739                 {
 2740                         service = (IOService *)inner->getAnyObject();
 2741                         if (service)
 2742                         {
 2743                                 service->retain();
 2744                                 inner->removeObject(service);
 2745                         }
 2746                 }
 2747                 IOLockUnlock( gPMHaltLock );    
 2748                 if (!service)
 2749                         break;  // no more work at this depth
 2750 
 2751                 clock_get_uptime(&startTime);
 2752 
 2753                 if (!service->isInactive() &&
 2754                         service->setProperty(gPMHaltClientAcknowledgeKey, me))
 2755                 {
 2756                         IOLockLock(me->lock);
 2757                         me->startTime = startTime;
 2758                         me->service   = service;
 2759                         me->timeout   = false;
 2760                         IOLockUnlock(me->lock);
 2761 
 2762                         service->systemWillShutdown( gPMHaltEvent );
 2763 
 2764                         // Wait for driver acknowledgement
 2765                         IOLockLock(me->lock);
 2766                         while (service->getProperty(gPMHaltClientAcknowledgeKey))
 2767                         {
 2768                                 IOLockSleep(me->lock, me, THREAD_UNINT);                        
 2769                         }
 2770                         me->service = 0;
 2771                         timeout = me->timeout;
 2772                         IOLockUnlock(me->lock);
 2773                 }
 2774 
 2775                 deltaTime = computeDeltaTimeMS(&startTime);
 2776                 if ((deltaTime > kPMHaltTimeoutMS) || timeout ||
 2777                         (gIOKitDebug & kIOLogDebugPower))
 2778                 {
 2779                         HaltRestartLog("%s driver %s (%p) took %lu ms\n",
 2780                                 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
 2781                                         "PowerOff" : "Restart",
 2782                                 service->getName(), service,
 2783                                 deltaTime );
 2784                 }
 2785 
 2786                 service->release();
 2787                 me->visits++;
 2788         }
 2789 }
 2790 
 2791 void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
 2792 {
 2793         UInt64                  nano;
 2794         AbsoluteTime    startTime;
 2795         AbsoluteTime    endTime;
 2796 
 2797         endTime = *now;
 2798 
 2799         IOLockLock(me->lock);
 2800         if (me->service && !me->timeout)
 2801         {
 2802                 startTime = me->startTime;
 2803                 nano = 0;
 2804             if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
 2805             {
 2806                         SUB_ABSOLUTETIME(&endTime, &startTime);
 2807                         absolutetime_to_nanoseconds(endTime, &nano);
 2808             }
 2809                 if (nano > 3000000000ULL)
 2810                 {
 2811                         me->timeout = true;
 2812                         HaltRestartLog("%s still waiting on %s\n",
 2813                                 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
 2814                                         "PowerOff" : "Restart",
 2815                                 me->service->getName());
 2816                 }
 2817         }
 2818         IOLockUnlock(me->lock);
 2819 }
 2820 
 2821 //*********************************************************************************
 2822 // acknowledgeSystemWillShutdown
 2823 //
 2824 // Acknowledgement from drivers that they have prepared for shutdown/restart.
 2825 //*********************************************************************************
 2826 
 2827 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
 2828 {
 2829         PMHaltWorker *  worker;
 2830         OSObject *              prop;
 2831 
 2832         if (!from)
 2833                 return;
 2834 
 2835         //DEBUG_LOG("%s acknowledged\n", from->getName());
 2836         prop = from->copyProperty( gPMHaltClientAcknowledgeKey );
 2837         if (prop)
 2838         {
 2839                 worker = (PMHaltWorker *) prop;
 2840                 IOLockLock(worker->lock);
 2841                 from->removeProperty( gPMHaltClientAcknowledgeKey );
 2842                 thread_wakeup((event_t) worker);
 2843                 IOLockUnlock(worker->lock);
 2844                 worker->release();
 2845         }
 2846         else
 2847         {
 2848                 DEBUG_LOG("%s acknowledged without worker property\n",
 2849                         from->getName());
 2850         }
 2851 }
 2852 
 2853 //*********************************************************************************
 2854 // notifySystemShutdown
 2855 //
 2856 // Notify all objects in PM tree that system will shutdown or restart
 2857 //*********************************************************************************
 2858 
 2859 static void
 2860 notifySystemShutdown( IOService * root, unsigned long event )
 2861 {
 2862 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
 2863         IORegistryIterator *    iter;
 2864         IORegistryEntry *               entry;
 2865         IOService *                             node;
 2866         OSSet *                                 inner;
 2867         PMHaltWorker *                  workers[kPMHaltMaxWorkers];
 2868         AbsoluteTime                    deadline;
 2869         unsigned int                    totalNodes = 0;
 2870         unsigned int                    depth;
 2871         unsigned int                    rootDepth;
 2872         unsigned int                    numWorkers;
 2873         unsigned int                    count;
 2874         int                                             waitResult;
 2875         void *                                  baseFunc;
 2876         bool                                    ok;
 2877 
 2878         DEBUG_LOG("%s event = %lx\n", __FUNCTION__, event);
 2879 
 2880         baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
 2881 
 2882         // Iterate the entire PM tree starting from root
 2883 
 2884         rootDepth = root->getDepth( gIOPowerPlane );
 2885         if (!rootDepth) goto done;
 2886 
 2887         // debug - for repeated test runs
 2888         while (PMHaltWorker::metaClass->getInstanceCount())
 2889                 IOSleep(1);
 2890 
 2891         if (!gPMHaltArray)
 2892         {
 2893                 gPMHaltArray = OSArray::withCapacity(40);
 2894                 if (!gPMHaltArray) goto done;
 2895         }
 2896         else // debug
 2897                 gPMHaltArray->flushCollection();
 2898 
 2899         if (!gPMHaltLock)
 2900         {
 2901                 gPMHaltLock = IOLockAlloc();
 2902                 if (!gPMHaltLock) goto done;
 2903         }
 2904 
 2905         if (!gPMHaltClientAcknowledgeKey)
 2906         {
 2907                 gPMHaltClientAcknowledgeKey =
 2908                         OSSymbol::withCStringNoCopy("PMShutdown");
 2909                 if (!gPMHaltClientAcknowledgeKey) goto done;
 2910         }
 2911 
 2912         gPMHaltEvent = event;
 2913 
 2914         // Depth-first walk of PM plane
 2915 
 2916         iter = IORegistryIterator::iterateOver(
 2917                 root, gIOPowerPlane, kIORegistryIterateRecursively);
 2918 
 2919         if (iter)
 2920         {
 2921                 while ((entry = iter->getNextObject()))
 2922                 {
 2923                         node = OSDynamicCast(IOService, entry);
 2924                         if (!node)
 2925                                 continue;
 2926 
 2927                         if (baseFunc == 
 2928                                 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
 2929                                 continue;
 2930 
 2931                         depth = node->getDepth( gIOPowerPlane );
 2932                         if (depth <= rootDepth)
 2933                                 continue;
 2934 
 2935                         ok = false;
 2936 
 2937                         // adjust to zero based depth
 2938                         depth -= (rootDepth + 1);
 2939 
 2940                         // gPMHaltArray is an array of containers, each container
 2941                         // refers to nodes with the same depth.
 2942 
 2943                         count = gPMHaltArray->getCount();
 2944                         while (depth >= count)
 2945                         {
 2946                                 // expand array and insert placeholders
 2947                                 gPMHaltArray->setObject(PLACEHOLDER);
 2948                                 count++;
 2949                         }
 2950                         count = gPMHaltArray->getCount();
 2951                         if (depth < count)
 2952                         {
 2953                                 inner = (OSSet *)gPMHaltArray->getObject(depth);
 2954                                 if (inner == PLACEHOLDER)
 2955                                 {
 2956                                         inner = OSSet::withCapacity(40);
 2957                                         if (inner)
 2958                                         {
 2959                                                 gPMHaltArray->replaceObject(depth, inner);
 2960                                                 inner->release();
 2961                                         }
 2962                                 }
 2963 
 2964                                 // PM nodes that appear more than once in the tree will have
 2965                                 // the same depth, OSSet will refuse to add the node twice.
 2966                                 if (inner)
 2967                                         ok = inner->setObject(node);
 2968                         }
 2969                         if (!ok)
 2970                                 DEBUG_LOG("Skipped PM node %s\n", node->getName());
 2971                 }
 2972                 iter->release();
 2973         }
 2974 
 2975         // debug only
 2976         for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++)
 2977         {
 2978                 count = 0;
 2979                 if (inner != PLACEHOLDER)
 2980                         count = inner->getCount();
 2981                 DEBUG_LOG("Nodes at depth %u = %u\n", i, count);
 2982         }
 2983 
 2984         // strip placeholders (not all depths are populated)
 2985         numWorkers = 0;
 2986         for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); )
 2987         {
 2988                 if (inner == PLACEHOLDER)
 2989                 {
 2990                         gPMHaltArray->removeObject(i);
 2991                         continue;
 2992                 }
 2993                 count = inner->getCount();
 2994                 if (count > numWorkers)
 2995                         numWorkers = count;
 2996                 totalNodes += count;
 2997                 i++;
 2998         }
 2999 
 3000         if (gPMHaltArray->getCount() == 0 || !numWorkers)
 3001                 goto done;
 3002 
 3003         gPMHaltBusyCount = 0;
 3004         gPMHaltIdleCount = 0;
 3005         gPMHaltDepth = gPMHaltArray->getCount() - 1;
 3006 
 3007         // Create multiple workers (and threads)
 3008 
 3009         if (numWorkers > kPMHaltMaxWorkers)
 3010                 numWorkers = kPMHaltMaxWorkers;
 3011 
 3012         DEBUG_LOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
 3013                 totalNodes, gPMHaltArray->getCount(), numWorkers);
 3014 
 3015         for (unsigned int i = 0; i < numWorkers; i++)
 3016                 workers[i] = PMHaltWorker::worker();
 3017 
 3018         // Wait for workers to exhaust all available work
 3019 
 3020         IOLockLock(gPMHaltLock);
 3021         while (gPMHaltDepth >= 0)
 3022         {
 3023                 clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
 3024 
 3025                 waitResult = IOLockSleepDeadline(
 3026                         gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
 3027                 if (THREAD_TIMED_OUT == waitResult)
 3028                 {
 3029                         AbsoluteTime now;
 3030                         clock_get_uptime(&now);
 3031 
 3032                         IOLockUnlock(gPMHaltLock);
 3033                         for (unsigned int i = 0 ; i < numWorkers; i++)
 3034                         {
 3035                                 if (workers[i])
 3036                                         PMHaltWorker::checkTimeout(workers[i], &now);
 3037                         }
 3038                         IOLockLock(gPMHaltLock);
 3039                 }
 3040         }
 3041         IOLockUnlock(gPMHaltLock);
 3042 
 3043         // Release all workers
 3044 
 3045         for (unsigned int i = 0; i < numWorkers; i++)
 3046         {
 3047                 if (workers[i])
 3048                         workers[i]->release();
 3049                 // worker also retained by it's own thread
 3050         }
 3051 
 3052 done:
 3053         DEBUG_LOG("%s done\n", __FUNCTION__);
 3054         return;
 3055 }
 3056 
 3057 #if DEBUG_TEST
 3058 // debug - exercise notifySystemShutdown()
 3059 bool IOPMrootDomain::serializeProperties( OSSerialize * s ) const
 3060 {
 3061         IOPMrootDomain * root = (IOPMrootDomain *) this;
 3062         notifySystemShutdown( root, kIOMessageSystemWillPowerOff );
 3063     return( super::serializeProperties(s) );
 3064 }
 3065 #endif
 3066 
 3067 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 3068 
 3069 
 3070 
 3071 #undef super
 3072 #define super OSObject
 3073 OSDefineMetaClassAndStructors(PMSettingObject, OSObject)
 3074 
 3075 void PMSettingObject::setPMSetting(const OSSymbol *type, OSObject *obj)
 3076 {
 3077         (*func)(target, type, obj, refcon);
 3078 }
 3079 
 3080 /* 
 3081  * Static constructor/initializer for PMSettingObject
 3082  */
 3083 PMSettingObject *PMSettingObject::pmSettingObject(
 3084     IOPMrootDomain                      *parent_arg,
 3085     IOPMSettingControllerCallback       handler_arg,
 3086     OSObject                            *target_arg,
 3087     uintptr_t                           refcon_arg,
 3088     uint32_t                            supportedPowerSources,
 3089     const OSSymbol *                    settings[])
 3090 {
 3091     uint32_t                            objCount = 0;
 3092     PMSettingObject                     *pmso;
 3093 
 3094     if( !parent_arg || !handler_arg || !settings ) return NULL;
 3095 
 3096      // count OSSymbol entries in NULL terminated settings array
 3097     while( settings[objCount] ) {
 3098         objCount++;
 3099     }
 3100     if(0 == objCount) return NULL;
 3101 
 3102     pmso = new PMSettingObject;
 3103     if(!pmso || !pmso->init()) return NULL;
 3104 
 3105     pmso->parent = parent_arg;
 3106     pmso->func = handler_arg;
 3107     pmso->target = target_arg;
 3108     pmso->refcon = refcon_arg;
 3109     pmso->releaseAtCount = objCount + 1; // release when it has count+1 retains
 3110  
 3111     pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*objCount);
 3112     if(pmso->publishedFeatureID) {
 3113         for(unsigned int i=0; i<objCount; i++) {
 3114             // Since there is now at least one listener to this setting, publish
 3115             // PM root domain support for it.
 3116             parent_arg->publishFeature( settings[i]->getCStringNoCopy(), 
 3117                     supportedPowerSources, &pmso->publishedFeatureID[i] );
 3118         }
 3119     }
 3120     
 3121     return pmso;
 3122 }
 3123 
 3124 void PMSettingObject::free(void)
 3125 {
 3126     OSCollectionIterator    *settings_iter;
 3127     OSSymbol                *sym;
 3128     OSArray                 *arr;
 3129     int                     arr_idx;
 3130     int                     i;
 3131     int                     objCount = releaseAtCount - 1;
 3132     
 3133     if(publishedFeatureID) {
 3134         for(i=0; i<objCount; i++) {
 3135             if(0 != publishedFeatureID[i]) {
 3136                 parent->removePublishedFeature( publishedFeatureID[i] );
 3137             }
 3138         }
 3139     
 3140         IOFree(publishedFeatureID, sizeof(uint32_t) * objCount);
 3141     }
 3142             
 3143     IORecursiveLockLock(parent->settingsCtrlLock);        
 3144     
 3145     // Search each PM settings array in the kernel.
 3146     settings_iter = OSCollectionIterator::withCollection(parent->settingsCallbacks);
 3147     if(settings_iter) 
 3148     {
 3149         while(( sym = OSDynamicCast(OSSymbol, settings_iter->getNextObject()) ))
 3150         {
 3151             arr = (OSArray *)parent->settingsCallbacks->getObject(sym);
 3152             arr_idx = arr->getNextIndexOfObject(this, 0);
 3153             if(-1 != arr_idx) {
 3154                 // 'this' was found in the array; remove it                
 3155                 arr->removeObject(arr_idx);
 3156             }
 3157         }
 3158     
 3159         settings_iter->release();
 3160     }
 3161     
 3162     IORecursiveLockUnlock(parent->settingsCtrlLock);
 3163     
 3164     super::free();
 3165 }
 3166 
 3167 void PMSettingObject::taggedRelease(const void *tag, const int when) const
 3168 {     
 3169     // We have n+1 retains - 1 per array that this PMSettingObject is a member
 3170     // of, and 1 retain to ourself. When we get a release with n+1 retains
 3171     // remaining, we go ahead and free ourselves, cleaning up array pointers
 3172     // in free();
 3173 
 3174     super::taggedRelease(tag, releaseAtCount);    
 3175 }
 3176 
 3177 
 3178 
 3179 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 3180 
 3181 #undef super
 3182 #define super IOService
 3183 
 3184 OSDefineMetaClassAndStructors(IORootParent, IOService)
 3185 
 3186 // This array exactly parallels the state array for the root domain.
 3187 // Power state changes initiated by a device can be vetoed by a client of the device, and
 3188 // power state changes initiated by the parent of a device cannot be vetoed by a client of the device,
 3189 // so when the root domain wants a power state change that cannot be vetoed (e.g. demand sleep), it asks
 3190 // its parent to make the change.  That is the reason for this complexity.
 3191 
 3192 static IOPMPowerState patriarchPowerStates[number_of_power_states] = {
 3193     {1,0,0,0,0,0,0,0,0,0,0,0},                                          // off
 3194     {1,0,RESTART_POWER,0,0,0,0,0,0,0,0,0},                              // reset
 3195     {1,0,SLEEP_POWER,0,0,0,0,0,0,0,0,0},                                // sleep
 3196     {1,0,DOZE_POWER,0,0,0,0,0,0,0,0,0},                                 // doze
 3197     {1,0,ON_POWER,0,0,0,0,0,0,0,0,0}                                    // running
 3198 };
 3199 
 3200 bool IORootParent::start ( IOService * nub )
 3201 {
 3202     mostRecentChange = ON_STATE;
 3203     super::start(nub);
 3204     PMinit();
 3205         youAreRoot();
 3206     registerPowerDriver(this,patriarchPowerStates,number_of_power_states);
 3207         wakeSystem();
 3208     powerOverrideOnPriv();      
 3209     return true;
 3210 }
 3211 
 3212 
 3213 void IORootParent::shutDownSystem ( void )
 3214 {
 3215     mostRecentChange = OFF_STATE;
 3216     changePowerStateToPriv(OFF_STATE);
 3217 }
 3218 
 3219 
 3220 void IORootParent::restartSystem ( void )
 3221 {
 3222     mostRecentChange = RESTART_STATE;
 3223     changePowerStateToPriv(RESTART_STATE);
 3224 }
 3225 
 3226 
 3227 void IORootParent::sleepSystem ( void )
 3228 {
 3229     mostRecentChange = SLEEP_STATE;
 3230     changePowerStateToPriv(SLEEP_STATE);
 3231 }
 3232 
 3233 
 3234 void IORootParent::dozeSystem ( void )
 3235 {
 3236     mostRecentChange = DOZE_STATE;
 3237     changePowerStateToPriv(DOZE_STATE);
 3238 }
 3239 
 3240 // Called in demand sleep when sleep discovered to be impossible after actually attaining that state.
 3241 // This brings the parent to doze, which allows the root to step up from sleep to doze.
 3242 
 3243 // In idle sleep, do nothing because the parent is still on and the root can freely change state.
 3244 
 3245 void IORootParent::sleepToDoze ( void )
 3246 {
 3247     if ( mostRecentChange == SLEEP_STATE ) {
 3248         changePowerStateToPriv(DOZE_STATE);
 3249     }
 3250 }
 3251 
 3252 
 3253 void IORootParent::wakeSystem ( void )
 3254 {
 3255     mostRecentChange = ON_STATE;
 3256     changePowerStateToPriv(ON_STATE);
 3257 }
 3258 
 3259 IOReturn IORootParent::changePowerStateToPriv ( unsigned long ordinal )
 3260 {
 3261     IOReturn        ret;
 3262 
 3263     if( (SLEEP_STATE == ordinal) && sleepSupportedPEFunction )
 3264     {
 3265 
 3266         // Determine if the machine supports sleep, or must doze.
 3267         ret = getPlatform()->callPlatformFunction(
 3268                             sleepSupportedPEFunction, false,
 3269                             NULL, NULL, NULL, NULL);
 3270     
 3271         // If the machine only supports doze, the callPlatformFunction call
 3272         // boils down toIOPMrootDomain::setSleepSupported(kPCICantSleep), 
 3273         // otherwise nothing.
 3274     }
 3275 
 3276     return super::changePowerStateToPriv(ordinal);
 3277 }
 3278 

Cache object: aa9d5b4319fed85accfc00a27237f44f


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


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