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