1/*
2 * Copyright (c) 1998-2008 Apple 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 <libkern/c++/OSKext.h>
29#include <libkern/c++/OSMetaClass.h>
30#include <libkern/OSAtomic.h>
31#include <libkern/OSDebug.h>
32#include <IOKit/IOWorkLoop.h>
33#include <IOKit/IOCommandGate.h>
34#include <IOKit/IOPlatformExpert.h>
35#include <IOKit/IOCPU.h>
36#include <IOKit/IOKitDebug.h>
37#include <IOKit/IOTimeStamp.h>
38#include <IOKit/pwr_mgt/IOPMlog.h>
39#include <IOKit/pwr_mgt/RootDomain.h>
40#include <IOKit/pwr_mgt/IOPMPrivate.h>
41#include <IOKit/IODeviceTreeSupport.h>
42#include <IOKit/IOMessage.h>
43#include <IOKit/IOReturn.h>
44#include <IOKit/IONVRAM.h>
45#include "RootDomainUserClient.h"
46#include "IOKit/pwr_mgt/IOPowerConnection.h"
47#include "IOPMPowerStateQueue.h"
48#include <IOKit/IOCatalogue.h>
49#include <IOKit/IOReportMacros.h>
50#if HIBERNATION
51#include <IOKit/IOHibernatePrivate.h>
52#endif
53#include <console/video_console.h>
54#include <sys/syslog.h>
55#include <sys/sysctl.h>
56#include <sys/vnode.h>
57#include <sys/vnode_internal.h>
58#include <sys/fcntl.h>
59
60#include <sys/time.h>
61#include "IOServicePrivate.h"   // _IOServiceInterestNotifier
62#include "IOServicePMPrivate.h"
63
64__BEGIN_DECLS
65#include <mach/shared_region.h>
66__END_DECLS
67
68#if defined(__i386__) || defined(__x86_64__)
69__BEGIN_DECLS
70#include "IOPMrootDomainInternal.h"
71__END_DECLS
72#endif
73
74#define kIOPMrootDomainClass    "IOPMrootDomain"
75#define LOG_PREFIX              "PMRD: "
76
77
78#define MSG(x...) \
79    do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
80
81#define LOG(x...)    \
82    do { kprintf(LOG_PREFIX x); } while (false)
83
84#define DLOG(x...)  do { \
85    if (kIOLogPMRootDomain & gIOKitDebug) \
86        kprintf(LOG_PREFIX x); \
87} while (false)
88
89#define DMSG(x...)  do { \
90    if (kIOLogPMRootDomain & gIOKitDebug) { \
91        kprintf(LOG_PREFIX x); IOLog(x); \
92    } \
93} while (false)
94
95
96#define _LOG(x...)
97
98#define CHECK_THREAD_CONTEXT
99#ifdef  CHECK_THREAD_CONTEXT
100static IOWorkLoop * gIOPMWorkLoop = 0;
101#define ASSERT_GATED()                                      \
102do {                                                        \
103    if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
104        panic("RootDomain: not inside PM gate");            \
105    }                                                       \
106} while(false)
107#else
108#define ASSERT_GATED()
109#endif /* CHECK_THREAD_CONTEXT */
110
111#define CAP_LOSS(c)  \
112        (((_pendingCapability & (c)) == 0) && \
113         ((_currentCapability & (c)) != 0))
114
115#define CAP_GAIN(c)  \
116        (((_currentCapability & (c)) == 0) && \
117         ((_pendingCapability & (c)) != 0))
118
119#define CAP_CHANGE(c)    \
120        (((_currentCapability ^ _pendingCapability) & (c)) != 0)
121
122#define CAP_CURRENT(c)  \
123        ((_currentCapability & (c)) != 0)
124
125#define CAP_HIGHEST(c)  \
126        ((_highestCapability & (c)) != 0)
127
128#if defined(__i386__) || defined(__x86_64__)
129#define DARK_TO_FULL_EVALUATE_CLAMSHELL     1
130#endif
131
132// Event types for IOPMPowerStateQueue::submitPowerEvent()
133enum {
134    kPowerEventFeatureChanged = 1,              // 1
135    kPowerEventReceivedPowerNotification,       // 2
136    kPowerEventSystemBootCompleted,             // 3
137    kPowerEventSystemShutdown,                  // 4
138    kPowerEventUserDisabledSleep,               // 5
139    kPowerEventRegisterSystemCapabilityClient,  // 6
140    kPowerEventRegisterKernelCapabilityClient,  // 7
141    kPowerEventPolicyStimulus,                  // 8
142    kPowerEventAssertionCreate,                 // 9
143    kPowerEventAssertionRelease,                // 10
144    kPowerEventAssertionSetLevel,               // 11
145    kPowerEventQueueSleepWakeUUID,              // 12
146    kPowerEventPublishSleepWakeUUID,            // 13
147    kPowerEventSetDisplayPowerOn                // 14
148};
149
150// For evaluatePolicy()
151// List of stimuli that affects the root domain policy.
152enum {
153    kStimulusDisplayWranglerSleep,      // 0
154    kStimulusDisplayWranglerWake,       // 1
155    kStimulusAggressivenessChanged,     // 2
156    kStimulusDemandSystemSleep,         // 3
157    kStimulusAllowSystemSleepChanged,   // 4
158    kStimulusDarkWakeActivityTickle,    // 5
159    kStimulusDarkWakeEntry,             // 6
160    kStimulusDarkWakeReentry,           // 7
161    kStimulusDarkWakeEvaluate,          // 8
162    kStimulusNoIdleSleepPreventers,     // 9
163    kStimulusEnterUserActiveState,      // 10
164    kStimulusLeaveUserActiveState       // 11
165};
166
167extern "C" {
168IOReturn OSKextSystemSleepOrWake( UInt32 );
169}
170extern "C" ppnum_t      pmap_find_phys(pmap_t pmap, addr64_t va);
171extern "C" addr64_t     kvtophys(vm_offset_t va);
172extern "C" int  stack_snapshot_from_kernel(pid_t pid, void *buf, uint32_t size, uint32_t flags, unsigned *bytesTraced);
173
174static void idleSleepTimerExpired( thread_call_param_t, thread_call_param_t );
175static void notifySystemShutdown( IOService * root, unsigned long event );
176static void handleAggressivesFunction( thread_call_param_t, thread_call_param_t );
177static void pmEventTimeStamp(uint64_t *recordTS);
178
179// "IOPMSetSleepSupported"  callPlatformFunction name
180static const OSSymbol *sleepSupportedPEFunction = NULL;
181static const OSSymbol *sleepMessagePEFunction   = NULL;
182
183#define kIOSleepSupportedKey        "IOSleepSupported"
184#define kIOPMSystemCapabilitiesKey  "System Capabilities"
185
186#define kIORequestWranglerIdleKey   "IORequestIdle"
187#define kDefaultWranglerIdlePeriod  25 // in milliseconds
188
189#define kIOSleepWakeDebugKey        "Persistent-memory-note"
190
191#define kRD_AllPowerSources (kIOPMSupportedOnAC \
192                           | kIOPMSupportedOnBatt \
193                           | kIOPMSupportedOnUPS)
194
195enum
196{
197    // not idle around autowake time, secs
198    kAutoWakePreWindow  = 45,
199    kAutoWakePostWindow = 15
200};
201
202#define kLocalEvalClamshellCommand  (1 << 15)
203#define kIdleSleepRetryInterval     (3 * 60)
204
205enum {
206    kWranglerPowerStateMin   = 0,
207    kWranglerPowerStateSleep = 2,
208    kWranglerPowerStateDim   = 3,
209    kWranglerPowerStateMax   = 4
210};
211
212enum {
213    OFF_STATE           = 0,
214    RESTART_STATE       = 1,
215    SLEEP_STATE         = 2,
216    ON_STATE            = 3,
217    NUM_POWER_STATES
218};
219
220#define ON_POWER        kIOPMPowerOn
221#define RESTART_POWER   kIOPMRestart
222#define SLEEP_POWER     kIOPMAuxPowerOn
223
224static IOPMPowerState ourPowerStates[NUM_POWER_STATES] =
225{
226    {1, 0,                      0,              0,             0,0,0,0,0,0,0,0},
227    {1, kIOPMRestartCapability, kIOPMRestart,   RESTART_POWER, 0,0,0,0,0,0,0,0},
228    {1, kIOPMSleepCapability,   kIOPMSleep,     SLEEP_POWER,   0,0,0,0,0,0,0,0},
229    {1, kIOPMPowerOn,           kIOPMPowerOn,   ON_POWER,      0,0,0,0,0,0,0,0}
230};
231
232#define kIOPMRootDomainWakeTypeSleepService     "SleepService"
233#define kIOPMRootDomainWakeTypeMaintenance      "Maintenance"
234#define kIOPMRootDomainWakeTypeSleepTimer       "SleepTimer"
235#define kIOPMrootDomainWakeTypeLowBattery       "LowBattery"
236#define kIOPMRootDomainWakeTypeUser             "User"
237#define kIOPMRootDomainWakeTypeAlarm            "Alarm"
238#define kIOPMRootDomainWakeTypeNetwork          "Network"
239#define kIOPMRootDomainWakeTypeHIDActivity      "HID Activity"
240#define kIOPMRootDomainWakeTypeNotification     "Notification"
241#define kIOPMRootDomainWakeTypeHibernateError   "HibernateError"
242
243// Special interest that entitles the interested client from receiving
244// all system messages. Only used by powerd.
245//
246#define kIOPMSystemCapabilityInterest       "IOPMSystemCapabilityInterest"
247
248#define WAKEEVENT_LOCK()        IOLockLock(wakeEventLock)
249#define WAKEEVENT_UNLOCK()      IOLockUnlock(wakeEventLock)
250
251/*
252 * Aggressiveness
253 */
254#define AGGRESSIVES_LOCK()      IOLockLock(featuresDictLock)
255#define AGGRESSIVES_UNLOCK()    IOLockUnlock(featuresDictLock)
256
257#define kAggressivesMinValue    1
258
259enum {
260    kAggressivesStateBusy           = 0x01,
261    kAggressivesStateQuickSpindown  = 0x02
262};
263
264struct AggressivesRecord {
265    uint32_t    flags;
266    uint32_t    type;
267    uint32_t    value;
268};
269
270struct AggressivesRequest {
271    queue_chain_t           chain;
272    uint32_t                options;
273    uint32_t                dataType;
274    union {
275        IOService *         service;
276        AggressivesRecord   record;
277    } data;
278};
279
280enum {
281    kAggressivesRequestTypeService  = 1,
282    kAggressivesRequestTypeRecord
283};
284
285enum {
286    kAggressivesOptionSynchronous          = 0x00000001,
287    kAggressivesOptionQuickSpindownEnable  = 0x00000100,
288    kAggressivesOptionQuickSpindownDisable = 0x00000200,
289    kAggressivesOptionQuickSpindownMask    = 0x00000300
290};
291
292enum {
293    kAggressivesRecordFlagModified         = 0x00000001,
294    kAggressivesRecordFlagMinValue         = 0x00000002
295};
296
297// gDarkWakeFlags
298enum {
299    kDarkWakeFlagHIDTickleEarly      = 0x01, // hid tickle before gfx suppression
300    kDarkWakeFlagHIDTickleLate       = 0x02, // hid tickle after gfx suppression
301    kDarkWakeFlagHIDTickleNone       = 0x03, // hid tickle is not posted
302    kDarkWakeFlagHIDTickleMask       = 0x03,
303    kDarkWakeFlagAlarmIsDark         = 0x0100,
304    kDarkWakeFlagGraphicsPowerState1 = 0x0200,
305    kDarkWakeFlagAudioNotSuppressed  = 0x0400
306};
307
308static IOPMrootDomain * gRootDomain;
309static IONotifier *     gSysPowerDownNotifier = 0;
310static UInt32           gSleepOrShutdownPending = 0;
311static UInt32           gWillShutdown = 0;
312static UInt32           gPagingOff = 0;
313static UInt32           gSleepWakeUUIDIsSet = false;
314static uint32_t         gAggressivesState = 0;
315
316uuid_string_t bootsessionuuid_string;
317
318static uint32_t         gDarkWakeFlags = kDarkWakeFlagHIDTickleNone;
319static PMStatsStruct    gPMStats;
320
321#if HIBERNATION
322static IOPMSystemSleepPolicyHandler     gSleepPolicyHandler = 0;
323static IOPMSystemSleepPolicyVariables * gSleepPolicyVars = 0;
324static void *                           gSleepPolicyTarget;
325#endif
326
327struct timeval gIOLastSleepTime;
328struct timeval gIOLastWakeTime;
329
330static char gWakeReasonString[128];
331static bool gWakeReasonSysctlRegistered = false;
332
333// Constants used as arguments to IOPMrootDomain::informCPUStateChange
334#define kCPUUnknownIndex    9999999
335enum {
336    kInformAC = 0,
337    kInformLid = 1,
338    kInformableCount = 2
339};
340
341const OSSymbol *gIOPMStatsApplicationResponseTimedOut;
342const OSSymbol *gIOPMStatsApplicationResponseCancel;
343const OSSymbol *gIOPMStatsApplicationResponseSlow;
344const OSSymbol *gIOPMStatsApplicationResponsePrompt;
345const OSSymbol *gIOPMStatsDriverPSChangeSlow;
346
347#define kBadPMFeatureID     0
348
349/*
350 * PMSettingHandle
351 * Opaque handle passed to clients of registerPMSettingController()
352 */
353class PMSettingHandle : public OSObject
354{
355    OSDeclareFinalStructors( PMSettingHandle )
356    friend class PMSettingObject;
357
358private:
359    PMSettingObject *pmso;
360    void free(void);
361};
362
363/*
364 * PMSettingObject
365 * Internal object to track each PM setting controller
366 */
367class PMSettingObject : public OSObject
368{
369    OSDeclareFinalStructors( PMSettingObject )
370    friend class IOPMrootDomain;
371
372private:
373    queue_head_t                    calloutQueue;
374    thread_t                        waitThread;
375    IOPMrootDomain                  *parent;
376    PMSettingHandle                 *pmsh;
377    IOPMSettingControllerCallback   func;
378    OSObject                        *target;
379    uintptr_t                       refcon;
380    uint32_t                        *publishedFeatureID;
381    uint32_t                        settingCount;
382    bool                            disabled;
383
384    void free(void);
385
386public:
387    static PMSettingObject *pmSettingObject(
388                IOPMrootDomain                  *parent_arg,
389                IOPMSettingControllerCallback   handler_arg,
390                OSObject                        *target_arg,
391                uintptr_t                       refcon_arg,
392                uint32_t                        supportedPowerSources,
393                const OSSymbol                  *settings[],
394                OSObject                        **handle_obj);
395
396    void dispatchPMSetting(const OSSymbol *type, OSObject *object);
397    void clientHandleFreed(void);
398};
399
400struct PMSettingCallEntry {
401    queue_chain_t   link;
402    thread_t        thread;
403};
404
405#define PMSETTING_LOCK()    IOLockLock(settingsCtrlLock)
406#define PMSETTING_UNLOCK()  IOLockUnlock(settingsCtrlLock)
407#define PMSETTING_WAIT(p)   IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
408#define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
409
410/*
411 * PMTraceWorker
412 * Internal helper object for logging trace points to RTC
413 * IOPMrootDomain and only IOPMrootDomain should instantiate
414 * exactly one of these.
415 */
416
417typedef void (*IOPMTracePointHandler)(
418        void * target, uint32_t code, uint32_t data );
419
420class PMTraceWorker : public OSObject
421{
422    OSDeclareDefaultStructors(PMTraceWorker)
423public:
424    typedef enum { kPowerChangeStart, kPowerChangeCompleted } change_t;
425
426    static PMTraceWorker        *tracer( IOPMrootDomain * );
427    void                        tracePCIPowerChange(change_t, IOService *, uint32_t, uint32_t);
428    void                        tracePoint(uint8_t phase);
429    void                        tracePoint(uint8_t phase, uint8_t data8);
430    void                        traceDetail(uint32_t detail);
431    void                        traceLoginWindowPhase(uint8_t phase);
432    int                         recordTopLevelPCIDevice(IOService *);
433    void                        RTC_TRACE(void);
434    virtual bool                serialize(OSSerialize *s) const;
435
436    IOPMTracePointHandler       tracePointHandler;
437    void *                      tracePointTarget;
438    uint64_t                    getPMStatusCode();
439private:
440    IOPMrootDomain              *owner;
441    IOLock                      *pciMappingLock;
442    OSArray                     *pciDeviceBitMappings;
443
444    uint8_t                     addedToRegistry;
445    uint8_t                     tracePhase;
446    uint8_t                     loginWindowPhase;
447    uint8_t                     traceData8;
448    uint32_t                    traceData32;
449};
450
451/*
452 * PMAssertionsTracker
453 * Tracks kernel and user space PM assertions
454 */
455class PMAssertionsTracker : public OSObject
456{
457    OSDeclareFinalStructors(PMAssertionsTracker)
458public:
459    static PMAssertionsTracker  *pmAssertionsTracker( IOPMrootDomain * );
460
461    IOReturn                    createAssertion(IOPMDriverAssertionType, IOPMDriverAssertionLevel, IOService *, const char *, IOPMDriverAssertionID *);
462    IOReturn                    releaseAssertion(IOPMDriverAssertionID);
463    IOReturn                    setAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
464    IOReturn                    setUserAssertionLevels(IOPMDriverAssertionType);
465
466    OSArray                     *copyAssertionsArray(void);
467    IOPMDriverAssertionType     getActivatedAssertions(void);
468    IOPMDriverAssertionLevel    getAssertionLevel(IOPMDriverAssertionType);
469
470    IOReturn                    handleCreateAssertion(OSData *);
471    IOReturn                    handleReleaseAssertion(IOPMDriverAssertionID);
472    IOReturn                    handleSetAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
473    IOReturn                    handleSetUserAssertionLevels(void * arg0);
474    void                        publishProperties(void);
475
476private:
477    typedef struct {
478        IOPMDriverAssertionID       id;
479        IOPMDriverAssertionType     assertionBits;
480        uint64_t                    createdTime;
481        uint64_t                    modifiedTime;
482        const OSSymbol              *ownerString;
483        IOService                   *ownerService;
484        uint64_t                    registryEntryID;
485        IOPMDriverAssertionLevel    level;
486    } PMAssertStruct;
487
488    uint32_t                    tabulateProducerCount;
489    uint32_t                    tabulateConsumerCount;
490
491    PMAssertStruct              *detailsForID(IOPMDriverAssertionID, int *);
492    void                        tabulate(void);
493
494    IOPMrootDomain              *owner;
495    OSArray                     *assertionsArray;
496    IOLock                      *assertionsArrayLock;
497    IOPMDriverAssertionID       issuingUniqueID __attribute__((aligned(8))); /* aligned for atomic access */
498    IOPMDriverAssertionType     assertionsKernel;
499    IOPMDriverAssertionType     assertionsUser;
500    IOPMDriverAssertionType     assertionsCombined;
501};
502
503OSDefineMetaClassAndFinalStructors(PMAssertionsTracker, OSObject);
504
505/*
506 * PMHaltWorker
507 * Internal helper object for Shutdown/Restart notifications.
508 */
509#define kPMHaltMaxWorkers   8
510#define kPMHaltTimeoutMS    100
511
512class PMHaltWorker : public OSObject
513{
514    OSDeclareFinalStructors( PMHaltWorker )
515
516public:
517    IOService *  service;    // service being worked on
518    AbsoluteTime startTime;  // time when work started
519    int          depth;      // work on nubs at this PM-tree depth
520    int          visits;     // number of nodes visited (debug)
521    IOLock *     lock;
522    bool         timeout;    // service took too long
523
524    static  PMHaltWorker * worker( void );
525    static  void main( void * arg, wait_result_t waitResult );
526    static  void work( PMHaltWorker * me );
527    static  void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
528    virtual void free( void );
529};
530
531OSDefineMetaClassAndFinalStructors( PMHaltWorker, OSObject )
532
533
534#define super IOService
535OSDefineMetaClassAndFinalStructors(IOPMrootDomain, IOService)
536
537static void IOPMRootDomainWillShutdown(void)
538{
539    if (OSCompareAndSwap(0, 1, &gWillShutdown))
540    {
541    OSKext::willShutdown();
542    for (int i = 0; i < 100; i++)
543    {
544        if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending)) break;
545        IOSleep( 100 );
546    }
547    }
548}
549
550extern "C"
551{
552    IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
553    {
554        return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
555    }
556
557    IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
558    {
559        return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
560    }
561
562    IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
563    {
564        return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
565    }
566
567    IOReturn vetoSleepWakeNotification(void * PMrefcon)
568    {
569        return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
570    }
571
572    IOReturn rootDomainRestart ( void )
573    {
574        return gRootDomain->restartSystem();
575    }
576
577    IOReturn rootDomainShutdown ( void )
578    {
579        return gRootDomain->shutdownSystem();
580    }
581
582    void IOSystemShutdownNotification(void)
583    {
584        IOPMRootDomainWillShutdown();
585        if (OSCompareAndSwap(0, 1, &gPagingOff))
586        {
587            gRootDomain->handlePlatformHaltRestart(kPEPagingOff);
588        }
589    }
590
591    int sync_internal(void);
592}
593
594/*
595A device is always in the highest power state which satisfies its driver,
596its policy-maker, and any power children it has, but within the constraint
597of the power state provided by its parent.  The driver expresses its desire by
598calling changePowerStateTo(), the policy-maker expresses its desire by calling
599changePowerStateToPriv(), and the children express their desires by calling
600requestPowerDomainState().
601
602The Root Power Domain owns the policy for idle and demand sleep for the system.
603It is a power-managed IOService just like the others in the system.
604It implements several power states which map to what we see as Sleep and On.
605
606The sleep policy is as follows:
6071. Sleep is prevented if the case is open so that nobody will think the machine
608   is off and plug/unplug cards.
6092. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
6103. System cannot Sleep if some object in the tree is in a power state marked
611   kIOPMPreventSystemSleep.
612
613These three conditions are enforced using the "driver clamp" by calling
614changePowerStateTo(). For example, if the case is opened,
615changePowerStateTo(ON_STATE) is called to hold the system on regardless
616of the desires of the children of the root or the state of the other clamp.
617
618Demand Sleep is initiated by pressing the front panel power button, closing
619the clamshell, or selecting the menu item. In this case the root's parent
620actually initiates the power state change so that the root domain has no
621choice and does not give applications the opportunity to veto the change.
622
623Idle Sleep occurs if no objects in the tree are in a state marked
624kIOPMPreventIdleSleep.  When this is true, the root's children are not holding
625the root on, so it sets the "policy-maker clamp" by calling
626changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
627This timer is set for the difference between the sleep timeout slider and the
628display dim timeout slider. When the timer expires, it releases its clamp and
629now nothing is holding it awake, so it falls asleep.
630
631Demand sleep is prevented when the system is booting.  When preferences are
632transmitted by the loginwindow at the end of boot, a flag is cleared,
633and this allows subsequent Demand Sleep.
634*/
635
636//******************************************************************************
637
638IOPMrootDomain * IOPMrootDomain::construct( void )
639{
640    IOPMrootDomain  *root;
641
642    root = new IOPMrootDomain;
643    if( root)
644        root->init();
645
646    return( root );
647}
648
649//******************************************************************************
650
651static void disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
652{
653    IOService * rootDomain = (IOService *) p0;
654    uint32_t    notifyRef  = (uint32_t)(uintptr_t) p1;
655    uint32_t    powerState = rootDomain->getPowerState();
656
657    DLOG("disk_sync_callout ps=%u\n", powerState);
658
659    if (ON_STATE == powerState)
660    {
661        sync_internal();
662    }
663#if HIBERNATION
664    else
665    {
666        IOHibernateSystemPostWake();
667    }
668#endif
669
670    rootDomain->allowPowerChange(notifyRef);
671    DLOG("disk_sync_callout finish\n");
672}
673
674//******************************************************************************
675
676static void hib_debugSetup_callout( thread_call_param_t p0, thread_call_param_t p1 )
677{
678    IOService * rootDomain = (IOService *) p0;
679    uint32_t    notifyRef  = (uint32_t)(uintptr_t) p1;
680
681#if	HIBERNATION
682    IOHibernateOpenForDebugData();
683#endif
684
685    rootDomain->allowPowerChange(notifyRef);
686    DLOG("hib_debugSetup_callout finish\n");
687}
688//******************************************************************************
689
690static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime )
691{
692    AbsoluteTime    endTime;
693    UInt64          nano = 0;
694
695    clock_get_uptime(&endTime);
696    if (CMP_ABSOLUTETIME(&endTime, startTime) > 0)
697    {
698        SUB_ABSOLUTETIME(&endTime, startTime);
699        absolutetime_to_nanoseconds(endTime, &nano);
700    }
701
702    return (UInt32)(nano / 1000000ULL);
703}
704
705//******************************************************************************
706
707static int
708sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
709{
710  struct timeval *swt = (struct timeval *)arg1;
711  struct proc *p = req->p;
712
713  if (p == kernproc) {
714    return sysctl_io_opaque(req, swt, sizeof(*swt), NULL);
715  } else if(proc_is64bit(p)) {
716    struct user64_timeval t;
717    t.tv_sec = swt->tv_sec;
718    t.tv_usec = swt->tv_usec;
719    return sysctl_io_opaque(req, &t, sizeof(t), NULL);
720  } else {
721    struct user32_timeval t;
722    t.tv_sec = swt->tv_sec;
723    t.tv_usec = swt->tv_usec;
724    return sysctl_io_opaque(req, &t, sizeof(t), NULL);
725  }
726}
727
728static SYSCTL_PROC(_kern, OID_AUTO, sleeptime,
729        CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
730        &gIOLastSleepTime, 0, sysctl_sleepwaketime, "S,timeval", "");
731
732static SYSCTL_PROC(_kern, OID_AUTO, waketime,
733        CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
734        &gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", "");
735
736
737static int
738sysctl_willshutdown
739(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
740{
741    int new_value, changed;
742    int error = sysctl_io_number(req, gWillShutdown, sizeof(int), &new_value, &changed);
743    if (changed) {
744    if (!gWillShutdown && (new_value == 1)) {
745        IOPMRootDomainWillShutdown();
746    } else
747        error = EINVAL;
748    }
749    return(error);
750}
751
752static SYSCTL_PROC(_kern, OID_AUTO, willshutdown,
753        CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
754        0, 0, sysctl_willshutdown, "I", "");
755
756
757static int
758sysctl_progressmeterenable
759(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
760{
761    int error;
762    int new_value, changed;
763
764    error = sysctl_io_number(req, vc_progressmeter_enable, sizeof(int), &new_value, &changed);
765
766    if (changed) vc_enable_progressmeter(new_value);
767
768    return (error);
769}
770
771static int
772sysctl_progressmeter
773(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
774{
775    int error;
776    int new_value, changed;
777
778    error = sysctl_io_number(req, vc_progressmeter_value, sizeof(int), &new_value, &changed);
779
780    if (changed) vc_set_progressmeter(new_value);
781
782    return (error);
783}
784
785static SYSCTL_PROC(_kern, OID_AUTO, progressmeterenable,
786        CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
787        0, 0, sysctl_progressmeterenable, "I", "");
788
789static SYSCTL_PROC(_kern, OID_AUTO, progressmeter,
790        CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
791        0, 0, sysctl_progressmeter, "I", "");
792
793
794static int
795sysctl_wakereason SYSCTL_HANDLER_ARGS
796{
797    char wr[ sizeof(gWakeReasonString) ];
798
799    wr[0] = '\0';
800    if (gRootDomain)
801        gRootDomain->copyWakeReasonString(wr, sizeof(wr));
802
803    return sysctl_io_string(req, wr, 0, 0, NULL);
804}
805
806SYSCTL_PROC(_kern, OID_AUTO, wakereason,
807    CTLTYPE_STRING| CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
808    NULL, 0, sysctl_wakereason, "A", "wakereason");
809
810static SYSCTL_INT(_debug, OID_AUTO, darkwake, CTLFLAG_RW, &gDarkWakeFlags, 0, "");
811
812static const OSSymbol * gIOPMSettingAutoWakeCalendarKey;
813static const OSSymbol * gIOPMSettingAutoWakeSecondsKey;
814static const OSSymbol * gIOPMSettingDebugWakeRelativeKey;
815static const OSSymbol * gIOPMSettingMaintenanceWakeCalendarKey;
816static const OSSymbol * gIOPMSettingSleepServiceWakeCalendarKey;
817static const OSSymbol * gIOPMSettingSilentRunningKey;
818static const OSSymbol * gIOPMUserTriggeredFullWakeKey;
819static const OSSymbol * gIOPMUserIsActiveKey;
820
821//******************************************************************************
822// start
823//
824//******************************************************************************
825
826#define kRootDomainSettingsCount        17
827
828bool IOPMrootDomain::start( IOService * nub )
829{
830    OSIterator      *psIterator;
831    OSDictionary    *tmpDict;
832    IORootParent *   patriarch;
833#if defined(__i386__) || defined(__x86_64__)
834    IONotifier   *   notifier;
835#endif
836
837    super::start(nub);
838
839    gRootDomain = this;
840    gIOPMSettingAutoWakeCalendarKey = OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey);
841    gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
842    gIOPMSettingDebugWakeRelativeKey = OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey);
843    gIOPMSettingMaintenanceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey);
844    gIOPMSettingSleepServiceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey);
845    gIOPMSettingSilentRunningKey = OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey);
846    gIOPMUserTriggeredFullWakeKey = OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey);
847    gIOPMUserIsActiveKey = OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey);
848
849    gIOPMStatsApplicationResponseTimedOut = OSSymbol::withCString(kIOPMStatsResponseTimedOut);
850    gIOPMStatsApplicationResponseCancel = OSSymbol::withCString(kIOPMStatsResponseCancel);
851    gIOPMStatsApplicationResponseSlow = OSSymbol::withCString(kIOPMStatsResponseSlow);
852    gIOPMStatsApplicationResponsePrompt = OSSymbol::withCString(kIOPMStatsResponsePrompt);
853    gIOPMStatsDriverPSChangeSlow = OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow);
854
855    sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
856    sleepMessagePEFunction = OSSymbol::withCString("IOPMSystemSleepMessage");
857
858    const OSSymbol  *settingsArr[kRootDomainSettingsCount] =
859        {
860            OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
861            gIOPMSettingAutoWakeSecondsKey,
862            OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
863            gIOPMSettingAutoWakeCalendarKey,
864            OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
865            gIOPMSettingDebugWakeRelativeKey,
866            OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
867            OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
868            OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
869            OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
870            OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
871            OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey),
872            OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
873            OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey),
874            OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey),
875            OSSymbol::withCString(kIOPMStateConsoleShutdown),
876            gIOPMSettingSilentRunningKey
877        };
878
879    PE_parse_boot_argn("darkwake", &gDarkWakeFlags, sizeof(gDarkWakeFlags));
880
881    queue_init(&aggressivesQueue);
882    aggressivesThreadCall = thread_call_allocate(handleAggressivesFunction, this);
883    aggressivesData = OSData::withCapacity(
884                        sizeof(AggressivesRecord) * (kPMLastAggressivenessType + 4));
885
886    featuresDictLock = IOLockAlloc();
887    settingsCtrlLock = IOLockAlloc();
888    wakeEventLock = IOLockAlloc();
889    setPMRootDomain(this);
890
891    extraSleepTimer = thread_call_allocate(
892                        idleSleepTimerExpired,
893                        (thread_call_param_t) this);
894
895    diskSyncCalloutEntry = thread_call_allocate(
896                        &disk_sync_callout,
897                        (thread_call_param_t) this);
898    hibDebugSetupEntry = thread_call_allocate(
899                        &hib_debugSetup_callout,
900                        (thread_call_param_t) this);
901
902#if DARK_TO_FULL_EVALUATE_CLAMSHELL
903    fullWakeThreadCall = thread_call_allocate(
904                            OSMemberFunctionCast(thread_call_func_t, this,
905                                &IOPMrootDomain::fullWakeDelayedWork),
906                            (thread_call_param_t) this);
907#endif
908
909    setProperty(kIOSleepSupportedKey, true);
910
911    bzero(&gPMStats, sizeof(gPMStats));
912
913    pmTracer = PMTraceWorker::tracer(this);
914
915    pmAssertions = PMAssertionsTracker::pmAssertionsTracker(this);
916
917    userDisabledAllSleep = false;
918    systemBooting = true;
919    sleepSlider = 0;
920    idleSleepTimerPending = false;
921    wrangler = NULL;
922    clamshellClosed    = false;
923    clamshellExists    = false;
924    clamshellDisabled  = true;
925    acAdaptorConnected = true;
926    clamshellSleepDisabled = false;
927    gWakeReasonString[0] = '\0';
928
929    // Initialize to user active.
930    // Will never transition to user inactive w/o wrangler.
931    fullWakeReason = kFullWakeReasonLocalUser;
932    userIsActive = userWasActive = true;
933    setProperty(gIOPMUserIsActiveKey, kOSBooleanTrue);
934
935    // Set the default system capabilities at boot.
936    _currentCapability = kIOPMSystemCapabilityCPU      |
937                         kIOPMSystemCapabilityGraphics |
938                         kIOPMSystemCapabilityAudio    |
939                         kIOPMSystemCapabilityNetwork;
940
941    _pendingCapability = _currentCapability;
942    _desiredCapability = _currentCapability;
943    _highestCapability = _currentCapability;
944    setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
945
946    queuedSleepWakeUUIDString = NULL;
947    initializeBootSessionUUID();
948    pmStatsAppResponses     = OSArray::withCapacity(5);
949    _statsNameKey           = OSSymbol::withCString(kIOPMStatsNameKey);
950    _statsPIDKey            = OSSymbol::withCString(kIOPMStatsPIDKey);
951    _statsTimeMSKey         = OSSymbol::withCString(kIOPMStatsTimeMSKey);
952    _statsResponseTypeKey   = OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey);
953    _statsMessageTypeKey    = OSSymbol::withCString(kIOPMStatsMessageTypeKey);
954    _statsPowerCapsKey      = OSSymbol::withCString(kIOPMStatsPowerCapabilityKey);
955
956    pmStatsLock = IOLockAlloc();
957    idxPMCPUClamshell = kCPUUnknownIndex;
958    idxPMCPULimitedPower = kCPUUnknownIndex;
959
960    tmpDict = OSDictionary::withCapacity(1);
961    setProperty(kRootDomainSupportedFeatures, tmpDict);
962    tmpDict->release();
963
964    settingsCallbacks = OSDictionary::withCapacity(1);
965
966    // Create a list of the valid PM settings that we'll relay to
967    // interested clients in setProperties() => setPMSetting()
968    allowedPMSettings = OSArray::withObjects(
969                    (const OSObject **)settingsArr,
970                    kRootDomainSettingsCount,
971                    0);
972
973    // List of PM settings that should not automatically publish itself
974    // as a feature when registered by a listener.
975    noPublishPMSettings = OSArray::withObjects(
976                    (const OSObject **) &gIOPMSettingSilentRunningKey, 1, 0);
977
978    fPMSettingsDict = OSDictionary::withCapacity(5);
979    preventIdleSleepList = OSSet::withCapacity(8);
980    preventSystemSleepList = OSSet::withCapacity(2);
981
982    PMinit();   // creates gIOPMWorkLoop
983
984    // Create IOPMPowerStateQueue used to queue external power
985    // events, and to handle those events on the PM work loop.
986    pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(
987        this, OSMemberFunctionCast(IOEventSource::Action, this,
988                &IOPMrootDomain::dispatchPowerEvent));
989    getPMworkloop()->addEventSource(pmPowerStateQueue);
990#ifdef CHECK_THREAD_CONTEXT
991    gIOPMWorkLoop = getPMworkloop();
992#endif
993
994    // create our power parent
995    patriarch = new IORootParent;
996    patriarch->init();
997    patriarch->attach(this);
998    patriarch->start(this);
999    patriarch->addPowerChild(this);
1000
1001    registerPowerDriver(this, ourPowerStates, NUM_POWER_STATES);
1002    changePowerStateToPriv(ON_STATE);
1003
1004    // install power change handler
1005    gSysPowerDownNotifier = registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
1006
1007#if !NO_KERNEL_HID
1008    // Register for a notification when IODisplayWrangler is published
1009    if ((tmpDict = serviceMatching("IODisplayWrangler")))
1010    {
1011        _displayWranglerNotifier = addMatchingNotification(
1012                gIOPublishNotification, tmpDict,
1013                (IOServiceMatchingNotificationHandler) &displayWranglerMatchPublished,
1014                this, 0);
1015        tmpDict->release();
1016    }
1017#endif
1018
1019#if defined(__i386__) || defined(__x86_64__)
1020
1021    if ((tmpDict = serviceMatching("IODTNVRAM")))
1022    {
1023        notifier = addMatchingNotification(
1024                gIOFirstPublishNotification, tmpDict,
1025                (IOServiceMatchingNotificationHandler) &IONVRAMMatchPublished,
1026                this, 0);
1027        tmpDict->release();
1028    }
1029
1030    wranglerIdleSettings = NULL;
1031    OSNumber * wranglerIdlePeriod = NULL;
1032    wranglerIdleSettings = OSDictionary::withCapacity(1);
1033    wranglerIdlePeriod  = OSNumber::withNumber(kDefaultWranglerIdlePeriod, 32);
1034
1035    if(wranglerIdleSettings && wranglerIdlePeriod)
1036        wranglerIdleSettings->setObject(kIORequestWranglerIdleKey,
1037                                        wranglerIdlePeriod);
1038
1039    if(wranglerIdlePeriod)
1040        wranglerIdlePeriod->release();
1041#endif
1042
1043    const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
1044    setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
1045    ucClassName->release();
1046
1047    // IOBacklightDisplay can take a long time to load at boot, or it may
1048    // not load at all if you're booting with clamshell closed. We publish
1049    // 'DisplayDims' here redundantly to get it published early and at all.
1050    psIterator = getMatchingServices( serviceMatching("IOPMPowerSource") );
1051    if( psIterator && psIterator->getNextObject() )
1052    {
1053        // There's at least one battery on the system, so we publish
1054        // 'DisplayDims' support for the LCD.
1055        publishFeature("DisplayDims");
1056    }
1057    if(psIterator) {
1058        psIterator->release();
1059    }
1060
1061    sysctl_register_oid(&sysctl__kern_sleeptime);
1062    sysctl_register_oid(&sysctl__kern_waketime);
1063    sysctl_register_oid(&sysctl__kern_willshutdown);
1064    sysctl_register_oid(&sysctl__kern_progressmeterenable);
1065    sysctl_register_oid(&sysctl__kern_progressmeter);
1066    sysctl_register_oid(&sysctl__kern_wakereason);
1067
1068#if HIBERNATION
1069    IOHibernateSystemInit(this);
1070#endif
1071
1072    registerService();                      // let clients find us
1073
1074    return true;
1075}
1076
1077//******************************************************************************
1078// setProperties
1079//
1080// Receive a setProperty call
1081// The "System Boot" property means the system is completely booted.
1082//******************************************************************************
1083
1084IOReturn IOPMrootDomain::setProperties( OSObject * props_obj )
1085{
1086    IOReturn        return_value = kIOReturnSuccess;
1087    OSDictionary    *dict = OSDynamicCast(OSDictionary, props_obj);
1088    OSBoolean       *b;
1089    OSNumber        *n;
1090    const OSSymbol  *key;
1091    OSObject        *obj;
1092    OSCollectionIterator * iter = 0;
1093
1094    const OSSymbol *publish_simulated_battery_string    = OSSymbol::withCString("SoftwareSimulatedBatteries");
1095    const OSSymbol *boot_complete_string                = OSSymbol::withCString("System Boot Complete");
1096    const OSSymbol *sys_shutdown_string                 = OSSymbol::withCString("System Shutdown");
1097    const OSSymbol *stall_halt_string                   = OSSymbol::withCString("StallSystemAtHalt");
1098    const OSSymbol *battery_warning_disabled_string     = OSSymbol::withCString("BatteryWarningsDisabled");
1099    const OSSymbol *idle_seconds_string                 = OSSymbol::withCString("System Idle Seconds");
1100    const OSSymbol *sleepdisabled_string                = OSSymbol::withCString("SleepDisabled");
1101    const OSSymbol *ondeck_sleepwake_uuid_string        = OSSymbol::withCString(kIOPMSleepWakeUUIDKey);
1102    const OSSymbol *loginwindow_tracepoint_string       = OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey);
1103#if HIBERNATION
1104    const OSSymbol *hibernatemode_string                = OSSymbol::withCString(kIOHibernateModeKey);
1105    const OSSymbol *hibernatefile_string                = OSSymbol::withCString(kIOHibernateFileKey);
1106    const OSSymbol *hibernatefilemin_string            = OSSymbol::withCString(kIOHibernateFileMinSizeKey);
1107    const OSSymbol *hibernatefilemax_string            = OSSymbol::withCString(kIOHibernateFileMaxSizeKey);
1108    const OSSymbol *hibernatefreeratio_string           = OSSymbol::withCString(kIOHibernateFreeRatioKey);
1109    const OSSymbol *hibernatefreetime_string            = OSSymbol::withCString(kIOHibernateFreeTimeKey);
1110#endif
1111
1112    if (!dict)
1113    {
1114        return_value = kIOReturnBadArgument;
1115        goto exit;
1116    }
1117
1118    iter = OSCollectionIterator::withCollection(dict);
1119    if (!iter)
1120    {
1121        return_value = kIOReturnNoMemory;
1122        goto exit;
1123    }
1124
1125    while ((key = (const OSSymbol *) iter->getNextObject()) &&
1126           (obj = dict->getObject(key)))
1127    {
1128        if (key->isEqualTo(publish_simulated_battery_string))
1129        {
1130            if (OSDynamicCast(OSBoolean, obj))
1131                publishResource(key, kOSBooleanTrue);
1132        }
1133        else if (key->isEqualTo(idle_seconds_string))
1134        {
1135            if ((n = OSDynamicCast(OSNumber, obj)))
1136            {
1137                setProperty(key, n);
1138                idleSeconds = n->unsigned32BitValue();
1139            }
1140        }
1141        else if (key->isEqualTo(boot_complete_string))
1142        {
1143            pmPowerStateQueue->submitPowerEvent(kPowerEventSystemBootCompleted);
1144        }
1145        else if (key->isEqualTo(sys_shutdown_string))
1146        {
1147            if ((b = OSDynamicCast(OSBoolean, obj)))
1148                pmPowerStateQueue->submitPowerEvent(kPowerEventSystemShutdown, (void *) b);
1149        }
1150        else if (key->isEqualTo(battery_warning_disabled_string))
1151        {
1152            setProperty(key, obj);
1153        }
1154#if HIBERNATION
1155        else if (key->isEqualTo(hibernatemode_string) ||
1156                 key->isEqualTo(hibernatefilemin_string) ||
1157                 key->isEqualTo(hibernatefilemax_string) ||
1158                 key->isEqualTo(hibernatefreeratio_string) ||
1159                 key->isEqualTo(hibernatefreetime_string))
1160        {
1161            if ((n = OSDynamicCast(OSNumber, obj)))
1162                setProperty(key, n);
1163        }
1164        else if (key->isEqualTo(hibernatefile_string))
1165        {
1166            OSString * str = OSDynamicCast(OSString, obj);
1167            if (str) setProperty(key, str);
1168        }
1169#endif
1170        else if (key->isEqualTo(sleepdisabled_string))
1171        {
1172            if ((b = OSDynamicCast(OSBoolean, obj)))
1173            {
1174                setProperty(key, b);
1175                pmPowerStateQueue->submitPowerEvent(kPowerEventUserDisabledSleep, (void *) b);
1176            }
1177        }
1178        else if (key->isEqualTo(ondeck_sleepwake_uuid_string))
1179        {
1180            obj->retain();
1181            pmPowerStateQueue->submitPowerEvent(kPowerEventQueueSleepWakeUUID, (void *)obj);
1182        }
1183        else if (key->isEqualTo(loginwindow_tracepoint_string))
1184        {
1185            if (pmTracer && (n = OSDynamicCast(OSNumber, obj)))
1186                pmTracer->traceLoginWindowPhase(n->unsigned8BitValue());
1187        }
1188        else if (key->isEqualTo(kIOPMDeepSleepEnabledKey)       ||
1189                 key->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey)  ||
1190                 key->isEqualTo(kIOPMAutoPowerOffEnabledKey)    ||
1191                 key->isEqualTo(stall_halt_string))
1192        {
1193            if ((b = OSDynamicCast(OSBoolean, obj)))
1194                setProperty(key, b);
1195        }
1196        else if (key->isEqualTo(kIOPMDeepSleepDelayKey) ||
1197                 key->isEqualTo(kIOPMAutoPowerOffDelayKey) ||
1198                 key->isEqualTo(kIOPMAutoPowerOffTimerKey))
1199        {
1200            if ((n = OSDynamicCast(OSNumber, obj)))
1201                setProperty(key, n);
1202        }
1203        else if (key->isEqualTo(kIOPMUserWakeAlarmScheduledKey))
1204        {
1205            if (kOSBooleanTrue == obj)
1206                OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_userScheduledAlarm);
1207            else
1208                OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_userScheduledAlarm);
1209            DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm);
1210        }
1211
1212        // Relay our allowed PM settings onto our registered PM clients
1213        else if ((allowedPMSettings->getNextIndexOfObject(key, 0) != (unsigned int) -1))
1214        {
1215            if ((gIOPMSettingAutoWakeSecondsKey == key) && ((n = OSDynamicCast(OSNumber, obj))))
1216            {
1217                UInt32 rsecs = n->unsigned32BitValue();
1218                if (!rsecs)
1219                autoWakeStart = autoWakeEnd = 0;
1220                else
1221                {
1222                AbsoluteTime deadline;
1223                clock_interval_to_deadline(rsecs + kAutoWakePostWindow, kSecondScale, &deadline);
1224                autoWakeEnd = AbsoluteTime_to_scalar(&deadline);
1225                if (rsecs > kAutoWakePreWindow)
1226                    rsecs -= kAutoWakePreWindow;
1227                else
1228                    rsecs = 0;
1229                clock_interval_to_deadline(rsecs, kSecondScale, &deadline);
1230                autoWakeStart = AbsoluteTime_to_scalar(&deadline);
1231                }
1232            }
1233
1234            return_value = setPMSetting(key, obj);
1235            if (kIOReturnSuccess != return_value)
1236                break;
1237
1238            if (gIOPMSettingDebugWakeRelativeKey == key)
1239            {
1240                if ((n = OSDynamicCast(OSNumber, obj)) &&
1241                    (_debugWakeSeconds = n->unsigned32BitValue()))
1242                {
1243                    OSBitOrAtomic(kIOPMAlarmBitDebugWake, &_scheduledAlarms);
1244                }
1245                else
1246                {
1247                    _debugWakeSeconds = 0;
1248                    OSBitAndAtomic(~kIOPMAlarmBitDebugWake, &_scheduledAlarms);
1249                }
1250                DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
1251            }
1252            else if (gIOPMSettingAutoWakeCalendarKey == key)
1253            {
1254                OSData * data;
1255                if ((data = OSDynamicCast(OSData, obj)) &&
1256                    (data->getLength() == sizeof(IOPMCalendarStruct)))
1257                {
1258                    const IOPMCalendarStruct * cs =
1259                        (const IOPMCalendarStruct *) data->getBytesNoCopy();
1260
1261                    if (cs->year)
1262                        OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_scheduledAlarms);
1263                    else
1264                        OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_scheduledAlarms);
1265                    DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
1266                }
1267            }
1268        }
1269        else
1270        {
1271            DLOG("setProperties(%s) not handled\n", key->getCStringNoCopy());
1272        }
1273    }
1274
1275exit:
1276    if(publish_simulated_battery_string) publish_simulated_battery_string->release();
1277    if(boot_complete_string) boot_complete_string->release();
1278    if(sys_shutdown_string) sys_shutdown_string->release();
1279    if(stall_halt_string) stall_halt_string->release();
1280    if(battery_warning_disabled_string) battery_warning_disabled_string->release();
1281    if(idle_seconds_string) idle_seconds_string->release();
1282    if(sleepdisabled_string) sleepdisabled_string->release();
1283    if(ondeck_sleepwake_uuid_string) ondeck_sleepwake_uuid_string->release();
1284    if(loginwindow_tracepoint_string) loginwindow_tracepoint_string->release();
1285#if HIBERNATION
1286    if(hibernatemode_string) hibernatemode_string->release();
1287    if(hibernatefile_string) hibernatefile_string->release();
1288    if(hibernatefreeratio_string) hibernatefreeratio_string->release();
1289    if(hibernatefreetime_string) hibernatefreetime_string->release();
1290#endif
1291    if (iter) iter->release();
1292    return return_value;
1293}
1294
1295// MARK: -
1296// MARK: Aggressiveness
1297
1298//******************************************************************************
1299// setAggressiveness
1300//
1301// Override IOService::setAggressiveness()
1302//******************************************************************************
1303
1304IOReturn IOPMrootDomain::setAggressiveness(
1305    unsigned long   type,
1306    unsigned long   value )
1307{
1308    return setAggressiveness( type, value, 0 );
1309}
1310
1311/*
1312 * Private setAggressiveness() with an internal options argument.
1313 */
1314IOReturn IOPMrootDomain::setAggressiveness(
1315    unsigned long   type,
1316    unsigned long   value,
1317    IOOptionBits    options )
1318{
1319    AggressivesRequest *    entry;
1320    AggressivesRequest *    request;
1321    bool                    found = false;
1322
1323    DLOG("setAggressiveness(%x) 0x%x = %u\n",
1324        (uint32_t) options, (uint32_t) type, (uint32_t) value);
1325
1326    request = IONew(AggressivesRequest, 1);
1327    if (!request)
1328        return kIOReturnNoMemory;
1329
1330    memset(request, 0, sizeof(*request));
1331    request->options  = options;
1332    request->dataType = kAggressivesRequestTypeRecord;
1333    request->data.record.type  = (uint32_t) type;
1334    request->data.record.value = (uint32_t) value;
1335
1336    AGGRESSIVES_LOCK();
1337
1338    // Update disk quick spindown flag used by getAggressiveness().
1339    // Never merge requests with quick spindown flags set.
1340
1341    if (options & kAggressivesOptionQuickSpindownEnable)
1342        gAggressivesState |= kAggressivesStateQuickSpindown;
1343    else if (options & kAggressivesOptionQuickSpindownDisable)
1344        gAggressivesState &= ~kAggressivesStateQuickSpindown;
1345    else
1346    {
1347        // Coalesce requests with identical aggressives types.
1348        // Deal with callers that calls us too "aggressively".
1349
1350        queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1351        {
1352            if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1353                (entry->data.record.type == type) &&
1354                ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1355            {
1356                entry->data.record.value = value;
1357                found = true;
1358                break;
1359            }
1360        }
1361    }
1362
1363    if (!found)
1364    {
1365        queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1366    }
1367
1368    AGGRESSIVES_UNLOCK();
1369
1370    if (found)
1371        IODelete(request, AggressivesRequest, 1);
1372
1373    if (options & kAggressivesOptionSynchronous)
1374        handleAggressivesRequests();   // not truly synchronous
1375    else
1376        thread_call_enter(aggressivesThreadCall);
1377
1378    return kIOReturnSuccess;
1379}
1380
1381//******************************************************************************
1382// getAggressiveness
1383//
1384// Override IOService::setAggressiveness()
1385// Fetch the aggressiveness factor with the given type.
1386//******************************************************************************
1387
1388IOReturn IOPMrootDomain::getAggressiveness (
1389    unsigned long   type,
1390    unsigned long * outLevel )
1391{
1392    uint32_t    value  = 0;
1393    int         source = 0;
1394
1395    if (!outLevel)
1396        return kIOReturnBadArgument;
1397
1398    AGGRESSIVES_LOCK();
1399
1400    // Disk quick spindown in effect, report value = 1
1401
1402    if ((gAggressivesState & kAggressivesStateQuickSpindown) &&
1403        (type == kPMMinutesToSpinDown))
1404    {
1405        value  = kAggressivesMinValue;
1406        source = 1;
1407    }
1408
1409    // Consult the pending request queue.
1410
1411    if (!source)
1412    {
1413        AggressivesRequest * entry;
1414
1415        queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1416        {
1417            if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1418                (entry->data.record.type == type) &&
1419                ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1420            {
1421                value  = entry->data.record.value;
1422                source = 2;
1423                break;
1424            }
1425        }
1426    }
1427
1428    // Consult the backend records.
1429
1430    if (!source && aggressivesData)
1431    {
1432        AggressivesRecord * record;
1433        int                 i, count;
1434
1435        count  = aggressivesData->getLength() / sizeof(AggressivesRecord);
1436        record = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1437
1438        for (i = 0; i < count; i++, record++)
1439        {
1440            if (record->type == type)
1441            {
1442                value  = record->value;
1443                source = 3;
1444                break;
1445            }
1446        }
1447    }
1448
1449    AGGRESSIVES_UNLOCK();
1450
1451    if (source)
1452    {
1453        DLOG("getAggressiveness(%d) 0x%x = %u\n",
1454            source, (uint32_t) type, value);
1455        *outLevel = (unsigned long) value;
1456        return kIOReturnSuccess;
1457    }
1458    else
1459    {
1460        DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type);
1461        *outLevel = 0;  // default return = 0, driver may not check for error
1462        return kIOReturnInvalid;
1463    }
1464}
1465
1466//******************************************************************************
1467// joinAggressiveness
1468//
1469// Request from IOService to join future aggressiveness broadcasts.
1470//******************************************************************************
1471
1472IOReturn IOPMrootDomain::joinAggressiveness(
1473    IOService * service )
1474{
1475    AggressivesRequest *    request;
1476
1477    if (!service || (service == this))
1478        return kIOReturnBadArgument;
1479
1480    DLOG("joinAggressiveness %s %p\n", service->getName(), OBFUSCATE(service));
1481
1482    request = IONew(AggressivesRequest, 1);
1483    if (!request)
1484        return kIOReturnNoMemory;
1485
1486    service->retain();  // released by synchronizeAggressives()
1487
1488    memset(request, 0, sizeof(*request));
1489    request->dataType = kAggressivesRequestTypeService;
1490    request->data.service = service;
1491
1492    AGGRESSIVES_LOCK();
1493    queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1494    AGGRESSIVES_UNLOCK();
1495
1496    thread_call_enter(aggressivesThreadCall);
1497
1498    return kIOReturnSuccess;
1499}
1500
1501//******************************************************************************
1502// handleAggressivesRequests
1503//
1504// Backend thread processes all incoming aggressiveness requests in the queue.
1505//******************************************************************************
1506
1507static void
1508handleAggressivesFunction(
1509    thread_call_param_t param1,
1510    thread_call_param_t param2 )
1511{
1512    if (param1)
1513    {
1514        ((IOPMrootDomain *) param1)->handleAggressivesRequests();
1515    }
1516}
1517
1518void IOPMrootDomain::handleAggressivesRequests( void )
1519{
1520    AggressivesRecord *     start;
1521    AggressivesRecord *     record;
1522    AggressivesRequest *    request;
1523    queue_head_t            joinedQueue;
1524    int                     i, count;
1525    bool                    broadcast;
1526    bool                    found;
1527    bool                    pingSelf = false;
1528
1529    AGGRESSIVES_LOCK();
1530
1531    if ((gAggressivesState & kAggressivesStateBusy) || !aggressivesData ||
1532        queue_empty(&aggressivesQueue))
1533        goto unlock_done;
1534
1535    gAggressivesState |= kAggressivesStateBusy;
1536    count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1537    start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1538
1539    do
1540    {
1541        broadcast = false;
1542        queue_init(&joinedQueue);
1543
1544        do
1545        {
1546            // Remove request from the incoming queue in FIFO order.
1547            queue_remove_first(&aggressivesQueue, request, AggressivesRequest *, chain);
1548            switch (request->dataType)
1549            {
1550                case kAggressivesRequestTypeRecord:
1551                    // Update existing record if found.
1552                    found = false;
1553                    for (i = 0, record = start; i < count; i++, record++)
1554                    {
1555                        if (record->type == request->data.record.type)
1556                        {
1557                            found = true;
1558
1559                            if (request->options & kAggressivesOptionQuickSpindownEnable)
1560                            {
1561                                if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1562                                {
1563                                    broadcast = true;
1564                                    record->flags |= (kAggressivesRecordFlagMinValue |
1565                                                      kAggressivesRecordFlagModified);
1566                                    DLOG("disk spindown accelerated, was %u min\n",
1567                                        record->value);
1568                                }
1569                            }
1570                            else if (request->options & kAggressivesOptionQuickSpindownDisable)
1571                            {
1572                                if (record->flags & kAggressivesRecordFlagMinValue)
1573                                {
1574                                    broadcast = true;
1575                                    record->flags |= kAggressivesRecordFlagModified;
1576                                    record->flags &= ~kAggressivesRecordFlagMinValue;
1577                                    DLOG("disk spindown restored to %u min\n",
1578                                        record->value);
1579                                }
1580                            }
1581                            else if (record->value != request->data.record.value)
1582                            {
1583                                record->value = request->data.record.value;
1584                                if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1585                                {
1586                                    broadcast = true;
1587                                    record->flags |= kAggressivesRecordFlagModified;
1588                                }
1589                            }
1590                            break;
1591                        }
1592                    }
1593
1594                    // No matching record, append a new record.
1595                    if (!found &&
1596                        ((request->options & kAggressivesOptionQuickSpindownDisable) == 0))
1597                    {
1598                        AggressivesRecord   newRecord;
1599
1600                        newRecord.flags = kAggressivesRecordFlagModified;
1601                        newRecord.type  = request->data.record.type;
1602                        newRecord.value = request->data.record.value;
1603                        if (request->options & kAggressivesOptionQuickSpindownEnable)
1604                        {
1605                            newRecord.flags |= kAggressivesRecordFlagMinValue;
1606                            DLOG("disk spindown accelerated\n");
1607                        }
1608
1609                        aggressivesData->appendBytes(&newRecord, sizeof(newRecord));
1610
1611                        // OSData may have switched to another (larger) buffer.
1612                        count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1613                        start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1614                        broadcast = true;
1615                    }
1616
1617                    // Finished processing the request, release it.
1618                    IODelete(request, AggressivesRequest, 1);
1619                    break;
1620
1621                case kAggressivesRequestTypeService:
1622                    // synchronizeAggressives() will free request.
1623                    queue_enter(&joinedQueue, request, AggressivesRequest *, chain);
1624                    break;
1625
1626                default:
1627                    panic("bad aggressives request type %x\n", request->dataType);
1628                    break;
1629            }
1630        } while (!queue_empty(&aggressivesQueue));
1631
1632        // Release the lock to perform work, with busy flag set.
1633        if (!queue_empty(&joinedQueue) || broadcast)
1634        {
1635            AGGRESSIVES_UNLOCK();
1636            if (!queue_empty(&joinedQueue))
1637                synchronizeAggressives(&joinedQueue, start, count);
1638            if (broadcast)
1639                broadcastAggressives(start, count);
1640            AGGRESSIVES_LOCK();
1641        }
1642
1643        // Remove the modified flag from all records.
1644        for (i = 0, record = start; i < count; i++, record++)
1645        {
1646            if ((record->flags & kAggressivesRecordFlagModified) &&
1647                ((record->type == kPMMinutesToDim) ||
1648                 (record->type == kPMMinutesToSleep)))
1649                pingSelf = true;
1650
1651            record->flags &= ~kAggressivesRecordFlagModified;
1652        }
1653
1654        // Check the incoming queue again since new entries may have been
1655        // added while lock was released above.
1656
1657    } while (!queue_empty(&aggressivesQueue));
1658
1659    gAggressivesState &= ~kAggressivesStateBusy;
1660
1661unlock_done:
1662    AGGRESSIVES_UNLOCK();
1663
1664    // Root domain is interested in system and display sleep slider changes.
1665    // Submit a power event to handle those changes on the PM work loop.
1666
1667    if (pingSelf && pmPowerStateQueue) {
1668        pmPowerStateQueue->submitPowerEvent(
1669            kPowerEventPolicyStimulus,
1670            (void *) kStimulusAggressivenessChanged );
1671    }
1672}
1673
1674//******************************************************************************
1675// synchronizeAggressives
1676//
1677// Push all known aggressiveness records to one or more IOService.
1678//******************************************************************************
1679
1680void IOPMrootDomain::synchronizeAggressives(
1681    queue_head_t *              joinedQueue,
1682    const AggressivesRecord *   array,
1683    int                         count )
1684{
1685    IOService *                 service;
1686    AggressivesRequest *        request;
1687    const AggressivesRecord *   record;
1688    IOPMDriverCallEntry         callEntry;
1689    uint32_t                    value;
1690    int                         i;
1691
1692    while (!queue_empty(joinedQueue))
1693    {
1694        queue_remove_first(joinedQueue, request, AggressivesRequest *, chain);
1695        if (request->dataType == kAggressivesRequestTypeService)
1696            service = request->data.service;
1697        else
1698            service = 0;
1699
1700        IODelete(request, AggressivesRequest, 1);
1701        request = 0;
1702
1703        if (service)
1704        {
1705            if (service->assertPMDriverCall(&callEntry))
1706            {
1707                for (i = 0, record = array; i < count; i++, record++)
1708                {
1709                    value = record->value;
1710                    if (record->flags & kAggressivesRecordFlagMinValue)
1711                        value = kAggressivesMinValue;
1712
1713                    _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1714                        record->type, value, service->getName());
1715                    service->setAggressiveness(record->type, value);
1716                }
1717                service->deassertPMDriverCall(&callEntry);
1718            }
1719            service->release();     // retained by joinAggressiveness()
1720        }
1721    }
1722}
1723
1724//******************************************************************************
1725// broadcastAggressives
1726//
1727// Traverse PM tree and call setAggressiveness() for records that have changed.
1728//******************************************************************************
1729
1730void IOPMrootDomain::broadcastAggressives(
1731    const AggressivesRecord *   array,
1732    int                         count )
1733{
1734    IORegistryIterator *        iter;
1735    IORegistryEntry *           entry;
1736    IOPowerConnection *         connect;
1737    IOService *                 service;
1738    const AggressivesRecord *   record;
1739    IOPMDriverCallEntry         callEntry;
1740    uint32_t                    value;
1741    int                         i;
1742
1743    iter = IORegistryIterator::iterateOver(
1744            this, gIOPowerPlane, kIORegistryIterateRecursively);
1745    if (iter)
1746    {
1747        do
1748        {
1749            iter->reset();
1750            while ((entry = iter->getNextObject()))
1751            {
1752                connect = OSDynamicCast(IOPowerConnection, entry);
1753                if (!connect || !connect->getReadyFlag())
1754                    continue;
1755
1756                if ((service = (IOService *) connect->copyChildEntry(gIOPowerPlane)))
1757                {
1758                    if (service->assertPMDriverCall(&callEntry))
1759                    {
1760                        for (i = 0, record = array; i < count; i++, record++)
1761                        {
1762                            if (record->flags & kAggressivesRecordFlagModified)
1763                            {
1764                                value = record->value;
1765                                if (record->flags & kAggressivesRecordFlagMinValue)
1766                                    value = kAggressivesMinValue;
1767                                _LOG("broadcastAggressives %x = %u to %s\n",
1768                                    record->type, value, service->getName());
1769                                service->setAggressiveness(record->type, value);
1770                            }
1771                        }
1772                        service->deassertPMDriverCall(&callEntry);
1773                    }
1774                    service->release();
1775                }
1776            }
1777        }
1778        while (!entry && !iter->isValid());
1779        iter->release();
1780    }
1781}
1782
1783// MARK: -
1784// MARK: System Sleep
1785
1786//******************************************************************************
1787// startIdleSleepTimer
1788//
1789//******************************************************************************
1790
1791void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds )
1792{
1793    AbsoluteTime deadline;
1794
1795    ASSERT_GATED();
1796    if (inSeconds)
1797    {
1798        clock_interval_to_deadline(inSeconds, kSecondScale, &deadline);
1799        thread_call_enter_delayed(extraSleepTimer, deadline);
1800        idleSleepTimerPending = true;
1801    }
1802    else
1803    {
1804        thread_call_enter(extraSleepTimer);
1805    }
1806    DLOG("idle timer set for %u seconds\n", inSeconds);
1807}
1808
1809//******************************************************************************
1810// cancelIdleSleepTimer
1811//
1812//******************************************************************************
1813
1814void IOPMrootDomain::cancelIdleSleepTimer( void )
1815{
1816    ASSERT_GATED();
1817    if (idleSleepTimerPending)
1818    {
1819        DLOG("idle timer cancelled\n");
1820        thread_call_cancel(extraSleepTimer);
1821        idleSleepTimerPending = false;
1822    }
1823}
1824
1825//******************************************************************************
1826// idleSleepTimerExpired
1827//
1828//******************************************************************************
1829
1830static void idleSleepTimerExpired(
1831    thread_call_param_t us, thread_call_param_t )
1832{
1833    ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
1834}
1835
1836//******************************************************************************
1837// handleSleepTimerExpiration
1838//
1839// The time between the sleep idle timeout and the next longest one has elapsed.
1840// It's time to sleep. Start that by removing the clamp that's holding us awake.
1841//******************************************************************************
1842
1843void IOPMrootDomain::handleSleepTimerExpiration( void )
1844{
1845    if (!getPMworkloop()->inGate())
1846    {
1847        getPMworkloop()->runAction(
1848            OSMemberFunctionCast(IOWorkLoop::Action, this,
1849                &IOPMrootDomain::handleSleepTimerExpiration),
1850            this);
1851        return;
1852    }
1853
1854    AbsoluteTime time;
1855
1856    DLOG("sleep timer expired\n");
1857    ASSERT_GATED();
1858
1859    idleSleepTimerPending = false;
1860
1861    clock_get_uptime(&time);
1862    if ((AbsoluteTime_to_scalar(&time) > autoWakeStart) &&
1863        (AbsoluteTime_to_scalar(&time) < autoWakeEnd))
1864    {
1865        thread_call_enter_delayed(extraSleepTimer, *((AbsoluteTime *) &autoWakeEnd));
1866        return;
1867    }
1868
1869    setQuickSpinDownTimeout();
1870    adjustPowerState(true);
1871}
1872
1873//******************************************************************************
1874// getTimeToIdleSleep
1875//
1876// Returns number of seconds left before going into idle sleep.
1877// Caller has to make sure that idle sleep is allowed at the time of calling
1878// this function
1879//******************************************************************************
1880
1881uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
1882{
1883
1884    AbsoluteTime    now, lastActivityTime;
1885    uint64_t        nanos;
1886    uint32_t        minutesSinceUserInactive = 0;
1887    uint32_t         sleepDelay = 0;
1888
1889    if (sleepSlider == 0)
1890        return 0xffffffff;
1891
1892    if (userActivityTime)
1893        lastActivityTime = userActivityTime;
1894    else
1895        lastActivityTime = userBecameInactiveTime;
1896
1897    clock_get_uptime(&now);
1898    if (CMP_ABSOLUTETIME(&now, &lastActivityTime) > 0)
1899    {
1900        SUB_ABSOLUTETIME(&now, &lastActivityTime);
1901        absolutetime_to_nanoseconds(now, &nanos);
1902        minutesSinceUserInactive = nanos / (60000000000ULL);
1903
1904        if (minutesSinceUserInactive >= sleepSlider)
1905            sleepDelay = 0;
1906        else
1907            sleepDelay = sleepSlider - minutesSinceUserInactive;
1908    }
1909    else
1910    {
1911        sleepDelay = sleepSlider;
1912    }
1913
1914    DLOG("user inactive %u min, time to idle sleep %u min\n",
1915        minutesSinceUserInactive, sleepDelay);
1916
1917    return (sleepDelay * 60);
1918}
1919
1920//******************************************************************************
1921// setQuickSpinDownTimeout
1922//
1923//******************************************************************************
1924
1925void IOPMrootDomain::setQuickSpinDownTimeout( void )
1926{
1927    ASSERT_GATED();
1928    setAggressiveness(
1929        kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownEnable );
1930}
1931
1932//******************************************************************************
1933// restoreUserSpinDownTimeout
1934//
1935//******************************************************************************
1936
1937void IOPMrootDomain::restoreUserSpinDownTimeout( void )
1938{
1939    ASSERT_GATED();
1940    setAggressiveness(
1941        kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownDisable );
1942}
1943
1944//******************************************************************************
1945// sleepSystem
1946//
1947//******************************************************************************
1948
1949/* public */
1950IOReturn IOPMrootDomain::sleepSystem( void )
1951{
1952    return sleepSystemOptions(NULL);
1953}
1954
1955/* private */
1956IOReturn IOPMrootDomain::sleepSystemOptions( OSDictionary *options )
1957{
1958    OSObject *obj = NULL;
1959    OSString *reason = NULL;
1960    /* sleepSystem is a public function, and may be called by any kernel driver.
1961     * And that's bad - drivers should sleep the system by calling
1962     * receivePowerNotification() instead. Drivers should not use sleepSystem.
1963     *
1964     * Note that user space app calls to IOPMSleepSystem() will also travel
1965     * this code path and thus be correctly identified as software sleeps.
1966     */
1967
1968    if (options && options->getObject("OSSwitch"))
1969    {
1970        // Log specific sleep cause for OS Switch hibernation
1971        return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate);
1972    }
1973
1974    if (options && (obj = options->getObject("Sleep Reason")))
1975    {
1976        reason = OSDynamicCast(OSString, obj);
1977        if (reason && reason->isEqualTo(kIOPMDarkWakeThermalEmergencyKey))
1978            return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency);
1979    }
1980
1981    return privateSleepSystem( kIOPMSleepReasonSoftware);
1982}
1983
1984/* private */
1985IOReturn IOPMrootDomain::privateSleepSystem( uint32_t sleepReason )
1986{
1987    /* Called from both gated and non-gated context */
1988
1989    if (!checkSystemSleepEnabled() || !pmPowerStateQueue)
1990    {
1991        return kIOReturnNotPermitted;
1992    }
1993
1994    pmPowerStateQueue->submitPowerEvent(
1995                            kPowerEventPolicyStimulus,
1996                            (void *) kStimulusDemandSystemSleep,
1997                            sleepReason);
1998
1999    return kIOReturnSuccess;
2000}
2001
2002//******************************************************************************
2003// powerChangeDone
2004//
2005// This overrides powerChangeDone in IOService.
2006//******************************************************************************
2007
2008void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
2009{
2010    ASSERT_GATED();
2011    DLOG("PowerChangeDone: %u->%u\n",
2012        (uint32_t) previousPowerState, (uint32_t) getPowerState());
2013
2014    switch ( getPowerState() )
2015    {
2016        case SLEEP_STATE: {
2017            if (previousPowerState != ON_STATE)
2018                break;
2019
2020            acceptSystemWakeEvents(true);
2021
2022            // re-enable this timer for next sleep
2023            cancelIdleSleepTimer();
2024
2025            clock_sec_t     secs;
2026            clock_usec_t    microsecs;
2027            clock_get_calendar_microtime(&secs, &microsecs);
2028            logtime(secs);
2029            gIOLastSleepTime.tv_sec  = secs;
2030            gIOLastSleepTime.tv_usec = microsecs;
2031            gIOLastWakeTime.tv_sec = 0;
2032            gIOLastWakeTime.tv_usec = 0;
2033
2034#if HIBERNATION
2035            LOG("System %sSleep\n", gIOHibernateState ? "Safe" : "");
2036
2037            IOHibernateSystemHasSlept();
2038
2039            evaluateSystemSleepPolicyFinal();
2040#else
2041            LOG("System Sleep\n");
2042#endif
2043
2044            ((IOService *)this)->stop_watchdog_timer(); //14456299
2045            getPlatform()->sleepKernel();
2046
2047            // The CPU(s) are off at this point,
2048            // Code will resume execution here upon wake.
2049
2050            clock_get_uptime(&systemWakeTime);
2051            _highestCapability = 0;
2052
2053            ((IOService *)this)->start_watchdog_timer(); //14456299
2054#if HIBERNATION
2055            IOHibernateSystemWake();
2056#endif
2057
2058            // sleep transition complete
2059            gSleepOrShutdownPending = 0;
2060
2061            // trip the reset of the calendar clock
2062            clock_wakeup_calendar();
2063
2064#if HIBERNATION
2065            LOG("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
2066#endif
2067
2068            // log system wake
2069            PMDebug(kPMLogSystemWake, 0, 0);
2070            lowBatteryCondition = false;
2071            lastSleepReason = 0;
2072
2073            _lastDebugWakeSeconds = _debugWakeSeconds;
2074            _debugWakeSeconds = 0;
2075            _scheduledAlarms = 0;
2076
2077#ifndef __LP64__
2078            systemWake();
2079#endif
2080
2081#if defined(__i386__) || defined(__x86_64__)
2082            wranglerTickled         = false;
2083            graphicsSuppressed      = false;
2084            darkWakePostTickle      = false;
2085            darkWakeHibernateError  = false;
2086            darkWakeToSleepASAP     = true;
2087            logGraphicsClamp        = true;
2088            sleepTimerMaintenance   = false;
2089            sleepToStandby          = false;
2090            wranglerTickleLatched   = false;
2091            userWasActive           = false;
2092            fullWakeReason = kFullWakeReasonNone;
2093
2094            OSString * wakeType = OSDynamicCast(
2095                OSString, getProperty(kIOPMRootDomainWakeTypeKey));
2096            OSString * wakeReason = OSDynamicCast(
2097                OSString, getProperty(kIOPMRootDomainWakeReasonKey));
2098
2099            if (wakeReason && (wakeReason->getLength() >= 2) &&
2100                gWakeReasonString[0] == '\0')
2101            {
2102                // Until the platform driver can claim its wake reasons
2103                strlcat(gWakeReasonString, wakeReason->getCStringNoCopy(),
2104                        sizeof(gWakeReasonString));
2105            }
2106
2107            if (wakeType && wakeType->isEqualTo(kIOPMrootDomainWakeTypeLowBattery))
2108            {
2109                lowBatteryCondition = true;
2110                darkWakeMaintenance = true;
2111            }
2112            else if ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0)
2113            {
2114                OSNumber * hibOptions = OSDynamicCast(
2115                    OSNumber, getProperty(kIOHibernateOptionsKey));
2116
2117                if (hibernateAborted || ((hibOptions &&
2118                    !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake))))
2119                {
2120                    // Hibernate aborted, or EFI brought up graphics
2121                    wranglerTickled = true;
2122                    DLOG("hibernation aborted %d, options 0x%x\n",
2123                        hibernateAborted,
2124                        hibOptions ? hibOptions->unsigned32BitValue() : 0);
2125                }
2126                else
2127                if (wakeType && (
2128                    wakeType->isEqualTo(kIOPMRootDomainWakeTypeUser) ||
2129                    wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm)))
2130                {
2131                    // User wake or RTC alarm
2132                    wranglerTickled = true;
2133                }
2134                else
2135                if (wakeType &&
2136                    wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
2137                {
2138                    // SMC standby timer trumps SleepX
2139                    darkWakeMaintenance = true;
2140                    sleepTimerMaintenance = true;
2141                }
2142                else
2143                if ((_lastDebugWakeSeconds != 0) &&
2144                    ((gDarkWakeFlags & kDarkWakeFlagAlarmIsDark) == 0))
2145                {
2146                    // SleepX before maintenance
2147                    wranglerTickled = true;
2148                }
2149                else
2150                if (wakeType &&
2151                    wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
2152                {
2153                    darkWakeMaintenance = true;
2154                }
2155                else
2156                if (wakeType &&
2157                    wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepService))
2158                {
2159                    darkWakeMaintenance = true;
2160                    darkWakeSleepService = true;
2161                    if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) {
2162                        sleepToStandby = true;
2163                    }
2164                }
2165                else
2166                if (wakeType &&
2167                    wakeType->isEqualTo(kIOPMRootDomainWakeTypeHibernateError))
2168                {
2169                    darkWakeMaintenance = true;
2170                    darkWakeHibernateError = true;
2171                }
2172                else
2173                {
2174                    // Unidentified wake source, resume to full wake if debug
2175                    // alarm is pending.
2176
2177                    if (_lastDebugWakeSeconds &&
2178                        (!wakeReason || wakeReason->isEqualTo("")))
2179                        wranglerTickled = true;
2180                }
2181            }
2182            else
2183            {
2184                if (wakeType &&
2185                    wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
2186                {
2187                    darkWakeMaintenance = true;
2188                    sleepTimerMaintenance = true;
2189                }
2190                else if (hibernateAborted || !wakeType ||
2191                    !wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance) ||
2192                    !wakeReason || !wakeReason->isEqualTo("RTC"))
2193                {
2194                    // Post a HID tickle immediately - except for RTC maintenance wake.
2195                    wranglerTickled = true;
2196                }
2197                else
2198                {
2199                    darkWakeMaintenance = true;
2200                }
2201            }
2202
2203            if (wranglerTickled)
2204            {
2205                darkWakeToSleepASAP = false;
2206                fullWakeReason = kFullWakeReasonLocalUser;
2207                reportUserInput();
2208            }
2209            else if (!darkWakeMaintenance)
2210            {
2211                // Early/late tickle for non-maintenance wake.
2212                if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
2213                     kDarkWakeFlagHIDTickleEarly) ||
2214                    ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
2215                     kDarkWakeFlagHIDTickleLate))
2216                {
2217                    darkWakePostTickle = true;
2218                }
2219            }
2220#else   /* !__i386__ && !__x86_64__ */
2221            // stay awake for at least 30 seconds
2222            wranglerTickled = true;
2223            fullWakeReason = kFullWakeReasonLocalUser;
2224            startIdleSleepTimer(30);
2225#endif
2226            sleepCnt++;
2227
2228            changePowerStateToPriv(ON_STATE);
2229        }   break;
2230
2231    }
2232}
2233
2234//******************************************************************************
2235// requestPowerDomainState
2236//
2237// Extend implementation in IOService. Running on PM work loop thread.
2238//******************************************************************************
2239
2240IOReturn IOPMrootDomain::requestPowerDomainState (
2241    IOPMPowerFlags      childDesire,
2242    IOPowerConnection * childConnection,
2243    unsigned long       specification )
2244{
2245    // Idle and system sleep prevention flags affects driver desire.
2246    // Children desire are irrelevant so they are cleared.
2247
2248    return super::requestPowerDomainState(0, childConnection, specification);
2249}
2250
2251//******************************************************************************
2252// updatePreventIdleSleepList
2253//
2254// Called by IOService on PM work loop.
2255// Returns true if PM policy recognized the driver's desire to prevent idle
2256// sleep and updated the list of idle sleep preventers. Returns false otherwise
2257//******************************************************************************
2258
2259bool IOPMrootDomain::updatePreventIdleSleepList(
2260        IOService * service, bool addNotRemove )
2261{
2262    unsigned int oldCount, newCount;
2263
2264    ASSERT_GATED();
2265
2266#if defined(__i386__) || defined(__x86_64__)
2267    // Disregard disk I/O (besides the display wrangler) as a factor preventing
2268    // idle sleep, except in the case of legacy disk I/O
2269    if ((service != wrangler) && (service != this))
2270    {
2271        return false;
2272    }
2273#endif
2274
2275    oldCount = preventIdleSleepList->getCount();
2276    if (addNotRemove)
2277    {
2278        preventIdleSleepList->setObject(service);
2279        DLOG("prevent idle sleep list: %s+ (%u)\n",
2280            service->getName(), preventIdleSleepList->getCount());
2281    }
2282    else if (preventIdleSleepList->member(service))
2283    {
2284        preventIdleSleepList->removeObject(service);
2285        DLOG("prevent idle sleep list: %s- (%u)\n",
2286            service->getName(), preventIdleSleepList->getCount());
2287    }
2288    newCount = preventIdleSleepList->getCount();
2289
2290    if ((oldCount == 0) && (newCount != 0))
2291    {
2292        // Driver added to empty prevent list.
2293        // Update the driver desire to prevent idle sleep.
2294        // Driver desire does not prevent demand sleep.
2295
2296        changePowerStateTo(ON_STATE);
2297    }
2298    else if ((oldCount != 0) && (newCount == 0))
2299    {
2300        // Last driver removed from prevent list.
2301        // Drop the driver clamp to allow idle sleep.
2302
2303        changePowerStateTo(SLEEP_STATE);
2304        evaluatePolicy( kStimulusNoIdleSleepPreventers );
2305    }
2306
2307#if defined(__i386__) || defined(__x86_64__)
2308    if (addNotRemove && (service == wrangler) && !checkSystemCanSustainFullWake())
2309    {
2310        return false;   // do not idle-cancel
2311    }
2312#endif
2313
2314    return true;
2315}
2316
2317//******************************************************************************
2318// preventSystemSleepListUpdate
2319//
2320// Called by IOService on PM work loop.
2321//******************************************************************************
2322
2323void IOPMrootDomain::updatePreventSystemSleepList(
2324        IOService * service, bool addNotRemove )
2325{
2326    unsigned int oldCount;
2327
2328    ASSERT_GATED();
2329    if (this == service)
2330        return;
2331
2332    oldCount = preventSystemSleepList->getCount();
2333    if (addNotRemove)
2334    {
2335        preventSystemSleepList->setObject(service);
2336        DLOG("prevent system sleep list: %s+ (%u)\n",
2337            service->getName(), preventSystemSleepList->getCount());
2338    }
2339    else if (preventSystemSleepList->member(service))
2340    {
2341        preventSystemSleepList->removeObject(service);
2342        DLOG("prevent system sleep list: %s- (%u)\n",
2343            service->getName(), preventSystemSleepList->getCount());
2344
2345        if ((oldCount != 0) && (preventSystemSleepList->getCount() == 0))
2346        {
2347            // Lost all system sleep preventers.
2348            // Send stimulus if system sleep was blocked, and is in dark wake.
2349            evaluatePolicy( kStimulusDarkWakeEvaluate );
2350        }
2351    }
2352}
2353
2354//******************************************************************************
2355// tellChangeDown
2356//
2357// Override the superclass implementation to send a different message type.
2358//******************************************************************************
2359
2360bool IOPMrootDomain::tellChangeDown( unsigned long stateNum )
2361{
2362    DLOG("tellChangeDown %u->%u\n",
2363        (uint32_t) getPowerState(), (uint32_t) stateNum);
2364
2365    if (SLEEP_STATE == stateNum)
2366    {
2367        // Legacy apps were already told in the full->dark transition
2368        if (!ignoreTellChangeDown)
2369            tracePoint( kIOPMTracePointSleepApplications );
2370        else
2371            tracePoint( kIOPMTracePointSleepPriorityClients );
2372    }
2373
2374    if ((SLEEP_STATE == stateNum) && !ignoreTellChangeDown)
2375    {
2376        userActivityAtSleep = userActivityCount;
2377        hibernateAborted = false;
2378        DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep);
2379
2380        // Direct callout into OSKext so it can disable kext unloads
2381        // during sleep/wake to prevent deadlocks.
2382        OSKextSystemSleepOrWake( kIOMessageSystemWillSleep );
2383
2384        IOService::updateConsoleUsers(NULL, kIOMessageSystemWillSleep);
2385
2386        // Two change downs are sent by IOServicePM. Ignore the 2nd.
2387        // But tellClientsWithResponse() must be called for both.
2388        ignoreTellChangeDown = true;
2389    }
2390
2391    return super::tellClientsWithResponse( kIOMessageSystemWillSleep );
2392}
2393
2394//******************************************************************************
2395// askChangeDown
2396//
2397// Override the superclass implementation to send a different message type.
2398// This must be idle sleep since we don't ask during any other power change.
2399//******************************************************************************
2400
2401bool IOPMrootDomain::askChangeDown( unsigned long stateNum )
2402{
2403    DLOG("askChangeDown %u->%u\n",
2404        (uint32_t) getPowerState(), (uint32_t) stateNum);
2405
2406    // Don't log for dark wake entry
2407    if (kSystemTransitionSleep == _systemTransitionType)
2408        tracePoint( kIOPMTracePointSleepApplications );
2409
2410    return super::tellClientsWithResponse( kIOMessageCanSystemSleep );
2411}
2412
2413//******************************************************************************
2414// askChangeDownDone
2415//
2416// An opportunity for root domain to cancel the power transition,
2417// possibily due to an assertion created by powerd in response to
2418// kIOMessageCanSystemSleep.
2419//
2420// Idle sleep:
2421//   full -> dark wake transition
2422//     1. Notify apps and powerd with kIOMessageCanSystemSleep
2423//     2. askChangeDownDone()
2424//   dark -> sleep transition
2425//     1. Notify powerd with kIOMessageCanSystemSleep
2426//     2. askChangeDownDone()
2427//
2428// Demand sleep:
2429//   full -> dark wake transition
2430//     1. Notify powerd with kIOMessageCanSystemSleep
2431//     2. askChangeDownDone()
2432//   dark -> sleep transition
2433//     1. Notify powerd with kIOMessageCanSystemSleep
2434//     2. askChangeDownDone()
2435//******************************************************************************
2436
2437void IOPMrootDomain::askChangeDownDone(
2438        IOPMPowerChangeFlags * inOutChangeFlags, bool * cancel )
2439{
2440    DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2441        *inOutChangeFlags, *cancel,
2442        _systemTransitionType,
2443        _currentCapability, _pendingCapability);
2444
2445    if ((false == *cancel) && (kSystemTransitionSleep == _systemTransitionType))
2446    {
2447        // Dark->Sleep transition.
2448        // Check if there are any deny sleep assertions.
2449        // lastSleepReason already set by handleOurPowerChangeStart()
2450
2451        if (!checkSystemCanSleep(lastSleepReason))
2452        {
2453            // Cancel dark wake to sleep transition.
2454            // Must re-scan assertions upon entering dark wake.
2455
2456            *cancel = true;
2457            DLOG("cancel dark->sleep\n");
2458        }
2459    }
2460}
2461
2462//******************************************************************************
2463// systemDidNotSleep
2464//
2465// Work common to both canceled or aborted sleep.
2466//******************************************************************************
2467
2468void IOPMrootDomain::systemDidNotSleep( void )
2469{
2470    if (!wrangler)
2471    {
2472        if (idleSeconds)
2473        {
2474            // stay awake for at least idleSeconds
2475            startIdleSleepTimer(idleSeconds);
2476        }
2477    }
2478    else
2479    {
2480        if (sleepSlider && !userIsActive)
2481        {
2482            // Manually start the idle sleep timer besides waiting for
2483            // the user to become inactive.
2484            startIdleSleepTimer( kIdleSleepRetryInterval );
2485        }
2486    }
2487
2488    preventTransitionToUserActive(false);
2489    IOService::setAdvisoryTickleEnable( true );
2490}
2491
2492//******************************************************************************
2493// tellNoChangeDown
2494//
2495// Notify registered applications and kernel clients that we are not dropping
2496// power.
2497//
2498// We override the superclass implementation so we can send a different message
2499// type to the client or application being notified.
2500//
2501// This must be a vetoed idle sleep, since no other power change can be vetoed.
2502//******************************************************************************
2503
2504void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum )
2505{
2506    DLOG("tellNoChangeDown %u->%u\n",
2507        (uint32_t) getPowerState(), (uint32_t) stateNum);
2508
2509    // Sleep canceled, clear the sleep trace point.
2510    tracePoint(kIOPMTracePointSystemUp);
2511
2512    systemDidNotSleep();
2513    return tellClients( kIOMessageSystemWillNotSleep );
2514}
2515
2516//******************************************************************************
2517// tellChangeUp
2518//
2519// Notify registered applications and kernel clients that we are raising power.
2520//
2521// We override the superclass implementation so we can send a different message
2522// type to the client or application being notified.
2523//******************************************************************************
2524
2525void IOPMrootDomain::tellChangeUp( unsigned long stateNum )
2526{
2527
2528    DLOG("tellChangeUp %u->%u\n",
2529        (uint32_t) getPowerState(), (uint32_t) stateNum);
2530
2531    ignoreTellChangeDown = false;
2532
2533    if ( stateNum == ON_STATE )
2534    {
2535        // Direct callout into OSKext so it can disable kext unloads
2536        // during sleep/wake to prevent deadlocks.
2537        OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn );
2538
2539        // Notify platform that sleep was cancelled or resumed.
2540        getPlatform()->callPlatformFunction(
2541                        sleepMessagePEFunction, false,
2542                        (void *)(uintptr_t) kIOMessageSystemHasPoweredOn,
2543                        NULL, NULL, NULL);
2544
2545        if (getPowerState() == ON_STATE)
2546        {
2547            // this is a quick wake from aborted sleep
2548            systemDidNotSleep();
2549            tellClients( kIOMessageSystemWillPowerOn );
2550        }
2551
2552
2553        tracePoint( kIOPMTracePointWakeApplications );
2554        tellClients( kIOMessageSystemHasPoweredOn );
2555    }
2556}
2557
2558//******************************************************************************
2559// sysPowerDownHandler
2560//
2561// Perform a vfs sync before system sleep.
2562//******************************************************************************
2563
2564IOReturn IOPMrootDomain::sysPowerDownHandler(
2565    void * target, void * refCon,
2566    UInt32 messageType, IOService * service,
2567    void * messageArgs, vm_size_t argSize )
2568{
2569    IOReturn    ret = 0;
2570
2571    DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType));
2572
2573    if (!gRootDomain)
2574        return kIOReturnUnsupported;
2575
2576    if (messageType == kIOMessageSystemWillSleep)
2577    {
2578#if HIBERNATION
2579        uint32_t mem_only = 0;
2580        IOPowerStateChangeNotification *notify =
2581                    (IOPowerStateChangeNotification *)messageArgs;
2582
2583       PE_parse_boot_argn("swd_mem_only", &mem_only, sizeof(mem_only));
2584       if ((mem_only != 1) && (gRootDomain->sleepWakeDebugIsWdogEnabled()))
2585       {
2586           notify->returnValue = 30 * 1000 * 1000;
2587           thread_call_enter1(
2588                              gRootDomain->hibDebugSetupEntry,
2589                              (thread_call_param_t)(uintptr_t) notify->powerRef);
2590       }
2591#endif
2592    }
2593    else if (messageType == kIOMessageSystemCapabilityChange)
2594    {
2595        IOPMSystemCapabilityChangeParameters * params =
2596            (IOPMSystemCapabilityChangeParameters *) messageArgs;
2597
2598        // Interested applications have been notified of an impending power
2599        // change and have acked (when applicable).
2600        // This is our chance to save whatever state we can before powering
2601        // down.
2602        // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2603        // via callout
2604
2605        DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2606            params->fromCapabilities, params->toCapabilities,
2607            params->changeFlags);
2608
2609        if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
2610            (params->fromCapabilities & kIOPMSystemCapabilityCPU) &&
2611            (params->toCapabilities & kIOPMSystemCapabilityCPU) == 0)
2612        {
2613            // We will ack within 20 seconds
2614            params->maxWaitForReply = 20 * 1000 * 1000;
2615#if HIBERNATION
2616            gRootDomain->evaluateSystemSleepPolicyEarly();
2617
2618            // add in time we could spend freeing pages
2619            if (gRootDomain->hibernateMode && !gRootDomain->hibernateDisabled)
2620            {
2621                params->maxWaitForReply = kCapabilityClientMaxWait;
2622            }
2623            DLOG("sysPowerDownHandler max wait %d s\n",
2624                (int) (params->maxWaitForReply / 1000 / 1000));
2625#endif
2626
2627            // Notify platform that sleep has begun, after the early
2628            // sleep policy evaluation.
2629            getPlatform()->callPlatformFunction(
2630                            sleepMessagePEFunction, false,
2631                            (void *)(uintptr_t) kIOMessageSystemWillSleep,
2632                            NULL, NULL, NULL);
2633
2634            if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) )
2635            {
2636                // Purposely delay the ack and hope that shutdown occurs quickly.
2637                // Another option is not to schedule the thread and wait for
2638                // ack timeout...
2639                AbsoluteTime deadline;
2640                clock_interval_to_deadline( 30, kSecondScale, &deadline );
2641                thread_call_enter1_delayed(
2642                    gRootDomain->diskSyncCalloutEntry,
2643                    (thread_call_param_t)(uintptr_t) params->notifyRef,
2644                    deadline );
2645            }
2646            else
2647                thread_call_enter1(
2648                    gRootDomain->diskSyncCalloutEntry,
2649                    (thread_call_param_t)(uintptr_t) params->notifyRef);
2650        }
2651        else
2652        if ((params->changeFlags & kIOPMSystemCapabilityDidChange) &&
2653            (params->toCapabilities & kIOPMSystemCapabilityCPU) &&
2654            (params->fromCapabilities & kIOPMSystemCapabilityCPU) == 0)
2655        {
2656#if HIBERNATION
2657            // We will ack within 110 seconds
2658            params->maxWaitForReply = 110 * 1000 * 1000;
2659
2660            thread_call_enter1(
2661                gRootDomain->diskSyncCalloutEntry,
2662                (thread_call_param_t)(uintptr_t) params->notifyRef);
2663#endif
2664        }
2665        ret = kIOReturnSuccess;
2666    }
2667
2668    return ret;
2669}
2670
2671//******************************************************************************
2672// handleQueueSleepWakeUUID
2673//
2674// Called from IOPMrootDomain when we're initiating a sleep,
2675// or indirectly from PM configd when PM decides to clear the UUID.
2676// PM clears the UUID several minutes after successful wake from sleep,
2677// so that we might associate App spindumps with the immediately previous
2678// sleep/wake.
2679//
2680// @param   obj has a retain on it. We're responsible for releasing that retain.
2681//******************************************************************************
2682
2683void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject *obj)
2684{
2685    OSString    *str = NULL;
2686
2687    if (kOSBooleanFalse == obj)
2688    {
2689        handlePublishSleepWakeUUID(NULL);
2690    }
2691    else if ((str = OSDynamicCast(OSString, obj)))
2692    {
2693        // This branch caches the UUID for an upcoming sleep/wake
2694        if (queuedSleepWakeUUIDString) {
2695            queuedSleepWakeUUIDString->release();
2696            queuedSleepWakeUUIDString = NULL;
2697        }
2698        queuedSleepWakeUUIDString = str;
2699        queuedSleepWakeUUIDString->retain();
2700
2701        DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString->getCStringNoCopy());
2702    }
2703
2704    if (obj) {
2705        obj->release();
2706    }
2707    return;
2708
2709}
2710//******************************************************************************
2711// handlePublishSleepWakeUUID
2712//
2713// Called from IOPMrootDomain when we're initiating a sleep,
2714// or indirectly from PM configd when PM decides to clear the UUID.
2715// PM clears the UUID several minutes after successful wake from sleep,
2716// so that we might associate App spindumps with the immediately previous
2717// sleep/wake.
2718//******************************************************************************
2719
2720void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish )
2721{
2722   ASSERT_GATED();
2723
2724   /*
2725    * Clear the current UUID
2726    */
2727   if (gSleepWakeUUIDIsSet)
2728   {
2729        DLOG("SleepWake UUID cleared\n");
2730
2731        gSleepWakeUUIDIsSet = false;
2732
2733        removeProperty(kIOPMSleepWakeUUIDKey);
2734        messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDCleared);
2735    }
2736
2737    /*
2738     * Optionally, publish a new UUID
2739     */
2740    if (queuedSleepWakeUUIDString && shouldPublish) {
2741
2742        OSString  *publishThisUUID = NULL;
2743
2744        publishThisUUID = queuedSleepWakeUUIDString;
2745        publishThisUUID->retain();
2746
2747        if (publishThisUUID)
2748        {
2749            setProperty(kIOPMSleepWakeUUIDKey, publishThisUUID);
2750            publishThisUUID->release();
2751        }
2752
2753        gSleepWakeUUIDIsSet = true;
2754        messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDSet);
2755
2756        queuedSleepWakeUUIDString->release();
2757        queuedSleepWakeUUIDString = NULL;
2758    }
2759}
2760
2761//******************************************************************************
2762// initializeBootSessionUUID
2763//
2764// Initialize the boot session uuid at boot up and sets it into registry.
2765//******************************************************************************
2766
2767void IOPMrootDomain::initializeBootSessionUUID(void)
2768{
2769    uuid_t          new_uuid;
2770    uuid_string_t   new_uuid_string;
2771
2772    uuid_generate(new_uuid);
2773    uuid_unparse_upper(new_uuid, new_uuid_string);
2774    memcpy(bootsessionuuid_string, new_uuid_string, sizeof(uuid_string_t));
2775
2776    setProperty(kIOPMBootSessionUUIDKey, new_uuid_string);
2777}
2778
2779//******************************************************************************
2780// changePowerStateTo & changePowerStateToPriv
2781//
2782// Override of these methods for logging purposes.
2783//******************************************************************************
2784
2785IOReturn IOPMrootDomain::changePowerStateTo( unsigned long ordinal )
2786{
2787    DLOG("changePowerStateTo(%lu)\n", ordinal);
2788
2789    if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE))
2790        return kIOReturnUnsupported;
2791
2792    return super::changePowerStateTo(ordinal);
2793}
2794
2795IOReturn IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal )
2796{
2797    DLOG("changePowerStateToPriv(%lu)\n", ordinal);
2798
2799    if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE))
2800        return kIOReturnUnsupported;
2801
2802    return super::changePowerStateToPriv(ordinal);
2803}
2804
2805//******************************************************************************
2806// activity detect
2807//
2808//******************************************************************************
2809
2810bool IOPMrootDomain::activitySinceSleep(void)
2811{
2812    return (userActivityCount != userActivityAtSleep);
2813}
2814
2815bool IOPMrootDomain::abortHibernation(void)
2816{
2817    bool ret = activitySinceSleep();
2818
2819    if (ret && !hibernateAborted && checkSystemCanSustainFullWake())
2820    {
2821        DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount, userActivityAtSleep);
2822        hibernateAborted = true;
2823    }
2824    return (ret);
2825}
2826
2827extern "C" int
2828hibernate_should_abort(void)
2829{
2830    if (gRootDomain)
2831        return (gRootDomain->abortHibernation());
2832    else
2833        return (0);
2834}
2835
2836//******************************************************************************
2837// willNotifyPowerChildren
2838//
2839// Called after all interested drivers have all acknowledged the power change,
2840// but before any power children is informed. Dispatched though a thread call,
2841// so it is safe to perform work that might block on a sleeping disk. PM state
2842// machine (not thread) will block w/o timeout until this function returns.
2843//******************************************************************************
2844
2845void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState )
2846{
2847#if HIBERNATION
2848    if (SLEEP_STATE == newPowerState)
2849    {
2850        IOHibernateSystemSleep();
2851        IOHibernateIOKitSleep();
2852    }
2853#endif
2854}
2855
2856//******************************************************************************
2857// sleepOnClamshellClosed
2858//
2859// contains the logic to determine if the system should sleep when the clamshell
2860// is closed.
2861//******************************************************************************
2862
2863bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
2864{
2865    if (!clamshellExists)
2866        return false;
2867
2868    DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
2869        clamshellClosed, clamshellDisabled, desktopMode, acAdaptorConnected, clamshellSleepDisabled);
2870
2871    return ( !clamshellDisabled && !(desktopMode && acAdaptorConnected) && !clamshellSleepDisabled );
2872}
2873
2874void IOPMrootDomain::sendClientClamshellNotification( void )
2875{
2876    /* Only broadcast clamshell alert if clamshell exists. */
2877    if (!clamshellExists)
2878        return;
2879
2880    setProperty(kAppleClamshellStateKey,
2881        clamshellClosed ? kOSBooleanTrue : kOSBooleanFalse);
2882
2883    setProperty(kAppleClamshellCausesSleepKey,
2884        shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
2885
2886    /* Argument to message is a bitfiel of
2887     *      ( kClamshellStateBit | kClamshellSleepBit )
2888     */
2889    messageClients(kIOPMMessageClamshellStateChange,
2890        (void *)(uintptr_t) ( (clamshellClosed ? kClamshellStateBit : 0)
2891             | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)) );
2892}
2893
2894//******************************************************************************
2895// getSleepSupported
2896//
2897// Deprecated
2898//******************************************************************************
2899
2900IOOptionBits IOPMrootDomain::getSleepSupported( void )
2901{
2902    return( platformSleepSupport );
2903}
2904
2905//******************************************************************************
2906// setSleepSupported
2907//
2908// Deprecated
2909//******************************************************************************
2910
2911void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
2912{
2913    DLOG("setSleepSupported(%x)\n", (uint32_t) flags);
2914    OSBitOrAtomic(flags, &platformSleepSupport);
2915}
2916
2917//******************************************************************************
2918// setDisableClamShellSleep
2919//
2920//******************************************************************************
2921
2922void IOPMrootDomain::setDisableClamShellSleep( bool val )
2923{
2924    if (gIOPMWorkLoop->inGate() == false) {
2925
2926       gIOPMWorkLoop->runAction(
2927               OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setDisableClamShellSleep),
2928               (OSObject *)this,
2929               (void *)val);
2930
2931       return;
2932    }
2933    else {
2934       DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val);
2935       if ( clamshellSleepDisabled != val )
2936       {
2937           clamshellSleepDisabled = val;
2938           // If clamshellSleepDisabled is reset to 0, reevaluate if
2939           // system need to go to sleep due to clamshell state
2940           if ( !clamshellSleepDisabled && clamshellClosed)
2941              handlePowerNotification(kLocalEvalClamshellCommand);
2942       }
2943    }
2944}
2945
2946//******************************************************************************
2947// wakeFromDoze
2948//
2949// Deprecated.
2950//******************************************************************************
2951
2952void IOPMrootDomain::wakeFromDoze( void )
2953{
2954    // Preserve symbol for familes (IOUSBFamily and IOGraphics)
2955}
2956
2957// MARK: -
2958// MARK: Features
2959
2960//******************************************************************************
2961// publishFeature
2962//
2963// Adds a new feature to the supported features dictionary
2964//******************************************************************************
2965
2966void IOPMrootDomain::publishFeature( const char * feature )
2967{
2968    publishFeature(feature, kRD_AllPowerSources, NULL);
2969}
2970
2971//******************************************************************************
2972// publishFeature (with supported power source specified)
2973//
2974// Adds a new feature to the supported features dictionary
2975//******************************************************************************
2976
2977void IOPMrootDomain::publishFeature(
2978    const char *feature,
2979    uint32_t supportedWhere,
2980    uint32_t *uniqueFeatureID)
2981{
2982    static uint16_t     next_feature_id = 500;
2983
2984    OSNumber            *new_feature_data = NULL;
2985    OSNumber            *existing_feature = NULL;
2986    OSArray             *existing_feature_arr = NULL;
2987    OSObject            *osObj = NULL;
2988    uint32_t            feature_value = 0;
2989
2990    supportedWhere &= kRD_AllPowerSources; // mask off any craziness!
2991
2992    if(!supportedWhere) {
2993        // Feature isn't supported anywhere!
2994        return;
2995    }
2996
2997    if(next_feature_id > 5000) {
2998        // Far, far too many features!
2999        return;
3000    }
3001
3002    if(featuresDictLock) IOLockLock(featuresDictLock);
3003
3004    OSDictionary *features =
3005        (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
3006
3007    // Create new features dict if necessary
3008    if ( features && OSDynamicCast(OSDictionary, features)) {
3009        features = OSDictionary::withDictionary(features);
3010    } else {
3011        features = OSDictionary::withCapacity(1);
3012    }
3013
3014    // Create OSNumber to track new feature
3015
3016    next_feature_id += 1;
3017    if( uniqueFeatureID ) {
3018        // We don't really mind if the calling kext didn't give us a place
3019        // to stash their unique id. Many kexts don't plan to unload, and thus
3020        // have no need to remove themselves later.
3021        *uniqueFeatureID = next_feature_id;
3022    }
3023
3024    feature_value = (uint32_t)next_feature_id;
3025    feature_value <<= 16;
3026    feature_value += supportedWhere;
3027
3028    new_feature_data = OSNumber::withNumber(
3029                                (unsigned long long)feature_value, 32);
3030
3031    // Does features object already exist?
3032    if( (osObj = features->getObject(feature)) )
3033    {
3034        if(( existing_feature = OSDynamicCast(OSNumber, osObj) ))
3035        {
3036            // We need to create an OSArray to hold the now 2 elements.
3037            existing_feature_arr = OSArray::withObjects(
3038                            (const OSObject **)&existing_feature, 1, 2);
3039        } else if(( existing_feature_arr = OSDynamicCast(OSArray, osObj) ))
3040        {
3041            // Add object to existing array
3042            existing_feature_arr = OSArray::withArray(
3043                            existing_feature_arr,
3044                            existing_feature_arr->getCount() + 1);
3045        }
3046
3047        if (existing_feature_arr)
3048        {
3049            existing_feature_arr->setObject(new_feature_data);
3050            features->setObject(feature, existing_feature_arr);
3051            existing_feature_arr->release();
3052            existing_feature_arr = 0;
3053        }
3054    } else {
3055        // The easy case: no previously existing features listed. We simply
3056        // set the OSNumber at key 'feature' and we're on our way.
3057        features->setObject(feature, new_feature_data);
3058    }
3059
3060    new_feature_data->release();
3061
3062    setProperty(kRootDomainSupportedFeatures, features);
3063
3064    features->release();
3065
3066    if(featuresDictLock) IOLockUnlock(featuresDictLock);
3067
3068    // Notify EnergySaver and all those in user space so they might
3069    // re-populate their feature specific UI
3070    if(pmPowerStateQueue) {
3071        pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
3072    }
3073}
3074
3075//******************************************************************************
3076// removePublishedFeature
3077//
3078// Removes previously published feature
3079//******************************************************************************
3080
3081IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
3082{
3083    IOReturn                ret = kIOReturnError;
3084    uint32_t                feature_value = 0;
3085    uint16_t                feature_id = 0;
3086    bool                    madeAChange = false;
3087
3088    OSSymbol                *dictKey = NULL;
3089    OSCollectionIterator    *dictIterator = NULL;
3090    OSArray                 *arrayMember  = NULL;
3091    OSNumber                *numberMember = NULL;
3092    OSObject                *osObj        = NULL;
3093    OSNumber                *osNum        = NULL;
3094    OSArray                 *arrayMemberCopy;
3095
3096    if (kBadPMFeatureID == removeFeatureID)
3097        return kIOReturnNotFound;
3098
3099    if(featuresDictLock) IOLockLock(featuresDictLock);
3100
3101    OSDictionary *features =
3102        (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
3103
3104    if ( features && OSDynamicCast(OSDictionary, features) )
3105    {
3106        // Any modifications to the dictionary are made to the copy to prevent
3107        // races & crashes with userland clients. Dictionary updated
3108        // automically later.
3109        features = OSDictionary::withDictionary(features);
3110    } else {
3111        features = NULL;
3112        ret = kIOReturnNotFound;
3113        goto exit;
3114    }
3115
3116    // We iterate 'features' dictionary looking for an entry tagged
3117    // with 'removeFeatureID'. If found, we remove it from our tracking
3118    // structures and notify the OS via a general interest message.
3119
3120    dictIterator = OSCollectionIterator::withCollection(features);
3121    if(!dictIterator) {
3122        goto exit;
3123    }
3124
3125    while( (dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject())) )
3126    {
3127        osObj = features->getObject(dictKey);
3128
3129        // Each Feature is either tracked by an OSNumber
3130        if( osObj && (numberMember = OSDynamicCast(OSNumber, osObj)) )
3131        {
3132            feature_value = numberMember->unsigned32BitValue();
3133            feature_id = (uint16_t)(feature_value >> 16);
3134
3135            if( feature_id == (uint16_t)removeFeatureID )
3136            {
3137                // Remove this node
3138                features->removeObject(dictKey);
3139                madeAChange = true;
3140                break;
3141            }
3142
3143        // Or tracked by an OSArray of OSNumbers
3144        } else if( osObj && (arrayMember = OSDynamicCast(OSArray, osObj)) )
3145        {
3146            unsigned int arrayCount = arrayMember->getCount();
3147
3148            for(unsigned int i=0; i<arrayCount; i++)
3149            {
3150                osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
3151                if(!osNum) {
3152                    continue;
3153                }
3154
3155                feature_value = osNum->unsigned32BitValue();
3156                feature_id = (uint16_t)(feature_value >> 16);
3157
3158                if( feature_id == (uint16_t)removeFeatureID )
3159                {
3160                    // Remove this node
3161                    if( 1 == arrayCount ) {
3162                        // If the array only contains one element, remove
3163                        // the whole thing.
3164                        features->removeObject(dictKey);
3165                    } else {
3166                        // Otherwise remove the element from a copy of the array.
3167                        arrayMemberCopy = OSArray::withArray(arrayMember);
3168                        if (arrayMemberCopy)
3169                        {
3170                            arrayMemberCopy->removeObject(i);
3171                            features->setObject(dictKey, arrayMemberCopy);
3172                            arrayMemberCopy->release();
3173                        }
3174                    }
3175
3176                    madeAChange = true;
3177                    break;
3178                }
3179            }
3180        }
3181    }
3182
3183    dictIterator->release();
3184
3185    if( madeAChange )
3186    {
3187        ret = kIOReturnSuccess;
3188
3189        setProperty(kRootDomainSupportedFeatures, features);
3190
3191        // Notify EnergySaver and all those in user space so they might
3192        // re-populate their feature specific UI
3193        if(pmPowerStateQueue) {
3194            pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
3195        }
3196    } else {
3197        ret = kIOReturnNotFound;
3198    }
3199
3200exit:
3201    if(features)    features->release();
3202    if(featuresDictLock) IOLockUnlock(featuresDictLock);
3203    return ret;
3204}
3205
3206//******************************************************************************
3207// publishPMSetting (private)
3208//
3209// Should only be called by PMSettingObject to publish a PM Setting as a
3210// supported feature.
3211//******************************************************************************
3212
3213void IOPMrootDomain::publishPMSetting(
3214    const OSSymbol * feature, uint32_t where, uint32_t * featureID )
3215{
3216    if (noPublishPMSettings &&
3217        (noPublishPMSettings->getNextIndexOfObject(feature, 0) != (unsigned int)-1))
3218    {
3219        // Setting found in noPublishPMSettings array
3220        *featureID = kBadPMFeatureID;
3221        return;
3222    }
3223
3224    publishFeature(
3225        feature->getCStringNoCopy(), where, featureID);
3226}
3227
3228//******************************************************************************
3229// setPMSetting (private)
3230//
3231// Internal helper to relay PM settings changes from user space to individual
3232// drivers. Should be called only by IOPMrootDomain::setProperties.
3233//******************************************************************************
3234
3235IOReturn IOPMrootDomain::setPMSetting(
3236    const OSSymbol  *type,
3237    OSObject        *object )
3238{
3239    PMSettingCallEntry  *entries = 0;
3240    OSArray             *chosen  = 0;
3241    const OSArray       *array;
3242    PMSettingObject     *pmso;
3243    thread_t            thisThread;
3244    int                 i, j, count, capacity;
3245
3246    if (NULL == type)
3247        return kIOReturnBadArgument;
3248
3249    PMSETTING_LOCK();
3250
3251    // Update settings dict so changes are visible from copyPMSetting().
3252    fPMSettingsDict->setObject(type, object);
3253
3254    // Prep all PMSetting objects with the given 'type' for callout.
3255    array = (const OSArray *) settingsCallbacks->getObject(type);
3256    if (!array || ((capacity = array->getCount()) == 0))
3257        goto unlock_exit;
3258
3259    // Array to retain PMSetting objects targeted for callout.
3260    chosen = OSArray::withCapacity(capacity);
3261    if (!chosen)
3262        goto unlock_exit;   // error
3263
3264    entries = IONew(PMSettingCallEntry, capacity);
3265    if (!entries)
3266        goto unlock_exit;   // error
3267    memset(entries, 0, sizeof(PMSettingCallEntry) * capacity);
3268
3269    thisThread = current_thread();
3270
3271    for (i = 0, j = 0; i<capacity; i++)
3272    {
3273        pmso = (PMSettingObject *) array->getObject(i);
3274        if (pmso->disabled)
3275            continue;
3276        entries[j].thread = thisThread;
3277        queue_enter(&pmso->calloutQueue, &entries[j], PMSettingCallEntry *, link);
3278        chosen->setObject(pmso);
3279        j++;
3280    }
3281    count = j;
3282    if (!count)
3283        goto unlock_exit;
3284
3285    PMSETTING_UNLOCK();
3286
3287    // Call each pmso in the chosen array.
3288    for (i=0; i<count; i++)
3289    {
3290        pmso = (PMSettingObject *) chosen->getObject(i);
3291        pmso->dispatchPMSetting(type, object);
3292    }
3293
3294    PMSETTING_LOCK();
3295    for (i=0; i<count; i++)
3296    {
3297        pmso = (PMSettingObject *) chosen->getObject(i);
3298        queue_remove(&pmso->calloutQueue, &entries[i], PMSettingCallEntry *, link);
3299        if (pmso->waitThread)
3300        {
3301            PMSETTING_WAKEUP(pmso);
3302        }
3303    }
3304unlock_exit:
3305    PMSETTING_UNLOCK();
3306
3307    if (chosen)  chosen->release();
3308    if (entries) IODelete(entries, PMSettingCallEntry, capacity);
3309
3310    return kIOReturnSuccess;
3311}
3312
3313//******************************************************************************
3314// copyPMSetting (public)
3315//
3316// Allows kexts to safely read setting values, without being subscribed to
3317// notifications.
3318//******************************************************************************
3319
3320OSObject * IOPMrootDomain::copyPMSetting(
3321    OSSymbol *whichSetting)
3322{
3323    OSObject *obj = NULL;
3324
3325    if(!whichSetting) return NULL;
3326
3327    PMSETTING_LOCK();
3328    obj = fPMSettingsDict->getObject(whichSetting);
3329    if(obj) {
3330        obj->retain();
3331    }
3332    PMSETTING_UNLOCK();
3333
3334    return obj;
3335}
3336
3337//******************************************************************************
3338// registerPMSettingController (public)
3339//
3340// direct wrapper to registerPMSettingController with uint32_t power source arg
3341//******************************************************************************
3342
3343IOReturn IOPMrootDomain::registerPMSettingController(
3344    const OSSymbol *                settings[],
3345    IOPMSettingControllerCallback   func,
3346    OSObject                        *target,
3347    uintptr_t                       refcon,
3348    OSObject                        **handle)
3349{
3350    return registerPMSettingController(
3351            settings,
3352            (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS),
3353            func, target, refcon, handle);
3354}
3355
3356//******************************************************************************
3357// registerPMSettingController (public)
3358//
3359// Kexts may register for notifications when a particular setting is changed.
3360// A list of settings is available in IOPM.h.
3361// Arguments:
3362//  * settings - An OSArray containing OSSymbols. Caller should populate this
3363//          array with a list of settings caller wants notifications from.
3364//  * func - A C function callback of the type IOPMSettingControllerCallback
3365//  * target - caller may provide an OSObject *, which PM will pass as an
3366//          target to calls to "func"
3367//  * refcon - caller may provide an void *, which PM will pass as an
3368//          argument to calls to "func"
3369//  * handle - This is a return argument. We will populate this pointer upon
3370//          call success. Hold onto this and pass this argument to
3371//          IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3372// Returns:
3373//      kIOReturnSuccess on success
3374//******************************************************************************
3375
3376IOReturn IOPMrootDomain::registerPMSettingController(
3377    const OSSymbol *                settings[],
3378    uint32_t                        supportedPowerSources,
3379    IOPMSettingControllerCallback   func,
3380    OSObject                        *target,
3381    uintptr_t                       refcon,
3382    OSObject                        **handle)
3383{
3384    PMSettingObject *pmso = NULL;
3385    OSObject        *pmsh = NULL;
3386    OSArray         *list = NULL;
3387    int             i;
3388
3389    if (NULL == settings ||
3390        NULL == func     ||
3391        NULL == handle)
3392    {
3393        return kIOReturnBadArgument;
3394    }
3395
3396    pmso = PMSettingObject::pmSettingObject(
3397                (IOPMrootDomain *) this, func, target,
3398                refcon, supportedPowerSources, settings, &pmsh);
3399
3400    if (!pmso) {
3401        *handle = NULL;
3402        return kIOReturnInternalError;
3403    }
3404
3405    PMSETTING_LOCK();
3406    for (i=0; settings[i]; i++)
3407    {
3408        list = (OSArray *) settingsCallbacks->getObject(settings[i]);
3409        if (!list) {
3410            // New array of callbacks for this setting
3411            list = OSArray::withCapacity(1);
3412            settingsCallbacks->setObject(settings[i], list);
3413            list->release();
3414        }
3415
3416        // Add caller to the callback list
3417        list->setObject(pmso);
3418    }
3419    PMSETTING_UNLOCK();
3420
3421    // Return handle to the caller, the setting object is private.
3422    *handle = pmsh;
3423
3424    return kIOReturnSuccess;
3425}
3426
3427//******************************************************************************
3428// deregisterPMSettingObject (private)
3429//
3430// Only called from PMSettingObject.
3431//******************************************************************************
3432
3433void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject * pmso )
3434{
3435    thread_t                thisThread = current_thread();
3436    PMSettingCallEntry      *callEntry;
3437    OSCollectionIterator    *iter;
3438    OSSymbol                *sym;
3439    OSArray                 *array;
3440    int                     index;
3441    bool                    wait;
3442
3443    PMSETTING_LOCK();
3444
3445    pmso->disabled = true;
3446
3447    // Wait for all callout threads to finish.
3448    do {
3449        wait = false;
3450        queue_iterate(&pmso->calloutQueue, callEntry, PMSettingCallEntry *, link)
3451        {
3452            if (callEntry->thread != thisThread)
3453            {
3454                wait = true;
3455                break;
3456            }
3457        }
3458        if (wait)
3459        {
3460            assert(0 == pmso->waitThread);
3461            pmso->waitThread = thisThread;
3462            PMSETTING_WAIT(pmso);
3463            pmso->waitThread = 0;
3464        }
3465    } while (wait);
3466
3467    // Search each PM settings array in the kernel.
3468    iter = OSCollectionIterator::withCollection(settingsCallbacks);
3469    if (iter)
3470    {
3471        while ((sym = OSDynamicCast(OSSymbol, iter->getNextObject())))
3472        {
3473            array = (OSArray *) settingsCallbacks->getObject(sym);
3474            index = array->getNextIndexOfObject(pmso, 0);
3475            if (-1 != index) {
3476                array->removeObject(index);
3477            }
3478        }
3479        iter->release();
3480    }
3481
3482    PMSETTING_UNLOCK();
3483
3484    pmso->release();
3485}
3486
3487//******************************************************************************
3488// informCPUStateChange
3489//
3490// Call into PM CPU code so that CPU power savings may dynamically adjust for
3491// running on battery, with the lid closed, etc.
3492//
3493// informCPUStateChange is a no-op on non x86 systems
3494// only x86 has explicit support in the IntelCPUPowerManagement kext
3495//******************************************************************************
3496
3497void IOPMrootDomain::informCPUStateChange(
3498    uint32_t type,
3499    uint32_t value )
3500{
3501#if defined(__i386__) || defined(__x86_64__)
3502
3503    pmioctlVariableInfo_t varInfoStruct;
3504    int                 pmCPUret = 0;
3505    const char          *varNameStr = NULL;
3506    int32_t             *varIndex   = NULL;
3507
3508    if (kInformAC == type) {
3509        varNameStr = kIOPMRootDomainBatPowerCString;
3510        varIndex = &idxPMCPULimitedPower;
3511    } else if (kInformLid == type) {
3512        varNameStr = kIOPMRootDomainLidCloseCString;
3513        varIndex = &idxPMCPUClamshell;
3514    } else {
3515        return;
3516    }
3517
3518    // Set the new value!
3519    // pmCPUControl will assign us a new ID if one doesn't exist yet
3520    bzero(&varInfoStruct, sizeof(pmioctlVariableInfo_t));
3521    varInfoStruct.varID         = *varIndex;
3522    varInfoStruct.varType       = vBool;
3523    varInfoStruct.varInitValue  = value;
3524    varInfoStruct.varCurValue   = value;
3525    strncpy( (char *)varInfoStruct.varName,
3526             (const char *)varNameStr,
3527             strlen(varNameStr) + 1 );
3528
3529    // Set!
3530    pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct );
3531
3532    // pmCPU only assigns numerical id's when a new varName is specified
3533    if ((0 == pmCPUret)
3534        && (*varIndex == kCPUUnknownIndex))
3535    {
3536        // pmCPUControl has assigned us a new variable ID.
3537        // Let's re-read the structure we just SET to learn that ID.
3538        pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct );
3539
3540        if (0 == pmCPUret)
3541        {
3542            // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3543            *varIndex = varInfoStruct.varID;
3544        }
3545    }
3546
3547    return;
3548
3549#endif /* __i386__ || __x86_64__ */
3550}
3551
3552// MARK: -
3553// MARK: Deep Sleep Policy
3554
3555#if HIBERNATION
3556
3557//******************************************************************************
3558// evaluateSystemSleepPolicy
3559//******************************************************************************
3560
3561#define kIOPlatformSystemSleepPolicyKey     "IOPlatformSystemSleepPolicy"
3562
3563// Sleep flags
3564enum {
3565    kIOPMSleepFlagHibernate         = 0x00000001,
3566    kIOPMSleepFlagSleepTimerEnable  = 0x00000002
3567};
3568
3569struct IOPMSystemSleepPolicyEntry
3570{
3571    uint32_t    factorMask;
3572    uint32_t    factorBits;
3573    uint32_t    sleepFlags;
3574    uint32_t    wakeEvents;
3575} __attribute__((packed));
3576
3577struct IOPMSystemSleepPolicyTable
3578{
3579    uint32_t    signature;
3580    uint16_t    version;
3581    uint16_t    entryCount;
3582    IOPMSystemSleepPolicyEntry  entries[];
3583} __attribute__((packed));
3584
3585enum {
3586    kIOPMSleepAttributeHibernateSetup   = 0x00000001,
3587    kIOPMSleepAttributeHibernateSleep   = 0x00000002
3588};
3589
3590static uint32_t
3591getSleepTypeAttributes( uint32_t sleepType )
3592{
3593    static const uint32_t sleepTypeAttributes[ kIOPMSleepTypeLast ] =
3594    {
3595    /* invalid   */ 0,
3596    /* abort     */ 0,
3597    /* normal    */ 0,
3598    /* safesleep */ kIOPMSleepAttributeHibernateSetup,
3599    /* hibernate */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
3600    /* standby   */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
3601    /* poweroff  */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
3602    /* deepidle  */ 0
3603    };
3604
3605    if (sleepType >= kIOPMSleepTypeLast)
3606        return 0;
3607
3608    return sleepTypeAttributes[sleepType];
3609}
3610
3611bool IOPMrootDomain::evaluateSystemSleepPolicy(
3612    IOPMSystemSleepParameters * params, int sleepPhase, uint32_t * hibMode )
3613{
3614    const IOPMSystemSleepPolicyTable * pt;
3615    OSObject *  prop = 0;
3616    OSData *    policyData;
3617    uint64_t    currentFactors = 0;
3618    uint32_t    standbyDelay   = 0;
3619    uint32_t    powerOffDelay  = 0;
3620    uint32_t    powerOffTimer  = 0;
3621    uint32_t    mismatch;
3622    bool        standbyEnabled;
3623    bool        powerOffEnabled;
3624    bool        found = false;
3625
3626    // Get platform's sleep policy table
3627    if (!gSleepPolicyHandler)
3628    {
3629        prop = getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey);
3630        if (!prop) goto done;
3631    }
3632
3633    // Fetch additional settings
3634    standbyEnabled = (getSleepOption(kIOPMDeepSleepDelayKey, &standbyDelay)
3635        && (getProperty(kIOPMDeepSleepEnabledKey) == kOSBooleanTrue));
3636    powerOffEnabled = (getSleepOption(kIOPMAutoPowerOffDelayKey, &powerOffDelay)
3637        && (getProperty(kIOPMAutoPowerOffEnabledKey) == kOSBooleanTrue));
3638    if (!getSleepOption(kIOPMAutoPowerOffTimerKey, &powerOffTimer))
3639        powerOffTimer = powerOffDelay;
3640
3641    DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
3642        sleepPhase, standbyEnabled, standbyDelay,
3643        powerOffEnabled, powerOffDelay, powerOffTimer, *hibMode);
3644
3645    // pmset level overrides
3646    if ((*hibMode & kIOHibernateModeOn) == 0)
3647    {
3648        if (!gSleepPolicyHandler)
3649        {
3650            standbyEnabled  = false;
3651            powerOffEnabled = false;
3652        }
3653    }
3654    else if (!(*hibMode & kIOHibernateModeSleep))
3655    {
3656        // Force hibernate (i.e. mode 25)
3657        // If standby is enabled, force standy.
3658        // If poweroff is enabled, force poweroff.
3659        if (standbyEnabled)
3660            currentFactors |= kIOPMSleepFactorStandbyForced;
3661        else if (powerOffEnabled)
3662            currentFactors |= kIOPMSleepFactorAutoPowerOffForced;
3663        else
3664            currentFactors |= kIOPMSleepFactorHibernateForced;
3665    }
3666
3667    // Current factors based on environment and assertions
3668    if (sleepTimerMaintenance)
3669        currentFactors |= kIOPMSleepFactorSleepTimerWake;
3670    if (standbyEnabled && sleepToStandby && !gSleepPolicyHandler)
3671        currentFactors |= kIOPMSleepFactorSleepTimerWake;
3672    if (!clamshellClosed)
3673        currentFactors |= kIOPMSleepFactorLidOpen;
3674    if (acAdaptorConnected)
3675        currentFactors |= kIOPMSleepFactorACPower;
3676    if (lowBatteryCondition)
3677        currentFactors |= kIOPMSleepFactorBatteryLow;
3678    if (!standbyDelay)
3679        currentFactors |= kIOPMSleepFactorStandbyNoDelay;
3680    if (!standbyEnabled)
3681        currentFactors |= kIOPMSleepFactorStandbyDisabled;
3682    if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit) !=
3683        kIOPMDriverAssertionLevelOff)
3684        currentFactors |= kIOPMSleepFactorUSBExternalDevice;
3685    if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit) !=
3686        kIOPMDriverAssertionLevelOff)
3687        currentFactors |= kIOPMSleepFactorBluetoothHIDDevice;
3688    if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit) !=
3689        kIOPMDriverAssertionLevelOff)
3690        currentFactors |= kIOPMSleepFactorExternalMediaMounted;
3691    if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) !=
3692        kIOPMDriverAssertionLevelOff)
3693        currentFactors |= kIOPMSleepFactorThunderboltDevice;
3694    if (_scheduledAlarms != 0)
3695        currentFactors |= kIOPMSleepFactorRTCAlarmScheduled;
3696    if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit) !=
3697        kIOPMDriverAssertionLevelOff)
3698        currentFactors |= kIOPMSleepFactorMagicPacketWakeEnabled;
3699#define TCPKEEPALIVE 1
3700#if TCPKEEPALIVE
3701    if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit) !=
3702        kIOPMDriverAssertionLevelOff)
3703        currentFactors |= kIOPMSleepFactorNetworkKeepAliveActive;
3704#endif
3705    if (!powerOffEnabled)
3706        currentFactors |= kIOPMSleepFactorAutoPowerOffDisabled;
3707    if (desktopMode)
3708        currentFactors |= kIOPMSleepFactorExternalDisplay;
3709    if (userWasActive)
3710        currentFactors |= kIOPMSleepFactorLocalUserActivity;
3711    if (darkWakeHibernateError && !CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
3712        currentFactors |= kIOPMSleepFactorHibernateFailed;
3713
3714    DLOG("sleep factors 0x%llx\n", currentFactors);
3715
3716    if (gSleepPolicyHandler)
3717    {
3718        uint32_t    savedHibernateMode;
3719        IOReturn    result;
3720
3721        if (!gSleepPolicyVars)
3722        {
3723            gSleepPolicyVars = IONew(IOPMSystemSleepPolicyVariables, 1);
3724            if (!gSleepPolicyVars)
3725                goto done;
3726            bzero(gSleepPolicyVars, sizeof(*gSleepPolicyVars));
3727        }
3728        gSleepPolicyVars->signature = kIOPMSystemSleepPolicySignature;
3729        gSleepPolicyVars->version   = kIOPMSystemSleepPolicyVersion;
3730        gSleepPolicyVars->currentCapability = _currentCapability;
3731        gSleepPolicyVars->highestCapability = _highestCapability;
3732        gSleepPolicyVars->sleepFactors      = currentFactors;
3733        gSleepPolicyVars->sleepReason       = lastSleepReason;
3734        gSleepPolicyVars->sleepPhase        = sleepPhase;
3735        gSleepPolicyVars->standbyDelay      = standbyDelay;
3736        gSleepPolicyVars->poweroffDelay     = powerOffDelay;
3737        gSleepPolicyVars->scheduledAlarms   = _scheduledAlarms | _userScheduledAlarm;
3738        gSleepPolicyVars->poweroffTimer     = powerOffTimer;
3739
3740        if (kIOPMSleepPhase0 == sleepPhase)
3741        {
3742            // preserve hibernateMode
3743            savedHibernateMode = gSleepPolicyVars->hibernateMode;
3744            gSleepPolicyVars->hibernateMode = *hibMode;
3745        }
3746        else if (kIOPMSleepPhase1 == sleepPhase)
3747        {
3748            // use original hibernateMode for phase2
3749            gSleepPolicyVars->hibernateMode = *hibMode;
3750        }
3751
3752        result = gSleepPolicyHandler(gSleepPolicyTarget, gSleepPolicyVars, params);
3753
3754        if (kIOPMSleepPhase0 == sleepPhase)
3755        {
3756            // restore hibernateMode
3757            gSleepPolicyVars->hibernateMode = savedHibernateMode;
3758        }
3759
3760        if ((result != kIOReturnSuccess) ||
3761             (kIOPMSleepTypeInvalid == params->sleepType) ||
3762             (params->sleepType >= kIOPMSleepTypeLast) ||
3763             (kIOPMSystemSleepParametersVersion != params->version))
3764        {
3765            MSG("sleep policy handler error\n");
3766            goto done;
3767        }
3768
3769        if ((getSleepTypeAttributes(params->sleepType) &
3770             kIOPMSleepAttributeHibernateSetup) &&
3771            ((*hibMode & kIOHibernateModeOn) == 0))
3772        {
3773            *hibMode |= (kIOHibernateModeOn | kIOHibernateModeSleep);
3774        }
3775
3776        DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
3777            params->version, params->sleepType, params->sleepFlags,
3778            params->ecWakeEvents, params->ecWakeTimer, params->ecPoweroffTimer);
3779        found = true;
3780        goto done;
3781    }
3782
3783    // Policy table is meaningless without standby enabled
3784    if (!standbyEnabled)
3785        goto done;
3786
3787    // Validate the sleep policy table
3788    policyData = OSDynamicCast(OSData, prop);
3789    if (!policyData || (policyData->getLength() <= sizeof(IOPMSystemSleepPolicyTable)))
3790        goto done;
3791
3792    pt = (const IOPMSystemSleepPolicyTable *) policyData->getBytesNoCopy();
3793    if ((pt->signature != kIOPMSystemSleepPolicySignature) ||
3794        (pt->version != 1) || (0 == pt->entryCount))
3795        goto done;
3796
3797    if (((policyData->getLength() - sizeof(IOPMSystemSleepPolicyTable)) !=
3798         (sizeof(IOPMSystemSleepPolicyEntry) * pt->entryCount)))
3799        goto done;
3800
3801    for (uint32_t i = 0; i < pt->entryCount; i++)
3802    {
3803        const IOPMSystemSleepPolicyEntry * entry = &pt->entries[i];
3804        mismatch = (((uint32_t)currentFactors ^ entry->factorBits) & entry->factorMask);
3805
3806        DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
3807            entry->factorMask, entry->factorBits,
3808            entry->sleepFlags, entry->wakeEvents, mismatch);
3809        if (mismatch)
3810            continue;
3811
3812        DLOG("^ found match\n");
3813        found = true;
3814
3815        params->version = kIOPMSystemSleepParametersVersion;
3816        params->reserved1 = 1;
3817        if (entry->sleepFlags & kIOPMSleepFlagHibernate)
3818            params->sleepType = kIOPMSleepTypeStandby;
3819        else
3820            params->sleepType = kIOPMSleepTypeNormalSleep;
3821
3822        params->ecWakeEvents = entry->wakeEvents;
3823        if (entry->sleepFlags & kIOPMSleepFlagSleepTimerEnable)
3824        {
3825            if (kIOPMSleepPhase2 == sleepPhase)
3826            {
3827                clock_sec_t now_secs = gIOLastSleepTime.tv_sec;
3828
3829                if (!_standbyTimerResetSeconds ||
3830                    (now_secs <= _standbyTimerResetSeconds))
3831                {
3832                    // Reset standby timer adjustment
3833                    _standbyTimerResetSeconds = now_secs;
3834                    DLOG("standby delay %u, reset %u\n",
3835                        standbyDelay, (uint32_t) _standbyTimerResetSeconds);
3836                }
3837                else if (standbyDelay)
3838                {
3839                    // Shorten the standby delay timer
3840                    clock_sec_t elapsed = now_secs - _standbyTimerResetSeconds;
3841                    if (standbyDelay > elapsed)
3842                        standbyDelay -= elapsed;
3843                    else
3844                        standbyDelay = 1; // must be > 0
3845
3846                    DLOG("standby delay %u, elapsed %u\n",
3847                        standbyDelay, (uint32_t) elapsed);
3848                }
3849            }
3850            params->ecWakeTimer = standbyDelay;
3851        }
3852        else if (kIOPMSleepPhase2 == sleepPhase)
3853        {
3854            // A sleep that does not enable the sleep timer will reset
3855            // the standby delay adjustment.
3856            _standbyTimerResetSeconds = 0;
3857        }
3858        break;
3859    }
3860
3861done:
3862    if (prop)
3863        prop->release();
3864
3865    return found;
3866}
3867
3868static IOPMSystemSleepParameters gEarlySystemSleepParams;
3869
3870void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
3871{
3872    // Evaluate early (priority interest phase), before drivers sleep.
3873
3874    DLOG("%s\n", __FUNCTION__);
3875    removeProperty(kIOPMSystemSleepParametersKey);
3876
3877    // Full wake resets the standby timer delay adjustment
3878    if (_highestCapability & kIOPMSystemCapabilityGraphics)
3879        _standbyTimerResetSeconds = 0;
3880
3881    hibernateDisabled = false;
3882    hibernateMode = 0;
3883    getSleepOption(kIOHibernateModeKey, &hibernateMode);
3884
3885    // Save for late evaluation if sleep is aborted
3886    bzero(&gEarlySystemSleepParams, sizeof(gEarlySystemSleepParams));
3887
3888    if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams, kIOPMSleepPhase1,
3889                                  &hibernateMode))
3890    {
3891        if (!hibernateRetry &&
3892            ((getSleepTypeAttributes(gEarlySystemSleepParams.sleepType) &
3893              kIOPMSleepAttributeHibernateSetup) == 0))
3894        {
3895            // skip hibernate setup
3896            hibernateDisabled = true;
3897        }
3898    }
3899
3900    // Publish IOPMSystemSleepType
3901    uint32_t sleepType = gEarlySystemSleepParams.sleepType;
3902    if (sleepType == kIOPMSleepTypeInvalid)
3903    {
3904        // no sleep policy
3905        sleepType = kIOPMSleepTypeNormalSleep;
3906        if (hibernateMode & kIOHibernateModeOn)
3907            sleepType = (hibernateMode & kIOHibernateModeSleep) ?
3908                        kIOPMSleepTypeSafeSleep : kIOPMSleepTypeHibernate;
3909    }
3910    else if ((sleepType == kIOPMSleepTypeStandby) &&
3911             (gEarlySystemSleepParams.ecPoweroffTimer))
3912    {
3913        // report the lowest possible sleep state
3914        sleepType = kIOPMSleepTypePowerOff;
3915    }
3916
3917    setProperty(kIOPMSystemSleepTypeKey, sleepType, 32);
3918}
3919
3920void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
3921{
3922    IOPMSystemSleepParameters   params;
3923    OSData *                    paramsData;
3924
3925    // Evaluate sleep policy after sleeping drivers but before platform sleep.
3926
3927    DLOG("%s\n", __FUNCTION__);
3928
3929    bzero(&params, sizeof(params));
3930    if (evaluateSystemSleepPolicy(&params, kIOPMSleepPhase2, &hibernateMode))
3931    {
3932        if ((hibernateDisabled || hibernateAborted) &&
3933            (getSleepTypeAttributes(params.sleepType) &
3934             kIOPMSleepAttributeHibernateSetup))
3935        {
3936            // Final evaluation picked a state requiring hibernation,
3937            // but hibernate setup was skipped. Arm a short sleep using
3938            // the early non-hibernate sleep parameters.
3939            // Set hibernateRetry flag to force hibernate setup on the
3940            // next sleep.
3941
3942            bcopy(&gEarlySystemSleepParams, &params, sizeof(params));
3943            params.sleepType = kIOPMSleepTypeAbortedSleep;
3944            params.ecWakeTimer = 1;
3945            hibernateRetry = true;
3946            DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
3947                params.ecWakeTimer, hibernateDisabled, hibernateAborted);
3948        }
3949        else
3950        {
3951            hibernateRetry = false;
3952        }
3953
3954        paramsData = OSData::withBytes(&params, sizeof(params));
3955        if (paramsData)
3956        {
3957            setProperty(kIOPMSystemSleepParametersKey, paramsData);
3958            paramsData->release();
3959        }
3960
3961        if (getSleepTypeAttributes(params.sleepType) &
3962            kIOPMSleepAttributeHibernateSleep)
3963        {
3964            // Disable sleep to force hibernation
3965            gIOHibernateMode &= ~kIOHibernateModeSleep;
3966        }
3967    }
3968}
3969
3970bool IOPMrootDomain::getHibernateSettings(
3971    uint32_t *  hibernateModePtr,
3972    uint32_t *  hibernateFreeRatio,
3973    uint32_t *  hibernateFreeTime )
3974{
3975    // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
3976    // has updated the hibernateDisabled flag.
3977
3978    bool ok = getSleepOption(kIOHibernateModeKey, hibernateModePtr);
3979    getSleepOption(kIOHibernateFreeRatioKey, hibernateFreeRatio);
3980    getSleepOption(kIOHibernateFreeTimeKey, hibernateFreeTime);
3981    if (hibernateDisabled)
3982        *hibernateModePtr = 0;
3983    else if (gSleepPolicyHandler)
3984        *hibernateModePtr = hibernateMode;
3985    DLOG("hibernateMode 0x%x\n", *hibernateModePtr);
3986    return ok;
3987}
3988
3989bool IOPMrootDomain::getSleepOption( const char * key, uint32_t * option )
3990{
3991    OSObject *      optionsProp;
3992    OSDictionary *  optionsDict;
3993    OSObject *      obj = 0;
3994    OSNumber *      num;
3995    bool            ok = false;
3996
3997    optionsProp = copyProperty(kRootDomainSleepOptionsKey);
3998    optionsDict = OSDynamicCast(OSDictionary, optionsProp);
3999
4000    if (optionsDict)
4001    {
4002        obj = optionsDict->getObject(key);
4003        if (obj) obj->retain();
4004    }
4005    if (!obj)
4006    {
4007        obj = copyProperty(key);
4008    }
4009    if (obj && (num = OSDynamicCast(OSNumber, obj)))
4010    {
4011        *option = num->unsigned32BitValue();
4012        ok = true;
4013    }
4014
4015    if (obj)
4016        obj->release();
4017    if (optionsProp)
4018        optionsProp->release();
4019
4020    return true;
4021}
4022#endif /* HIBERNATION */
4023
4024IOReturn IOPMrootDomain::getSystemSleepType( uint32_t * sleepType )
4025{
4026#if HIBERNATION
4027    IOPMSystemSleepParameters   params;
4028    uint32_t                    hibMode = 0;
4029    bool                        ok;
4030
4031    if (gIOPMWorkLoop->inGate() == false)
4032    {
4033        IOReturn ret = gIOPMWorkLoop->runAction(
4034                        OSMemberFunctionCast(IOWorkLoop::Action, this,
4035                            &IOPMrootDomain::getSystemSleepType),
4036                        (OSObject *) this,
4037                        (void *) sleepType);
4038        return ret;
4039    }
4040
4041    getSleepOption(kIOHibernateModeKey, &hibMode);
4042    bzero(&params, sizeof(params));
4043
4044    ok = evaluateSystemSleepPolicy(&params, kIOPMSleepPhase0, &hibMode);
4045    if (ok)
4046    {
4047        *sleepType = params.sleepType;
4048        return kIOReturnSuccess;
4049    }
4050#endif
4051
4052    return kIOReturnUnsupported;
4053}
4054
4055// MARK: -
4056// MARK: Shutdown and Restart
4057
4058//******************************************************************************
4059// handlePlatformHaltRestart
4060//
4061//******************************************************************************
4062
4063struct HaltRestartApplierContext {
4064    IOPMrootDomain *    RootDomain;
4065    unsigned long       PowerState;
4066    IOPMPowerFlags      PowerFlags;
4067    UInt32              MessageType;
4068    UInt32              Counter;
4069};
4070
4071static void
4072platformHaltRestartApplier( OSObject * object, void * context )
4073{
4074    IOPowerStateChangeNotification  notify;
4075    HaltRestartApplierContext *     ctx;
4076    AbsoluteTime                    startTime;
4077    UInt32                          deltaTime;
4078
4079    ctx = (HaltRestartApplierContext *) context;
4080
4081    memset(&notify, 0, sizeof(notify));
4082    notify.powerRef    = (void *)(uintptr_t)ctx->Counter;
4083    notify.returnValue = 0;
4084    notify.stateNumber = ctx->PowerState;
4085    notify.stateFlags  = ctx->PowerFlags;
4086
4087    clock_get_uptime(&startTime);
4088    ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)&notify );
4089    deltaTime = computeDeltaTimeMS(&startTime);
4090
4091    if ((deltaTime > kPMHaltTimeoutMS) ||
4092        (gIOKitDebug & kIOLogPMRootDomain))
4093    {
4094        _IOServiceInterestNotifier * notifier;
4095        notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
4096
4097        // IOService children of IOPMrootDomain are not instrumented.
4098        // Only IORootParent currently falls under that group.
4099
4100        if (notifier)
4101        {
4102            LOG("%s handler %p took %u ms\n",
4103                (ctx->MessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" :
4104                     (ctx->MessageType == kIOMessageSystemPagingOff) ? "PagingOff" : "Restart",
4105                OBFUSCATE(notifier->handler), (uint32_t) deltaTime );
4106        }
4107    }
4108
4109    ctx->Counter++;
4110}
4111
4112void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
4113{
4114    HaltRestartApplierContext   ctx;
4115    AbsoluteTime                startTime;
4116    UInt32                      deltaTime;
4117
4118    memset(&ctx, 0, sizeof(ctx));
4119    ctx.RootDomain = this;
4120
4121    clock_get_uptime(&startTime);
4122    switch (pe_type)
4123    {
4124        case kPEHaltCPU:
4125        case kPEUPSDelayHaltCPU:
4126            ctx.PowerState  = OFF_STATE;
4127            ctx.MessageType = kIOMessageSystemWillPowerOff;
4128            break;
4129
4130        case kPERestartCPU:
4131            ctx.PowerState  = RESTART_STATE;
4132            ctx.MessageType = kIOMessageSystemWillRestart;
4133            break;
4134
4135        case kPEPagingOff:
4136            ctx.PowerState  = ON_STATE;
4137            ctx.MessageType = kIOMessageSystemPagingOff;
4138            IOService::updateConsoleUsers(NULL, kIOMessageSystemPagingOff);
4139#if HIBERNATION
4140            IOHibernateSystemRestart();
4141#endif
4142            break;
4143
4144        default:
4145            return;
4146    }
4147
4148    // Notify legacy clients
4149    applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &ctx);
4150
4151    // For normal shutdown, turn off File Server Mode.
4152    if (kPEHaltCPU == pe_type)
4153    {
4154        const OSSymbol * setting = OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey);
4155        OSNumber * num = OSNumber::withNumber((unsigned long long) 0, 32);
4156        if (setting && num)
4157        {
4158            setPMSetting(setting, num);
4159            setting->release();
4160            num->release();
4161        }
4162    }
4163
4164    if (kPEPagingOff != pe_type)
4165    {
4166        // Notify in power tree order
4167        notifySystemShutdown(this, ctx.MessageType);
4168    }
4169
4170    IOCPURunPlatformHaltRestartActions(pe_type);
4171
4172    deltaTime = computeDeltaTimeMS(&startTime);
4173    LOG("%s all drivers took %u ms\n",
4174        (ctx.MessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" :
4175            (ctx.MessageType == kIOMessageSystemPagingOff) ? "PagingOff" : "Restart",
4176        (uint32_t) deltaTime );
4177}
4178
4179//******************************************************************************
4180// shutdownSystem
4181//
4182//******************************************************************************
4183
4184IOReturn IOPMrootDomain::shutdownSystem( void )
4185{
4186    return kIOReturnUnsupported;
4187}
4188
4189//******************************************************************************
4190// restartSystem
4191//
4192//******************************************************************************
4193
4194IOReturn IOPMrootDomain::restartSystem( void )
4195{
4196    return kIOReturnUnsupported;
4197}
4198
4199// MARK: -
4200// MARK: System Capability
4201
4202//******************************************************************************
4203// tagPowerPlaneService
4204//
4205// Running on PM work loop thread.
4206//******************************************************************************
4207
4208void IOPMrootDomain::tagPowerPlaneService(
4209        IOService *     service,
4210        IOPMActions *   actions )
4211{
4212    uint32_t    flags = 0;
4213    bool        isDisplayWrangler;
4214
4215    memset(actions, 0, sizeof(*actions));
4216    actions->target = this;
4217
4218    if (service == this)
4219    {
4220        actions->actionPowerChangeStart =
4221            OSMemberFunctionCast(
4222                IOPMActionPowerChangeStart, this,
4223                &IOPMrootDomain::handleOurPowerChangeStart);
4224
4225        actions->actionPowerChangeDone =
4226            OSMemberFunctionCast(
4227                IOPMActionPowerChangeDone, this,
4228                &IOPMrootDomain::handleOurPowerChangeDone);
4229
4230        actions->actionPowerChangeOverride =
4231            OSMemberFunctionCast(
4232                IOPMActionPowerChangeOverride, this,
4233                &IOPMrootDomain::overrideOurPowerChange);
4234        return;
4235    }
4236
4237#if !NO_KERNEL_HID
4238    isDisplayWrangler = (0 != service->metaCast("IODisplayWrangler"));
4239    if (isDisplayWrangler)
4240    {
4241        wrangler = service;
4242    }
4243#else
4244    isDisplayWrangler = false;
4245#endif
4246
4247#if defined(__i386__) || defined(__x86_64__)
4248    if (isDisplayWrangler)
4249        flags |= kPMActionsFlagIsDisplayWrangler;
4250    if (service->getProperty("IOPMStrictTreeOrder"))
4251        flags |= kPMActionsFlagIsGraphicsDevice;
4252    if (service->getProperty("IOPMUnattendedWakePowerState"))
4253        flags |= kPMActionsFlagIsAudioDevice;
4254#endif
4255
4256    // Find the power connection object that is a child of the PCI host
4257    // bridge, and has a graphics/audio device attached below. Mark the
4258    // power branch for delayed child notifications.
4259
4260    if (flags)
4261    {
4262        IORegistryEntry * child  = service;
4263        IORegistryEntry * parent = child->getParentEntry(gIOPowerPlane);
4264
4265        while (child != this)
4266        {
4267            if ((parent == pciHostBridgeDriver) ||
4268                (parent == this))
4269            {
4270                if (OSDynamicCast(IOPowerConnection, child))
4271                {
4272                    IOPowerConnection * conn = (IOPowerConnection *) child;
4273                    conn->delayChildNotification = true;
4274                }
4275                break;
4276            }
4277            child = parent;
4278            parent = child->getParentEntry(gIOPowerPlane);
4279        }
4280    }
4281
4282    if (flags)
4283    {
4284        DLOG("%s tag flags %x\n", service->getName(), flags);
4285        actions->parameter |= flags;
4286        actions->actionPowerChangeOverride =
4287            OSMemberFunctionCast(
4288                IOPMActionPowerChangeOverride, this,
4289                &IOPMrootDomain::overridePowerChangeForUIService);
4290
4291        if (flags & kPMActionsFlagIsDisplayWrangler)
4292        {
4293            actions->actionActivityTickle =
4294                OSMemberFunctionCast(
4295                    IOPMActionActivityTickle, this,
4296                    &IOPMrootDomain::handleActivityTickleForDisplayWrangler);
4297
4298            actions->actionUpdatePowerClient =
4299                OSMemberFunctionCast(
4300                    IOPMActionUpdatePowerClient, this,
4301                    &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler);
4302        }
4303        return;
4304    }
4305
4306    // Locate the first PCI host bridge for PMTrace.
4307    if (!pciHostBridgeDevice && service->metaCast("IOPCIBridge"))
4308    {
4309        IOService * provider = service->getProvider();
4310        if (OSDynamicCast(IOPlatformDevice, provider) &&
4311            provider->inPlane(gIODTPlane))
4312        {
4313            pciHostBridgeDevice = provider;
4314            pciHostBridgeDriver = service;
4315            DLOG("PMTrace found PCI host bridge %s->%s\n",
4316                provider->getName(), service->getName());
4317        }
4318    }
4319
4320    // Tag top-level PCI devices. The order of PMinit() call does not
4321    // change across boots and is used as the PCI bit number.
4322    if (pciHostBridgeDevice && service->metaCast("IOPCIDevice"))
4323    {
4324        // Would prefer to check built-in property, but tagPowerPlaneService()
4325        // is called before pciDevice->registerService().
4326        IORegistryEntry * parent = service->getParentEntry(gIODTPlane);
4327        if ((parent == pciHostBridgeDevice) && service->getProperty("acpi-device"))
4328        {
4329            int bit = pmTracer->recordTopLevelPCIDevice( service );
4330            if (bit >= 0)
4331            {
4332                // Save the assigned bit for fast lookup.
4333                actions->parameter |= (bit & kPMActionsPCIBitNumberMask);
4334
4335                actions->actionPowerChangeStart =
4336                    OSMemberFunctionCast(
4337                        IOPMActionPowerChangeStart, this,
4338                        &IOPMrootDomain::handlePowerChangeStartForPCIDevice);
4339
4340                actions->actionPowerChangeDone =
4341                    OSMemberFunctionCast(
4342                        IOPMActionPowerChangeDone, this,
4343                        &IOPMrootDomain::handlePowerChangeDoneForPCIDevice);
4344            }
4345        }
4346    }
4347}
4348
4349//******************************************************************************
4350// PM actions for root domain
4351//******************************************************************************
4352
4353void IOPMrootDomain::overrideOurPowerChange(
4354    IOService *             service,
4355    IOPMActions *           actions,
4356    IOPMPowerStateIndex *   inOutPowerState,
4357    IOPMPowerChangeFlags *  inOutChangeFlags,
4358    IOPMRequestTag          requestTag )
4359{
4360    uint32_t powerState  = (uint32_t) *inOutPowerState;
4361    uint32_t changeFlags = *inOutChangeFlags;
4362    uint32_t currentPowerState = (uint32_t) getPowerState();
4363
4364    if (changeFlags & kIOPMParentInitiated)
4365    {
4366        // Root parent is permanently pegged at max power,
4367        // a parent initiated power change is unexpected.
4368        *inOutChangeFlags |= kIOPMNotDone;
4369        return;
4370    }
4371
4372    if (powerState < currentPowerState)
4373    {
4374        if (CAP_CURRENT(kIOPMSystemCapabilityGraphics))
4375        {
4376            // Root domain is dropping power state ON->SLEEP.
4377            // If system is in full wake, first enter dark wake by
4378            // converting the power drop to a capability change.
4379            // Once in dark wake, transition to sleep state ASAP.
4380
4381            darkWakeToSleepASAP = true;
4382
4383            // Drop graphics and audio capability
4384            _desiredCapability &= ~(
4385                kIOPMSystemCapabilityGraphics |
4386                kIOPMSystemCapabilityAudio    );
4387
4388            // Convert to capability change (ON->ON)
4389            *inOutPowerState = ON_STATE;
4390            *inOutChangeFlags |= kIOPMSynchronize;
4391
4392            // Revert device desire from SLEEP to ON
4393            changePowerStateToPriv(ON_STATE);
4394        }
4395        else
4396        {
4397            // System is in dark wake, ok to drop power state.
4398            // Broadcast root powering down to entire tree.
4399            *inOutChangeFlags |= kIOPMRootChangeDown;
4400        }
4401    }
4402    else if (powerState > currentPowerState)
4403    {
4404        if ((_currentCapability & kIOPMSystemCapabilityCPU) == 0)
4405        {
4406            // Broadcast power up when waking from sleep, but not for the
4407            // initial power change at boot by checking for cpu capability.
4408            *inOutChangeFlags |= kIOPMRootChangeUp;
4409        }
4410    }
4411}
4412
4413void IOPMrootDomain::handleOurPowerChangeStart(
4414    IOService *             service,
4415    IOPMActions *           actions,
4416    IOPMPowerStateIndex     powerState,
4417    IOPMPowerChangeFlags *  inOutChangeFlags,
4418    IOPMRequestTag          requestTag )
4419{
4420    uint32_t changeFlags        = *inOutChangeFlags;
4421    uint32_t currentPowerState  = (uint32_t) getPowerState();
4422    uint32_t sleepReason        = requestTag ? requestTag : kIOPMSleepReasonIdle;
4423    bool     publishSleepReason = false;
4424
4425    _systemTransitionType    = kSystemTransitionNone;
4426    _systemMessageClientMask = 0;
4427    capabilityLoss           = false;
4428
4429    if (lowBatteryCondition)
4430    {
4431        // Low battery notification may arrive after the initial sleep request
4432        // has been queued. Override the sleep reason so powerd and others can
4433        // treat this as an emergency sleep.
4434        sleepReason = kIOPMSleepReasonLowPower;
4435    }
4436
4437    // 1. Explicit capability change.
4438
4439    if (changeFlags & kIOPMSynchronize)
4440    {
4441        if (powerState == ON_STATE)
4442        {
4443            if (changeFlags & kIOPMSyncNoChildNotify)
4444                _systemTransitionType = kSystemTransitionNewCapClient;
4445            else
4446                _systemTransitionType = kSystemTransitionCapability;
4447        }
4448    }
4449
4450    // 2. Going to sleep (cancellation still possible).
4451
4452    else if (powerState < currentPowerState)
4453        _systemTransitionType = kSystemTransitionSleep;
4454
4455    // 3. Woke from (idle or demand) sleep.
4456
4457    else if (!systemBooting &&
4458             (changeFlags & kIOPMSelfInitiated) &&
4459             (powerState > currentPowerState))
4460    {
4461        _systemTransitionType = kSystemTransitionWake;
4462        _desiredCapability = kIOPMSystemCapabilityCPU |
4463                             kIOPMSystemCapabilityNetwork;
4464
4465        // Early exit from dark wake to full (e.g. LID open)
4466        if (kFullWakeReasonNone != fullWakeReason)
4467        {
4468            _desiredCapability |= (
4469                kIOPMSystemCapabilityGraphics |
4470                kIOPMSystemCapabilityAudio );
4471        }
4472#if HIBERNATION
4473    IOHibernateSetWakeCapabilities(_desiredCapability);
4474#endif
4475    }
4476
4477    // Update pending wake capability at the beginning of every
4478    // state transition (including synchronize). This will become
4479    // the current capability at the end of the transition.
4480
4481    if (kSystemTransitionSleep == _systemTransitionType)
4482    {
4483        _pendingCapability = 0;
4484        capabilityLoss = true;
4485
4486        // Clear previous stats
4487        IOLockLock(pmStatsLock);
4488        if (pmStatsAppResponses)
4489        {
4490            pmStatsAppResponses->release();
4491            pmStatsAppResponses = OSArray::withCapacity(5);
4492        }
4493        IOLockUnlock(pmStatsLock);
4494
4495    }
4496    else if (kSystemTransitionNewCapClient != _systemTransitionType)
4497    {
4498        _pendingCapability = _desiredCapability |
4499                             kIOPMSystemCapabilityCPU |
4500                             kIOPMSystemCapabilityNetwork;
4501
4502        if (_pendingCapability & kIOPMSystemCapabilityGraphics)
4503            _pendingCapability |= kIOPMSystemCapabilityAudio;
4504
4505        if ((kSystemTransitionCapability == _systemTransitionType) &&
4506            (_pendingCapability == _currentCapability))
4507        {
4508            // Cancel the PM state change.
4509            _systemTransitionType = kSystemTransitionNone;
4510            *inOutChangeFlags |= kIOPMNotDone;
4511        }
4512        if (__builtin_popcount(_pendingCapability) <
4513            __builtin_popcount(_currentCapability))
4514            capabilityLoss = true;
4515    }
4516
4517    // 1. Capability change.
4518
4519    if (kSystemTransitionCapability == _systemTransitionType)
4520    {
4521        // Dark to Full transition.
4522        if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
4523        {
4524            tracePoint( kIOPMTracePointDarkWakeExit );
4525
4526            willEnterFullWake();
4527        }
4528
4529        // Full to Dark transition.
4530        if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
4531        {
4532            tracePoint( kIOPMTracePointDarkWakeEntry );
4533            *inOutChangeFlags |= kIOPMSyncTellPowerDown;
4534            _systemMessageClientMask = kSystemMessageClientPowerd |
4535                                       kSystemMessageClientLegacyApp;
4536
4537
4538            // rdar://15971327
4539            // Prevent user active transitions before notifying clients
4540            // that system will sleep.
4541            preventTransitionToUserActive(true);
4542
4543            IOService::setAdvisoryTickleEnable( false );
4544
4545            // Publish the sleep reason for full to dark wake
4546            publishSleepReason = true;
4547            lastSleepReason = fullToDarkReason = sleepReason;
4548
4549            // Publish a UUID for the Sleep --> Wake cycle
4550            handlePublishSleepWakeUUID(true);
4551        }
4552    }
4553
4554    // 2. System sleep.
4555
4556    else if (kSystemTransitionSleep == _systemTransitionType)
4557    {
4558        // Beginning of a system sleep transition.
4559        // Cancellation is still possible.
4560        tracePoint( kIOPMTracePointSleepStarted, sleepReason );
4561
4562        _systemMessageClientMask = kSystemMessageClientAll;
4563        if ((_currentCapability & kIOPMSystemCapabilityGraphics) == 0)
4564            _systemMessageClientMask &= ~kSystemMessageClientLegacyApp;
4565        if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
4566            _systemMessageClientMask &= ~kSystemMessageClientKernel;
4567
4568        // Record the reason for dark wake back to sleep
4569        // System may not have ever achieved full wake
4570
4571        publishSleepReason = true;
4572        lastSleepReason = sleepReason;
4573    }
4574
4575    // 3. System wake.
4576
4577    else if (kSystemTransitionWake == _systemTransitionType)
4578    {
4579        tracePoint( kIOPMTracePointWakeWillPowerOnClients );
4580        // Clear stats about sleep
4581
4582        if (_pendingCapability & kIOPMSystemCapabilityGraphics)
4583        {
4584            willEnterFullWake();
4585        }
4586        else
4587        {
4588            // Message powerd only
4589            _systemMessageClientMask = kSystemMessageClientPowerd;
4590            tellClients(kIOMessageSystemWillPowerOn);
4591        }
4592    }
4593
4594    // The only location where the sleep reason is published. At this point
4595    // sleep can still be cancelled, but sleep reason should be published
4596    // early for logging purposes.
4597
4598    if (publishSleepReason)
4599    {
4600        static const char * IOPMSleepReasons[] =
4601        {
4602            kIOPMClamshellSleepKey,
4603            kIOPMPowerButtonSleepKey,
4604            kIOPMSoftwareSleepKey,
4605            kIOPMOSSwitchHibernationKey,
4606            kIOPMIdleSleepKey,
4607            kIOPMLowPowerSleepKey,
4608            kIOPMThermalEmergencySleepKey,
4609            kIOPMMaintenanceSleepKey,
4610            kIOPMSleepServiceExitKey,
4611            kIOPMDarkWakeThermalEmergencyKey
4612        };
4613
4614        // Record sleep cause in IORegistry
4615        uint32_t reasonIndex = sleepReason - kIOPMSleepReasonClamshell;
4616        if (reasonIndex < sizeof(IOPMSleepReasons)/sizeof(IOPMSleepReasons[0])) {
4617            DLOG("sleep reason %s\n", IOPMSleepReasons[reasonIndex]);
4618            setProperty(kRootDomainSleepReasonKey, IOPMSleepReasons[reasonIndex]);
4619        }
4620    }
4621
4622    if ((kSystemTransitionNone != _systemTransitionType) &&
4623        (kSystemTransitionNewCapClient != _systemTransitionType))
4624    {
4625        _systemStateGeneration++;
4626        systemDarkWake = false;
4627
4628        DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4629             "dcp %x:%x:%x\n",
4630            currentPowerState, (uint32_t) powerState, *inOutChangeFlags,
4631            _systemTransitionType, _systemStateGeneration,
4632            _systemMessageClientMask,
4633            _desiredCapability, _currentCapability, _pendingCapability);
4634    }
4635}
4636
4637void IOPMrootDomain::handleOurPowerChangeDone(
4638    IOService *             service,
4639    IOPMActions *           actions,
4640    IOPMPowerStateIndex     powerState,
4641    IOPMPowerChangeFlags    changeFlags,
4642    IOPMRequestTag          requestTag __unused )
4643{
4644    if (kSystemTransitionNewCapClient == _systemTransitionType)
4645    {
4646        _systemTransitionType = kSystemTransitionNone;
4647        return;
4648    }
4649
4650    if (_systemTransitionType != kSystemTransitionNone)
4651    {
4652        uint32_t currentPowerState = (uint32_t) getPowerState();
4653
4654        if (changeFlags & kIOPMNotDone)
4655        {
4656            // Power down was cancelled or vetoed.
4657            _pendingCapability = _currentCapability;
4658            lastSleepReason = 0;
4659
4660            if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics) &&
4661                 CAP_CURRENT(kIOPMSystemCapabilityCPU))
4662            {
4663                pmPowerStateQueue->submitPowerEvent(
4664                    kPowerEventPolicyStimulus,
4665                    (void *) kStimulusDarkWakeReentry,
4666                    _systemStateGeneration );
4667            }
4668
4669            // Revert device desire to max.
4670            changePowerStateToPriv(ON_STATE);
4671        }
4672        else
4673        {
4674            // Send message on dark wake to full wake promotion.
4675            // tellChangeUp() handles the normal SLEEP->ON case.
4676
4677            if (kSystemTransitionCapability == _systemTransitionType)
4678            {
4679                if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
4680                {
4681                    lastSleepReason = 0; // stop logging wrangler tickles
4682                    tellClients(kIOMessageSystemHasPoweredOn);
4683                }
4684                if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
4685                {
4686                    // Going dark, reset full wake state
4687                    // userIsActive will be cleared by wrangler powering down
4688                    wranglerTickled = false;
4689                    fullWakeReason = kFullWakeReasonNone;
4690                }
4691            }
4692
4693            // Reset state after exiting from dark wake.
4694
4695            if (CAP_GAIN(kIOPMSystemCapabilityGraphics) ||
4696                CAP_LOSS(kIOPMSystemCapabilityCPU))
4697            {
4698                darkWakeMaintenance = false;
4699                darkWakeToSleepASAP = false;
4700                pciCantSleepValid   = false;
4701                darkWakeSleepService = false;
4702
4703                if (CAP_LOSS(kIOPMSystemCapabilityCPU))
4704                {
4705                    // Remove the influence of display power assertion
4706                    // before next system wake.
4707                    if (wrangler) wrangler->changePowerStateForRootDomain(
4708                                                kWranglerPowerStateMin );
4709                    removeProperty(gIOPMUserTriggeredFullWakeKey);
4710                }
4711            }
4712
4713            // Entered dark mode.
4714
4715            if (((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
4716                 (_pendingCapability & kIOPMSystemCapabilityCPU))
4717            {
4718                // Queue an evaluation of whether to remain in dark wake,
4719                // and for how long. This serves the purpose of draining
4720                // any assertions from the queue.
4721
4722                pmPowerStateQueue->submitPowerEvent(
4723                    kPowerEventPolicyStimulus,
4724                    (void *) kStimulusDarkWakeEntry,
4725                    _systemStateGeneration );
4726            }
4727        }
4728
4729        DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4730             "dcp %x:%x:%x, dbgtimer %u\n",
4731            currentPowerState, (uint32_t) powerState, changeFlags,
4732            _systemTransitionType, _systemStateGeneration,
4733            _systemMessageClientMask,
4734            _desiredCapability, _currentCapability, _pendingCapability,
4735            _lastDebugWakeSeconds);
4736
4737        if (_pendingCapability & kIOPMSystemCapabilityGraphics)
4738        {
4739            displayWakeCnt++;
4740#if DARK_TO_FULL_EVALUATE_CLAMSHELL
4741            if (clamshellExists && fullWakeThreadCall &&
4742                CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
4743            {
4744                // Not the initial graphics full power, graphics won't
4745                // send a power notification to trigger a lid state
4746                // evaluation.
4747
4748                AbsoluteTime deadline;
4749                clock_interval_to_deadline(45, kSecondScale, &deadline);
4750                thread_call_enter_delayed(fullWakeThreadCall, deadline);
4751            }
4752#endif
4753        }
4754        else if (CAP_GAIN(kIOPMSystemCapabilityCPU))
4755            darkWakeCnt++;
4756
4757        // Update current system capability.
4758        if (_currentCapability != _pendingCapability)
4759            _currentCapability = _pendingCapability;
4760
4761        // Update highest system capability.
4762
4763        _highestCapability |= _currentCapability;
4764
4765        if (darkWakePostTickle &&
4766            (kSystemTransitionWake == _systemTransitionType) &&
4767            (gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
4768             kDarkWakeFlagHIDTickleLate)
4769        {
4770            darkWakePostTickle = false;
4771            reportUserInput();
4772        }
4773
4774        // Reset tracepoint at completion of capability change,
4775        // completion of wake transition, and aborted sleep transition.
4776
4777        if ((_systemTransitionType == kSystemTransitionCapability) ||
4778            (_systemTransitionType == kSystemTransitionWake) ||
4779            ((_systemTransitionType == kSystemTransitionSleep) &&
4780             (changeFlags & kIOPMNotDone)))
4781        {
4782            setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
4783            tracePoint( kIOPMTracePointSystemUp, 0 );
4784        }
4785
4786        _systemTransitionType = kSystemTransitionNone;
4787        _systemMessageClientMask = 0;
4788
4789        logGraphicsClamp = false;
4790    }
4791}
4792
4793//******************************************************************************
4794// PM actions for graphics and audio.
4795//******************************************************************************
4796
4797void IOPMrootDomain::overridePowerChangeForUIService(
4798    IOService *             service,
4799    IOPMActions *           actions,
4800    IOPMPowerStateIndex *   inOutPowerState,
4801    IOPMPowerChangeFlags *  inOutChangeFlags )
4802{
4803    uint32_t powerState  = (uint32_t) *inOutPowerState;
4804    uint32_t changeFlags = (uint32_t) *inOutChangeFlags;
4805
4806    if (kSystemTransitionNone == _systemTransitionType)
4807    {
4808        // Not in midst of a system transition.
4809        // Do not modify power limit enable state.
4810    }
4811    else if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
4812    {
4813        // Activate power limiter.
4814
4815        if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
4816            ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
4817            (changeFlags & kIOPMSynchronize))
4818        {
4819            actions->parameter |= kPMActionsFlagLimitPower;
4820        }
4821        else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
4822                 ((gDarkWakeFlags & kDarkWakeFlagAudioNotSuppressed) == 0) &&
4823                 ((_pendingCapability & kIOPMSystemCapabilityAudio) == 0) &&
4824                 (changeFlags & kIOPMSynchronize))
4825        {
4826            actions->parameter |= kPMActionsFlagLimitPower;
4827        }
4828        else if ((actions->parameter & kPMActionsFlagIsGraphicsDevice) &&
4829                 (_systemTransitionType == kSystemTransitionSleep))
4830        {
4831            // For graphics devices, arm the limiter when entering
4832            // system sleep. Not when dropping to dark wake.
4833            actions->parameter |= kPMActionsFlagLimitPower;
4834        }
4835
4836        if (actions->parameter & kPMActionsFlagLimitPower)
4837        {
4838            DLOG("+ plimit %s %p\n",
4839                service->getName(), OBFUSCATE(service));
4840        }
4841    }
4842    else
4843    {
4844        // Remove power limit.
4845
4846        if ((actions->parameter & (
4847            kPMActionsFlagIsDisplayWrangler |
4848            kPMActionsFlagIsGraphicsDevice )) &&
4849            (_pendingCapability & kIOPMSystemCapabilityGraphics))
4850        {
4851            actions->parameter &= ~kPMActionsFlagLimitPower;
4852        }
4853        else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
4854                 (_pendingCapability & kIOPMSystemCapabilityAudio))
4855        {
4856            actions->parameter &= ~kPMActionsFlagLimitPower;
4857        }
4858
4859        if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
4860        {
4861            DLOG("- plimit %s %p\n",
4862                service->getName(), OBFUSCATE(service));
4863        }
4864    }
4865
4866    if (actions->parameter & kPMActionsFlagLimitPower)
4867    {
4868        uint32_t maxPowerState = (uint32_t)(-1);
4869
4870        if (changeFlags & (kIOPMDomainDidChange | kIOPMDomainWillChange))
4871        {
4872            // Enforce limit for system power/cap transitions.
4873
4874            maxPowerState = 0;
4875            if ((service->getPowerState() > maxPowerState) &&
4876                (actions->parameter & kPMActionsFlagIsDisplayWrangler))
4877            {
4878                maxPowerState++;
4879
4880                // Remove lingering effects of any tickle before entering
4881                // dark wake. It will take a new tickle to return to full
4882                // wake, so the existing tickle state is useless.
4883
4884                if (changeFlags & kIOPMDomainDidChange)
4885                    *inOutChangeFlags |= kIOPMExpireIdleTimer;
4886            }
4887            else if (actions->parameter & kPMActionsFlagIsGraphicsDevice)
4888            {
4889                maxPowerState++;
4890            }
4891        }
4892        else
4893        {
4894            // Deny all self-initiated changes when power is limited.
4895            // Wrangler tickle should never defeat the limiter.
4896
4897            maxPowerState = service->getPowerState();
4898        }
4899
4900        if (powerState > maxPowerState)
4901        {
4902            DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
4903                service->getName(), OBFUSCATE(service), powerState, maxPowerState,
4904                changeFlags);
4905            *inOutPowerState = maxPowerState;
4906
4907            if (darkWakePostTickle &&
4908                (actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
4909                (changeFlags & kIOPMDomainWillChange) &&
4910                ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
4911                 kDarkWakeFlagHIDTickleEarly))
4912            {
4913                darkWakePostTickle = false;
4914                reportUserInput();
4915            }
4916        }
4917
4918        if (!graphicsSuppressed && (changeFlags & kIOPMDomainDidChange))
4919        {
4920            if (logGraphicsClamp)
4921            {
4922                AbsoluteTime    now;
4923                uint64_t        nsec;
4924
4925                clock_get_uptime(&now);
4926                SUB_ABSOLUTETIME(&now, &systemWakeTime);
4927                absolutetime_to_nanoseconds(now, &nsec);
4928                if (kIOLogPMRootDomain & gIOKitDebug)
4929                    MSG("Graphics suppressed %u ms\n",
4930                        ((int)((nsec) / 1000000ULL)));
4931            }
4932            graphicsSuppressed = true;
4933        }
4934    }
4935}
4936
4937void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
4938    IOService *     service,
4939    IOPMActions *   actions )
4940{
4941#if !NO_KERNEL_HID
4942    // Warning: Not running in PM work loop context - don't modify state !!!
4943    // Trap tickle directed to IODisplayWrangler while running with graphics
4944    // capability suppressed.
4945
4946    assert(service == wrangler);
4947
4948    clock_get_uptime(&userActivityTime);
4949    bool aborting = ((lastSleepReason == kIOPMSleepReasonIdle)
4950                  || (lastSleepReason == kIOPMSleepReasonMaintenance));
4951    if (aborting) {
4952        userActivityCount++;
4953        DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
4954            userActivityCount, lastSleepReason);
4955    }
4956
4957    if (!wranglerTickled &&
4958        ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0))
4959    {
4960        DLOG("display wrangler tickled\n");
4961        if (kIOLogPMRootDomain & gIOKitDebug)
4962            OSReportWithBacktrace("Dark wake display tickle");
4963        if (pmPowerStateQueue)
4964        {
4965            pmPowerStateQueue->submitPowerEvent(
4966                kPowerEventPolicyStimulus,
4967                (void *) kStimulusDarkWakeActivityTickle,
4968                true /* set wake type */ );
4969        }
4970    }
4971#endif
4972}
4973
4974void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
4975    IOService *             service,
4976    IOPMActions *           actions,
4977    const OSSymbol *        powerClient,
4978    IOPMPowerStateIndex     oldPowerState,
4979    IOPMPowerStateIndex     newPowerState )
4980{
4981#if !NO_KERNEL_HID
4982    assert(service == wrangler);
4983
4984    // This function implements half of the user active detection
4985    // by monitoring changes to the display wrangler's device desire.
4986    //
4987    // User becomes active when either:
4988    // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
4989    //    in max power state. This desire change in absence of a power state
4990    //    change is detected within. This handles the case when user becomes
4991    //    active while the display is already lit by setDisplayPowerOn().
4992    //
4993    // 2. Power state change to max, and DeviceDesire is also at max.
4994    //    Handled by displayWranglerNotification().
4995    //
4996    // User becomes inactive when DeviceDesire drops to sleep state or below.
4997
4998    DLOG("wrangler %s (ps %u, %u->%u)\n",
4999        powerClient->getCStringNoCopy(),
5000        (uint32_t) service->getPowerState(),
5001        (uint32_t) oldPowerState, (uint32_t) newPowerState);
5002
5003    if (powerClient == gIOPMPowerClientDevice)
5004    {
5005        if ((newPowerState > oldPowerState) &&
5006            (newPowerState == kWranglerPowerStateMax) &&
5007            (service->getPowerState() == kWranglerPowerStateMax))
5008        {
5009            evaluatePolicy( kStimulusEnterUserActiveState );
5010        }
5011        else
5012        if ((newPowerState < oldPowerState) &&
5013            (newPowerState <= kWranglerPowerStateSleep))
5014        {
5015            evaluatePolicy( kStimulusLeaveUserActiveState );
5016        }
5017    }
5018#endif
5019}
5020
5021//******************************************************************************
5022// User active state management
5023//******************************************************************************
5024
5025void IOPMrootDomain::preventTransitionToUserActive( bool prevent )
5026{
5027#if !NO_KERNEL_HID
5028    _preventUserActive = prevent;
5029    if (wrangler && !_preventUserActive)
5030    {
5031        // Allowing transition to user active, but the wrangler may have
5032        // already powered ON in case of sleep cancel/revert. Poll the
5033        // same conditions checked for in displayWranglerNotification()
5034        // to bring the user active state up to date.
5035
5036        if ((wrangler->getPowerState() == kWranglerPowerStateMax) &&
5037            (wrangler->getPowerStateForClient(gIOPMPowerClientDevice) ==
5038             kWranglerPowerStateMax))
5039        {
5040            evaluatePolicy( kStimulusEnterUserActiveState );
5041        }
5042    }
5043#endif
5044}
5045
5046//******************************************************************************
5047// Approve usage of delayed child notification by PM.
5048//******************************************************************************
5049
5050bool IOPMrootDomain::shouldDelayChildNotification(
5051    IOService * service )
5052{
5053    if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0) &&
5054        (kFullWakeReasonNone == fullWakeReason) &&
5055        (kSystemTransitionWake == _systemTransitionType))
5056    {
5057        DLOG("%s: delay child notify\n", service->getName());
5058        return true;
5059    }
5060    return false;
5061}
5062
5063//******************************************************************************
5064// PM actions for PCI device.
5065//******************************************************************************
5066
5067void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5068    IOService *             service,
5069    IOPMActions *           actions,
5070    IOPMPowerStateIndex     powerState,
5071    IOPMPowerChangeFlags *  inOutChangeFlags )
5072{
5073    pmTracer->tracePCIPowerChange(
5074        PMTraceWorker::kPowerChangeStart,
5075        service, *inOutChangeFlags,
5076        (actions->parameter & kPMActionsPCIBitNumberMask));
5077}
5078
5079void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5080    IOService *             service,
5081    IOPMActions *           actions,
5082    IOPMPowerStateIndex     powerState,
5083    IOPMPowerChangeFlags    changeFlags )
5084{
5085    pmTracer->tracePCIPowerChange(
5086        PMTraceWorker::kPowerChangeCompleted,
5087        service, changeFlags,
5088        (actions->parameter & kPMActionsPCIBitNumberMask));
5089}
5090
5091//******************************************************************************
5092// registerInterest
5093//
5094// Override IOService::registerInterest() to intercept special clients.
5095//******************************************************************************
5096
5097class IOPMServiceInterestNotifier: public _IOServiceInterestNotifier
5098{
5099
5100    friend class IOPMrootDomain;
5101    OSDeclareDefaultStructors(IOPMServiceInterestNotifier)
5102
5103protected:
5104    uint32_t    ackTimeoutCnt;
5105
5106};
5107
5108OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier, _IOServiceInterestNotifier)
5109
5110IONotifier * IOPMrootDomain::registerInterest(
5111                const OSSymbol * typeOfInterest,
5112                IOServiceInterestHandler handler,
5113                void * target, void * ref )
5114{
5115    IOPMServiceInterestNotifier *notifier = 0;
5116    bool            isSystemCapabilityClient;
5117    bool            isKernelCapabilityClient;
5118    IOReturn        rc = kIOReturnError;;
5119
5120    isSystemCapabilityClient =
5121        typeOfInterest &&
5122        typeOfInterest->isEqualTo(kIOPMSystemCapabilityInterest);
5123
5124    isKernelCapabilityClient =
5125        typeOfInterest &&
5126        typeOfInterest->isEqualTo(gIOPriorityPowerStateInterest);
5127
5128    if (isSystemCapabilityClient)
5129        typeOfInterest = gIOAppPowerStateInterest;
5130
5131    notifier = new IOPMServiceInterestNotifier;
5132    if (!notifier) return NULL;
5133
5134    if (notifier->init()) {
5135        rc  = super::registerInterestForNotifer(notifier, typeOfInterest, handler, target, ref);
5136    }
5137    if (rc != kIOReturnSuccess) {
5138        notifier->release();
5139        notifier = 0;
5140    }
5141    if (pmPowerStateQueue)
5142    {
5143        notifier->ackTimeoutCnt = 0;
5144        if (isSystemCapabilityClient)
5145        {
5146            notifier->retain();
5147            if (pmPowerStateQueue->submitPowerEvent(
5148                kPowerEventRegisterSystemCapabilityClient, notifier) == false)
5149                notifier->release();
5150        }
5151
5152        if (isKernelCapabilityClient)
5153        {
5154            notifier->retain();
5155            if (pmPowerStateQueue->submitPowerEvent(
5156                kPowerEventRegisterKernelCapabilityClient, notifier) == false)
5157                notifier->release();
5158        }
5159    }
5160
5161    return notifier;
5162}
5163
5164//******************************************************************************
5165// systemMessageFilter
5166//
5167//******************************************************************************
5168
5169bool IOPMrootDomain::systemMessageFilter(
5170    void * object, void * arg1, void * arg2, void * arg3 )
5171{
5172    const IOPMInterestContext * context = (const IOPMInterestContext *) arg1;
5173    bool  isCapMsg = (context->messageType == kIOMessageSystemCapabilityChange);
5174    bool  isCapClient = false;
5175    bool  allow = false;
5176
5177    do {
5178        if ((kSystemTransitionNewCapClient == _systemTransitionType) &&
5179            (!isCapMsg || !_joinedCapabilityClients ||
5180             !_joinedCapabilityClients->containsObject((OSObject *) object)))
5181            break;
5182
5183        // Capability change message for app and kernel clients.
5184
5185        if (isCapMsg)
5186        {
5187            if ((context->notifyType == kNotifyPriority) ||
5188                (context->notifyType == kNotifyCapabilityChangePriority))
5189                isCapClient = true;
5190
5191            if ((context->notifyType == kNotifyCapabilityChangeApps) &&
5192                (object == (void *) systemCapabilityNotifier))
5193                isCapClient = true;
5194        }
5195
5196        if (isCapClient)
5197        {
5198            IOPMSystemCapabilityChangeParameters * capArgs =
5199                (IOPMSystemCapabilityChangeParameters *) arg2;
5200
5201            if (kSystemTransitionNewCapClient == _systemTransitionType)
5202            {
5203                capArgs->fromCapabilities = 0;
5204                capArgs->toCapabilities = _currentCapability;
5205                capArgs->changeFlags = 0;
5206            }
5207            else
5208            {
5209                capArgs->fromCapabilities = _currentCapability;
5210                capArgs->toCapabilities = _pendingCapability;
5211
5212                if (context->isPreChange)
5213                    capArgs->changeFlags = kIOPMSystemCapabilityWillChange;
5214                else
5215                    capArgs->changeFlags = kIOPMSystemCapabilityDidChange;
5216            }
5217
5218            // Capability change messages only go to the PM configd plugin.
5219            // Wait for response post-change if capabilitiy is increasing.
5220            // Wait for response pre-change if capability is decreasing.
5221
5222            if ((context->notifyType == kNotifyCapabilityChangeApps) && arg3 &&
5223                ( (capabilityLoss && context->isPreChange) ||
5224                  (!capabilityLoss && !context->isPreChange) ) )
5225            {
5226                // app has not replied yet, wait for it
5227                *((OSObject **) arg3) = kOSBooleanFalse;
5228            }
5229
5230            allow = true;
5231            break;
5232        }
5233
5234        // Capability client will always see kIOMessageCanSystemSleep,
5235        // even for demand sleep. It will also have a chance to veto
5236        // sleep one last time after all clients have responded to
5237        // kIOMessageSystemWillSleep
5238
5239        if ((kIOMessageCanSystemSleep == context->messageType) ||
5240            (kIOMessageSystemWillNotSleep == context->messageType))
5241        {
5242            if (object == (OSObject *) systemCapabilityNotifier)
5243            {
5244                allow = true;
5245                break;
5246            }
5247
5248            // Not idle sleep, don't ask apps.
5249            if (context->changeFlags & kIOPMSkipAskPowerDown)
5250            {
5251                break;
5252            }
5253        }
5254
5255        if (kIOPMMessageLastCallBeforeSleep == context->messageType)
5256        {
5257            if ((object == (OSObject *) systemCapabilityNotifier) &&
5258                CAP_HIGHEST(kIOPMSystemCapabilityGraphics) &&
5259                (fullToDarkReason == kIOPMSleepReasonIdle))
5260                allow = true;
5261            break;
5262        }
5263
5264        // Reject capability change messages for legacy clients.
5265        // Reject legacy system sleep messages for capability client.
5266
5267        if (isCapMsg || (object == (OSObject *) systemCapabilityNotifier))
5268        {
5269            break;
5270        }
5271
5272        // Filter system sleep messages.
5273
5274        if ((context->notifyType == kNotifyApps) &&
5275            (_systemMessageClientMask & kSystemMessageClientLegacyApp))
5276        {
5277            IOPMServiceInterestNotifier *notify;
5278            allow = true;
5279
5280            if ((notify = OSDynamicCast(IOPMServiceInterestNotifier, (OSObject *)object))
5281                && arg3) {
5282
5283                if (notify->ackTimeoutCnt >= 3)
5284                    *((OSObject **) arg3) = kOSBooleanFalse;
5285                else
5286                    *((OSObject **) arg3) = kOSBooleanTrue;
5287            }
5288        }
5289        else if ((context->notifyType == kNotifyPriority) &&
5290                 (_systemMessageClientMask & kSystemMessageClientKernel))
5291        {
5292            allow = true;
5293        }
5294    }
5295    while (false);
5296
5297    if (allow && isCapMsg && _joinedCapabilityClients)
5298    {
5299        _joinedCapabilityClients->removeObject((OSObject *) object);
5300        if (_joinedCapabilityClients->getCount() == 0)
5301        {
5302            DLOG("destroyed capability client set %p\n",
5303                OBFUSCATE(_joinedCapabilityClients));
5304            _joinedCapabilityClients->release();
5305            _joinedCapabilityClients = 0;
5306        }
5307    }
5308
5309    return allow;
5310}
5311
5312//******************************************************************************
5313// setMaintenanceWakeCalendar
5314//
5315//******************************************************************************
5316
5317IOReturn IOPMrootDomain::setMaintenanceWakeCalendar(
5318    const IOPMCalendarStruct * calendar )
5319{
5320    OSData * data;
5321    IOReturn ret = 0;
5322
5323    if (!calendar)
5324        return kIOReturnBadArgument;
5325
5326    data = OSData::withBytesNoCopy((void *) calendar, sizeof(*calendar));
5327    if (!data)
5328        return kIOReturnNoMemory;
5329
5330    if (kPMCalendarTypeMaintenance == calendar->selector) {
5331        ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey, data);
5332        if (kIOReturnSuccess == ret)
5333            OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake, &_scheduledAlarms);
5334    } else
5335    if (kPMCalendarTypeSleepService == calendar->selector)
5336    {
5337        ret = setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey, data);
5338        if (kIOReturnSuccess == ret)
5339            OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake, &_scheduledAlarms);
5340    }
5341    DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
5342
5343    data->release();
5344    return ret;
5345}
5346
5347// MARK: -
5348// MARK: Display Wrangler
5349
5350//******************************************************************************
5351// displayWranglerNotification
5352//
5353// Handle the notification when the IODisplayWrangler changes power state.
5354//******************************************************************************
5355
5356IOReturn IOPMrootDomain::displayWranglerNotification(
5357    void * target, void * refCon,
5358    UInt32 messageType, IOService * service,
5359    void * messageArgument, vm_size_t argSize )
5360{
5361#if !NO_KERNEL_HID
5362    int                                 displayPowerState;
5363    IOPowerStateChangeNotification *    params =
5364            (IOPowerStateChangeNotification *) messageArgument;
5365
5366    if ((messageType != kIOMessageDeviceWillPowerOff) &&
5367        (messageType != kIOMessageDeviceHasPoweredOn))
5368        return kIOReturnUnsupported;
5369
5370    ASSERT_GATED();
5371    if (!gRootDomain)
5372        return kIOReturnUnsupported;
5373
5374    displayPowerState = params->stateNumber;
5375    DLOG("wrangler %s ps %d\n",
5376         getIOMessageString(messageType), displayPowerState);
5377
5378    switch (messageType) {
5379       case kIOMessageDeviceWillPowerOff:
5380            // Display wrangler has dropped power due to display idle
5381            // or force system sleep.
5382            //
5383            // 4 Display ON             kWranglerPowerStateMax
5384            // 3 Display Dim            kWranglerPowerStateDim
5385            // 2 Display Sleep          kWranglerPowerStateSleep
5386            // 1 Not visible to user
5387            // 0 Not visible to user    kWranglerPowerStateMin
5388
5389            if (displayPowerState <= kWranglerPowerStateSleep)
5390                gRootDomain->evaluatePolicy( kStimulusDisplayWranglerSleep );
5391            break;
5392
5393        case kIOMessageDeviceHasPoweredOn:
5394            // Display wrangler has powered on due to user activity
5395            // or wake from sleep.
5396
5397            if (kWranglerPowerStateMax == displayPowerState)
5398            {
5399                gRootDomain->evaluatePolicy( kStimulusDisplayWranglerWake );
5400
5401                // See comment in handleUpdatePowerClientForDisplayWrangler
5402                if (service->getPowerStateForClient(gIOPMPowerClientDevice) ==
5403                    kWranglerPowerStateMax)
5404                {
5405                    gRootDomain->evaluatePolicy( kStimulusEnterUserActiveState );
5406                }
5407            }
5408            break;
5409    }
5410#endif
5411    return kIOReturnUnsupported;
5412}
5413
5414//******************************************************************************
5415// displayWranglerMatchPublished
5416//
5417// Receives a notification when the IODisplayWrangler is published.
5418// When it's published we install a power state change handler.
5419//******************************************************************************
5420
5421bool IOPMrootDomain::displayWranglerMatchPublished(
5422    void * target,
5423    void * refCon,
5424    IOService * newService,
5425    IONotifier * notifier __unused)
5426{
5427#if !NO_KERNEL_HID
5428    // found the display wrangler, now install a handler
5429    if( !newService->registerInterest( gIOGeneralInterest,
5430                            &displayWranglerNotification, target, 0) )
5431    {
5432        return false;
5433    }
5434#endif
5435    return true;
5436}
5437
5438#if defined(__i386__) || defined(__x86_64__)
5439
5440bool IOPMrootDomain::IONVRAMMatchPublished(
5441    void * target,
5442    void * refCon,
5443    IOService * newService,
5444    IONotifier * notifier)
5445{
5446    unsigned int     len = 0;
5447    IOPMrootDomain *rd = (IOPMrootDomain *)target;
5448    OSNumber    *statusCode = NULL;
5449
5450    if (PEReadNVRAMProperty(kIOSleepWakeDebugKey, NULL, &len))
5451    {
5452        statusCode = OSDynamicCast(OSNumber, rd->getProperty(kIOPMSleepWakeFailureCodeKey));
5453        if (statusCode != NULL) {
5454            if (statusCode->unsigned64BitValue() != 0) {
5455                rd->swd_flags |= SWD_BOOT_BY_SW_WDOG;
5456                MSG("System was rebooted due to Sleep/Wake failure\n");
5457            }
5458            else {
5459                rd->swd_flags |= SWD_BOOT_BY_OSX_WDOG;
5460                MSG("System was non-responsive and was rebooted by watchdog\n");
5461            }
5462        }
5463
5464        rd->swd_logBufMap = rd->sleepWakeDebugRetrieve();
5465    }
5466    if (notifier) notifier->remove();
5467    return true;
5468}
5469
5470#else
5471bool IOPMrootDomain::IONVRAMMatchPublished(
5472    void * target,
5473    void * refCon,
5474    IOService * newService,
5475    IONotifier * notifier __unused)
5476{
5477    return false;
5478}
5479
5480#endif
5481
5482//******************************************************************************
5483// reportUserInput
5484//
5485//******************************************************************************
5486
5487void IOPMrootDomain::reportUserInput( void )
5488{
5489#if !NO_KERNEL_HID
5490    OSIterator * iter;
5491
5492    if(!wrangler)
5493    {
5494        iter = getMatchingServices(serviceMatching("IODisplayWrangler"));
5495        if(iter)
5496        {
5497            wrangler = (IOService *) iter->getNextObject();
5498            iter->release();
5499        }
5500    }
5501
5502    if(wrangler)
5503        wrangler->activityTickle(0,0);
5504#endif
5505}
5506
5507//******************************************************************************
5508// latchDisplayWranglerTickle
5509//******************************************************************************
5510
5511bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch )
5512{
5513#if !NO_KERNEL_HID
5514    if (latch)
5515    {
5516        if (!(_currentCapability & kIOPMSystemCapabilityGraphics) &&
5517            !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
5518            !checkSystemCanSustainFullWake())
5519        {
5520            // Currently in dark wake, and not transitioning to full wake.
5521            // Full wake is unsustainable, so latch the tickle to prevent
5522            // the display from lighting up momentarily.
5523            wranglerTickleLatched = true;
5524        }
5525        else
5526        {
5527            wranglerTickleLatched = false;
5528        }
5529    }
5530    else if (wranglerTickleLatched && checkSystemCanSustainFullWake())
5531    {
5532        wranglerTickleLatched = false;
5533
5534        pmPowerStateQueue->submitPowerEvent(
5535            kPowerEventPolicyStimulus,
5536            (void *) kStimulusDarkWakeActivityTickle );
5537    }
5538
5539    return wranglerTickleLatched;
5540#else
5541    return false;
5542#endif
5543}
5544
5545//******************************************************************************
5546// setDisplayPowerOn
5547//
5548// For root domain user client
5549//******************************************************************************
5550
5551void IOPMrootDomain::setDisplayPowerOn( uint32_t options )
5552{
5553    if (checkSystemCanSustainFullWake())
5554    {
5555        pmPowerStateQueue->submitPowerEvent( kPowerEventSetDisplayPowerOn,
5556                                             (void *) 0, options );
5557    }
5558}
5559
5560// MARK: -
5561// MARK: Battery
5562
5563//******************************************************************************
5564// batteryPublished
5565//
5566// Notification on battery class IOPowerSource appearance
5567//******************************************************************************
5568
5569bool IOPMrootDomain::batteryPublished(
5570    void * target,
5571    void * root_domain,
5572    IOService * resourceService,
5573    IONotifier * notifier __unused )
5574{
5575    // rdar://2936060&4435589
5576    // All laptops have dimmable LCD displays
5577    // All laptops have batteries
5578    // So if this machine has a battery, publish the fact that the backlight
5579    // supports dimming.
5580    ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims");
5581
5582    return (true);
5583}
5584
5585// MARK: -
5586// MARK: System PM Policy
5587
5588//******************************************************************************
5589// checkSystemSleepAllowed
5590//
5591//******************************************************************************
5592
5593bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options,
5594                                              uint32_t     sleepReason )
5595{
5596    int err = 0;
5597
5598    // Conditions that prevent idle and demand system sleep.
5599
5600    do {
5601        if (userDisabledAllSleep)
5602        {
5603            err = 1;        // 1. user-space sleep kill switch
5604            break;
5605        }
5606
5607        if (systemBooting || systemShutdown || gWillShutdown)
5608        {
5609            err = 2;        // 2. restart or shutdown in progress
5610            break;
5611        }
5612
5613        if (options == 0)
5614            break;
5615
5616        // Conditions above pegs the system at full wake.
5617        // Conditions below prevent system sleep but does not prevent
5618        // dark wake, and must be called from gated context.
5619
5620#if !CONFIG_SLEEP
5621        err = 3;            // 3. config does not support sleep
5622        break;
5623#endif
5624
5625        if (lowBatteryCondition)
5626        {
5627            break;          // always sleep on low battery
5628        }
5629
5630        if (sleepReason == kIOPMSleepReasonDarkWakeThermalEmergency)
5631        {
5632            break;          // always sleep on dark wake thermal emergencies
5633        }
5634
5635        if (preventSystemSleepList->getCount() != 0)
5636        {
5637            err = 4;        // 4. child prevent system sleep clamp
5638            break;
5639        }
5640
5641        if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit ) ==
5642            kIOPMDriverAssertionLevelOn)
5643        {
5644            err = 5;        // 5. CPU assertion
5645            break;
5646        }
5647
5648        if (pciCantSleepValid)
5649        {
5650            if (pciCantSleepFlag)
5651                err = 6;    // 6. PCI card does not support PM (cached)
5652            break;
5653        }
5654        else if (sleepSupportedPEFunction &&
5655                 CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
5656        {
5657            IOReturn ret;
5658            OSBitAndAtomic(~kPCICantSleep, &platformSleepSupport);
5659            ret = getPlatform()->callPlatformFunction(
5660                                    sleepSupportedPEFunction, false,
5661                                    NULL, NULL, NULL, NULL);
5662            pciCantSleepValid = true;
5663            pciCantSleepFlag  = false;
5664            if ((platformSleepSupport & kPCICantSleep) ||
5665                ((ret != kIOReturnSuccess) && (ret != kIOReturnUnsupported)))
5666            {
5667                err = 6;    // 6. PCI card does not support PM
5668                pciCantSleepFlag = true;
5669                break;
5670            }
5671        }
5672    }
5673    while (false);
5674
5675    if (err)
5676    {
5677        DLOG("System sleep prevented by %d\n", err);
5678        return false;
5679    }
5680    return true;
5681}
5682
5683bool IOPMrootDomain::checkSystemSleepEnabled( void )
5684{
5685    return checkSystemSleepAllowed(0, 0);
5686}
5687
5688bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason )
5689{
5690    ASSERT_GATED();
5691    return checkSystemSleepAllowed(1, sleepReason);
5692}
5693
5694//******************************************************************************
5695// checkSystemCanSustainFullWake
5696//******************************************************************************
5697
5698bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
5699{
5700#if !NO_KERNEL_HID
5701    if (lowBatteryCondition)
5702    {
5703        // Low battery wake, or received a low battery notification
5704        // while system is awake. This condition will persist until
5705        // the following wake.
5706        return false;
5707    }
5708
5709    if (clamshellExists && clamshellClosed && !clamshellSleepDisabled)
5710    {
5711        // Graphics state is unknown and external display might not be probed.
5712        // Do not incorporate state that requires graphics to be in max power
5713        // such as desktopMode or clamshellDisabled.
5714
5715        if (!acAdaptorConnected)
5716        {
5717            DLOG("full wake check: no AC\n");
5718            return false;
5719        }
5720    }
5721#endif
5722    return true;
5723}
5724
5725//******************************************************************************
5726// adjustPowerState
5727//
5728// Conditions that affect our wake/sleep decision has changed.
5729// If conditions dictate that the system must remain awake, clamp power
5730// state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
5731// is TRUE, then remove the power clamp and allow the power state to drop
5732// to SLEEP_STATE.
5733//******************************************************************************
5734
5735void IOPMrootDomain::adjustPowerState( bool sleepASAP )
5736{
5737    DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
5738        (uint32_t) getPowerState(), sleepASAP, sleepSlider);
5739
5740    ASSERT_GATED();
5741
5742    if ((sleepSlider == 0) || !checkSystemSleepEnabled())
5743    {
5744        changePowerStateToPriv(ON_STATE);
5745    }
5746    else if ( sleepASAP )
5747    {
5748        changePowerStateToPriv(SLEEP_STATE);
5749    }
5750}
5751
5752//******************************************************************************
5753// dispatchPowerEvent
5754//
5755// IOPMPowerStateQueue callback function. Running on PM work loop thread.
5756//******************************************************************************
5757
5758void IOPMrootDomain::dispatchPowerEvent(
5759    uint32_t event, void * arg0, uint64_t arg1 )
5760{
5761    DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
5762    ASSERT_GATED();
5763
5764    switch (event)
5765    {
5766        case kPowerEventFeatureChanged:
5767            messageClients(kIOPMMessageFeatureChange, this);
5768            break;
5769
5770        case kPowerEventReceivedPowerNotification:
5771            handlePowerNotification( (UInt32)(uintptr_t) arg0 );
5772            break;
5773
5774        case kPowerEventSystemBootCompleted:
5775            if (systemBooting)
5776            {
5777                systemBooting = false;
5778
5779                if (lowBatteryCondition)
5780                {
5781                    privateSleepSystem (kIOPMSleepReasonLowPower);
5782
5783                    // The rest is unnecessary since the system is expected
5784                    // to sleep immediately. The following wake will update
5785                    // everything.
5786                    break;
5787                }
5788
5789                if (swd_flags & SWD_VALID_LOGS) {
5790                    if (swd_flags & SWD_LOGS_IN_MEM) {
5791                        sleepWakeDebugDumpFromMem(swd_logBufMap);
5792                        swd_logBufMap->release();
5793                        swd_logBufMap = 0;
5794                    }
5795                    else if (swd_flags & SWD_LOGS_IN_FILE)
5796                        sleepWakeDebugDumpFromFile();
5797                }
5798                else if (swd_flags & (SWD_BOOT_BY_SW_WDOG|SWD_BOOT_BY_OSX_WDOG)) {
5799                    // If logs are invalid, write the failure code
5800                    sleepWakeDebugDumpFromMem(NULL);
5801                }
5802                // If lid is closed, re-send lid closed notification
5803                // now that booting is complete.
5804                if ( clamshellClosed )
5805                {
5806                    handlePowerNotification(kLocalEvalClamshellCommand);
5807                }
5808                evaluatePolicy( kStimulusAllowSystemSleepChanged );
5809
5810            }
5811            break;
5812
5813        case kPowerEventSystemShutdown:
5814            if (kOSBooleanTrue == (OSBoolean *) arg0)
5815            {
5816                /* We set systemShutdown = true during shutdown
5817                   to prevent sleep at unexpected times while loginwindow is trying
5818                   to shutdown apps and while the OS is trying to transition to
5819                   complete power of.
5820
5821                   Set to true during shutdown, as soon as loginwindow shows
5822                   the "shutdown countdown dialog", through individual app
5823                   termination, and through black screen kernel shutdown.
5824                 */
5825                systemShutdown = true;
5826            } else {
5827                /*
5828                 A shutdown was initiated, but then the shutdown
5829                 was cancelled, clearing systemShutdown to false here.
5830                */
5831                systemShutdown = false;
5832            }
5833            break;
5834
5835        case kPowerEventUserDisabledSleep:
5836            userDisabledAllSleep = (kOSBooleanTrue == (OSBoolean *) arg0);
5837            break;
5838
5839        case kPowerEventRegisterSystemCapabilityClient:
5840            if (systemCapabilityNotifier)
5841            {
5842                systemCapabilityNotifier->release();
5843                systemCapabilityNotifier = 0;
5844            }
5845            if (arg0)
5846            {
5847                systemCapabilityNotifier = (IONotifier *) arg0;
5848                systemCapabilityNotifier->retain();
5849            }
5850            /* intentional fall-through */
5851
5852        case kPowerEventRegisterKernelCapabilityClient:
5853            if (!_joinedCapabilityClients)
5854                _joinedCapabilityClients = OSSet::withCapacity(8);
5855            if (arg0)
5856            {
5857                IONotifier * notify = (IONotifier *) arg0;
5858                if (_joinedCapabilityClients)
5859                {
5860                    _joinedCapabilityClients->setObject(notify);
5861                    synchronizePowerTree( kIOPMSyncNoChildNotify );
5862                }
5863                notify->release();
5864            }
5865            break;
5866
5867        case kPowerEventPolicyStimulus:
5868            if (arg0)
5869            {
5870                int stimulus = (uintptr_t) arg0;
5871                evaluatePolicy( stimulus, (uint32_t) arg1 );
5872            }
5873            break;
5874
5875        case kPowerEventAssertionCreate:
5876            if (pmAssertions) {
5877                pmAssertions->handleCreateAssertion((OSData *)arg0);
5878            }
5879            break;
5880
5881
5882        case kPowerEventAssertionRelease:
5883            if (pmAssertions) {
5884                pmAssertions->handleReleaseAssertion(arg1);
5885            }
5886            break;
5887
5888        case kPowerEventAssertionSetLevel:
5889            if (pmAssertions) {
5890                pmAssertions->handleSetAssertionLevel(arg1, (IOPMDriverAssertionLevel)(uintptr_t)arg0);
5891            }
5892            break;
5893
5894        case kPowerEventQueueSleepWakeUUID:
5895            handleQueueSleepWakeUUID((OSObject *)arg0);
5896            break;
5897        case kPowerEventPublishSleepWakeUUID:
5898            handlePublishSleepWakeUUID((bool)arg0);
5899            break;
5900
5901        case kPowerEventSetDisplayPowerOn:
5902            if (!wrangler) break;
5903            if (arg1 != 0)
5904            {
5905                // Force wrangler to max power state. If system is in dark wake
5906                // this alone won't raise the wrangler's power state.
5907
5908                wrangler->changePowerStateForRootDomain(kWranglerPowerStateMax);
5909
5910                // System in dark wake, always requesting full wake should
5911                // not have any bad side-effects, even if the request fails.
5912
5913                if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics))
5914                {
5915                    setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeNotification);
5916                    requestFullWake( kFullWakeReasonDisplayOn );
5917                }
5918            }
5919            else
5920            {
5921                // Relenquish desire to power up display.
5922                // Must first transition to state 1 since wrangler doesn't
5923                // power off the displays at state 0. At state 0 the root
5924                // domain is removed from the wrangler's power client list.
5925
5926                wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin + 1);
5927                wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin);
5928            }
5929            break;
5930    }
5931}
5932
5933//******************************************************************************
5934// systemPowerEventOccurred
5935//
5936// The power controller is notifying us of a hardware-related power management
5937// event that we must handle.
5938//
5939// systemPowerEventOccurred covers the same functionality that
5940// receivePowerNotification does; it simply provides a richer API for conveying
5941// more information.
5942//******************************************************************************
5943
5944IOReturn IOPMrootDomain::systemPowerEventOccurred(
5945    const OSSymbol *event,
5946    uint32_t intValue)
5947{
5948    IOReturn        attempt = kIOReturnSuccess;
5949    OSNumber        *newNumber = NULL;
5950
5951    if (!event)
5952        return kIOReturnBadArgument;
5953
5954    newNumber = OSNumber::withNumber(intValue, 8*sizeof(intValue));
5955    if (!newNumber)
5956        return kIOReturnInternalError;
5957
5958    attempt = systemPowerEventOccurred(event, (OSObject *)newNumber);
5959
5960    newNumber->release();
5961
5962    return attempt;
5963}
5964
5965IOReturn IOPMrootDomain::systemPowerEventOccurred(
5966    const OSSymbol *event,
5967    OSObject *value)
5968{
5969    OSDictionary *thermalsDict = NULL;
5970    bool shouldUpdate = true;
5971
5972    if (!event || !value)
5973        return kIOReturnBadArgument;
5974
5975    // LOCK
5976    // We reuse featuresDict Lock because it already exists and guards
5977    // the very infrequently used publish/remove feature mechanism; so there's zero rsk
5978    // of stepping on that lock.
5979    if (featuresDictLock) IOLockLock(featuresDictLock);
5980
5981    thermalsDict = (OSDictionary *)getProperty(kIOPMRootDomainPowerStatusKey);
5982
5983    if (thermalsDict && OSDynamicCast(OSDictionary, thermalsDict)) {
5984        thermalsDict = OSDictionary::withDictionary(thermalsDict);
5985    } else {
5986        thermalsDict = OSDictionary::withCapacity(1);
5987    }
5988
5989    if (!thermalsDict) {
5990        shouldUpdate = false;
5991        goto exit;
5992    }
5993
5994    thermalsDict->setObject (event, value);
5995
5996    setProperty (kIOPMRootDomainPowerStatusKey, thermalsDict);
5997
5998    thermalsDict->release();
5999
6000exit:
6001    // UNLOCK
6002    if (featuresDictLock) IOLockUnlock(featuresDictLock);
6003
6004    if (shouldUpdate)
6005        messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
6006
6007    return kIOReturnSuccess;
6008}
6009
6010//******************************************************************************
6011// receivePowerNotification
6012//
6013// The power controller is notifying us of a hardware-related power management
6014// event that we must handle. This may be a result of an 'environment' interrupt
6015// from the power mgt micro.
6016//******************************************************************************
6017
6018IOReturn IOPMrootDomain::receivePowerNotification( UInt32 msg )
6019{
6020    pmPowerStateQueue->submitPowerEvent(
6021        kPowerEventReceivedPowerNotification, (void *)(uintptr_t) msg );
6022    return kIOReturnSuccess;
6023}
6024
6025void IOPMrootDomain::handlePowerNotification( UInt32 msg )
6026{
6027    bool        eval_clamshell = false;
6028
6029    ASSERT_GATED();
6030
6031    /*
6032     * Local (IOPMrootDomain only) eval clamshell command
6033     */
6034    if (msg & kLocalEvalClamshellCommand)
6035    {
6036        eval_clamshell = true;
6037    }
6038
6039    /*
6040     * Overtemp
6041     */
6042    if (msg & kIOPMOverTemp)
6043    {
6044        MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6045        privateSleepSystem (kIOPMSleepReasonThermalEmergency);
6046    }
6047
6048    /*
6049     * Sleep if system is in dark wake
6050     */
6051    if (msg & kIOPMDWOverTemp)
6052    {
6053        DLOG("DarkWake thermal limits message received!\n");
6054
6055        // Inform cap client that we're going to sleep
6056        messageClients(kIOPMMessageDarkWakeThermalEmergency);
6057
6058    }
6059
6060    /*
6061     * Sleep Now!
6062     */
6063    if (msg & kIOPMSleepNow)
6064    {
6065        privateSleepSystem (kIOPMSleepReasonSoftware);
6066    }
6067
6068    /*
6069     * Power Emergency
6070     */
6071    if (msg & kIOPMPowerEmergency)
6072    {
6073        lowBatteryCondition = true;
6074        privateSleepSystem (kIOPMSleepReasonLowPower);
6075    }
6076
6077    /*
6078     * Clamshell OPEN
6079     */
6080    if (msg & kIOPMClamshellOpened)
6081    {
6082        // Received clamshel open message from clamshell controlling driver
6083        // Update our internal state and tell general interest clients
6084        clamshellClosed = false;
6085        clamshellExists = true;
6086
6087        // Don't issue a hid tickle when lid is open and polled on wake
6088        if (msg & kIOPMSetValue)
6089        {
6090            setProperty(kIOPMRootDomainWakeTypeKey, "Lid Open");
6091            reportUserInput();
6092        }
6093
6094        // Tell PMCPU
6095        informCPUStateChange(kInformLid, 0);
6096
6097        // Tell general interest clients
6098        sendClientClamshellNotification();
6099
6100        bool aborting =  ((lastSleepReason == kIOPMSleepReasonClamshell)
6101                       || (lastSleepReason == kIOPMSleepReasonIdle)
6102                       || (lastSleepReason == kIOPMSleepReasonMaintenance));
6103        if (aborting) userActivityCount++;
6104        DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
6105    }
6106
6107    /*
6108     * Clamshell CLOSED
6109     * Send the clamshell interest notification since the lid is closing.
6110     */
6111    if (msg & kIOPMClamshellClosed)
6112    {
6113        // Received clamshel open message from clamshell controlling driver
6114        // Update our internal state and tell general interest clients
6115        clamshellClosed = true;
6116        clamshellExists = true;
6117
6118        // Tell PMCPU
6119        informCPUStateChange(kInformLid, 1);
6120
6121        // Tell general interest clients
6122        sendClientClamshellNotification();
6123
6124        // And set eval_clamshell = so we can attempt
6125        eval_clamshell = true;
6126    }
6127
6128    /*
6129     * Set Desktop mode (sent from graphics)
6130     *
6131     *  -> reevaluate lid state
6132     */
6133    if (msg & kIOPMSetDesktopMode)
6134    {
6135        desktopMode = (0 != (msg & kIOPMSetValue));
6136        msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
6137
6138        sendClientClamshellNotification();
6139
6140        // Re-evaluate the lid state
6141        eval_clamshell = true;
6142    }
6143
6144    /*
6145     * AC Adaptor connected
6146     *
6147     *  -> reevaluate lid state
6148     */
6149    if (msg & kIOPMSetACAdaptorConnected)
6150    {
6151        acAdaptorConnected = (0 != (msg & kIOPMSetValue));
6152        msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
6153
6154        // Tell CPU PM
6155        informCPUStateChange(kInformAC, !acAdaptorConnected);
6156
6157        // Tell BSD if AC is connected
6158        //      0 == external power source; 1 == on battery
6159        post_sys_powersource(acAdaptorConnected ? 0:1);
6160
6161        sendClientClamshellNotification();
6162
6163        // Re-evaluate the lid state
6164        eval_clamshell = true;
6165
6166        // Lack of AC may have latched a display wrangler tickle.
6167        // This mirrors the hardware's USB wake event latch, where a latched
6168        // USB wake event followed by an AC attach will trigger a full wake.
6169        latchDisplayWranglerTickle( false );
6170
6171#if HIBERNATION
6172        // AC presence will reset the standy timer delay adjustment.
6173        _standbyTimerResetSeconds = 0;
6174#endif
6175        if (!userIsActive) {
6176            // Reset userActivityTime when power supply is changed(rdr 13789330)
6177            clock_get_uptime(&userActivityTime);
6178        }
6179    }
6180
6181    /*
6182     * Enable Clamshell (external display disappear)
6183     *
6184     *  -> reevaluate lid state
6185     */
6186    if (msg & kIOPMEnableClamshell)
6187    {
6188        // Re-evaluate the lid state
6189        // System should sleep on external display disappearance
6190        // in lid closed operation.
6191        if (true == clamshellDisabled)
6192        {
6193            eval_clamshell = true;
6194        }
6195
6196        clamshellDisabled = false;
6197        sendClientClamshellNotification();
6198    }
6199
6200    /*
6201     * Disable Clamshell (external display appeared)
6202     * We don't bother re-evaluating clamshell state. If the system is awake,
6203     * the lid is probably open.
6204     */
6205    if (msg & kIOPMDisableClamshell)
6206    {
6207        clamshellDisabled = true;
6208        sendClientClamshellNotification();
6209    }
6210
6211    /*
6212     * Evaluate clamshell and SLEEP if appropiate
6213     */
6214    if (eval_clamshell && clamshellClosed)
6215    {
6216        if (shouldSleepOnClamshellClosed())
6217            privateSleepSystem (kIOPMSleepReasonClamshell);
6218        else
6219            evaluatePolicy( kStimulusDarkWakeEvaluate );
6220    }
6221
6222    /*
6223     * Power Button
6224     */
6225    if (msg & kIOPMPowerButton)
6226    {
6227        if (!wranglerAsleep)
6228        {
6229            OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
6230            // Check that power button sleep is enabled
6231            if( pbs ) {
6232                if( kOSBooleanTrue != getProperty(pbs))
6233                    privateSleepSystem (kIOPMSleepReasonPowerButton);
6234            }
6235        }
6236        else
6237            reportUserInput();
6238    }
6239}
6240
6241//******************************************************************************
6242// evaluatePolicy
6243//
6244// Evaluate root-domain policy in response to external changes.
6245//******************************************************************************
6246
6247void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
6248{
6249    union {
6250        struct {
6251            int idleSleepEnabled    : 1;
6252            int idleSleepDisabled   : 1;
6253            int displaySleep        : 1;
6254            int sleepDelayChanged   : 1;
6255            int evaluateDarkWake    : 1;
6256            int adjustPowerState    : 1;
6257            int userBecameInactive  : 1;
6258        } bit;
6259        uint32_t u32;
6260    } flags;
6261
6262    DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
6263
6264    ASSERT_GATED();
6265    flags.u32 = 0;
6266
6267    switch (stimulus)
6268    {
6269        case kStimulusDisplayWranglerSleep:
6270            if (!wranglerAsleep)
6271            {
6272                // first transition to wrangler sleep or lower
6273                wranglerAsleep = true;
6274                flags.bit.displaySleep = true;
6275            }
6276            break;
6277
6278        case kStimulusDisplayWranglerWake:
6279            displayIdleForDemandSleep = false;
6280            wranglerAsleep = false;
6281            break;
6282
6283        case kStimulusEnterUserActiveState:
6284            if (_preventUserActive)
6285            {
6286                DLOG("user active dropped\n");
6287                break;
6288            }
6289            if (!userIsActive)
6290            {
6291                userIsActive = true;
6292                userWasActive = true;
6293
6294                // Stay awake after dropping demand for display power on
6295                if (kFullWakeReasonDisplayOn == fullWakeReason)
6296                    fullWakeReason = fFullWakeReasonDisplayOnAndLocalUser;
6297
6298                setProperty(gIOPMUserIsActiveKey, kOSBooleanTrue);
6299                messageClients(kIOPMMessageUserIsActiveChanged);
6300            }
6301            flags.bit.idleSleepDisabled = true;
6302            break;
6303
6304        case kStimulusLeaveUserActiveState:
6305            if (userIsActive)
6306            {
6307                userIsActive = false;
6308                clock_get_uptime(&userBecameInactiveTime);
6309                flags.bit.userBecameInactive = true;
6310
6311                setProperty(gIOPMUserIsActiveKey, kOSBooleanFalse);
6312                messageClients(kIOPMMessageUserIsActiveChanged);
6313            }
6314            break;
6315
6316        case kStimulusAggressivenessChanged:
6317        {
6318            unsigned long   minutesToIdleSleep  = 0;
6319            unsigned long   minutesToDisplayDim = 0;
6320            unsigned long   minutesDelta        = 0;
6321
6322            // Fetch latest display and system sleep slider values.
6323            getAggressiveness(kPMMinutesToSleep, &minutesToIdleSleep);
6324            getAggressiveness(kPMMinutesToDim,   &minutesToDisplayDim);
6325            DLOG("aggressiveness changed: system %u->%u, display %u\n",
6326                (uint32_t) sleepSlider,
6327                (uint32_t) minutesToIdleSleep,
6328                (uint32_t) minutesToDisplayDim);
6329
6330            DLOG("idle time -> %ld secs (ena %d)\n",
6331                idleSeconds, (minutesToIdleSleep != 0));
6332
6333            if (0x7fffffff == minutesToIdleSleep)
6334                minutesToIdleSleep = idleSeconds;
6335
6336            // How long to wait before sleeping the system once
6337            // the displays turns off is indicated by 'extraSleepDelay'.
6338
6339            if ( minutesToIdleSleep > minutesToDisplayDim )
6340                minutesDelta = minutesToIdleSleep - minutesToDisplayDim;
6341            else if ( minutesToIdleSleep == minutesToDisplayDim )
6342                minutesDelta = 1;
6343
6344            if ((sleepSlider == 0) && (minutesToIdleSleep != 0))
6345                flags.bit.idleSleepEnabled = true;
6346
6347            if ((sleepSlider != 0) && (minutesToIdleSleep == 0))
6348                flags.bit.idleSleepDisabled = true;
6349
6350            if (((minutesDelta != extraSleepDelay) ||
6351                        (userActivityTime != userActivityTime_prev)) &&
6352                !flags.bit.idleSleepEnabled && !flags.bit.idleSleepDisabled)
6353                flags.bit.sleepDelayChanged = true;
6354
6355            if (systemDarkWake && !darkWakeToSleepASAP &&
6356                (flags.bit.idleSleepEnabled || flags.bit.idleSleepDisabled))
6357            {
6358                // Reconsider decision to remain in dark wake
6359                flags.bit.evaluateDarkWake = true;
6360            }
6361
6362            sleepSlider = minutesToIdleSleep;
6363            extraSleepDelay = minutesDelta;
6364            userActivityTime_prev = userActivityTime;
6365        }   break;
6366
6367        case kStimulusDemandSystemSleep:
6368            displayIdleForDemandSleep = true;
6369            if (wrangler && wranglerIdleSettings)
6370            {
6371                // Request wrangler idle only when demand sleep is triggered
6372                // from full wake.
6373                if(CAP_CURRENT(kIOPMSystemCapabilityGraphics))
6374                {
6375                    wrangler->setProperties(wranglerIdleSettings);
6376                    DLOG("Requested wrangler idle\n");
6377                }
6378            }
6379            // arg = sleepReason
6380            changePowerStateWithOverrideTo( SLEEP_STATE, arg );
6381            break;
6382
6383        case kStimulusAllowSystemSleepChanged:
6384            flags.bit.adjustPowerState = true;
6385            break;
6386
6387        case kStimulusDarkWakeActivityTickle:
6388            // arg == true implies real and not self generated wrangler tickle.
6389            // Update wake type on PM work loop instead of the tickle thread to
6390            // eliminate the possibility of an early tickle clobbering the wake
6391            // type set by the platform driver.
6392            if (arg == true)
6393                setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeHIDActivity);
6394
6395            if (false == wranglerTickled)
6396            {
6397                if (latchDisplayWranglerTickle(true))
6398                {
6399                    DLOG("latched tickle\n");
6400                    break;
6401                }
6402
6403                wranglerTickled = true;
6404                DLOG("Requesting full wake after dark wake activity tickle\n");
6405                requestFullWake( kFullWakeReasonLocalUser );
6406            }
6407            break;
6408
6409        case kStimulusDarkWakeEntry:
6410        case kStimulusDarkWakeReentry:
6411            // Any system transitions since the last dark wake transition
6412            // will invalid the stimulus.
6413
6414            if (arg == _systemStateGeneration)
6415            {
6416                DLOG("dark wake entry\n");
6417                systemDarkWake = true;
6418
6419                // Keep wranglerAsleep an invariant when wrangler is absent
6420                if (wrangler)
6421                    wranglerAsleep = true;
6422
6423                if (kStimulusDarkWakeEntry == stimulus)
6424                {
6425                    clock_get_uptime(&userBecameInactiveTime);
6426                    flags.bit.evaluateDarkWake = true;
6427                }
6428
6429                // Always accelerate disk spindown while in dark wake,
6430                // even if system does not support/allow sleep.
6431
6432                cancelIdleSleepTimer();
6433                setQuickSpinDownTimeout();
6434            }
6435            break;
6436
6437        case kStimulusDarkWakeEvaluate:
6438            if (systemDarkWake)
6439            {
6440                flags.bit.evaluateDarkWake = true;
6441            }
6442            break;
6443
6444        case kStimulusNoIdleSleepPreventers:
6445            flags.bit.adjustPowerState = true;
6446            break;
6447
6448    } /* switch(stimulus) */
6449
6450    if (flags.bit.evaluateDarkWake && (kFullWakeReasonNone == fullWakeReason))
6451    {
6452        if (darkWakeToSleepASAP ||
6453            (clamshellClosed && !(desktopMode && acAdaptorConnected)))
6454        {
6455            uint32_t newSleepReason;
6456
6457            if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
6458            {
6459                // System was previously in full wake. Sleep reason from
6460                // full to dark already recorded in fullToDarkReason.
6461
6462                if (lowBatteryCondition)
6463                    newSleepReason = kIOPMSleepReasonLowPower;
6464                else
6465                    newSleepReason = fullToDarkReason;
6466            }
6467            else
6468            {
6469                // In dark wake from system sleep.
6470
6471                if (darkWakeSleepService)
6472                    newSleepReason = kIOPMSleepReasonSleepServiceExit;
6473                else
6474                    newSleepReason = kIOPMSleepReasonMaintenance;
6475            }
6476
6477            if (checkSystemCanSleep(newSleepReason))
6478            {
6479                privateSleepSystem(newSleepReason);
6480            }
6481        }
6482        else // non-maintenance (network) dark wake
6483        {
6484            if (checkSystemCanSleep(kIOPMSleepReasonIdle))
6485            {
6486                // Release power clamp, and wait for children idle.
6487                adjustPowerState(true);
6488            }
6489            else
6490            {
6491                changePowerStateToPriv(ON_STATE);
6492            }
6493        }
6494    }
6495
6496    if (systemDarkWake)
6497    {
6498        // The rest are irrelevant while system is in dark wake.
6499        flags.u32 = 0;
6500    }
6501
6502    if ((flags.bit.displaySleep) &&
6503        (kFullWakeReasonDisplayOn == fullWakeReason))
6504    {
6505        // kIOPMSleepReasonMaintenance?
6506        changePowerStateWithOverrideTo( SLEEP_STATE, kIOPMSleepReasonMaintenance );
6507    }
6508
6509    if (flags.bit.userBecameInactive || flags.bit.sleepDelayChanged)
6510    {
6511        bool cancelQuickSpindown = false;
6512
6513        if (flags.bit.sleepDelayChanged)
6514        {
6515            // Cancel existing idle sleep timer and quick disk spindown.
6516            // New settings will be applied by the idleSleepEnabled flag
6517            // handler below if idle sleep is enabled.
6518
6519            DLOG("extra sleep timer changed\n");
6520            cancelIdleSleepTimer();
6521            cancelQuickSpindown = true;
6522        }
6523        else
6524        {
6525            DLOG("user inactive\n");
6526        }
6527
6528        if (!userIsActive && sleepSlider)
6529        {
6530            startIdleSleepTimer(getTimeToIdleSleep());
6531        }
6532
6533        if (cancelQuickSpindown)
6534            restoreUserSpinDownTimeout();
6535    }
6536
6537    if (flags.bit.idleSleepEnabled)
6538    {
6539        DLOG("idle sleep timer enabled\n");
6540        if (!wrangler)
6541        {
6542            changePowerStateToPriv(ON_STATE);
6543            if (idleSeconds)
6544            {
6545                startIdleSleepTimer( idleSeconds );
6546            }
6547        }
6548        else
6549        {
6550            // Start idle timer if prefs now allow system sleep
6551            // and user is already inactive. Disk spindown is
6552            // accelerated upon timer expiration.
6553
6554            if (!userIsActive)
6555            {
6556                startIdleSleepTimer(getTimeToIdleSleep());
6557            }
6558        }
6559    }
6560
6561    if (flags.bit.idleSleepDisabled)
6562    {
6563        DLOG("idle sleep timer disabled\n");
6564        cancelIdleSleepTimer();
6565        restoreUserSpinDownTimeout();
6566        adjustPowerState();
6567    }
6568
6569    if (flags.bit.adjustPowerState)
6570    {
6571        bool sleepASAP = false;
6572
6573        if (!systemBooting && (preventIdleSleepList->getCount() == 0))
6574        {
6575            if (!wrangler)
6576            {
6577                changePowerStateToPriv(ON_STATE);
6578                if (idleSeconds)
6579                {
6580                    // stay awake for at least idleSeconds
6581                    startIdleSleepTimer(idleSeconds);
6582                }
6583            }
6584            else if (!extraSleepDelay && !idleSleepTimerPending && !systemDarkWake)
6585            {
6586                sleepASAP = true;
6587            }
6588        }
6589
6590        adjustPowerState(sleepASAP);
6591    }
6592}
6593
6594//******************************************************************************
6595// requestFullWake
6596//
6597// Request transition from dark wake to full wake
6598//******************************************************************************
6599
6600void IOPMrootDomain::requestFullWake( FullWakeReason reason )
6601{
6602    uint32_t        options = 0;
6603    IOService *     pciRoot = 0;
6604    bool            promotion = false;
6605
6606    // System must be in dark wake and a valid reason for entering full wake
6607    if ((kFullWakeReasonNone == reason) ||
6608        (kFullWakeReasonNone != fullWakeReason) ||
6609        (CAP_CURRENT(kIOPMSystemCapabilityGraphics)))
6610    {
6611        return;
6612    }
6613
6614    // Will clear reason upon exit from full wake
6615    fullWakeReason = reason;
6616
6617    _desiredCapability |= (kIOPMSystemCapabilityGraphics |
6618                           kIOPMSystemCapabilityAudio);
6619
6620    if ((kSystemTransitionWake == _systemTransitionType) &&
6621        !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
6622        !graphicsSuppressed)
6623    {
6624        // Promote to full wake while waking up to dark wake due to tickle.
6625        // PM will hold off notifying the graphics subsystem about system wake
6626        // as late as possible, so if a HID tickle does arrive, graphics can
6627        // power up on this same wake cycle. The latency to power up graphics
6628        // on the next cycle can be huge on some systems. However, once any
6629        // graphics suppression has taken effect, it is too late. All other
6630        // graphics devices must be similarly suppressed. But the delay till
6631        // the following cycle should be short.
6632
6633        _pendingCapability |= (kIOPMSystemCapabilityGraphics |
6634                               kIOPMSystemCapabilityAudio);
6635
6636        // Immediately bring up audio and graphics
6637        pciRoot = pciHostBridgeDriver;
6638        willEnterFullWake();
6639        promotion = true;
6640    }
6641
6642    // Unsafe to cancel once graphics was powered.
6643    // If system woke from dark wake, the return to sleep can
6644    // be cancelled. "awake -> dark -> sleep" transition
6645    // can be canceled also, during the "dark --> sleep" phase
6646    // *prior* to driver power down.
6647    if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics) ||
6648        _pendingCapability == 0) {
6649        options |= kIOPMSyncCancelPowerDown;
6650    }
6651
6652    synchronizePowerTree(options, pciRoot);
6653    if (kFullWakeReasonLocalUser == fullWakeReason)
6654    {
6655        // IOGraphics doesn't light the display even though graphics is
6656        // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
6657        // So, do an explicit activity tickle
6658        if (wrangler)
6659            wrangler->activityTickle(0,0);
6660    }
6661
6662    // Log a timestamp for the initial full wake request.
6663    // System may not always honor this full wake request.
6664    if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
6665    {
6666        AbsoluteTime    now;
6667        uint64_t        nsec;
6668
6669        clock_get_uptime(&now);
6670        SUB_ABSOLUTETIME(&now, &systemWakeTime);
6671        absolutetime_to_nanoseconds(now, &nsec);
6672        MSG("full wake %s (reason %u) %u ms\n",
6673            promotion ? "promotion" : "request",
6674            fullWakeReason, ((int)((nsec) / 1000000ULL)));
6675    }
6676}
6677
6678//******************************************************************************
6679// willEnterFullWake
6680//
6681// System will enter full wake from sleep, from dark wake, or from dark
6682// wake promotion. This function aggregate things that are in common to
6683// all three full wake transitions.
6684//
6685// Assumptions: fullWakeReason was updated
6686//******************************************************************************
6687
6688void IOPMrootDomain::willEnterFullWake( void )
6689{
6690    hibernateRetry = false;
6691    sleepToStandby = false;
6692    sleepTimerMaintenance = false;
6693
6694    _systemMessageClientMask = kSystemMessageClientPowerd |
6695                               kSystemMessageClientLegacyApp;
6696
6697    if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
6698    {
6699        // Initial graphics full power
6700        _systemMessageClientMask |= kSystemMessageClientKernel;
6701
6702        // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
6703        setProperty(gIOPMUserTriggeredFullWakeKey,
6704            (kFullWakeReasonLocalUser == fullWakeReason) ?
6705                kOSBooleanTrue : kOSBooleanFalse);
6706    }
6707#if HIBERNATION
6708    IOHibernateSetWakeCapabilities(_pendingCapability);
6709#endif
6710
6711    IOService::setAdvisoryTickleEnable( true );
6712    tellClients(kIOMessageSystemWillPowerOn);
6713    preventTransitionToUserActive(false);
6714}
6715
6716//******************************************************************************
6717// fullWakeDelayedWork
6718//
6719// System has already entered full wake. Invoked by a delayed thread call.
6720//******************************************************************************
6721
6722void IOPMrootDomain::fullWakeDelayedWork( void )
6723{
6724#if DARK_TO_FULL_EVALUATE_CLAMSHELL
6725    // Not gated, don't modify state
6726    if ((kSystemTransitionNone == _systemTransitionType) &&
6727        CAP_CURRENT(kIOPMSystemCapabilityGraphics))
6728    {
6729        receivePowerNotification( kLocalEvalClamshellCommand );
6730    }
6731#endif
6732}
6733
6734//******************************************************************************
6735// evaluateAssertions
6736//
6737//******************************************************************************
6738void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions, IOPMDriverAssertionType oldAssertions)
6739{
6740    IOPMDriverAssertionType changedBits = newAssertions ^ oldAssertions;
6741
6742    messageClients(kIOPMMessageDriverAssertionsChanged);
6743
6744    if (changedBits & kIOPMDriverAssertionPreventDisplaySleepBit) {
6745
6746        if (wrangler) {
6747            bool value = (newAssertions & kIOPMDriverAssertionPreventDisplaySleepBit) ? true : false;
6748
6749            DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value);
6750            wrangler->setIgnoreIdleTimer( value );
6751        }
6752    }
6753
6754    if (changedBits & kIOPMDriverAssertionCPUBit)
6755        evaluatePolicy(kStimulusDarkWakeEvaluate);
6756
6757    if (changedBits & kIOPMDriverAssertionReservedBit7) {
6758        bool value = (newAssertions & kIOPMDriverAssertionReservedBit7) ? true : false;
6759        if (value) {
6760            DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
6761            updatePreventIdleSleepList(this, true);
6762        }
6763        else {
6764            DLOG("Driver assertion ReservedBit7 dropped\n");
6765            updatePreventIdleSleepList(this, false);
6766        }
6767    }
6768}
6769
6770// MARK: -
6771// MARK: Statistics
6772
6773//******************************************************************************
6774// pmStats
6775//
6776//******************************************************************************
6777
6778void IOPMrootDomain::pmStatsRecordEvent(
6779    int                 eventIndex,
6780    AbsoluteTime        timestamp)
6781{
6782    bool        starting = eventIndex & kIOPMStatsEventStartFlag ? true:false;
6783    bool        stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false;
6784    uint64_t    delta;
6785    uint64_t    nsec;
6786    OSData *publishPMStats = NULL;
6787
6788    eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
6789
6790    absolutetime_to_nanoseconds(timestamp, &nsec);
6791
6792    switch (eventIndex) {
6793        case kIOPMStatsHibernateImageWrite:
6794            if (starting)
6795                gPMStats.hibWrite.start = nsec;
6796            else if (stopping)
6797                gPMStats.hibWrite.stop = nsec;
6798
6799            if (stopping) {
6800                delta = gPMStats.hibWrite.stop - gPMStats.hibWrite.start;
6801                IOLog("PMStats: Hibernate write took %qd ms\n", delta/1000000ULL);
6802            }
6803            break;
6804        case kIOPMStatsHibernateImageRead:
6805            if (starting)
6806                gPMStats.hibRead.start = nsec;
6807            else if (stopping)
6808                gPMStats.hibRead.stop = nsec;
6809
6810            if (stopping) {
6811                delta = gPMStats.hibRead.stop - gPMStats.hibRead.start;
6812                IOLog("PMStats: Hibernate read took %qd ms\n", delta/1000000ULL);
6813
6814                publishPMStats = OSData::withBytes(&gPMStats, sizeof(gPMStats));
6815                setProperty(kIOPMSleepStatisticsKey, publishPMStats);
6816                publishPMStats->release();
6817                bzero(&gPMStats, sizeof(gPMStats));
6818            }
6819            break;
6820    }
6821}
6822
6823/*
6824 * Appends a record of the application response to
6825 * IOPMrootDomain::pmStatsAppResponses
6826 */
6827void IOPMrootDomain::pmStatsRecordApplicationResponse(
6828    const OSSymbol      *response,
6829    const char          *name,
6830    int                 messageType,
6831    uint32_t            delay_ms,
6832    int                 app_pid,
6833    OSObject            *object,
6834    IOPMPowerStateIndex powerState)
6835{
6836    OSDictionary    *responseDescription    = NULL;
6837    OSNumber        *delayNum               = NULL;
6838    OSNumber        *powerCaps              = NULL;
6839    OSNumber        *pidNum                 = NULL;
6840    OSNumber        *msgNum                 = NULL;
6841    const OSSymbol  *appname;
6842    const OSSymbol  *sleep = NULL, *wake = NULL;
6843    IOPMServiceInterestNotifier *notify = 0;
6844
6845    if (object && (notify = OSDynamicCast(IOPMServiceInterestNotifier, object)))
6846    {
6847        if (response->isEqualTo(gIOPMStatsApplicationResponseTimedOut))
6848            notify->ackTimeoutCnt++;
6849        else
6850            notify->ackTimeoutCnt = 0;
6851
6852    }
6853
6854    if (response->isEqualTo(gIOPMStatsApplicationResponsePrompt) ||
6855         (_systemTransitionType == kSystemTransitionNone) || (_systemTransitionType == kSystemTransitionNewCapClient))
6856        return;
6857
6858
6859    responseDescription = OSDictionary::withCapacity(5);
6860    if (responseDescription)
6861    {
6862        if (response) {
6863            responseDescription->setObject(_statsResponseTypeKey, response);
6864        }
6865
6866        msgNum = OSNumber::withNumber(messageType, 32);
6867        if (msgNum) {
6868            responseDescription->setObject(_statsMessageTypeKey, msgNum);
6869            msgNum->release();
6870        }
6871
6872        if (name && (strlen(name) > 0))
6873        {
6874            appname = OSSymbol::withCString(name);
6875            if (appname) {
6876                responseDescription->setObject(_statsNameKey, appname);
6877                appname->release();
6878            }
6879        }
6880
6881        if (app_pid != -1) {
6882            pidNum = OSNumber::withNumber(app_pid, 32);
6883            if (pidNum) {
6884                responseDescription->setObject(_statsPIDKey, pidNum);
6885                pidNum->release();
6886            }
6887        }
6888
6889        delayNum = OSNumber::withNumber(delay_ms, 32);
6890        if (delayNum) {
6891            responseDescription->setObject(_statsTimeMSKey, delayNum);
6892            delayNum->release();
6893        }
6894
6895        if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow)) {
6896            powerCaps = OSNumber::withNumber(powerState, 32);
6897
6898#if !defined(__i386__) && !defined(__x86_64__)
6899            IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
6900                  name, messageType,
6901                  powerState, delay_ms);
6902#endif
6903
6904        }
6905        else {
6906            powerCaps = OSNumber::withNumber(_pendingCapability, 32);
6907        }
6908        if (powerCaps) {
6909            responseDescription->setObject(_statsPowerCapsKey, powerCaps);
6910            powerCaps->release();
6911        }
6912
6913        sleep = OSSymbol::withCString("Sleep");
6914        wake = OSSymbol::withCString("Wake");
6915        if (_systemTransitionType == kSystemTransitionSleep)  {
6916            responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep);
6917        }
6918        else if (_systemTransitionType == kSystemTransitionWake) {
6919            responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake);
6920        }
6921        else if (_systemTransitionType == kSystemTransitionCapability) {
6922            if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
6923                responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep);
6924            else if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
6925                responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake);
6926        }
6927        if (sleep) sleep->release();
6928        if (wake) wake->release();
6929
6930
6931
6932        IOLockLock(pmStatsLock);
6933        if (pmStatsAppResponses && pmStatsAppResponses->getCount() < 50) {
6934            pmStatsAppResponses->setObject(responseDescription);
6935        }
6936        IOLockUnlock(pmStatsLock);
6937
6938        responseDescription->release();
6939    }
6940
6941    return;
6942}
6943
6944// MARK: -
6945// MARK: PMTraceWorker
6946
6947//******************************************************************************
6948// TracePoint support
6949//
6950//******************************************************************************
6951
6952#define kIOPMRegisterNVRAMTracePointHandlerKey  \
6953        "IOPMRegisterNVRAMTracePointHandler"
6954
6955IOReturn IOPMrootDomain::callPlatformFunction(
6956    const OSSymbol * functionName,
6957    bool waitForFunction,
6958    void * param1, void * param2,
6959    void * param3, void * param4 )
6960{
6961    if (pmTracer && functionName &&
6962        functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) &&
6963        !pmTracer->tracePointHandler && !pmTracer->tracePointTarget)
6964    {
6965        uint32_t    tracePointPhases, tracePointPCI;
6966        uint64_t    statusCode;
6967
6968        pmTracer->tracePointHandler = (IOPMTracePointHandler) param1;
6969        pmTracer->tracePointTarget  = (void *) param2;
6970        tracePointPCI               = (uint32_t)(uintptr_t) param3;
6971        tracePointPhases            = (uint32_t)(uintptr_t) param4;
6972        statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
6973        if ((tracePointPhases >> 24) != kIOPMTracePointSystemUp)
6974        {
6975            MSG("Sleep failure code 0x%08x 0x%08x\n",
6976                tracePointPCI, tracePointPhases);
6977        }
6978        setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64);
6979        pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 );
6980
6981        return kIOReturnSuccess;
6982    }
6983#if HIBERNATION
6984    else if (functionName &&
6985             functionName->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey))
6986    {
6987        if (gSleepPolicyHandler)
6988            return kIOReturnExclusiveAccess;
6989        if (!param1)
6990            return kIOReturnBadArgument;
6991        gSleepPolicyHandler = (IOPMSystemSleepPolicyHandler) param1;
6992        gSleepPolicyTarget  = (void *) param2;
6993        setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue);
6994        return kIOReturnSuccess;
6995    }
6996#endif
6997
6998    return super::callPlatformFunction(
6999        functionName, waitForFunction, param1, param2, param3, param4);
7000}
7001
7002void IOPMrootDomain::tracePoint( uint8_t point )
7003{
7004    if (systemBooting) return;
7005
7006    if (kIOPMTracePointWakeCapabilityClients == point)
7007        acceptSystemWakeEvents(false);
7008
7009    PMDebug(kPMLogSleepWakeTracePoint, point, 0);
7010    pmTracer->tracePoint(point);
7011}
7012
7013void IOPMrootDomain::tracePoint( uint8_t point, uint8_t data )
7014{
7015    if (systemBooting) return;
7016
7017    PMDebug(kPMLogSleepWakeTracePoint, point, data);
7018    pmTracer->tracePoint(point, data);
7019}
7020
7021void IOPMrootDomain::traceDetail( uint32_t detail )
7022{
7023    if (!systemBooting)
7024        pmTracer->traceDetail( detail );
7025}
7026
7027
7028IOReturn IOPMrootDomain::configureReport(IOReportChannelList    *channelList,
7029                                    IOReportConfigureAction action,
7030                                    void                   *result,
7031                                    void                   *destination)
7032{
7033    unsigned cnt;
7034    if (action != kIOReportGetDimensions) goto exit;
7035
7036    for (cnt = 0; cnt < channelList->nchannels; cnt++) {
7037        if ( (channelList->channels[cnt].channel_id == kSleepCntChID) ||
7038               (channelList->channels[cnt].channel_id == kDarkWkCntChID) ||
7039               (channelList->channels[cnt].channel_id == kUserWkCntChID) ) {
7040            SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
7041        }
7042    }
7043
7044exit:
7045    return super::configureReport(channelList, action, result, destination);
7046}
7047
7048
7049IOReturn IOPMrootDomain::updateReport(IOReportChannelList      *channelList,
7050                                 IOReportUpdateAction      action,
7051                                 void                     *result,
7052                                 void                     *destination)
7053{
7054    uint32_t size2cpy;
7055    void *data2cpy;
7056    uint8_t buf[SIMPLEREPORT_BUFSIZE];
7057    IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
7058    unsigned cnt;
7059    uint64_t ch_id;
7060
7061    if (action != kIOReportCopyChannelData) goto exit;
7062
7063    for (cnt = 0; cnt < channelList->nchannels; cnt++) {
7064        ch_id = channelList->channels[cnt].channel_id ;
7065
7066        if ((ch_id == kSleepCntChID) ||
7067                (ch_id == kDarkWkCntChID) || (ch_id == kUserWkCntChID)) {
7068            SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), ch_id, kIOReportCategoryPower);
7069        }
7070        else continue;
7071
7072        if (ch_id == kSleepCntChID)
7073            SIMPLEREPORT_SETVALUE(buf, sleepCnt);
7074        else if (ch_id == kDarkWkCntChID)
7075            SIMPLEREPORT_SETVALUE(buf, darkWakeCnt);
7076        else if (ch_id == kUserWkCntChID)
7077            SIMPLEREPORT_SETVALUE(buf, displayWakeCnt);
7078
7079        SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy);
7080        SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result);
7081        dest->appendBytes(data2cpy, size2cpy);
7082    }
7083
7084exit:
7085    return super::updateReport(channelList, action, result, destination);
7086}
7087
7088
7089//******************************************************************************
7090// PMTraceWorker Class
7091//
7092//******************************************************************************
7093
7094#undef super
7095#define super OSObject
7096OSDefineMetaClassAndStructors(PMTraceWorker, OSObject)
7097
7098#define kPMBestGuessPCIDevicesCount     25
7099#define kPMMaxRTCBitfieldSize           32
7100
7101PMTraceWorker *PMTraceWorker::tracer(IOPMrootDomain *owner)
7102{
7103    PMTraceWorker           *me;
7104
7105    me = OSTypeAlloc( PMTraceWorker );
7106    if (!me || !me->init())
7107    {
7108        return NULL;
7109    }
7110
7111    DLOG("PMTraceWorker %p\n", OBFUSCATE(me));
7112
7113    // Note that we cannot instantiate the PCI device -> bit mappings here, since
7114    // the IODeviceTree has not yet been created by IOPlatformExpert. We create
7115    // this dictionary lazily.
7116    me->owner = owner;
7117    me->pciDeviceBitMappings = NULL;
7118    me->pciMappingLock = IOLockAlloc();
7119    me->tracePhase = kIOPMTracePointSystemUp;
7120    me->loginWindowPhase = 0;
7121    me->traceData32 = 0;
7122    return me;
7123}
7124
7125void PMTraceWorker::RTC_TRACE(void)
7126{
7127    if (tracePointHandler && tracePointTarget)
7128    {
7129        uint32_t    wordA;
7130
7131        wordA = (tracePhase << 24) | (loginWindowPhase << 16) |
7132                (traceData8 << 8);
7133
7134        tracePointHandler( tracePointTarget, traceData32, wordA );
7135        _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA);
7136    }
7137}
7138
7139int PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
7140{
7141    const OSSymbol *    deviceName;
7142    int                 index = -1;
7143
7144    IOLockLock(pciMappingLock);
7145
7146    if (!pciDeviceBitMappings)
7147    {
7148        pciDeviceBitMappings = OSArray::withCapacity(kPMBestGuessPCIDevicesCount);
7149        if (!pciDeviceBitMappings)
7150            goto exit;
7151    }
7152
7153    // Check for bitmask overflow.
7154    if (pciDeviceBitMappings->getCount() >= kPMMaxRTCBitfieldSize)
7155        goto exit;
7156
7157    if ((deviceName = pciDevice->copyName()) &&
7158        (pciDeviceBitMappings->getNextIndexOfObject(deviceName, 0) == (unsigned int)-1) &&
7159        pciDeviceBitMappings->setObject(deviceName))
7160    {
7161        index = pciDeviceBitMappings->getCount() - 1;
7162        _LOG("PMTrace PCI array: set object %s => %d\n",
7163            deviceName->getCStringNoCopy(), index);
7164    }
7165    if (deviceName)
7166        deviceName->release();
7167    if (!addedToRegistry && (index >= 0))
7168        addedToRegistry = owner->setProperty("PCITopLevel", this);
7169
7170exit:
7171    IOLockUnlock(pciMappingLock);
7172    return index;
7173}
7174
7175bool PMTraceWorker::serialize(OSSerialize *s) const
7176{
7177    bool ok = false;
7178    if (pciDeviceBitMappings)
7179    {
7180        IOLockLock(pciMappingLock);
7181        ok = pciDeviceBitMappings->serialize(s);
7182        IOLockUnlock(pciMappingLock);
7183    }
7184    return ok;
7185}
7186
7187void PMTraceWorker::tracePoint(uint8_t phase)
7188{
7189    // clear trace detail when phase begins
7190    if (tracePhase != phase)
7191        traceData32 = 0;
7192
7193    tracePhase = phase;
7194
7195    DLOG("trace point 0x%02x\n", tracePhase);
7196    RTC_TRACE();
7197}
7198
7199void PMTraceWorker::tracePoint(uint8_t phase, uint8_t data8)
7200{
7201    // clear trace detail when phase begins
7202    if (tracePhase != phase)
7203        traceData32 = 0;
7204
7205    tracePhase = phase;
7206    traceData8 = data8;
7207
7208    DLOG("trace point 0x%02x 0x%02x\n", tracePhase, traceData8);
7209    RTC_TRACE();
7210}
7211
7212void PMTraceWorker::traceDetail(uint32_t detail)
7213{
7214    if (kIOPMTracePointSleepPriorityClients != tracePhase)
7215        return;
7216
7217    traceData32 = detail;
7218    DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
7219
7220    RTC_TRACE();
7221}
7222
7223void PMTraceWorker::traceLoginWindowPhase(uint8_t phase)
7224{
7225    loginWindowPhase = phase;
7226
7227    DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase);
7228    RTC_TRACE();
7229}
7230
7231void PMTraceWorker::tracePCIPowerChange(
7232    change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
7233{
7234    uint32_t    bitMask;
7235    uint32_t    expectedFlag;
7236
7237    // Ignore PCI changes outside of system sleep/wake.
7238    if ((kIOPMTracePointSleepPowerPlaneDrivers != tracePhase) &&
7239        (kIOPMTracePointWakePowerPlaneDrivers  != tracePhase))
7240        return;
7241
7242    // Only record the WillChange transition when going to sleep,
7243    // and the DidChange on the way up.
7244    changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange);
7245    expectedFlag = (kIOPMTracePointSleepPowerPlaneDrivers == tracePhase) ?
7246                    kIOPMDomainWillChange : kIOPMDomainDidChange;
7247    if (changeFlags != expectedFlag)
7248        return;
7249
7250    // Mark this device off in our bitfield
7251    if (bitNum < kPMMaxRTCBitfieldSize)
7252    {
7253        bitMask = (1 << bitNum);
7254
7255        if (kPowerChangeStart == type)
7256        {
7257            traceData32 |= bitMask;
7258            _LOG("PMTrace: Device %s started  - bit %2d mask 0x%08x => 0x%08x\n",
7259                service->getName(), bitNum, bitMask, traceData32);
7260        }
7261        else
7262        {
7263            traceData32 &= ~bitMask;
7264            _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
7265                service->getName(), bitNum, bitMask, traceData32);
7266        }
7267
7268        DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
7269        RTC_TRACE();
7270    }
7271}
7272
7273uint64_t  PMTraceWorker::getPMStatusCode( )
7274{
7275    return (((uint64_t)traceData32 << 32) | (tracePhase << 24) |
7276            (loginWindowPhase << 16) | (traceData8 << 8));
7277
7278}
7279
7280// MARK: -
7281// MARK: PMHaltWorker
7282
7283//******************************************************************************
7284// PMHaltWorker Class
7285//
7286//******************************************************************************
7287
7288static unsigned int     gPMHaltBusyCount;
7289static unsigned int     gPMHaltIdleCount;
7290static int              gPMHaltDepth;
7291static unsigned long    gPMHaltEvent;
7292static IOLock *         gPMHaltLock  = 0;
7293static OSArray *        gPMHaltArray = 0;
7294static const OSSymbol * gPMHaltClientAcknowledgeKey = 0;
7295
7296PMHaltWorker * PMHaltWorker::worker( void )
7297{
7298    PMHaltWorker *  me;
7299    IOThread        thread;
7300
7301    do {
7302        me = OSTypeAlloc( PMHaltWorker );
7303        if (!me || !me->init())
7304            break;
7305
7306        me->lock = IOLockAlloc();
7307        if (!me->lock)
7308            break;
7309
7310        DLOG("PMHaltWorker %p\n", OBFUSCATE(me));
7311        me->retain();   // thread holds extra retain
7312        if (KERN_SUCCESS != kernel_thread_start(&PMHaltWorker::main, (void *) me, &thread))
7313        {
7314            me->release();
7315            break;
7316        }
7317        thread_deallocate(thread);
7318        return me;
7319
7320    } while (false);
7321
7322    if (me) me->release();
7323    return 0;
7324}
7325
7326void PMHaltWorker::free( void )
7327{
7328    DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
7329    if (lock)
7330    {
7331        IOLockFree(lock);
7332        lock = 0;
7333    }
7334    return OSObject::free();
7335}
7336
7337void PMHaltWorker::main( void * arg, wait_result_t waitResult )
7338{
7339    PMHaltWorker * me = (PMHaltWorker *) arg;
7340
7341    IOLockLock( gPMHaltLock );
7342    gPMHaltBusyCount++;
7343    me->depth = gPMHaltDepth;
7344    IOLockUnlock( gPMHaltLock );
7345
7346    while (me->depth >= 0)
7347    {
7348        PMHaltWorker::work( me );
7349
7350        IOLockLock( gPMHaltLock );
7351        if (++gPMHaltIdleCount >= gPMHaltBusyCount)
7352        {
7353            // This is the last thread to finish work on this level,
7354            // inform everyone to start working on next lower level.
7355            gPMHaltDepth--;
7356            me->depth = gPMHaltDepth;
7357            gPMHaltIdleCount = 0;
7358            thread_wakeup((event_t) &gPMHaltIdleCount);
7359        }
7360        else
7361        {
7362            // One or more threads are still working on this level,
7363            // this thread must wait.
7364            me->depth = gPMHaltDepth - 1;
7365            do {
7366                IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
7367            } while (me->depth != gPMHaltDepth);
7368        }
7369        IOLockUnlock( gPMHaltLock );
7370    }
7371
7372    // No more work to do, terminate thread
7373    DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me), me->visits);
7374    thread_wakeup( &gPMHaltDepth );
7375    me->release();
7376}
7377
7378void PMHaltWorker::work( PMHaltWorker * me )
7379{
7380    IOService *     service;
7381    OSSet *         inner;
7382    AbsoluteTime    startTime;
7383    UInt32          deltaTime;
7384    bool            timeout;
7385
7386    while (true)
7387    {
7388        service = 0;
7389        timeout = false;
7390
7391        // Claim an unit of work from the shared pool
7392        IOLockLock( gPMHaltLock );
7393        inner = (OSSet *)gPMHaltArray->getObject(me->depth);
7394        if (inner)
7395        {
7396            service = (IOService *)inner->getAnyObject();
7397            if (service)
7398            {
7399                service->retain();
7400                inner->removeObject(service);
7401            }
7402        }
7403        IOLockUnlock( gPMHaltLock );
7404        if (!service)
7405            break;  // no more work at this depth
7406
7407        clock_get_uptime(&startTime);
7408
7409        if (!service->isInactive() &&
7410            service->setProperty(gPMHaltClientAcknowledgeKey, me))
7411        {
7412            IOLockLock(me->lock);
7413            me->startTime = startTime;
7414            me->service   = service;
7415            me->timeout   = false;
7416            IOLockUnlock(me->lock);
7417
7418            service->systemWillShutdown( gPMHaltEvent );
7419
7420            // Wait for driver acknowledgement
7421            IOLockLock(me->lock);
7422            while (service->getProperty(gPMHaltClientAcknowledgeKey))
7423            {
7424                IOLockSleep(me->lock, me, THREAD_UNINT);
7425            }
7426            me->service = 0;
7427            timeout = me->timeout;
7428            IOLockUnlock(me->lock);
7429        }
7430
7431        deltaTime = computeDeltaTimeMS(&startTime);
7432        if ((deltaTime > kPMHaltTimeoutMS) || timeout ||
7433            (gIOKitDebug & kIOLogPMRootDomain))
7434        {
7435            LOG("%s driver %s (%p) took %u ms\n",
7436                (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
7437                    "PowerOff" : "Restart",
7438                service->getName(), OBFUSCATE(service),
7439                (uint32_t) deltaTime );
7440        }
7441
7442        service->release();
7443        me->visits++;
7444    }
7445}
7446
7447void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
7448{
7449    UInt64          nano;
7450    AbsoluteTime    startTime;
7451    AbsoluteTime    endTime;
7452
7453    endTime = *now;
7454
7455    IOLockLock(me->lock);
7456    if (me->service && !me->timeout)
7457    {
7458        startTime = me->startTime;
7459        nano = 0;
7460        if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
7461        {
7462            SUB_ABSOLUTETIME(&endTime, &startTime);
7463            absolutetime_to_nanoseconds(endTime, &nano);
7464        }
7465        if (nano > 3000000000ULL)
7466        {
7467            me->timeout = true;
7468            MSG("%s still waiting on %s\n",
7469                (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
7470                    "PowerOff" : "Restart",
7471                me->service->getName());
7472        }
7473    }
7474    IOLockUnlock(me->lock);
7475}
7476
7477
7478//******************************************************************************
7479// acknowledgeSystemWillShutdown
7480//
7481// Acknowledgement from drivers that they have prepared for shutdown/restart.
7482//******************************************************************************
7483
7484void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
7485{
7486    PMHaltWorker *  worker;
7487    OSObject *      prop;
7488
7489    if (!from)
7490        return;
7491
7492    //DLOG("%s acknowledged\n", from->getName());
7493    prop = from->copyProperty( gPMHaltClientAcknowledgeKey );
7494    if (prop)
7495    {
7496        worker = (PMHaltWorker *) prop;
7497        IOLockLock(worker->lock);
7498        from->removeProperty( gPMHaltClientAcknowledgeKey );
7499        thread_wakeup((event_t) worker);
7500        IOLockUnlock(worker->lock);
7501        worker->release();
7502    }
7503    else
7504    {
7505        DLOG("%s acknowledged without worker property\n",
7506            from->getName());
7507    }
7508}
7509
7510
7511//******************************************************************************
7512// notifySystemShutdown
7513//
7514// Notify all objects in PM tree that system will shutdown or restart
7515//******************************************************************************
7516
7517static void
7518notifySystemShutdown( IOService * root, unsigned long event )
7519{
7520#define PLACEHOLDER ((OSSet *)gPMHaltArray)
7521    IORegistryIterator *    iter;
7522    IORegistryEntry *       entry;
7523    IOService *             node;
7524    OSSet *                 inner;
7525    PMHaltWorker *          workers[kPMHaltMaxWorkers];
7526    AbsoluteTime            deadline;
7527    unsigned int            totalNodes = 0;
7528    unsigned int            depth;
7529    unsigned int            rootDepth;
7530    unsigned int            numWorkers;
7531    unsigned int            count;
7532    int                     waitResult;
7533    void *                  baseFunc;
7534    bool                    ok;
7535
7536    DLOG("%s event = %lx\n", __FUNCTION__, event);
7537
7538    baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
7539
7540    // Iterate the entire PM tree starting from root
7541
7542    rootDepth = root->getDepth( gIOPowerPlane );
7543    if (!rootDepth) goto done;
7544
7545    // debug - for repeated test runs
7546    while (PMHaltWorker::metaClass->getInstanceCount())
7547        IOSleep(1);
7548
7549    if (!gPMHaltArray)
7550    {
7551        gPMHaltArray = OSArray::withCapacity(40);
7552        if (!gPMHaltArray) goto done;
7553    }
7554    else // debug
7555        gPMHaltArray->flushCollection();
7556
7557    if (!gPMHaltLock)
7558    {
7559        gPMHaltLock = IOLockAlloc();
7560        if (!gPMHaltLock) goto done;
7561    }
7562
7563    if (!gPMHaltClientAcknowledgeKey)
7564    {
7565        gPMHaltClientAcknowledgeKey =
7566            OSSymbol::withCStringNoCopy("PMShutdown");
7567        if (!gPMHaltClientAcknowledgeKey) goto done;
7568    }
7569
7570    gPMHaltEvent = event;
7571
7572    // Depth-first walk of PM plane
7573
7574    iter = IORegistryIterator::iterateOver(
7575        root, gIOPowerPlane, kIORegistryIterateRecursively);
7576
7577    if (iter)
7578    {
7579        while ((entry = iter->getNextObject()))
7580        {
7581            node = OSDynamicCast(IOService, entry);
7582            if (!node)
7583                continue;
7584
7585            if (baseFunc ==
7586                OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
7587                continue;
7588
7589            depth = node->getDepth( gIOPowerPlane );
7590            if (depth <= rootDepth)
7591                continue;
7592
7593            ok = false;
7594
7595            // adjust to zero based depth
7596            depth -= (rootDepth + 1);
7597
7598            // gPMHaltArray is an array of containers, each container
7599            // refers to nodes with the same depth.
7600
7601            count = gPMHaltArray->getCount();
7602            while (depth >= count)
7603            {
7604                // expand array and insert placeholders
7605                gPMHaltArray->setObject(PLACEHOLDER);
7606                count++;
7607            }
7608            count = gPMHaltArray->getCount();
7609            if (depth < count)
7610            {
7611                inner = (OSSet *)gPMHaltArray->getObject(depth);
7612                if (inner == PLACEHOLDER)
7613                {
7614                    inner = OSSet::withCapacity(40);
7615                    if (inner)
7616                    {
7617                        gPMHaltArray->replaceObject(depth, inner);
7618                        inner->release();
7619                    }
7620                }
7621
7622                // PM nodes that appear more than once in the tree will have
7623                // the same depth, OSSet will refuse to add the node twice.
7624                if (inner)
7625                    ok = inner->setObject(node);
7626            }
7627            if (!ok)
7628                DLOG("Skipped PM node %s\n", node->getName());
7629        }
7630        iter->release();
7631    }
7632
7633    // debug only
7634    for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++)
7635    {
7636        count = 0;
7637        if (inner != PLACEHOLDER)
7638            count = inner->getCount();
7639        DLOG("Nodes at depth %u = %u\n", i, count);
7640    }
7641
7642    // strip placeholders (not all depths are populated)
7643    numWorkers = 0;
7644    for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); )
7645    {
7646        if (inner == PLACEHOLDER)
7647        {
7648            gPMHaltArray->removeObject(i);
7649            continue;
7650        }
7651        count = inner->getCount();
7652        if (count > numWorkers)
7653            numWorkers = count;
7654        totalNodes += count;
7655        i++;
7656    }
7657
7658    if (gPMHaltArray->getCount() == 0 || !numWorkers)
7659        goto done;
7660
7661    gPMHaltBusyCount = 0;
7662    gPMHaltIdleCount = 0;
7663    gPMHaltDepth = gPMHaltArray->getCount() - 1;
7664
7665    // Create multiple workers (and threads)
7666
7667    if (numWorkers > kPMHaltMaxWorkers)
7668        numWorkers = kPMHaltMaxWorkers;
7669
7670    DLOG("PM nodes %u, maxDepth %u, workers %u\n",
7671        totalNodes, gPMHaltArray->getCount(), numWorkers);
7672
7673    for (unsigned int i = 0; i < numWorkers; i++)
7674        workers[i] = PMHaltWorker::worker();
7675
7676    // Wait for workers to exhaust all available work
7677
7678    IOLockLock(gPMHaltLock);
7679    while (gPMHaltDepth >= 0)
7680    {
7681        clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
7682
7683        waitResult = IOLockSleepDeadline(
7684            gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
7685        if (THREAD_TIMED_OUT == waitResult)
7686        {
7687            AbsoluteTime now;
7688            clock_get_uptime(&now);
7689
7690            IOLockUnlock(gPMHaltLock);
7691            for (unsigned int i = 0 ; i < numWorkers; i++)
7692            {
7693                if (workers[i])
7694                    PMHaltWorker::checkTimeout(workers[i], &now);
7695            }
7696            IOLockLock(gPMHaltLock);
7697        }
7698    }
7699    IOLockUnlock(gPMHaltLock);
7700
7701    // Release all workers
7702
7703    for (unsigned int i = 0; i < numWorkers; i++)
7704    {
7705        if (workers[i])
7706            workers[i]->release();
7707        // worker also retained by it's own thread
7708    }
7709
7710done:
7711    DLOG("%s done\n", __FUNCTION__);
7712    return;
7713}
7714
7715// MARK: -
7716// MARK: Kernel Assertion
7717
7718/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7719
7720IOPMDriverAssertionID IOPMrootDomain::createPMAssertion(
7721    IOPMDriverAssertionType whichAssertionBits,
7722    IOPMDriverAssertionLevel assertionLevel,
7723    IOService *ownerService,
7724    const char *ownerDescription)
7725{
7726    IOReturn            ret;
7727    IOPMDriverAssertionID     newAssertion;
7728
7729    if (!pmAssertions)
7730        return 0;
7731
7732    ret = pmAssertions->createAssertion(whichAssertionBits, assertionLevel, ownerService, ownerDescription, &newAssertion);
7733
7734    if (kIOReturnSuccess == ret)
7735        return newAssertion;
7736    else
7737        return 0;
7738}
7739
7740IOReturn IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion)
7741{
7742    if (!pmAssertions)
7743        return kIOReturnInternalError;
7744
7745    return pmAssertions->releaseAssertion(releaseAssertion);
7746}
7747
7748
7749IOReturn IOPMrootDomain::setPMAssertionLevel(
7750    IOPMDriverAssertionID assertionID,
7751    IOPMDriverAssertionLevel assertionLevel)
7752{
7753    return pmAssertions->setAssertionLevel(assertionID, assertionLevel);
7754}
7755
7756IOPMDriverAssertionLevel IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion)
7757{
7758    IOPMDriverAssertionType       sysLevels;
7759
7760    if (!pmAssertions || whichAssertion == 0)
7761        return kIOPMDriverAssertionLevelOff;
7762
7763    sysLevels = pmAssertions->getActivatedAssertions();
7764
7765    // Check that every bit set in argument 'whichAssertion' is asserted
7766    // in the aggregate bits.
7767    if ((sysLevels & whichAssertion) == whichAssertion)
7768        return kIOPMDriverAssertionLevelOn;
7769    else
7770        return kIOPMDriverAssertionLevelOff;
7771}
7772
7773IOReturn IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels)
7774{
7775    if (!pmAssertions)
7776        return kIOReturnNotFound;
7777
7778    return pmAssertions->setUserAssertionLevels(inLevels);
7779}
7780
7781bool IOPMrootDomain::serializeProperties( OSSerialize * s ) const
7782{
7783    if (pmAssertions)
7784    {
7785        pmAssertions->publishProperties();
7786    }
7787    return( IOService::serializeProperties(s) );
7788}
7789
7790OSObject * IOPMrootDomain::copyProperty( const char * aKey) const
7791{
7792    OSObject *obj = NULL;
7793    obj = IOService::copyProperty(aKey);
7794
7795    if (obj)  return obj;
7796
7797    if (!strncmp(aKey, kIOPMSleepWakeWdogRebootKey,
7798                        sizeof(kIOPMSleepWakeWdogRebootKey))) {
7799        if (swd_flags & SWD_BOOT_BY_SW_WDOG)
7800            return OSBoolean::withBoolean(true);
7801        else
7802            return OSBoolean::withBoolean(false);
7803
7804    }
7805
7806    if (!strncmp(aKey, kIOPMSleepWakeWdogLogsValidKey,
7807                        sizeof(kIOPMSleepWakeWdogLogsValidKey))) {
7808        if (swd_flags & SWD_VALID_LOGS)
7809            return OSBoolean::withBoolean(true);
7810        else
7811            return OSBoolean::withBoolean(false);
7812
7813    }
7814
7815    /*
7816     * XXX: We should get rid of "DesktopMode" property  when 'kAppleClamshellCausesSleepKey'
7817     * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
7818     * issued by DisplayWrangler on darkwake.
7819     */
7820    if (!strcmp(aKey, "DesktopMode")) {
7821        if (desktopMode)
7822            return OSBoolean::withBoolean(true);
7823        else
7824            return OSBoolean::withBoolean(false);
7825    }
7826    if (!strcmp(aKey, "DisplayIdleForDemandSleep")) {
7827        if (displayIdleForDemandSleep) {
7828            return OSBoolean::withBoolean(true);
7829        }
7830        else  {
7831            return OSBoolean::withBoolean(false);
7832        }
7833    }
7834
7835    if (!strcmp(aKey, kIOPMDriverWakeEventsKey))
7836    {
7837        OSArray * array = 0;
7838        WAKEEVENT_LOCK();
7839        if (_systemWakeEventsArray && _systemWakeEventsArray->getCount())
7840            array = OSArray::withArray(_systemWakeEventsArray);
7841        WAKEEVENT_UNLOCK();
7842        return array;
7843    }
7844
7845    if (!strcmp(aKey, kIOPMSleepStatisticsAppsKey))
7846    {
7847        OSArray * array = 0;
7848        IOLockLock(pmStatsLock);
7849        if (pmStatsAppResponses && pmStatsAppResponses->getCount()) {
7850            array = OSArray::withArray(pmStatsAppResponses);
7851            pmStatsAppResponses->flushCollection();
7852        }
7853        IOLockUnlock(pmStatsLock);
7854        return array;
7855    }
7856
7857    return NULL;
7858}
7859
7860// MARK: -
7861// MARK: Wake Event Reporting
7862
7863void IOPMrootDomain::copyWakeReasonString( char * outBuf, size_t bufSize )
7864{
7865    WAKEEVENT_LOCK();
7866    strlcpy(outBuf, gWakeReasonString, bufSize);
7867    WAKEEVENT_UNLOCK();
7868}
7869
7870//******************************************************************************
7871// acceptSystemWakeEvents
7872//
7873// Private control for the acceptance of driver wake event claims.
7874//******************************************************************************
7875
7876void IOPMrootDomain::acceptSystemWakeEvents( bool accept )
7877{
7878    bool logWakeReason = false;
7879
7880    WAKEEVENT_LOCK();
7881    if (accept)
7882    {
7883        gWakeReasonString[0] = '\0';
7884        if (!_systemWakeEventsArray)
7885            _systemWakeEventsArray = OSArray::withCapacity(4);
7886        if ((_acceptSystemWakeEvents = (_systemWakeEventsArray != 0)))
7887            _systemWakeEventsArray->flushCollection();
7888    }
7889    else
7890    {
7891        _acceptSystemWakeEvents = false;
7892    }
7893    WAKEEVENT_UNLOCK();
7894
7895    if (logWakeReason)
7896        MSG("system wake events:%s\n", gWakeReasonString);
7897}
7898
7899//******************************************************************************
7900// claimSystemWakeEvent
7901//
7902// For a driver to claim a device is the source/conduit of a system wake event.
7903//******************************************************************************
7904
7905void IOPMrootDomain::claimSystemWakeEvent(
7906    IOService *     device,
7907    IOOptionBits    flags,
7908    const char *    reason,
7909    OSObject *      details )
7910{
7911    const OSSymbol *    deviceName   = 0;
7912    OSNumber *          deviceRegId  = 0;
7913    OSNumber *          claimTime    = 0;
7914    OSData *            flagsData    = 0;
7915    OSString *          reasonString = 0;
7916    OSDictionary *      d = 0;
7917    uint64_t            timestamp;
7918    bool                ok = false;
7919
7920    pmEventTimeStamp(&timestamp);
7921
7922    if (!device || !reason) return;
7923
7924    deviceName   = device->copyName(gIOServicePlane);
7925    deviceRegId  = OSNumber::withNumber(device->getRegistryEntryID(), 64);
7926    claimTime    = OSNumber::withNumber(timestamp, 64);
7927    flagsData    = OSData::withBytes(&flags, sizeof(flags));
7928    reasonString = OSString::withCString(reason);
7929    d = OSDictionary::withCapacity(5 + (details ? 1 : 0));
7930    if (!deviceName || !deviceRegId || !claimTime || !flagsData || !reasonString)
7931        goto done;
7932
7933    d->setObject(gIONameKey, deviceName);
7934    d->setObject(gIORegistryEntryIDKey, deviceRegId);
7935    d->setObject(kIOPMWakeEventTimeKey, claimTime);
7936    d->setObject(kIOPMWakeEventFlagsKey, flagsData);
7937    d->setObject(kIOPMWakeEventReasonKey, reasonString);
7938    if (details)
7939        d->setObject(kIOPMWakeEventDetailsKey, details);
7940
7941    WAKEEVENT_LOCK();
7942    if (!gWakeReasonSysctlRegistered)
7943    {
7944        // Lazy registration until the platform driver stops registering
7945        // the same name.
7946        gWakeReasonSysctlRegistered = true;
7947    }
7948    if (_acceptSystemWakeEvents)
7949    {
7950        ok = _systemWakeEventsArray->setObject(d);
7951        if (gWakeReasonString[0] != '\0')
7952            strlcat(gWakeReasonString, " ", sizeof(gWakeReasonString));
7953        strlcat(gWakeReasonString, reason, sizeof(gWakeReasonString));
7954    }
7955    WAKEEVENT_UNLOCK();
7956
7957done:
7958    if (deviceName)   deviceName->release();
7959    if (deviceRegId)  deviceRegId->release();
7960    if (claimTime)    claimTime->release();
7961    if (flagsData)    flagsData->release();
7962    if (reasonString) reasonString->release();
7963    if (d) d->release();
7964}
7965
7966/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7967
7968// MARK: -
7969// MARK: PMSettingHandle
7970
7971OSDefineMetaClassAndStructors( PMSettingHandle, OSObject )
7972
7973void PMSettingHandle::free( void )
7974{
7975    if (pmso)
7976    {
7977        pmso->clientHandleFreed();
7978        pmso->release();
7979        pmso = 0;
7980    }
7981
7982    OSObject::free();
7983}
7984
7985// MARK: -
7986// MARK: PMSettingObject
7987
7988#undef super
7989#define super OSObject
7990OSDefineMetaClassAndFinalStructors( PMSettingObject, OSObject )
7991
7992/*
7993 * Static constructor/initializer for PMSettingObject
7994 */
7995PMSettingObject *PMSettingObject::pmSettingObject(
7996    IOPMrootDomain                      *parent_arg,
7997    IOPMSettingControllerCallback       handler_arg,
7998    OSObject                            *target_arg,
7999    uintptr_t                           refcon_arg,
8000    uint32_t                            supportedPowerSources,
8001    const OSSymbol *                    settings[],
8002    OSObject                            **handle_obj)
8003{
8004    uint32_t                            settingCount = 0;
8005    PMSettingObject                     *pmso = 0;
8006    PMSettingHandle                     *pmsh = 0;
8007
8008    if ( !parent_arg || !handler_arg || !settings || !handle_obj )
8009        return NULL;
8010
8011    // count OSSymbol entries in NULL terminated settings array
8012    while (settings[settingCount]) {
8013        settingCount++;
8014    }
8015    if (0 == settingCount)
8016        return NULL;
8017
8018    pmso = new PMSettingObject;
8019    if (!pmso || !pmso->init())
8020        goto fail;
8021
8022    pmsh = new PMSettingHandle;
8023    if (!pmsh || !pmsh->init())
8024        goto fail;
8025
8026    queue_init(&pmso->calloutQueue);
8027    pmso->parent       = parent_arg;
8028    pmso->func         = handler_arg;
8029    pmso->target       = target_arg;
8030    pmso->refcon       = refcon_arg;
8031    pmso->settingCount = settingCount;
8032
8033    pmso->retain();     // handle holds a retain on pmso
8034    pmsh->pmso = pmso;
8035    pmso->pmsh = pmsh;
8036
8037    pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount);
8038    if (pmso->publishedFeatureID) {
8039        for (unsigned int i=0; i<settingCount; i++) {
8040            // Since there is now at least one listener to this setting, publish
8041            // PM root domain support for it.
8042            parent_arg->publishPMSetting( settings[i],
8043                    supportedPowerSources, &pmso->publishedFeatureID[i] );
8044        }
8045    }
8046
8047    *handle_obj = pmsh;
8048    return pmso;
8049
8050fail:
8051    if (pmso) pmso->release();
8052    if (pmsh) pmsh->release();
8053    return NULL;
8054}
8055
8056void PMSettingObject::free( void )
8057{
8058    if (publishedFeatureID) {
8059        for (uint32_t i=0; i<settingCount; i++) {
8060            if (publishedFeatureID[i]) {
8061                parent->removePublishedFeature( publishedFeatureID[i] );
8062            }
8063        }
8064
8065        IOFree(publishedFeatureID, sizeof(uint32_t) * settingCount);
8066    }
8067
8068    super::free();
8069}
8070
8071void PMSettingObject::dispatchPMSetting( const OSSymbol * type, OSObject * object )
8072{
8073    (*func)(target, type, object, refcon);
8074}
8075
8076void PMSettingObject::clientHandleFreed( void )
8077{
8078    parent->deregisterPMSettingObject(this);
8079}
8080
8081// MARK: -
8082// MARK: PMAssertionsTracker
8083
8084//*********************************************************************************
8085//*********************************************************************************
8086//*********************************************************************************
8087// class PMAssertionsTracker Implementation
8088
8089#define kAssertUniqueIDStart    500
8090
8091PMAssertionsTracker *PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain *rootDomain )
8092{
8093    PMAssertionsTracker    *myself;
8094
8095    myself = new PMAssertionsTracker;
8096
8097    if (myself) {
8098        myself->init();
8099        myself->owner = rootDomain;
8100        myself->issuingUniqueID = kAssertUniqueIDStart;
8101        myself->assertionsArray = OSArray::withCapacity(5);
8102        myself->assertionsKernel = 0;
8103        myself->assertionsUser = 0;
8104        myself->assertionsCombined = 0;
8105        myself->assertionsArrayLock = IOLockAlloc();
8106        myself->tabulateProducerCount = myself->tabulateConsumerCount = 0;
8107
8108        if (!myself->assertionsArray || !myself->assertionsArrayLock)
8109            myself = NULL;
8110    }
8111
8112    return myself;
8113}
8114
8115/* tabulate
8116 * - Update assertionsKernel to reflect the state of all
8117 * assertions in the kernel.
8118 * - Update assertionsCombined to reflect both kernel & user space.
8119 */
8120void PMAssertionsTracker::tabulate(void)
8121{
8122    int i;
8123    int count;
8124    PMAssertStruct      *_a = NULL;
8125    OSData              *_d = NULL;
8126
8127    IOPMDriverAssertionType oldKernel = assertionsKernel;
8128    IOPMDriverAssertionType oldCombined = assertionsCombined;
8129
8130    ASSERT_GATED();
8131
8132    assertionsKernel = 0;
8133    assertionsCombined = 0;
8134
8135    if (!assertionsArray)
8136        return;
8137
8138    if ((count = assertionsArray->getCount()))
8139    {
8140        for (i=0; i<count; i++)
8141        {
8142            _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
8143            if (_d)
8144            {
8145                _a = (PMAssertStruct *)_d->getBytesNoCopy();
8146                if (_a && (kIOPMDriverAssertionLevelOn == _a->level))
8147                    assertionsKernel |= _a->assertionBits;
8148            }
8149        }
8150    }
8151
8152    tabulateProducerCount++;
8153    assertionsCombined = assertionsKernel | assertionsUser;
8154
8155    if ((assertionsKernel != oldKernel) ||
8156        (assertionsCombined != oldCombined))
8157    {
8158        owner->evaluateAssertions(assertionsCombined, oldCombined);
8159    }
8160}
8161
8162void PMAssertionsTracker::publishProperties( void )
8163{
8164    OSArray             *assertionsSummary = NULL;
8165
8166    if (tabulateConsumerCount != tabulateProducerCount)
8167    {
8168        IOLockLock(assertionsArrayLock);
8169
8170        tabulateConsumerCount = tabulateProducerCount;
8171
8172        /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8173         */
8174        assertionsSummary = copyAssertionsArray();
8175        if (assertionsSummary)
8176        {
8177            owner->setProperty(kIOPMAssertionsDriverDetailedKey, assertionsSummary);
8178            assertionsSummary->release();
8179        }
8180        else
8181        {
8182            owner->removeProperty(kIOPMAssertionsDriverDetailedKey);
8183        }
8184
8185        /* Publish the IOPMrootDomain property "DriverPMAssertions"
8186         */
8187        owner->setProperty(kIOPMAssertionsDriverKey, assertionsKernel, 64);
8188
8189        IOLockUnlock(assertionsArrayLock);
8190    }
8191}
8192
8193PMAssertionsTracker::PMAssertStruct *PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id, int *index)
8194{
8195    PMAssertStruct      *_a = NULL;
8196    OSData              *_d = NULL;
8197    int                 found = -1;
8198    int                 count = 0;
8199    int                 i = 0;
8200
8201    if (assertionsArray
8202        && (count = assertionsArray->getCount()))
8203    {
8204        for (i=0; i<count; i++)
8205        {
8206            _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
8207            if (_d)
8208            {
8209                _a = (PMAssertStruct *)_d->getBytesNoCopy();
8210                if (_a && (_id == _a->id)) {
8211                    found = i;
8212                    break;
8213                }
8214            }
8215        }
8216    }
8217
8218    if (-1 == found) {
8219        return NULL;
8220    } else {
8221        if (index)
8222            *index = found;
8223        return _a;
8224    }
8225}
8226
8227/* PMAssertionsTracker::handleCreateAssertion
8228 * Perform assertion work on the PM workloop. Do not call directly.
8229 */
8230IOReturn PMAssertionsTracker::handleCreateAssertion(OSData *newAssertion)
8231{
8232    ASSERT_GATED();
8233
8234    if (newAssertion)
8235    {
8236        IOLockLock(assertionsArrayLock);
8237        assertionsArray->setObject(newAssertion);
8238        IOLockUnlock(assertionsArrayLock);
8239        newAssertion->release();
8240
8241        tabulate();
8242    }
8243    return kIOReturnSuccess;
8244}
8245
8246/* PMAssertionsTracker::createAssertion
8247 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
8248 * appropiate.
8249 */
8250IOReturn PMAssertionsTracker::createAssertion(
8251    IOPMDriverAssertionType which,
8252    IOPMDriverAssertionLevel level,
8253    IOService *serviceID,
8254    const char *whoItIs,
8255    IOPMDriverAssertionID *outID)
8256{
8257    OSData          *dataStore = NULL;
8258    PMAssertStruct  track;
8259
8260    // Warning: trillions and trillions of created assertions may overflow the unique ID.
8261    track.id = OSIncrementAtomic64((SInt64*) &issuingUniqueID);
8262    track.level = level;
8263    track.assertionBits = which;
8264    track.ownerString = whoItIs ? OSSymbol::withCString(whoItIs):0;
8265    track.ownerService = serviceID;
8266    track.registryEntryID = serviceID ? serviceID->getRegistryEntryID():0;
8267    track.modifiedTime = 0;
8268    pmEventTimeStamp(&track.createdTime);
8269
8270    dataStore = OSData::withBytes(&track, sizeof(PMAssertStruct));
8271    if (!dataStore)
8272    {
8273        if (track.ownerString)
8274            track.ownerString->release();
8275        return kIOReturnNoMemory;
8276    }
8277
8278    *outID = track.id;
8279
8280    if (owner && owner->pmPowerStateQueue) {
8281        owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionCreate, (void *)dataStore);
8282    }
8283
8284    return kIOReturnSuccess;
8285}
8286
8287/* PMAssertionsTracker::handleReleaseAssertion
8288 * Runs in PM workloop. Do not call directly.
8289 */
8290IOReturn PMAssertionsTracker::handleReleaseAssertion(
8291    IOPMDriverAssertionID _id)
8292{
8293    ASSERT_GATED();
8294
8295    int             index;
8296    PMAssertStruct  *assertStruct = detailsForID(_id, &index);
8297
8298    if (!assertStruct)
8299        return kIOReturnNotFound;
8300
8301    IOLockLock(assertionsArrayLock);
8302    if (assertStruct->ownerString)
8303        assertStruct->ownerString->release();
8304
8305    assertionsArray->removeObject(index);
8306    IOLockUnlock(assertionsArrayLock);
8307
8308    tabulate();
8309    return kIOReturnSuccess;
8310}
8311
8312/* PMAssertionsTracker::releaseAssertion
8313 * Releases an assertion and affects system behavior if appropiate.
8314 * Actual work happens on PM workloop.
8315 */
8316IOReturn PMAssertionsTracker::releaseAssertion(
8317    IOPMDriverAssertionID _id)
8318{
8319    if (owner && owner->pmPowerStateQueue) {
8320        owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionRelease, 0, _id);
8321    }
8322    return kIOReturnSuccess;
8323}
8324
8325/* PMAssertionsTracker::handleSetAssertionLevel
8326 * Runs in PM workloop. Do not call directly.
8327 */
8328IOReturn PMAssertionsTracker::handleSetAssertionLevel(
8329    IOPMDriverAssertionID    _id,
8330    IOPMDriverAssertionLevel _level)
8331{
8332    PMAssertStruct      *assertStruct = detailsForID(_id, NULL);
8333
8334    ASSERT_GATED();
8335
8336    if (!assertStruct) {
8337        return kIOReturnNotFound;
8338    }
8339
8340    IOLockLock(assertionsArrayLock);
8341    pmEventTimeStamp(&assertStruct->modifiedTime);
8342    assertStruct->level = _level;
8343    IOLockUnlock(assertionsArrayLock);
8344
8345    tabulate();
8346    return kIOReturnSuccess;
8347}
8348
8349/* PMAssertionsTracker::setAssertionLevel
8350 */
8351IOReturn PMAssertionsTracker::setAssertionLevel(
8352    IOPMDriverAssertionID    _id,
8353    IOPMDriverAssertionLevel _level)
8354{
8355    if (owner && owner->pmPowerStateQueue) {
8356        owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionSetLevel,
8357                (void *)(uintptr_t)_level, _id);
8358    }
8359
8360    return kIOReturnSuccess;
8361}
8362
8363IOReturn PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0)
8364{
8365    IOPMDriverAssertionType new_user_levels = *(IOPMDriverAssertionType *) arg0;
8366
8367    ASSERT_GATED();
8368
8369    if (new_user_levels != assertionsUser)
8370    {
8371        assertionsUser = new_user_levels;
8372        DLOG("assertionsUser 0x%llx\n", assertionsUser);
8373    }
8374
8375    tabulate();
8376    return kIOReturnSuccess;
8377}
8378
8379IOReturn PMAssertionsTracker::setUserAssertionLevels(
8380    IOPMDriverAssertionType new_user_levels)
8381{
8382    if (gIOPMWorkLoop) {
8383        gIOPMWorkLoop->runAction(
8384            OSMemberFunctionCast(
8385                IOWorkLoop::Action,
8386                this,
8387                &PMAssertionsTracker::handleSetUserAssertionLevels),
8388            this,
8389            (void *) &new_user_levels, 0, 0, 0);
8390    }
8391
8392    return kIOReturnSuccess;
8393}
8394
8395
8396OSArray *PMAssertionsTracker::copyAssertionsArray(void)
8397{
8398    int count;
8399    int i;
8400    OSArray     *outArray = NULL;
8401
8402    if (!assertionsArray ||
8403        (0 == (count = assertionsArray->getCount())) ||
8404        (NULL == (outArray = OSArray::withCapacity(count))))
8405    {
8406        goto exit;
8407    }
8408
8409    for (i=0; i<count; i++)
8410    {
8411        PMAssertStruct  *_a = NULL;
8412        OSData          *_d = NULL;
8413        OSDictionary    *details = NULL;
8414
8415        _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
8416        if (_d && (_a = (PMAssertStruct *)_d->getBytesNoCopy()))
8417        {
8418            OSNumber        *_n = NULL;
8419
8420            details = OSDictionary::withCapacity(7);
8421            if (!details)
8422                continue;
8423
8424            outArray->setObject(details);
8425            details->release();
8426
8427            _n = OSNumber::withNumber(_a->id, 64);
8428            if (_n) {
8429                details->setObject(kIOPMDriverAssertionIDKey, _n);
8430                _n->release();
8431            }
8432            _n = OSNumber::withNumber(_a->createdTime, 64);
8433            if (_n) {
8434                details->setObject(kIOPMDriverAssertionCreatedTimeKey, _n);
8435                _n->release();
8436            }
8437            _n = OSNumber::withNumber(_a->modifiedTime, 64);
8438            if (_n) {
8439                details->setObject(kIOPMDriverAssertionModifiedTimeKey, _n);
8440                _n->release();
8441            }
8442            _n = OSNumber::withNumber((uintptr_t)_a->registryEntryID, 64);
8443            if (_n) {
8444                details->setObject(kIOPMDriverAssertionRegistryEntryIDKey, _n);
8445                _n->release();
8446            }
8447            _n = OSNumber::withNumber(_a->level, 64);
8448            if (_n) {
8449                details->setObject(kIOPMDriverAssertionLevelKey, _n);
8450                _n->release();
8451            }
8452            _n = OSNumber::withNumber(_a->assertionBits, 64);
8453            if (_n) {
8454                details->setObject(kIOPMDriverAssertionAssertedKey, _n);
8455                _n->release();
8456            }
8457
8458            if (_a->ownerString) {
8459                details->setObject(kIOPMDriverAssertionOwnerStringKey, _a->ownerString);
8460            }
8461        }
8462    }
8463
8464exit:
8465    return outArray;
8466}
8467
8468IOPMDriverAssertionType PMAssertionsTracker::getActivatedAssertions(void)
8469{
8470    return assertionsCombined;
8471}
8472
8473IOPMDriverAssertionLevel PMAssertionsTracker::getAssertionLevel(
8474    IOPMDriverAssertionType type)
8475{
8476    if (type && ((type & assertionsKernel) == assertionsKernel))
8477    {
8478        return kIOPMDriverAssertionLevelOn;
8479    } else {
8480        return kIOPMDriverAssertionLevelOff;
8481    }
8482}
8483
8484//*********************************************************************************
8485//*********************************************************************************
8486//*********************************************************************************
8487
8488
8489static void pmEventTimeStamp(uint64_t *recordTS)
8490{
8491    clock_sec_t     tsec;
8492    clock_usec_t    tusec;
8493
8494    if (!recordTS)
8495        return;
8496
8497    // We assume tsec fits into 32 bits; 32 bits holds enough
8498    // seconds for 136 years since the epoch in 1970.
8499    clock_get_calendar_microtime(&tsec, &tusec);
8500
8501
8502    // Pack the sec & microsec calendar time into a uint64_t, for fun.
8503    *recordTS = 0;
8504    *recordTS |= (uint32_t)tusec;
8505    *recordTS |= ((uint64_t)tsec << 32);
8506
8507    return;
8508}
8509
8510// MARK: -
8511// MARK: IORootParent
8512
8513/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8514
8515OSDefineMetaClassAndFinalStructors(IORootParent, IOService)
8516
8517// The reason that root domain needs a root parent is to facilitate demand
8518// sleep, since a power change from the root parent cannot be vetoed.
8519//
8520// The above statement is no longer true since root domain now performs
8521// demand sleep using overrides. But root parent remains to avoid changing
8522// the power tree stacking. Root parent is parked at the max power state.
8523
8524
8525static IOPMPowerState patriarchPowerStates[2] =
8526{
8527    {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
8528    {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
8529};
8530
8531void IORootParent::initialize( void )
8532{
8533}
8534
8535bool IORootParent::start( IOService * nub )
8536{
8537    IOService::start(nub);
8538    attachToParent( getRegistryRoot(), gIOPowerPlane );
8539    PMinit();
8540    registerPowerDriver(this, patriarchPowerStates, 2);
8541    makeUsable();
8542    return true;
8543}
8544
8545void IORootParent::shutDownSystem( void )
8546{
8547}
8548
8549void IORootParent::restartSystem( void )
8550{
8551}
8552
8553void IORootParent::sleepSystem( void )
8554{
8555}
8556
8557void IORootParent::dozeSystem( void )
8558{
8559}
8560
8561void IORootParent::sleepToDoze( void )
8562{
8563}
8564
8565void IORootParent::wakeSystem( void )
8566{
8567}
8568
8569OSObject * IORootParent::copyProperty( const char * aKey) const
8570{
8571    return (IOService::copyProperty(aKey));
8572}
8573
8574
8575#if defined(__i386__) || defined(__x86_64__)
8576IOReturn IOPMrootDomain::restartWithStackshot()
8577{
8578    if ((swd_flags & SWD_WDOG_ENABLED) == 0)
8579        return kIOReturnError;
8580
8581    takeStackshot(true, true);
8582
8583    return kIOReturnSuccess;
8584}
8585
8586void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger)
8587{
8588    takeStackshot(wdogTrigger, false);
8589}
8590
8591void IOPMrootDomain::takeStackshot(bool wdogTrigger, bool isOSXWatchdog)
8592{
8593   swd_hdr *         hdr = NULL;
8594   addr64_t          data[3];
8595   uint32_t          wdog_panic = 0;
8596   int               cnt = 0;
8597   pid_t             pid = 0;
8598   uint32_t          flags;
8599
8600   char *            dstAddr;
8601   uint32_t          size;
8602   uint32_t          bytesRemaining;
8603   unsigned int      len;
8604   OSString *        UUIDstring = NULL;
8605   uint64_t          code;
8606   IOMemoryMap *     logBufMap = NULL;
8607
8608   swd_stackshot_hdr *stackshotHdr = NULL;
8609   if ( kIOSleepWakeWdogOff & gIOKitDebug )
8610      return;
8611
8612   if (wdogTrigger) {
8613       if (PE_parse_boot_argn("swd_panic", &wdog_panic, sizeof(wdog_panic)) &&
8614                  (wdog_panic == 1)) {
8615           // If boot-arg is set to panic on sleep/wake hang, call panic
8616           panic("Sleep/Wake hang detected\n");
8617           return;
8618       }
8619       else if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
8620           // If current boot is due to this watch dog trigger restart in previous boot,
8621           // then don't trigger again until at least 1 successful sleep & wake.
8622           sleepCnt = displayWakeCnt = 1;
8623           if (!(sleepCnt && displayWakeCnt)) {
8624               IOLog("Shutting down due to repeated Sleep/Wake failures\n");
8625               PEHaltRestart(kPEHaltCPU);
8626               return;
8627           }
8628       }
8629
8630   }
8631
8632   if (sleepWakeDebugIsWdogEnabled() == false)
8633       return;
8634
8635   if (swd_buffer == NULL) {
8636      sleepWakeDebugMemAlloc();
8637      if (swd_buffer == NULL) return;
8638   }
8639
8640   if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
8641       return;
8642
8643
8644   hdr = (swd_hdr *)swd_buffer;
8645   memset(hdr->UUID, 0x20, sizeof(hdr->UUID));
8646   if ((UUIDstring = OSDynamicCast(OSString, getProperty(kIOPMSleepWakeUUIDKey))) != NULL ) {
8647
8648      if (wdogTrigger || (!UUIDstring->isEqualTo(hdr->UUID))) {
8649         const char *str = UUIDstring->getCStringNoCopy();
8650         snprintf(hdr->UUID, sizeof(hdr->UUID), "UUID: %s", str);
8651      }
8652      else {
8653         DLOG("Data for current UUID already exists\n");
8654         goto exit;
8655      }
8656   }
8657
8658   dstAddr = (char*)hdr + hdr->spindump_offset;
8659   bytesRemaining = SWD_BUF_SIZE - hdr->spindump_offset;
8660
8661   /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
8662   hdr->is_osx_watchdog = isOSXWatchdog;
8663
8664   DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining);
8665
8666   while (bytesRemaining > sizeof(swd_stackshot_hdr)) {
8667
8668       stackshotHdr = (swd_stackshot_hdr *)dstAddr;
8669       stackshotHdr->magic = SWD_STACKSHOTHDR_MAGIC;
8670       stackshotHdr->size = 0;
8671       bytesRemaining -= sizeof(swd_stackshot_hdr);
8672       dstAddr += sizeof(swd_stackshot_hdr);
8673
8674       if (isOSXWatchdog) {
8675           pid = -1;
8676           size = bytesRemaining;
8677           flags = STACKSHOT_SAVE_LOADINFO | STACKSHOT_SAVE_KEXT_LOADINFO;
8678       }
8679       else if (cnt == 0) {
8680           /*
8681            * Take stackshot of all process on first sample. Size is restricted
8682            * to SWD_INITIAL_STACK_SIZE
8683            */
8684           pid = -1;
8685           size = (bytesRemaining > SWD_INITIAL_STACK_SIZE) ? SWD_INITIAL_STACK_SIZE : bytesRemaining;
8686           flags = STACKSHOT_SAVE_LOADINFO | STACKSHOT_SAVE_KEXT_LOADINFO|STACKSHOT_SAVE_KERNEL_FRAMES_ONLY;
8687       }
8688       else {
8689           /* Take sample of kernel threads only */
8690           pid = 0;
8691           size = bytesRemaining;
8692           flags = 0;
8693       }
8694
8695       stack_snapshot_from_kernel(pid, dstAddr, size, flags, &stackshotHdr->size);
8696
8697       dstAddr += stackshotHdr->size;
8698       bytesRemaining -= stackshotHdr->size;
8699
8700       DLOG("Sample: %d size: %d bytesRemaining: %d\n", cnt, stackshotHdr->size, bytesRemaining);
8701       if ((stackshotHdr->size == 0) || (++cnt == 10))
8702           break;
8703       IOSleep(10); // 10 ms
8704   }
8705
8706   hdr->spindump_size = (SWD_BUF_SIZE - bytesRemaining - hdr->spindump_offset);
8707
8708
8709   memset(hdr->cps, 0x20, sizeof(hdr->cps));
8710   snprintf(hdr->cps, sizeof(hdr->cps), "\ncps: %d", ((IOService*)this)->getPowerState());
8711   code = pmTracer->getPMStatusCode();
8712   memset(hdr->PMStatusCode, 0x20, sizeof(hdr->PMStatusCode));
8713   snprintf(hdr->PMStatusCode, sizeof(hdr->PMStatusCode), "\nCode: %08x %08x",
8714           (uint32_t)((code >> 32) & 0xffffffff), (uint32_t)(code & 0xffffffff));
8715   memset(hdr->reason, 0x20, sizeof(hdr->reason));
8716   snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: Watchdog\n\n");
8717
8718
8719   data[0] = round_page(sizeof(swd_hdr) + hdr->spindump_size);
8720   /* Header & rootdomain log is constantly changing and  is not covered by CRC */
8721   data[1] = hdr->crc = crc32(0, ((char*)swd_buffer+hdr->spindump_offset), hdr->spindump_size);
8722   data[2] = kvtophys((vm_offset_t)swd_buffer);
8723   len = sizeof(addr64_t)*3;
8724   DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
8725         data[0], data[1], data[2]);
8726
8727   if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey, data, len) == false)
8728   {
8729      DLOG("Failed to update nvram boot-args\n");
8730      goto exit;
8731   }
8732
8733exit:
8734
8735   gRootDomain->swd_lock = 0;
8736
8737   if (wdogTrigger) {
8738      IOLog("Restarting to collect Sleep wake debug logs\n");
8739      PEHaltRestart(kPERestartCPU);
8740   }
8741   else {
8742     logBufMap = sleepWakeDebugRetrieve();
8743      if (logBufMap) {
8744          sleepWakeDebugDumpFromMem(logBufMap);
8745          logBufMap->release();
8746          logBufMap = 0;
8747      }
8748   }
8749}
8750
8751void IOPMrootDomain::sleepWakeDebugMemAlloc( )
8752{
8753    vm_size_t    size = SWD_BUF_SIZE;
8754
8755    swd_hdr      *hdr = NULL;
8756
8757    IOBufferMemoryDescriptor  *memDesc = NULL;
8758
8759
8760    if ( kIOSleepWakeWdogOff & gIOKitDebug )
8761      return;
8762
8763    if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
8764       return;
8765
8766    // Try allocating above 4GB. If that fails, try at 2GB
8767    memDesc = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
8768                            kernel_task, kIOMemoryPhysicallyContiguous|kIOMemoryMapperNone,
8769                            size, 0xFFFFFFFF00000000ULL);
8770    if (!memDesc) {
8771       memDesc = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
8772                            kernel_task, kIOMemoryPhysicallyContiguous|kIOMemoryMapperNone,
8773                            size, 0xFFFFFFFF10000000ULL);
8774    }
8775
8776    if (memDesc == NULL)
8777    {
8778      DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
8779      goto exit;
8780    }
8781
8782
8783    hdr = (swd_hdr *)memDesc->getBytesNoCopy();
8784    memset(hdr, 0, sizeof(swd_hdr));
8785
8786    hdr->signature = SWD_HDR_SIGNATURE;
8787    hdr->alloc_size = size;
8788
8789    hdr->spindump_offset = sizeof(swd_hdr);
8790    swd_buffer = (void *)hdr;
8791    DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr->alloc_size, hdr->spindump_offset);
8792
8793exit:
8794    gRootDomain->swd_lock = 0;
8795}
8796
8797void IOPMrootDomain::sleepWakeDebugEnableWdog()
8798{
8799    swd_flags |= SWD_WDOG_ENABLED;
8800    if (!swd_buffer)
8801        sleepWakeDebugMemAlloc();
8802}
8803
8804bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
8805{
8806    return ((swd_flags & SWD_WDOG_ENABLED) &&
8807            !systemBooting && !systemShutdown);
8808}
8809
8810errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
8811{
8812   struct vnode         *vp = NULL;
8813   vfs_context_t        ctx = vfs_context_create(vfs_context_current());
8814   kauth_cred_t         cred = vfs_context_ucred(ctx);
8815   struct vnode_attr    va;
8816   errno_t      error = EIO;
8817
8818   if (vnode_open(name, (O_CREAT | FWRITE | O_NOFOLLOW),
8819                        S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
8820   {
8821      IOLog("Failed to open the file %s\n", name);
8822      goto exit;
8823   }
8824   VATTR_INIT(&va);
8825   VATTR_WANTED(&va, va_nlink);
8826   /* Don't dump to non-regular files or files with links. */
8827   if (vp->v_type != VREG ||
8828        vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
8829        IOLog("Bailing as this is not a regular file\n");
8830        goto exit;
8831    }
8832    VATTR_INIT(&va);
8833    VATTR_SET(&va, va_data_size, 0);
8834    vnode_setattr(vp, &va, ctx);
8835
8836
8837    error = vn_rdwr(UIO_WRITE, vp, buf, len, 0,
8838        UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0,  vfs_context_proc(ctx));
8839    if (error != 0)
8840       IOLog("Failed to save sleep wake log. err 0x%x\n", error);
8841    else
8842       DLOG("Saved %d bytes to file %s\n",len, name);
8843
8844exit:
8845    if (vp) vnode_close(vp, FWRITE, ctx);
8846    if (ctx) vfs_context_rele(ctx);
8847
8848    return error;
8849
8850}
8851
8852errno_t IOPMrootDomain::sleepWakeDebugCopyFile(
8853                               struct vnode *srcVp,
8854                               vfs_context_t srcCtx,
8855                               char *tmpBuf, uint64_t tmpBufSize,
8856                               uint64_t srcOffset,
8857                               const char *dstFname,
8858                               uint64_t numBytes,
8859                               uint32_t crc)
8860{
8861   struct vnode         *vp = NULL;
8862   vfs_context_t        ctx = vfs_context_create(vfs_context_current());
8863   struct vnode_attr    va;
8864   errno_t      error = EIO;
8865   uint64_t bytesToRead, bytesToWrite;
8866   uint64_t readFileOffset, writeFileOffset, srcDataOffset;
8867   uint32_t newcrc = 0;
8868
8869   if (vnode_open(dstFname, (O_CREAT | FWRITE | O_NOFOLLOW),
8870                        S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
8871   {
8872      DLOG("Failed to open the file %s\n", dstFname);
8873      goto exit;
8874   }
8875   VATTR_INIT(&va);
8876   VATTR_WANTED(&va, va_nlink);
8877   /* Don't dump to non-regular files or files with links. */
8878   if (vp->v_type != VREG ||
8879        vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
8880        DLOG("Bailing as this is not a regular file\n");
8881        goto exit;
8882	}
8883    VATTR_INIT(&va);
8884    VATTR_SET(&va, va_data_size, 0);
8885    vnode_setattr(vp, &va, ctx);
8886
8887    writeFileOffset = 0;
8888    while(numBytes) {
8889        bytesToRead = (round_page(numBytes) > tmpBufSize) ? tmpBufSize : round_page(numBytes);
8890        readFileOffset = trunc_page(srcOffset);
8891
8892       DLOG("Read file (numBytes:0x%llx)\n", bytesToRead);
8893       error = vn_rdwr(UIO_READ, srcVp, tmpBuf, bytesToRead, readFileOffset,
8894               UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
8895               vfs_context_ucred(srcCtx), (int *) 0,
8896               vfs_context_proc(srcCtx));
8897       if (error) {
8898           DLOG("Failed to read file(numBytes:0x%llx)\n", bytesToRead);
8899           break;
8900       }
8901
8902       srcDataOffset = (uint64_t)tmpBuf + (srcOffset - readFileOffset);
8903       bytesToWrite = bytesToRead - (srcOffset - readFileOffset);
8904       if (bytesToWrite > numBytes) bytesToWrite = numBytes;
8905
8906       if (crc) {
8907           newcrc = crc32(newcrc, (void *)srcDataOffset, bytesToWrite);
8908       }
8909       error = vn_rdwr(UIO_WRITE, vp, (char *)srcDataOffset, bytesToWrite, writeFileOffset,
8910               UIO_SYSSPACE, IO_SYNC|IO_NODELOCKED|IO_UNIT,
8911               vfs_context_ucred(ctx), (int *) 0,
8912               vfs_context_proc(ctx));
8913       if (error) {
8914           DLOG("Failed to write file(numBytes:0x%llx)\n", bytesToWrite);
8915           break;
8916       }
8917
8918       writeFileOffset += bytesToWrite;
8919       numBytes -= bytesToWrite;
8920       srcOffset += bytesToWrite;
8921
8922    }
8923    if (crc != newcrc) {
8924        swd_stackshot_hdr *shdr = (swd_stackshot_hdr *)tmpBuf;;
8925
8926        /* Set statckshot size to 0 if crc doesn't match */
8927        shdr->magic = SWD_STACKSHOTHDR_MAGIC;
8928        shdr->size = 0;
8929
8930        assert(tmpBufSize > sizeof(swd_stackshot_hdr));
8931        bytesToWrite = round_page(sizeof(swd_stackshot_hdr));
8932        vn_rdwr(UIO_WRITE, vp, (char *)tmpBuf, bytesToWrite, 0,
8933               UIO_SYSSPACE, IO_SYNC|IO_NODELOCKED|IO_UNIT,
8934               vfs_context_ucred(ctx), (int *) 0,
8935               vfs_context_proc(ctx));
8936
8937        DLOG("CRC check failed. expected:0x%x actual:0x%x\n", crc, newcrc);
8938        error = EFAULT;
8939    }
8940exit:
8941    if (vp) {
8942        error = vnode_close(vp, FWRITE, ctx);
8943        DLOG("vnode_close returned 0x%x\n", error);
8944    }
8945    if (ctx) vfs_context_rele(ctx);
8946
8947    return error;
8948
8949
8950
8951}
8952
8953void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
8954{
8955
8956    int             rc;
8957    char			hibernateFilename[MAXPATHLEN+1];
8958    char            PMStatusCode[100];
8959    void            *tmpBuf;
8960    swd_hdr         *hdr = NULL;
8961    uint32_t        stacksSize, logSize;
8962    uint64_t        tmpBufSize;
8963    uint64_t        hdrOffset, stacksOffset, logOffset;
8964    errno_t         error = EIO;
8965    OSObject        *obj = NULL;
8966    OSString        *str = NULL;
8967    OSNumber        *failStat = NULL;
8968    struct vnode    *vp = NULL;
8969    vfs_context_t   ctx = NULL;
8970
8971    struct vnode_attr           va;
8972    IOBufferMemoryDescriptor    *tmpBufDesc = NULL;
8973    IOHibernateImageHeader      *imageHdr;
8974
8975    DLOG("sleepWakeDebugDumpFromFile\n");
8976    if ((swd_flags & SWD_LOGS_IN_FILE) == 0)
8977        return;
8978
8979   if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
8980       return;
8981
8982
8983    hibernateFilename[0] = 0;
8984    if ((obj = copyProperty(kIOHibernateFileKey)))
8985    {
8986        if ((str = OSDynamicCast(OSString, obj)))
8987            strlcpy(hibernateFilename, str->getCStringNoCopy(),
8988                    sizeof(hibernateFilename));
8989        obj->release();
8990    }
8991    if (!hibernateFilename[0]) {
8992        DMSG("sleepWakeDebugDumpFromFile: Failed to hib file name\n");
8993        goto exit;
8994    }
8995    DLOG("sleepWakeDebugDumpFromFile: Hib file name %s\n", hibernateFilename);
8996
8997    /* Allocate a temp buffer to copy data between files */
8998    tmpBufSize = 2*4096;
8999    tmpBufDesc = IOBufferMemoryDescriptor::
9000        inTaskWithOptions(kernel_task, kIODirectionOutIn | kIOMemoryMapperNone,
9001                          tmpBufSize, PAGE_SIZE);
9002
9003    if (!tmpBufDesc) {
9004        DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
9005        goto exit;
9006    }
9007
9008    tmpBuf = tmpBufDesc->getBytesNoCopy();
9009
9010   ctx = vfs_context_create(vfs_context_current());
9011    if (vnode_open(hibernateFilename, (FREAD | O_NOFOLLOW), 0,
9012                   VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
9013    {
9014        DMSG("sleepWakeDebugDumpFromFile: Failed to open the hibernate file %s\n", hibernateFilename);
9015        goto exit;
9016    }
9017    VATTR_INIT(&va);
9018    VATTR_WANTED(&va, va_nlink);
9019    VATTR_WANTED(&va, va_data_alloc);
9020    if (vp->v_type != VREG ||
9021        vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
9022        DMSG("sleepWakeDebugDumpFromFile: Bailing as this is not a regular file\n");
9023        goto exit;
9024    }
9025
9026    /* Read the sleepimage file header */
9027    rc = vn_rdwr(UIO_READ, vp, (char *)tmpBuf, round_page(sizeof(IOHibernateImageHeader)), 0,
9028                UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
9029                vfs_context_ucred(ctx), (int *) 0,
9030                vfs_context_proc(ctx));
9031    if (rc != 0) {
9032        DMSG("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d)\n", round_page(sizeof(IOHibernateImageHeader)), rc);
9033        goto exit;
9034    }
9035
9036    imageHdr = ((IOHibernateImageHeader *)tmpBuf);
9037    if (imageHdr->signature != kIOHibernateHeaderDebugDataSignature) {
9038        DMSG("sleepWakeDebugDumpFromFile: File header has unexpected value 0x%x\n", imageHdr->signature);
9039        goto exit;
9040    }
9041
9042    /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
9043    hdrOffset = imageHdr->deviceBlockSize;
9044    if (hdrOffset + sizeof(swd_hdr) >= va.va_data_alloc) {
9045        DMSG("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx)\n",  va.va_data_alloc);
9046        goto exit;
9047    }
9048
9049    DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr)), trunc_page(hdrOffset));
9050    /* Read the sleep/wake debug header(swd_hdr) */
9051    rc = vn_rdwr(UIO_READ, vp, (char *)tmpBuf, round_page(sizeof(swd_hdr)), trunc_page(hdrOffset),
9052                UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
9053                vfs_context_ucred(ctx), (int *) 0,
9054                vfs_context_proc(ctx));
9055    if (rc != 0) {
9056        DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %lu. rc=%d\n",
9057             round_page(sizeof(swd_hdr)), rc);
9058        goto exit;
9059    }
9060
9061    hdr = (swd_hdr *)((char *)tmpBuf + (hdrOffset - trunc_page(hdrOffset)));
9062    if ((hdr->signature != SWD_HDR_SIGNATURE) || (hdr->alloc_size > SWD_BUF_SIZE) ||
9063        (hdr->spindump_offset > SWD_BUF_SIZE) || (hdr->spindump_size > SWD_BUF_SIZE)) {
9064        DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
9065             hdr->signature, hdr->alloc_size, hdr->spindump_offset, hdr->spindump_size);
9066        goto exit;
9067    }
9068    stacksSize = hdr->spindump_size;
9069
9070    /* Get stacks & log offsets in the image file */
9071    stacksOffset = hdrOffset + hdr->spindump_offset;
9072    logOffset = hdrOffset + offsetof(swd_hdr, UUID);
9073    logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
9074
9075    error = sleepWakeDebugCopyFile(vp, ctx, (char *)tmpBuf, tmpBufSize, stacksOffset,
9076                                   getDumpStackFilename(hdr), stacksSize, hdr->crc);
9077    if (error == EFAULT) {
9078        DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
9079        goto exit;
9080    }
9081    error = sleepWakeDebugCopyFile(vp, ctx, (char *)tmpBuf, tmpBufSize, logOffset,
9082                                   getDumpLogFilename(hdr), logSize, 0);
9083    if (error) {
9084        DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error);
9085        goto exit;
9086    }
9087exit:
9088    if (error) {
9089      // Write just the SleepWakeLog.dump with failure code
9090      uint64_t fcode = 0;
9091      const char *fname;
9092      if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
9093          failStat = OSDynamicCast(OSNumber, getProperty(kIOPMSleepWakeFailureCodeKey));
9094          fcode = failStat->unsigned64BitValue();
9095          fname = kSleepWakeLogFilename;
9096      }
9097      else {
9098          fname = kAppleOSXWatchdogLogFilename;
9099      }
9100      memset(PMStatusCode, 0x20, sizeof(PMStatusCode)); // Fill with spaces
9101      PMStatusCode[sizeof(PMStatusCode)-1] = 0xa; // And an end-of-line at the end
9102      snprintf(PMStatusCode, sizeof(PMStatusCode)-1, "Code: 0x%llx", fcode);
9103      sleepWakeDebugSaveFile(fname, PMStatusCode, sizeof(PMStatusCode));
9104    }
9105    gRootDomain->swd_lock = 0;
9106
9107    if (vp) vnode_close(vp, FREAD, ctx);
9108    if (ctx) vfs_context_rele(ctx);
9109    if (tmpBufDesc) tmpBufDesc->release();
9110
9111}
9112
9113void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap *logBufMap)
9114{
9115   IOVirtualAddress     srcBuf = NULL;
9116   char                 *stackBuf = NULL, *logOffset = NULL;
9117   int                  logSize = 0;
9118
9119   errno_t      error = EIO;
9120   uint64_t     bufSize = 0;
9121   swd_hdr      *hdr = NULL;
9122   char PMStatusCode[100];
9123   OSNumber  *failStat = NULL;
9124
9125   if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9126       return;
9127
9128   if ((logBufMap == 0) || ( (srcBuf = logBufMap->getVirtualAddress()) == 0) )
9129   {
9130      DLOG("Nothing saved to dump to file\n");
9131      goto exit;
9132   }
9133
9134   hdr = (swd_hdr *)srcBuf;
9135   bufSize = logBufMap->getLength();
9136   if (bufSize <= sizeof(swd_hdr))
9137   {
9138      IOLog("SleepWake log buffer contents are invalid\n");
9139      goto exit;
9140   }
9141
9142   stackBuf = (char*)hdr+hdr->spindump_offset;
9143
9144   error = sleepWakeDebugSaveFile(getDumpStackFilename(hdr), stackBuf, hdr->spindump_size);
9145   if (error) goto exit;
9146
9147   logOffset = (char*)hdr+offsetof(swd_hdr, UUID);
9148   logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
9149
9150   error = sleepWakeDebugSaveFile(getDumpLogFilename(hdr), logOffset, logSize);
9151   if (error) goto exit;
9152
9153    hdr->spindump_size = 0;
9154    error = 0;
9155
9156exit:
9157    if (error) {
9158      // Write just the SleepWakeLog.dump with failure code
9159      uint64_t fcode = 0;
9160      const char *sname, *lname;
9161      swd_stackshot_hdr shdr;
9162
9163        /* Try writing an empty stacks file */
9164        shdr.magic = SWD_STACKSHOTHDR_MAGIC;
9165        shdr.size = 0;
9166
9167
9168      if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
9169          failStat = OSDynamicCast(OSNumber, getProperty(kIOPMSleepWakeFailureCodeKey));
9170          fcode = failStat->unsigned64BitValue();
9171          lname = kSleepWakeLogFilename;
9172          sname = kSleepWakeStackFilename;
9173      }
9174      else {
9175          lname = kAppleOSXWatchdogLogFilename;
9176          sname= kAppleOSXWatchdogStackFilename;
9177      }
9178
9179      sleepWakeDebugSaveFile(sname, (char*)(&shdr), sizeof(shdr));
9180      memset(PMStatusCode, 0x20, sizeof(PMStatusCode)); // Fill with spaces
9181      PMStatusCode[sizeof(PMStatusCode)-1] = 0xa; // And an end-of-line at the end
9182      snprintf(PMStatusCode, sizeof(PMStatusCode)-1, "Code: 0x%llx", fcode);
9183      sleepWakeDebugSaveFile(lname, PMStatusCode, sizeof(PMStatusCode));
9184    }
9185    gRootDomain->swd_lock = 0;
9186}
9187
9188IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
9189{
9190   IOVirtualAddress     vaddr = NULL;
9191   IOMemoryDescriptor * desc = NULL;
9192   IOMemoryMap *        logBufMap = NULL;
9193
9194   uint32_t          len;
9195   addr64_t          data[3];
9196   uint64_t          bufSize = 0;
9197   uint64_t          crc = 0;
9198   uint64_t          newcrc = 0;
9199   uint64_t          paddr = 0;
9200   swd_hdr           *hdr = NULL;
9201   bool              ret = false;
9202   char              str[20];
9203
9204
9205   if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9206       return NULL;
9207
9208   if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey, 0, &len)) {
9209      DLOG("No sleepWakeDebug note to read\n");
9210      goto exit;
9211   }
9212
9213   if (len == strlen("sleepimage")) {
9214       str[0] = 0;
9215       PEReadNVRAMProperty(kIOSleepWakeDebugKey, str, &len);
9216
9217       if (!strncmp((char*)str, "sleepimage", strlen("sleepimage"))) {
9218           DLOG("sleepWakeDebugRetrieve: in file logs\n");
9219           swd_flags |= SWD_LOGS_IN_FILE|SWD_VALID_LOGS;
9220           goto exit;
9221       }
9222   }
9223   else if (len == sizeof(addr64_t)*3)
9224       PEReadNVRAMProperty(kIOSleepWakeDebugKey, data, &len);
9225   else {
9226      DLOG("Invalid sleepWakeDebug note length(%d)\n", len);
9227      goto exit;
9228   }
9229
9230
9231
9232   DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
9233        data[0], data[1], data[2]);
9234   DLOG("sleepWakeDebugRetrieve: in mem logs\n");
9235   bufSize = data[0];
9236   crc = data[1];
9237   paddr = data[2];
9238   if ( (bufSize <= sizeof(swd_hdr)) ||(bufSize > SWD_BUF_SIZE) || (crc == 0) )
9239   {
9240      IOLog("SleepWake log buffer contents are invalid\n");
9241      return NULL;
9242   }
9243
9244   DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
9245         bufSize, crc, paddr);
9246
9247
9248   desc = IOMemoryDescriptor::withAddressRange( paddr, bufSize,
9249                          kIODirectionOutIn | kIOMemoryMapperNone, NULL);
9250   if (desc == NULL)
9251   {
9252      IOLog("Fail to map SleepWake log buffer\n");
9253      goto exit;
9254   }
9255
9256   logBufMap = desc->map();
9257
9258   vaddr = logBufMap->getVirtualAddress();
9259
9260
9261   if ( (logBufMap->getLength() <= sizeof(swd_hdr)) || (vaddr == NULL) ) {
9262      IOLog("Fail to map SleepWake log buffer\n");
9263      goto exit;
9264   }
9265
9266   hdr = (swd_hdr *)vaddr;
9267   if (hdr->spindump_offset+hdr->spindump_size > bufSize)
9268   {
9269      IOLog("SleepWake log buffer contents are invalid\n");
9270      goto exit;
9271   }
9272
9273   hdr->crc = crc;
9274   newcrc = crc32(0, (void *)((char*)vaddr+hdr->spindump_offset),
9275            hdr->spindump_size);
9276   if (newcrc != crc) {
9277      IOLog("SleepWake log buffer contents are invalid\n");
9278      goto exit;
9279   }
9280
9281   ret = true;
9282   swd_flags |= SWD_LOGS_IN_MEM | SWD_VALID_LOGS;
9283
9284
9285exit:
9286   PERemoveNVRAMProperty(kIOSleepWakeDebugKey);
9287   if (!ret) {
9288      if (logBufMap) logBufMap->release();
9289      logBufMap = 0;
9290   }
9291   if (desc) desc->release();
9292    gRootDomain->swd_lock = 0;
9293
9294   return logBufMap;
9295}
9296
9297#else
9298
9299void IOPMrootDomain::sleepWakeDebugTrig(bool restart)
9300{
9301}
9302
9303void IOPMrootDomain::takeStackshot(bool restart, bool isOSXWatchdog)
9304{
9305#pragma unused(restart)
9306#pragma unused(isOSXWatchdog)
9307}
9308
9309void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9310{
9311}
9312void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap *map)
9313{
9314}
9315errno_t IOPMrootDomain::sleepWakeDebugCopyFile(
9316                               struct vnode *srcVp,
9317                               vfs_context_t srcCtx,
9318                               char *tmpBuf, uint64_t tmpBufSize,
9319                               uint64_t srcOffset,
9320                               const char *dstFname,
9321                               uint64_t numBytes,
9322                               uint32_t crc)
9323{
9324    return EIO;
9325}
9326
9327void IOPMrootDomain::sleepWakeDebugDumpFromFile()
9328{
9329}
9330
9331IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
9332{
9333   return NULL;
9334}
9335
9336void IOPMrootDomain::sleepWakeDebugEnableWdog()
9337{
9338}
9339
9340bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9341{
9342    return false;
9343}
9344
9345errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
9346{
9347    return 0;
9348}
9349
9350#endif
9351
9352