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