2 * Copyright (c) 1998-2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <libkern/c++/OSKext.h>
29 #include <libkern/c++/OSMetaClass.h>
30 #include <libkern/OSAtomic.h>
31 #include <libkern/OSDebug.h>
32 #include <IOKit/IOWorkLoop.h>
33 #include <IOKit/IOCommandGate.h>
34 #include <IOKit/IOPlatformExpert.h>
35 #include <IOKit/IOCPU.h>
36 #include <IOKit/IOKitDebug.h>
37 #include <IOKit/IOTimeStamp.h>
38 #include <IOKit/pwr_mgt/IOPMlog.h>
39 #include <IOKit/pwr_mgt/RootDomain.h>
40 #include <IOKit/pwr_mgt/IOPMPrivate.h>
41 #include <IOKit/IODeviceTreeSupport.h>
42 #include <IOKit/IOMessage.h>
43 #include <IOKit/IOReturn.h>
44 #include <IOKit/IONVRAM.h>
45 #include "RootDomainUserClient.h"
46 #include "IOKit/pwr_mgt/IOPowerConnection.h"
47 #include "IOPMPowerStateQueue.h"
48 #include <IOKit/IOCatalogue.h>
49 #include <IOKit/IOReportMacros.h>
51 #include <IOKit/IOHibernatePrivate.h>
53 #include <console/video_console.h>
54 #include <sys/syslog.h>
55 #include <sys/sysctl.h>
56 #include <sys/vnode.h>
57 #include <sys/vnode_internal.h>
58 #include <sys/fcntl.h>
61 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
62 #include "IOServicePMPrivate.h"
65 #include <mach/shared_region.h>
68 #if defined(__i386__) || defined(__x86_64__)
70 #include "IOPMrootDomainInternal.h"
74 #define kIOPMrootDomainClass "IOPMrootDomain"
75 #define LOG_PREFIX "PMRD: "
79 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
82 do { kprintf(LOG_PREFIX x); } while (false)
84 #define DLOG(x...) do { \
85 if (kIOLogPMRootDomain & gIOKitDebug) \
86 kprintf(LOG_PREFIX x); \
89 #define DMSG(x...) do { \
90 if (kIOLogPMRootDomain & gIOKitDebug) { \
91 kprintf(LOG_PREFIX x); IOLog(x); \
98 #define CHECK_THREAD_CONTEXT
99 #ifdef CHECK_THREAD_CONTEXT
100 static IOWorkLoop
* gIOPMWorkLoop
= 0;
101 #define ASSERT_GATED() \
103 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
104 panic("RootDomain: not inside PM gate"); \
108 #define ASSERT_GATED()
109 #endif /* CHECK_THREAD_CONTEXT */
111 #define CAP_LOSS(c) \
112 (((_pendingCapability & (c)) == 0) && \
113 ((_currentCapability & (c)) != 0))
115 #define CAP_GAIN(c) \
116 (((_currentCapability & (c)) == 0) && \
117 ((_pendingCapability & (c)) != 0))
119 #define CAP_CHANGE(c) \
120 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
122 #define CAP_CURRENT(c) \
123 ((_currentCapability & (c)) != 0)
125 #define CAP_HIGHEST(c) \
126 ((_highestCapability & (c)) != 0)
128 #if defined(__i386__) || defined(__x86_64__)
129 #define DARK_TO_FULL_EVALUATE_CLAMSHELL 1
132 // Event types for IOPMPowerStateQueue::submitPowerEvent()
134 kPowerEventFeatureChanged
= 1, // 1
135 kPowerEventReceivedPowerNotification
, // 2
136 kPowerEventSystemBootCompleted
, // 3
137 kPowerEventSystemShutdown
, // 4
138 kPowerEventUserDisabledSleep
, // 5
139 kPowerEventRegisterSystemCapabilityClient
, // 6
140 kPowerEventRegisterKernelCapabilityClient
, // 7
141 kPowerEventPolicyStimulus
, // 8
142 kPowerEventAssertionCreate
, // 9
143 kPowerEventAssertionRelease
, // 10
144 kPowerEventAssertionSetLevel
, // 11
145 kPowerEventQueueSleepWakeUUID
, // 12
146 kPowerEventPublishSleepWakeUUID
, // 13
147 kPowerEventSetDisplayPowerOn
// 14
150 // For evaluatePolicy()
151 // List of stimuli that affects the root domain policy.
153 kStimulusDisplayWranglerSleep
, // 0
154 kStimulusDisplayWranglerWake
, // 1
155 kStimulusAggressivenessChanged
, // 2
156 kStimulusDemandSystemSleep
, // 3
157 kStimulusAllowSystemSleepChanged
, // 4
158 kStimulusDarkWakeActivityTickle
, // 5
159 kStimulusDarkWakeEntry
, // 6
160 kStimulusDarkWakeReentry
, // 7
161 kStimulusDarkWakeEvaluate
, // 8
162 kStimulusNoIdleSleepPreventers
, // 9
163 kStimulusEnterUserActiveState
, // 10
164 kStimulusLeaveUserActiveState
// 11
168 IOReturn
OSKextSystemSleepOrWake( UInt32
);
170 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
171 extern "C" addr64_t
kvtophys(vm_offset_t va
);
172 extern "C" int stack_snapshot_from_kernel(pid_t pid
, void *buf
, uint32_t size
, uint32_t flags
, unsigned *bytesTraced
);
174 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
175 static void notifySystemShutdown( IOService
* root
, unsigned long event
);
176 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
177 static void pmEventTimeStamp(uint64_t *recordTS
);
179 // "IOPMSetSleepSupported" callPlatformFunction name
180 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
181 static const OSSymbol
*sleepMessagePEFunction
= NULL
;
183 #define kIOSleepSupportedKey "IOSleepSupported"
184 #define kIOPMSystemCapabilitiesKey "System Capabilities"
186 #define kIORequestWranglerIdleKey "IORequestIdle"
187 #define kDefaultWranglerIdlePeriod 25 // in milliseconds
189 #define kIOSleepWakeDebugKey "Persistent-memory-note"
191 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
192 | kIOPMSupportedOnBatt \
193 | kIOPMSupportedOnUPS)
197 // not idle around autowake time, secs
198 kAutoWakePreWindow
= 45,
199 kAutoWakePostWindow
= 15
202 #define kLocalEvalClamshellCommand (1 << 15)
203 #define kIdleSleepRetryInterval (3 * 60)
206 kWranglerPowerStateMin
= 0,
207 kWranglerPowerStateSleep
= 2,
208 kWranglerPowerStateDim
= 3,
209 kWranglerPowerStateMax
= 4
220 #define ON_POWER kIOPMPowerOn
221 #define RESTART_POWER kIOPMRestart
222 #define SLEEP_POWER kIOPMAuxPowerOn
224 static IOPMPowerState ourPowerStates
[NUM_POWER_STATES
] =
226 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
227 {1, kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
, 0,0,0,0,0,0,0,0},
228 {1, kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
, 0,0,0,0,0,0,0,0},
229 {1, kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
, 0,0,0,0,0,0,0,0}
232 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
233 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
234 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
235 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
236 #define kIOPMRootDomainWakeTypeUser "User"
237 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
238 #define kIOPMRootDomainWakeTypeNetwork "Network"
239 #define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
240 #define kIOPMRootDomainWakeTypeNotification "Notification"
241 #define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
243 // Special interest that entitles the interested client from receiving
244 // all system messages. Only used by powerd.
246 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
248 #define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
249 #define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
254 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
255 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
257 #define kAggressivesMinValue 1
260 kAggressivesStateBusy
= 0x01,
261 kAggressivesStateQuickSpindown
= 0x02
264 struct AggressivesRecord
{
270 struct AggressivesRequest
{
276 AggressivesRecord record
;
281 kAggressivesRequestTypeService
= 1,
282 kAggressivesRequestTypeRecord
286 kAggressivesOptionSynchronous
= 0x00000001,
287 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
288 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
289 kAggressivesOptionQuickSpindownMask
= 0x00000300
293 kAggressivesRecordFlagModified
= 0x00000001,
294 kAggressivesRecordFlagMinValue
= 0x00000002
299 kDarkWakeFlagHIDTickleEarly
= 0x01, // hid tickle before gfx suppression
300 kDarkWakeFlagHIDTickleLate
= 0x02, // hid tickle after gfx suppression
301 kDarkWakeFlagHIDTickleNone
= 0x03, // hid tickle is not posted
302 kDarkWakeFlagHIDTickleMask
= 0x03,
303 kDarkWakeFlagAlarmIsDark
= 0x0100,
304 kDarkWakeFlagGraphicsPowerState1
= 0x0200,
305 kDarkWakeFlagAudioNotSuppressed
= 0x0400
308 static IOPMrootDomain
* gRootDomain
;
309 static IONotifier
* gSysPowerDownNotifier
= 0;
310 static UInt32 gSleepOrShutdownPending
= 0;
311 static UInt32 gWillShutdown
= 0;
312 static UInt32 gPagingOff
= 0;
313 static UInt32 gSleepWakeUUIDIsSet
= false;
314 static uint32_t gAggressivesState
= 0;
316 uuid_string_t bootsessionuuid_string
;
318 static uint32_t gDarkWakeFlags
= kDarkWakeFlagHIDTickleNone
;
319 static PMStatsStruct gPMStats
;
322 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= 0;
323 static IOPMSystemSleepPolicyVariables
* gSleepPolicyVars
= 0;
324 static void * gSleepPolicyTarget
;
327 struct timeval gIOLastSleepTime
;
328 struct timeval gIOLastWakeTime
;
330 static char gWakeReasonString
[128];
331 static bool gWakeReasonSysctlRegistered
= false;
333 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
334 #define kCPUUnknownIndex 9999999
341 const OSSymbol
*gIOPMStatsApplicationResponseTimedOut
;
342 const OSSymbol
*gIOPMStatsApplicationResponseCancel
;
343 const OSSymbol
*gIOPMStatsApplicationResponseSlow
;
344 const OSSymbol
*gIOPMStatsApplicationResponsePrompt
;
345 const OSSymbol
*gIOPMStatsDriverPSChangeSlow
;
347 #define kBadPMFeatureID 0
351 * Opaque handle passed to clients of registerPMSettingController()
353 class PMSettingHandle
: public OSObject
355 OSDeclareFinalStructors( PMSettingHandle
)
356 friend class PMSettingObject
;
359 PMSettingObject
*pmso
;
365 * Internal object to track each PM setting controller
367 class PMSettingObject
: public OSObject
369 OSDeclareFinalStructors( PMSettingObject
)
370 friend class IOPMrootDomain
;
373 queue_head_t calloutQueue
;
375 IOPMrootDomain
*parent
;
376 PMSettingHandle
*pmsh
;
377 IOPMSettingControllerCallback func
;
380 uint32_t *publishedFeatureID
;
381 uint32_t settingCount
;
387 static PMSettingObject
*pmSettingObject(
388 IOPMrootDomain
*parent_arg
,
389 IOPMSettingControllerCallback handler_arg
,
390 OSObject
*target_arg
,
391 uintptr_t refcon_arg
,
392 uint32_t supportedPowerSources
,
393 const OSSymbol
*settings
[],
394 OSObject
**handle_obj
);
396 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
397 void clientHandleFreed(void);
400 struct PMSettingCallEntry
{
405 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
406 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
407 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
408 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
412 * Internal helper object for logging trace points to RTC
413 * IOPMrootDomain and only IOPMrootDomain should instantiate
414 * exactly one of these.
417 typedef void (*IOPMTracePointHandler
)(
418 void * target
, uint32_t code
, uint32_t data
);
420 class PMTraceWorker
: public OSObject
422 OSDeclareDefaultStructors(PMTraceWorker
)
424 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
426 static PMTraceWorker
*tracer( IOPMrootDomain
* );
427 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
428 void tracePoint(uint8_t phase
);
429 void tracePoint(uint8_t phase
, uint8_t data8
);
430 void traceDetail(uint32_t detail
);
431 void traceLoginWindowPhase(uint8_t phase
);
432 int recordTopLevelPCIDevice(IOService
*);
433 void RTC_TRACE(void);
434 virtual bool serialize(OSSerialize
*s
) const;
436 IOPMTracePointHandler tracePointHandler
;
437 void * tracePointTarget
;
438 uint64_t getPMStatusCode();
440 IOPMrootDomain
*owner
;
441 IOLock
*pciMappingLock
;
442 OSArray
*pciDeviceBitMappings
;
444 uint8_t addedToRegistry
;
446 uint8_t loginWindowPhase
;
448 uint32_t traceData32
;
452 * PMAssertionsTracker
453 * Tracks kernel and user space PM assertions
455 class PMAssertionsTracker
: public OSObject
457 OSDeclareFinalStructors(PMAssertionsTracker
)
459 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
461 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
462 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
463 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
464 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
466 OSArray
*copyAssertionsArray(void);
467 IOPMDriverAssertionType
getActivatedAssertions(void);
468 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
470 IOReturn
handleCreateAssertion(OSData
*);
471 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
472 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
473 IOReturn
handleSetUserAssertionLevels(void * arg0
);
474 void publishProperties(void);
478 IOPMDriverAssertionID id
;
479 IOPMDriverAssertionType assertionBits
;
480 uint64_t createdTime
;
481 uint64_t modifiedTime
;
482 const OSSymbol
*ownerString
;
483 IOService
*ownerService
;
484 uint64_t registryEntryID
;
485 IOPMDriverAssertionLevel level
;
488 uint32_t tabulateProducerCount
;
489 uint32_t tabulateConsumerCount
;
491 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
494 IOPMrootDomain
*owner
;
495 OSArray
*assertionsArray
;
496 IOLock
*assertionsArrayLock
;
497 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8))); /* aligned for atomic access */
498 IOPMDriverAssertionType assertionsKernel
;
499 IOPMDriverAssertionType assertionsUser
;
500 IOPMDriverAssertionType assertionsCombined
;
503 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
507 * Internal helper object for Shutdown/Restart notifications.
509 #define kPMHaltMaxWorkers 8
510 #define kPMHaltTimeoutMS 100
512 class PMHaltWorker
: public OSObject
514 OSDeclareFinalStructors( PMHaltWorker
)
517 IOService
* service
; // service being worked on
518 AbsoluteTime startTime
; // time when work started
519 int depth
; // work on nubs at this PM-tree depth
520 int visits
; // number of nodes visited (debug)
522 bool timeout
; // service took too long
524 static PMHaltWorker
* worker( void );
525 static void main( void * arg
, wait_result_t waitResult
);
526 static void work( PMHaltWorker
* me
);
527 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
528 virtual void free( void );
531 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
534 #define super IOService
535 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
537 static void IOPMRootDomainWillShutdown(void)
539 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
541 OSKext::willShutdown();
542 for (int i
= 0; i
< 100; i
++)
544 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
552 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
554 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
557 IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
559 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
562 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
564 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
567 IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
569 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
572 IOReturn
rootDomainRestart ( void )
574 return gRootDomain
->restartSystem();
577 IOReturn
rootDomainShutdown ( void )
579 return gRootDomain
->shutdownSystem();
582 void IOSystemShutdownNotification(void)
584 IOPMRootDomainWillShutdown();
585 if (OSCompareAndSwap(0, 1, &gPagingOff
))
587 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
591 int sync_internal(void);
595 A device is always in the highest power state which satisfies its driver,
596 its policy-maker, and any power children it has, but within the constraint
597 of the power state provided by its parent. The driver expresses its desire by
598 calling changePowerStateTo(), the policy-maker expresses its desire by calling
599 changePowerStateToPriv(), and the children express their desires by calling
600 requestPowerDomainState().
602 The Root Power Domain owns the policy for idle and demand sleep for the system.
603 It is a power-managed IOService just like the others in the system.
604 It implements several power states which map to what we see as Sleep and On.
606 The sleep policy is as follows:
607 1. Sleep is prevented if the case is open so that nobody will think the machine
608 is off and plug/unplug cards.
609 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
610 3. System cannot Sleep if some object in the tree is in a power state marked
611 kIOPMPreventSystemSleep.
613 These three conditions are enforced using the "driver clamp" by calling
614 changePowerStateTo(). For example, if the case is opened,
615 changePowerStateTo(ON_STATE) is called to hold the system on regardless
616 of the desires of the children of the root or the state of the other clamp.
618 Demand Sleep is initiated by pressing the front panel power button, closing
619 the clamshell, or selecting the menu item. In this case the root's parent
620 actually initiates the power state change so that the root domain has no
621 choice and does not give applications the opportunity to veto the change.
623 Idle Sleep occurs if no objects in the tree are in a state marked
624 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
625 the root on, so it sets the "policy-maker clamp" by calling
626 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
627 This timer is set for the difference between the sleep timeout slider and the
628 display dim timeout slider. When the timer expires, it releases its clamp and
629 now nothing is holding it awake, so it falls asleep.
631 Demand sleep is prevented when the system is booting. When preferences are
632 transmitted by the loginwindow at the end of boot, a flag is cleared,
633 and this allows subsequent Demand Sleep.
636 //******************************************************************************
638 IOPMrootDomain
* IOPMrootDomain::construct( void )
640 IOPMrootDomain
*root
;
642 root
= new IOPMrootDomain
;
649 //******************************************************************************
651 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
653 IOService
* rootDomain
= (IOService
*) p0
;
654 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
655 uint32_t powerState
= rootDomain
->getPowerState();
657 DLOG("disk_sync_callout ps=%u\n", powerState
);
659 if (ON_STATE
== powerState
)
666 IOHibernateSystemPostWake();
670 rootDomain
->allowPowerChange(notifyRef
);
671 DLOG("disk_sync_callout finish\n");
674 //******************************************************************************
676 static void hib_debugSetup_callout( thread_call_param_t p0
, thread_call_param_t p1
)
678 IOService
* rootDomain
= (IOService
*) p0
;
679 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
682 IOHibernateOpenForDebugData();
685 rootDomain
->allowPowerChange(notifyRef
);
686 DLOG("hib_debugSetup_callout finish\n");
688 //******************************************************************************
690 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
)
692 AbsoluteTime endTime
;
695 clock_get_uptime(&endTime
);
696 if (CMP_ABSOLUTETIME(&endTime
, startTime
) > 0)
698 SUB_ABSOLUTETIME(&endTime
, startTime
);
699 absolutetime_to_nanoseconds(endTime
, &nano
);
702 return (UInt32
)(nano
/ 1000000ULL);
705 //******************************************************************************
708 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
710 struct timeval
*swt
= (struct timeval
*)arg1
;
711 struct proc
*p
= req
->p
;
714 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
715 } else if(proc_is64bit(p
)) {
716 struct user64_timeval t
;
717 t
.tv_sec
= swt
->tv_sec
;
718 t
.tv_usec
= swt
->tv_usec
;
719 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
721 struct user32_timeval t
;
722 t
.tv_sec
= swt
->tv_sec
;
723 t
.tv_usec
= swt
->tv_usec
;
724 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
728 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
729 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
730 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
732 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
733 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
734 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
739 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
741 int new_value
, changed
;
742 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
744 if (!gWillShutdown
&& (new_value
== 1)) {
745 IOPMRootDomainWillShutdown();
752 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
753 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
754 0, 0, sysctl_willshutdown
, "I", "");
758 sysctl_progressmeterenable
759 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
762 int new_value
, changed
;
764 error
= sysctl_io_number(req
, vc_progressmeter_enable
, sizeof(int), &new_value
, &changed
);
766 if (changed
) vc_enable_progressmeter(new_value
);
773 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
776 int new_value
, changed
;
778 error
= sysctl_io_number(req
, vc_progressmeter_value
, sizeof(int), &new_value
, &changed
);
780 if (changed
) vc_set_progressmeter(new_value
);
785 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
786 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
787 0, 0, sysctl_progressmeterenable
, "I", "");
789 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
790 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
791 0, 0, sysctl_progressmeter
, "I", "");
795 sysctl_wakereason SYSCTL_HANDLER_ARGS
797 char wr
[ sizeof(gWakeReasonString
) ];
801 gRootDomain
->copyWakeReasonString(wr
, sizeof(wr
));
803 return sysctl_io_string(req
, wr
, 0, 0, NULL
);
806 SYSCTL_PROC(_kern
, OID_AUTO
, wakereason
,
807 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
808 NULL
, 0, sysctl_wakereason
, "A", "wakereason");
810 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
812 static const OSSymbol
* gIOPMSettingAutoWakeCalendarKey
;
813 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
814 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
815 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
816 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
817 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
818 static const OSSymbol
* gIOPMUserTriggeredFullWakeKey
;
819 static const OSSymbol
* gIOPMUserIsActiveKey
;
821 //******************************************************************************
824 //******************************************************************************
826 #define kRootDomainSettingsCount 17
828 bool IOPMrootDomain::start( IOService
* nub
)
830 OSIterator
*psIterator
;
831 OSDictionary
*tmpDict
;
832 IORootParent
* patriarch
;
833 #if defined(__i386__) || defined(__x86_64__)
834 IONotifier
* notifier
;
840 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
841 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
842 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
843 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
844 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
845 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
846 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
847 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
849 gIOPMStatsApplicationResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
850 gIOPMStatsApplicationResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
851 gIOPMStatsApplicationResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
852 gIOPMStatsApplicationResponsePrompt
= OSSymbol::withCString(kIOPMStatsResponsePrompt
);
853 gIOPMStatsDriverPSChangeSlow
= OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow
);
855 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
856 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
858 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
860 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
861 gIOPMSettingAutoWakeSecondsKey
,
862 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
863 gIOPMSettingAutoWakeCalendarKey
,
864 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
865 gIOPMSettingDebugWakeRelativeKey
,
866 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
867 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
868 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
869 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
870 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
871 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
872 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
873 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
874 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
875 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
876 gIOPMSettingSilentRunningKey
879 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
881 queue_init(&aggressivesQueue
);
882 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
883 aggressivesData
= OSData::withCapacity(
884 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
886 featuresDictLock
= IOLockAlloc();
887 settingsCtrlLock
= IOLockAlloc();
888 wakeEventLock
= IOLockAlloc();
889 setPMRootDomain(this);
891 extraSleepTimer
= thread_call_allocate(
892 idleSleepTimerExpired
,
893 (thread_call_param_t
) this);
895 diskSyncCalloutEntry
= thread_call_allocate(
897 (thread_call_param_t
) this);
898 hibDebugSetupEntry
= thread_call_allocate(
899 &hib_debugSetup_callout
,
900 (thread_call_param_t
) this);
902 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
903 fullWakeThreadCall
= thread_call_allocate(
904 OSMemberFunctionCast(thread_call_func_t
, this,
905 &IOPMrootDomain::fullWakeDelayedWork
),
906 (thread_call_param_t
) this);
909 setProperty(kIOSleepSupportedKey
, true);
911 bzero(&gPMStats
, sizeof(gPMStats
));
913 pmTracer
= PMTraceWorker::tracer(this);
915 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
917 userDisabledAllSleep
= false;
918 systemBooting
= true;
920 idleSleepTimerPending
= false;
922 clamshellClosed
= false;
923 clamshellExists
= false;
924 clamshellDisabled
= true;
925 acAdaptorConnected
= true;
926 clamshellSleepDisabled
= false;
927 gWakeReasonString
[0] = '\0';
929 // Initialize to user active.
930 // Will never transition to user inactive w/o wrangler.
931 fullWakeReason
= kFullWakeReasonLocalUser
;
932 userIsActive
= userWasActive
= true;
933 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
935 // Set the default system capabilities at boot.
936 _currentCapability
= kIOPMSystemCapabilityCPU
|
937 kIOPMSystemCapabilityGraphics
|
938 kIOPMSystemCapabilityAudio
|
939 kIOPMSystemCapabilityNetwork
;
941 _pendingCapability
= _currentCapability
;
942 _desiredCapability
= _currentCapability
;
943 _highestCapability
= _currentCapability
;
944 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
946 queuedSleepWakeUUIDString
= NULL
;
947 initializeBootSessionUUID();
948 pmStatsAppResponses
= OSArray::withCapacity(5);
949 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
950 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
951 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
952 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
953 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
954 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
956 pmStatsLock
= IOLockAlloc();
957 idxPMCPUClamshell
= kCPUUnknownIndex
;
958 idxPMCPULimitedPower
= kCPUUnknownIndex
;
960 tmpDict
= OSDictionary::withCapacity(1);
961 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
964 settingsCallbacks
= OSDictionary::withCapacity(1);
966 // Create a list of the valid PM settings that we'll relay to
967 // interested clients in setProperties() => setPMSetting()
968 allowedPMSettings
= OSArray::withObjects(
969 (const OSObject
**)settingsArr
,
970 kRootDomainSettingsCount
,
973 // List of PM settings that should not automatically publish itself
974 // as a feature when registered by a listener.
975 noPublishPMSettings
= OSArray::withObjects(
976 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
978 fPMSettingsDict
= OSDictionary::withCapacity(5);
979 preventIdleSleepList
= OSSet::withCapacity(8);
980 preventSystemSleepList
= OSSet::withCapacity(2);
982 PMinit(); // creates gIOPMWorkLoop
984 // Create IOPMPowerStateQueue used to queue external power
985 // events, and to handle those events on the PM work loop.
986 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
987 this, OSMemberFunctionCast(IOEventSource::Action
, this,
988 &IOPMrootDomain::dispatchPowerEvent
));
989 getPMworkloop()->addEventSource(pmPowerStateQueue
);
990 #ifdef CHECK_THREAD_CONTEXT
991 gIOPMWorkLoop
= getPMworkloop();
994 // create our power parent
995 patriarch
= new IORootParent
;
997 patriarch
->attach(this);
998 patriarch
->start(this);
999 patriarch
->addPowerChild(this);
1001 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1002 changePowerStateToPriv(ON_STATE
);
1004 // install power change handler
1005 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
1008 // Register for a notification when IODisplayWrangler is published
1009 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
1011 _displayWranglerNotifier
= addMatchingNotification(
1012 gIOPublishNotification
, tmpDict
,
1013 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
1019 #if defined(__i386__) || defined(__x86_64__)
1021 if ((tmpDict
= serviceMatching("IODTNVRAM")))
1023 notifier
= addMatchingNotification(
1024 gIOFirstPublishNotification
, tmpDict
,
1025 (IOServiceMatchingNotificationHandler
) &IONVRAMMatchPublished
,
1030 wranglerIdleSettings
= NULL
;
1031 OSNumber
* wranglerIdlePeriod
= NULL
;
1032 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1033 wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1035 if(wranglerIdleSettings
&& wranglerIdlePeriod
)
1036 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1037 wranglerIdlePeriod
);
1039 if(wranglerIdlePeriod
)
1040 wranglerIdlePeriod
->release();
1043 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1044 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1045 ucClassName
->release();
1047 // IOBacklightDisplay can take a long time to load at boot, or it may
1048 // not load at all if you're booting with clamshell closed. We publish
1049 // 'DisplayDims' here redundantly to get it published early and at all.
1050 psIterator
= getMatchingServices( serviceMatching("IOPMPowerSource") );
1051 if( psIterator
&& psIterator
->getNextObject() )
1053 // There's at least one battery on the system, so we publish
1054 // 'DisplayDims' support for the LCD.
1055 publishFeature("DisplayDims");
1058 psIterator
->release();
1061 sysctl_register_oid(&sysctl__kern_sleeptime
);
1062 sysctl_register_oid(&sysctl__kern_waketime
);
1063 sysctl_register_oid(&sysctl__kern_willshutdown
);
1064 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1065 sysctl_register_oid(&sysctl__kern_progressmeter
);
1066 sysctl_register_oid(&sysctl__kern_wakereason
);
1069 IOHibernateSystemInit(this);
1072 registerService(); // let clients find us
1077 //******************************************************************************
1080 // Receive a setProperty call
1081 // The "System Boot" property means the system is completely booted.
1082 //******************************************************************************
1084 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1086 IOReturn return_value
= kIOReturnSuccess
;
1087 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1090 const OSSymbol
*key
;
1092 OSCollectionIterator
* iter
= 0;
1094 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1095 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1096 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1097 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1098 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1099 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1100 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1101 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1102 const OSSymbol
*loginwindow_tracepoint_string
= OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey
);
1104 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1105 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1106 const OSSymbol
*hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1107 const OSSymbol
*hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1108 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1109 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1114 return_value
= kIOReturnBadArgument
;
1118 iter
= OSCollectionIterator::withCollection(dict
);
1121 return_value
= kIOReturnNoMemory
;
1125 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1126 (obj
= dict
->getObject(key
)))
1128 if (key
->isEqualTo(publish_simulated_battery_string
))
1130 if (OSDynamicCast(OSBoolean
, obj
))
1131 publishResource(key
, kOSBooleanTrue
);
1133 else if (key
->isEqualTo(idle_seconds_string
))
1135 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1137 setProperty(key
, n
);
1138 idleSeconds
= n
->unsigned32BitValue();
1141 else if (key
->isEqualTo(boot_complete_string
))
1143 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1145 else if (key
->isEqualTo(sys_shutdown_string
))
1147 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1148 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1150 else if (key
->isEqualTo(battery_warning_disabled_string
))
1152 setProperty(key
, obj
);
1155 else if (key
->isEqualTo(hibernatemode_string
) ||
1156 key
->isEqualTo(hibernatefilemin_string
) ||
1157 key
->isEqualTo(hibernatefilemax_string
) ||
1158 key
->isEqualTo(hibernatefreeratio_string
) ||
1159 key
->isEqualTo(hibernatefreetime_string
))
1161 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1162 setProperty(key
, n
);
1164 else if (key
->isEqualTo(hibernatefile_string
))
1166 OSString
* str
= OSDynamicCast(OSString
, obj
);
1167 if (str
) setProperty(key
, str
);
1170 else if (key
->isEqualTo(sleepdisabled_string
))
1172 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1174 setProperty(key
, b
);
1175 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1178 else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
))
1181 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1183 else if (key
->isEqualTo(loginwindow_tracepoint_string
))
1185 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
)))
1186 pmTracer
->traceLoginWindowPhase(n
->unsigned8BitValue());
1188 else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1189 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1190 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1191 key
->isEqualTo(stall_halt_string
))
1193 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1194 setProperty(key
, b
);
1196 else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1197 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1198 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
))
1200 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1201 setProperty(key
, n
);
1203 else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
))
1205 if (kOSBooleanTrue
== obj
)
1206 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1208 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1209 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm
);
1212 // Relay our allowed PM settings onto our registered PM clients
1213 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1))
1215 if ((gIOPMSettingAutoWakeSecondsKey
== key
) && ((n
= OSDynamicCast(OSNumber
, obj
))))
1217 UInt32 rsecs
= n
->unsigned32BitValue();
1219 autoWakeStart
= autoWakeEnd
= 0;
1222 AbsoluteTime deadline
;
1223 clock_interval_to_deadline(rsecs
+ kAutoWakePostWindow
, kSecondScale
, &deadline
);
1224 autoWakeEnd
= AbsoluteTime_to_scalar(&deadline
);
1225 if (rsecs
> kAutoWakePreWindow
)
1226 rsecs
-= kAutoWakePreWindow
;
1229 clock_interval_to_deadline(rsecs
, kSecondScale
, &deadline
);
1230 autoWakeStart
= AbsoluteTime_to_scalar(&deadline
);
1234 return_value
= setPMSetting(key
, obj
);
1235 if (kIOReturnSuccess
!= return_value
)
1238 if (gIOPMSettingDebugWakeRelativeKey
== key
)
1240 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1241 (_debugWakeSeconds
= n
->unsigned32BitValue()))
1243 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1247 _debugWakeSeconds
= 0;
1248 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1250 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1252 else if (gIOPMSettingAutoWakeCalendarKey
== key
)
1255 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1256 (data
->getLength() == sizeof(IOPMCalendarStruct
)))
1258 const IOPMCalendarStruct
* cs
=
1259 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1262 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1264 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1265 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1271 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1276 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1277 if(boot_complete_string
) boot_complete_string
->release();
1278 if(sys_shutdown_string
) sys_shutdown_string
->release();
1279 if(stall_halt_string
) stall_halt_string
->release();
1280 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1281 if(idle_seconds_string
) idle_seconds_string
->release();
1282 if(sleepdisabled_string
) sleepdisabled_string
->release();
1283 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1284 if(loginwindow_tracepoint_string
) loginwindow_tracepoint_string
->release();
1286 if(hibernatemode_string
) hibernatemode_string
->release();
1287 if(hibernatefile_string
) hibernatefile_string
->release();
1288 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1289 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1291 if (iter
) iter
->release();
1292 return return_value
;
1296 // MARK: Aggressiveness
1298 //******************************************************************************
1299 // setAggressiveness
1301 // Override IOService::setAggressiveness()
1302 //******************************************************************************
1304 IOReturn
IOPMrootDomain::setAggressiveness(
1306 unsigned long value
)
1308 return setAggressiveness( type
, value
, 0 );
1312 * Private setAggressiveness() with an internal options argument.
1314 IOReturn
IOPMrootDomain::setAggressiveness(
1316 unsigned long value
,
1317 IOOptionBits options
)
1319 AggressivesRequest
* entry
;
1320 AggressivesRequest
* request
;
1323 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1324 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1326 request
= IONew(AggressivesRequest
, 1);
1328 return kIOReturnNoMemory
;
1330 memset(request
, 0, sizeof(*request
));
1331 request
->options
= options
;
1332 request
->dataType
= kAggressivesRequestTypeRecord
;
1333 request
->data
.record
.type
= (uint32_t) type
;
1334 request
->data
.record
.value
= (uint32_t) value
;
1338 // Update disk quick spindown flag used by getAggressiveness().
1339 // Never merge requests with quick spindown flags set.
1341 if (options
& kAggressivesOptionQuickSpindownEnable
)
1342 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1343 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1344 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1347 // Coalesce requests with identical aggressives types.
1348 // Deal with callers that calls us too "aggressively".
1350 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1352 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1353 (entry
->data
.record
.type
== type
) &&
1354 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1356 entry
->data
.record
.value
= value
;
1365 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1368 AGGRESSIVES_UNLOCK();
1371 IODelete(request
, AggressivesRequest
, 1);
1373 if (options
& kAggressivesOptionSynchronous
)
1374 handleAggressivesRequests(); // not truly synchronous
1376 thread_call_enter(aggressivesThreadCall
);
1378 return kIOReturnSuccess
;
1381 //******************************************************************************
1382 // getAggressiveness
1384 // Override IOService::setAggressiveness()
1385 // Fetch the aggressiveness factor with the given type.
1386 //******************************************************************************
1388 IOReturn
IOPMrootDomain::getAggressiveness (
1390 unsigned long * outLevel
)
1396 return kIOReturnBadArgument
;
1400 // Disk quick spindown in effect, report value = 1
1402 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1403 (type
== kPMMinutesToSpinDown
))
1405 value
= kAggressivesMinValue
;
1409 // Consult the pending request queue.
1413 AggressivesRequest
* entry
;
1415 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1417 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1418 (entry
->data
.record
.type
== type
) &&
1419 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1421 value
= entry
->data
.record
.value
;
1428 // Consult the backend records.
1430 if (!source
&& aggressivesData
)
1432 AggressivesRecord
* record
;
1435 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1436 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1438 for (i
= 0; i
< count
; i
++, record
++)
1440 if (record
->type
== type
)
1442 value
= record
->value
;
1449 AGGRESSIVES_UNLOCK();
1453 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1454 source
, (uint32_t) type
, value
);
1455 *outLevel
= (unsigned long) value
;
1456 return kIOReturnSuccess
;
1460 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1461 *outLevel
= 0; // default return = 0, driver may not check for error
1462 return kIOReturnInvalid
;
1466 //******************************************************************************
1467 // joinAggressiveness
1469 // Request from IOService to join future aggressiveness broadcasts.
1470 //******************************************************************************
1472 IOReturn
IOPMrootDomain::joinAggressiveness(
1473 IOService
* service
)
1475 AggressivesRequest
* request
;
1477 if (!service
|| (service
== this))
1478 return kIOReturnBadArgument
;
1480 DLOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
1482 request
= IONew(AggressivesRequest
, 1);
1484 return kIOReturnNoMemory
;
1486 service
->retain(); // released by synchronizeAggressives()
1488 memset(request
, 0, sizeof(*request
));
1489 request
->dataType
= kAggressivesRequestTypeService
;
1490 request
->data
.service
= service
;
1493 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1494 AGGRESSIVES_UNLOCK();
1496 thread_call_enter(aggressivesThreadCall
);
1498 return kIOReturnSuccess
;
1501 //******************************************************************************
1502 // handleAggressivesRequests
1504 // Backend thread processes all incoming aggressiveness requests in the queue.
1505 //******************************************************************************
1508 handleAggressivesFunction(
1509 thread_call_param_t param1
,
1510 thread_call_param_t param2
)
1514 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1518 void IOPMrootDomain::handleAggressivesRequests( void )
1520 AggressivesRecord
* start
;
1521 AggressivesRecord
* record
;
1522 AggressivesRequest
* request
;
1523 queue_head_t joinedQueue
;
1527 bool pingSelf
= false;
1531 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1532 queue_empty(&aggressivesQueue
))
1535 gAggressivesState
|= kAggressivesStateBusy
;
1536 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1537 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1542 queue_init(&joinedQueue
);
1546 // Remove request from the incoming queue in FIFO order.
1547 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1548 switch (request
->dataType
)
1550 case kAggressivesRequestTypeRecord
:
1551 // Update existing record if found.
1553 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1555 if (record
->type
== request
->data
.record
.type
)
1559 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1561 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1564 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1565 kAggressivesRecordFlagModified
);
1566 DLOG("disk spindown accelerated, was %u min\n",
1570 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1572 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1575 record
->flags
|= kAggressivesRecordFlagModified
;
1576 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1577 DLOG("disk spindown restored to %u min\n",
1581 else if (record
->value
!= request
->data
.record
.value
)
1583 record
->value
= request
->data
.record
.value
;
1584 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1587 record
->flags
|= kAggressivesRecordFlagModified
;
1594 // No matching record, append a new record.
1596 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1598 AggressivesRecord newRecord
;
1600 newRecord
.flags
= kAggressivesRecordFlagModified
;
1601 newRecord
.type
= request
->data
.record
.type
;
1602 newRecord
.value
= request
->data
.record
.value
;
1603 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1605 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1606 DLOG("disk spindown accelerated\n");
1609 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1611 // OSData may have switched to another (larger) buffer.
1612 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1613 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1617 // Finished processing the request, release it.
1618 IODelete(request
, AggressivesRequest
, 1);
1621 case kAggressivesRequestTypeService
:
1622 // synchronizeAggressives() will free request.
1623 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1627 panic("bad aggressives request type %x\n", request
->dataType
);
1630 } while (!queue_empty(&aggressivesQueue
));
1632 // Release the lock to perform work, with busy flag set.
1633 if (!queue_empty(&joinedQueue
) || broadcast
)
1635 AGGRESSIVES_UNLOCK();
1636 if (!queue_empty(&joinedQueue
))
1637 synchronizeAggressives(&joinedQueue
, start
, count
);
1639 broadcastAggressives(start
, count
);
1643 // Remove the modified flag from all records.
1644 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1646 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1647 ((record
->type
== kPMMinutesToDim
) ||
1648 (record
->type
== kPMMinutesToSleep
)))
1651 record
->flags
&= ~kAggressivesRecordFlagModified
;
1654 // Check the incoming queue again since new entries may have been
1655 // added while lock was released above.
1657 } while (!queue_empty(&aggressivesQueue
));
1659 gAggressivesState
&= ~kAggressivesStateBusy
;
1662 AGGRESSIVES_UNLOCK();
1664 // Root domain is interested in system and display sleep slider changes.
1665 // Submit a power event to handle those changes on the PM work loop.
1667 if (pingSelf
&& pmPowerStateQueue
) {
1668 pmPowerStateQueue
->submitPowerEvent(
1669 kPowerEventPolicyStimulus
,
1670 (void *) kStimulusAggressivenessChanged
);
1674 //******************************************************************************
1675 // synchronizeAggressives
1677 // Push all known aggressiveness records to one or more IOService.
1678 //******************************************************************************
1680 void IOPMrootDomain::synchronizeAggressives(
1681 queue_head_t
* joinedQueue
,
1682 const AggressivesRecord
* array
,
1685 IOService
* service
;
1686 AggressivesRequest
* request
;
1687 const AggressivesRecord
* record
;
1688 IOPMDriverCallEntry callEntry
;
1692 while (!queue_empty(joinedQueue
))
1694 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1695 if (request
->dataType
== kAggressivesRequestTypeService
)
1696 service
= request
->data
.service
;
1700 IODelete(request
, AggressivesRequest
, 1);
1705 if (service
->assertPMDriverCall(&callEntry
))
1707 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1709 value
= record
->value
;
1710 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1711 value
= kAggressivesMinValue
;
1713 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1714 record
->type
, value
, service
->getName());
1715 service
->setAggressiveness(record
->type
, value
);
1717 service
->deassertPMDriverCall(&callEntry
);
1719 service
->release(); // retained by joinAggressiveness()
1724 //******************************************************************************
1725 // broadcastAggressives
1727 // Traverse PM tree and call setAggressiveness() for records that have changed.
1728 //******************************************************************************
1730 void IOPMrootDomain::broadcastAggressives(
1731 const AggressivesRecord
* array
,
1734 IORegistryIterator
* iter
;
1735 IORegistryEntry
* entry
;
1736 IOPowerConnection
* connect
;
1737 IOService
* service
;
1738 const AggressivesRecord
* record
;
1739 IOPMDriverCallEntry callEntry
;
1743 iter
= IORegistryIterator::iterateOver(
1744 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1750 while ((entry
= iter
->getNextObject()))
1752 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1753 if (!connect
|| !connect
->getReadyFlag())
1756 if ((service
= (IOService
*) connect
->copyChildEntry(gIOPowerPlane
)))
1758 if (service
->assertPMDriverCall(&callEntry
))
1760 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1762 if (record
->flags
& kAggressivesRecordFlagModified
)
1764 value
= record
->value
;
1765 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1766 value
= kAggressivesMinValue
;
1767 _LOG("broadcastAggressives %x = %u to %s\n",
1768 record
->type
, value
, service
->getName());
1769 service
->setAggressiveness(record
->type
, value
);
1772 service
->deassertPMDriverCall(&callEntry
);
1778 while (!entry
&& !iter
->isValid());
1784 // MARK: System Sleep
1786 //******************************************************************************
1787 // startIdleSleepTimer
1789 //******************************************************************************
1791 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1793 AbsoluteTime deadline
;
1798 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1799 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1800 idleSleepTimerPending
= true;
1804 thread_call_enter(extraSleepTimer
);
1806 DLOG("idle timer set for %u seconds\n", inSeconds
);
1809 //******************************************************************************
1810 // cancelIdleSleepTimer
1812 //******************************************************************************
1814 void IOPMrootDomain::cancelIdleSleepTimer( void )
1817 if (idleSleepTimerPending
)
1819 DLOG("idle timer cancelled\n");
1820 thread_call_cancel(extraSleepTimer
);
1821 idleSleepTimerPending
= false;
1825 //******************************************************************************
1826 // idleSleepTimerExpired
1828 //******************************************************************************
1830 static void idleSleepTimerExpired(
1831 thread_call_param_t us
, thread_call_param_t
)
1833 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
1836 //******************************************************************************
1837 // handleSleepTimerExpiration
1839 // The time between the sleep idle timeout and the next longest one has elapsed.
1840 // It's time to sleep. Start that by removing the clamp that's holding us awake.
1841 //******************************************************************************
1843 void IOPMrootDomain::handleSleepTimerExpiration( void )
1845 if (!getPMworkloop()->inGate())
1847 getPMworkloop()->runAction(
1848 OSMemberFunctionCast(IOWorkLoop::Action
, this,
1849 &IOPMrootDomain::handleSleepTimerExpiration
),
1856 DLOG("sleep timer expired\n");
1859 idleSleepTimerPending
= false;
1861 clock_get_uptime(&time
);
1862 if ((AbsoluteTime_to_scalar(&time
) > autoWakeStart
) &&
1863 (AbsoluteTime_to_scalar(&time
) < autoWakeEnd
))
1865 thread_call_enter_delayed(extraSleepTimer
, *((AbsoluteTime
*) &autoWakeEnd
));
1869 setQuickSpinDownTimeout();
1870 adjustPowerState(true);
1873 //******************************************************************************
1874 // getTimeToIdleSleep
1876 // Returns number of seconds left before going into idle sleep.
1877 // Caller has to make sure that idle sleep is allowed at the time of calling
1879 //******************************************************************************
1881 uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
1884 AbsoluteTime now
, lastActivityTime
;
1886 uint32_t minutesSinceUserInactive
= 0;
1887 uint32_t sleepDelay
= 0;
1889 if (sleepSlider
== 0)
1892 if (userActivityTime
)
1893 lastActivityTime
= userActivityTime
;
1895 lastActivityTime
= userBecameInactiveTime
;
1897 clock_get_uptime(&now
);
1898 if (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)
1900 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
1901 absolutetime_to_nanoseconds(now
, &nanos
);
1902 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
1904 if (minutesSinceUserInactive
>= sleepSlider
)
1907 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
1911 sleepDelay
= sleepSlider
;
1914 DLOG("user inactive %u min, time to idle sleep %u min\n",
1915 minutesSinceUserInactive
, sleepDelay
);
1917 return (sleepDelay
* 60);
1920 //******************************************************************************
1921 // setQuickSpinDownTimeout
1923 //******************************************************************************
1925 void IOPMrootDomain::setQuickSpinDownTimeout( void )
1929 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
1932 //******************************************************************************
1933 // restoreUserSpinDownTimeout
1935 //******************************************************************************
1937 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
1941 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
1944 //******************************************************************************
1947 //******************************************************************************
1950 IOReturn
IOPMrootDomain::sleepSystem( void )
1952 return sleepSystemOptions(NULL
);
1956 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
1958 OSObject
*obj
= NULL
;
1959 OSString
*reason
= NULL
;
1960 /* sleepSystem is a public function, and may be called by any kernel driver.
1961 * And that's bad - drivers should sleep the system by calling
1962 * receivePowerNotification() instead. Drivers should not use sleepSystem.
1964 * Note that user space app calls to IOPMSleepSystem() will also travel
1965 * this code path and thus be correctly identified as software sleeps.
1968 if (options
&& options
->getObject("OSSwitch"))
1970 // Log specific sleep cause for OS Switch hibernation
1971 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
1974 if (options
&& (obj
= options
->getObject("Sleep Reason")))
1976 reason
= OSDynamicCast(OSString
, obj
);
1977 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
))
1978 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
1981 return privateSleepSystem( kIOPMSleepReasonSoftware
);
1985 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
1987 /* Called from both gated and non-gated context */
1989 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
)
1991 return kIOReturnNotPermitted
;
1994 pmPowerStateQueue
->submitPowerEvent(
1995 kPowerEventPolicyStimulus
,
1996 (void *) kStimulusDemandSystemSleep
,
1999 return kIOReturnSuccess
;
2002 //******************************************************************************
2005 // This overrides powerChangeDone in IOService.
2006 //******************************************************************************
2008 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2011 DLOG("PowerChangeDone: %u->%u\n",
2012 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2014 switch ( getPowerState() )
2017 if (previousPowerState
!= ON_STATE
)
2020 acceptSystemWakeEvents(true);
2022 // re-enable this timer for next sleep
2023 cancelIdleSleepTimer();
2026 clock_usec_t microsecs
;
2027 clock_get_calendar_microtime(&secs
, µsecs
);
2029 gIOLastSleepTime
.tv_sec
= secs
;
2030 gIOLastSleepTime
.tv_usec
= microsecs
;
2031 gIOLastWakeTime
.tv_sec
= 0;
2032 gIOLastWakeTime
.tv_usec
= 0;
2035 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2037 IOHibernateSystemHasSlept();
2039 evaluateSystemSleepPolicyFinal();
2041 LOG("System Sleep\n");
2044 ((IOService
*)this)->stop_watchdog_timer(); //14456299
2045 getPlatform()->sleepKernel();
2047 // The CPU(s) are off at this point,
2048 // Code will resume execution here upon wake.
2050 clock_get_uptime(&systemWakeTime
);
2051 _highestCapability
= 0;
2053 ((IOService
*)this)->start_watchdog_timer(); //14456299
2055 IOHibernateSystemWake();
2058 // sleep transition complete
2059 gSleepOrShutdownPending
= 0;
2061 // trip the reset of the calendar clock
2062 clock_wakeup_calendar();
2065 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2069 PMDebug(kPMLogSystemWake
, 0, 0);
2070 lowBatteryCondition
= false;
2071 lastSleepReason
= 0;
2073 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2074 _debugWakeSeconds
= 0;
2075 _scheduledAlarms
= 0;
2081 #if defined(__i386__) || defined(__x86_64__)
2082 wranglerTickled
= false;
2083 graphicsSuppressed
= false;
2084 darkWakePostTickle
= false;
2085 darkWakeHibernateError
= false;
2086 darkWakeToSleepASAP
= true;
2087 logGraphicsClamp
= true;
2088 sleepTimerMaintenance
= false;
2089 sleepToStandby
= false;
2090 wranglerTickleLatched
= false;
2091 userWasActive
= false;
2092 fullWakeReason
= kFullWakeReasonNone
;
2094 OSString
* wakeType
= OSDynamicCast(
2095 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2096 OSString
* wakeReason
= OSDynamicCast(
2097 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2099 if (wakeReason
&& (wakeReason
->getLength() >= 2) &&
2100 gWakeReasonString
[0] == '\0')
2102 // Until the platform driver can claim its wake reasons
2103 strlcat(gWakeReasonString
, wakeReason
->getCStringNoCopy(),
2104 sizeof(gWakeReasonString
));
2107 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2109 lowBatteryCondition
= true;
2110 darkWakeMaintenance
= true;
2112 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2114 OSNumber
* hibOptions
= OSDynamicCast(
2115 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2117 if (hibernateAborted
|| ((hibOptions
&&
2118 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2120 // Hibernate aborted, or EFI brought up graphics
2121 wranglerTickled
= true;
2122 DLOG("hibernation aborted %d, options 0x%x\n",
2124 hibOptions
? hibOptions
->unsigned32BitValue() : 0);
2128 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2129 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2131 // User wake or RTC alarm
2132 wranglerTickled
= true;
2136 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2138 // SMC standby timer trumps SleepX
2139 darkWakeMaintenance
= true;
2140 sleepTimerMaintenance
= true;
2143 if ((_lastDebugWakeSeconds
!= 0) &&
2144 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2146 // SleepX before maintenance
2147 wranglerTickled
= true;
2151 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2153 darkWakeMaintenance
= true;
2157 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2159 darkWakeMaintenance
= true;
2160 darkWakeSleepService
= true;
2161 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
2162 sleepToStandby
= true;
2167 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeHibernateError
))
2169 darkWakeMaintenance
= true;
2170 darkWakeHibernateError
= true;
2174 // Unidentified wake source, resume to full wake if debug
2175 // alarm is pending.
2177 if (_lastDebugWakeSeconds
&&
2178 (!wakeReason
|| wakeReason
->isEqualTo("")))
2179 wranglerTickled
= true;
2185 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2187 darkWakeMaintenance
= true;
2188 sleepTimerMaintenance
= true;
2190 else if (hibernateAborted
|| !wakeType
||
2191 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2192 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2194 // Post a HID tickle immediately - except for RTC maintenance wake.
2195 wranglerTickled
= true;
2199 darkWakeMaintenance
= true;
2203 if (wranglerTickled
)
2205 darkWakeToSleepASAP
= false;
2206 fullWakeReason
= kFullWakeReasonLocalUser
;
2209 else if (!darkWakeMaintenance
)
2211 // Early/late tickle for non-maintenance wake.
2212 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2213 kDarkWakeFlagHIDTickleEarly
) ||
2214 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2215 kDarkWakeFlagHIDTickleLate
))
2217 darkWakePostTickle
= true;
2220 #else /* !__i386__ && !__x86_64__ */
2221 // stay awake for at least 30 seconds
2222 wranglerTickled
= true;
2223 fullWakeReason
= kFullWakeReasonLocalUser
;
2224 startIdleSleepTimer(30);
2228 changePowerStateToPriv(ON_STATE
);
2234 //******************************************************************************
2235 // requestPowerDomainState
2237 // Extend implementation in IOService. Running on PM work loop thread.
2238 //******************************************************************************
2240 IOReturn
IOPMrootDomain::requestPowerDomainState (
2241 IOPMPowerFlags childDesire
,
2242 IOPowerConnection
* childConnection
,
2243 unsigned long specification
)
2245 // Idle and system sleep prevention flags affects driver desire.
2246 // Children desire are irrelevant so they are cleared.
2248 return super::requestPowerDomainState(0, childConnection
, specification
);
2251 //******************************************************************************
2252 // updatePreventIdleSleepList
2254 // Called by IOService on PM work loop.
2255 // Returns true if PM policy recognized the driver's desire to prevent idle
2256 // sleep and updated the list of idle sleep preventers. Returns false otherwise
2257 //******************************************************************************
2259 bool IOPMrootDomain::updatePreventIdleSleepList(
2260 IOService
* service
, bool addNotRemove
)
2262 unsigned int oldCount
, newCount
;
2266 #if defined(__i386__) || defined(__x86_64__)
2267 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2268 // idle sleep, except in the case of legacy disk I/O
2269 if ((service
!= wrangler
) && (service
!= this))
2275 oldCount
= preventIdleSleepList
->getCount();
2278 preventIdleSleepList
->setObject(service
);
2279 DLOG("prevent idle sleep list: %s+ (%u)\n",
2280 service
->getName(), preventIdleSleepList
->getCount());
2282 else if (preventIdleSleepList
->member(service
))
2284 preventIdleSleepList
->removeObject(service
);
2285 DLOG("prevent idle sleep list: %s- (%u)\n",
2286 service
->getName(), preventIdleSleepList
->getCount());
2288 newCount
= preventIdleSleepList
->getCount();
2290 if ((oldCount
== 0) && (newCount
!= 0))
2292 // Driver added to empty prevent list.
2293 // Update the driver desire to prevent idle sleep.
2294 // Driver desire does not prevent demand sleep.
2296 changePowerStateTo(ON_STATE
);
2298 else if ((oldCount
!= 0) && (newCount
== 0))
2300 // Last driver removed from prevent list.
2301 // Drop the driver clamp to allow idle sleep.
2303 changePowerStateTo(SLEEP_STATE
);
2304 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2307 #if defined(__i386__) || defined(__x86_64__)
2308 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake())
2310 return false; // do not idle-cancel
2317 //******************************************************************************
2318 // preventSystemSleepListUpdate
2320 // Called by IOService on PM work loop.
2321 //******************************************************************************
2323 void IOPMrootDomain::updatePreventSystemSleepList(
2324 IOService
* service
, bool addNotRemove
)
2326 unsigned int oldCount
;
2329 if (this == service
)
2332 oldCount
= preventSystemSleepList
->getCount();
2335 preventSystemSleepList
->setObject(service
);
2336 DLOG("prevent system sleep list: %s+ (%u)\n",
2337 service
->getName(), preventSystemSleepList
->getCount());
2339 else if (preventSystemSleepList
->member(service
))
2341 preventSystemSleepList
->removeObject(service
);
2342 DLOG("prevent system sleep list: %s- (%u)\n",
2343 service
->getName(), preventSystemSleepList
->getCount());
2345 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2347 // Lost all system sleep preventers.
2348 // Send stimulus if system sleep was blocked, and is in dark wake.
2349 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2354 //******************************************************************************
2357 // Override the superclass implementation to send a different message type.
2358 //******************************************************************************
2360 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2362 DLOG("tellChangeDown %u->%u\n",
2363 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2365 if (SLEEP_STATE
== stateNum
)
2367 // Legacy apps were already told in the full->dark transition
2368 if (!ignoreTellChangeDown
)
2369 tracePoint( kIOPMTracePointSleepApplications
);
2371 tracePoint( kIOPMTracePointSleepPriorityClients
);
2374 if ((SLEEP_STATE
== stateNum
) && !ignoreTellChangeDown
)
2376 userActivityAtSleep
= userActivityCount
;
2377 hibernateAborted
= false;
2378 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2380 // Direct callout into OSKext so it can disable kext unloads
2381 // during sleep/wake to prevent deadlocks.
2382 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2384 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2386 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2387 // But tellClientsWithResponse() must be called for both.
2388 ignoreTellChangeDown
= true;
2391 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2394 //******************************************************************************
2397 // Override the superclass implementation to send a different message type.
2398 // This must be idle sleep since we don't ask during any other power change.
2399 //******************************************************************************
2401 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2403 DLOG("askChangeDown %u->%u\n",
2404 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2406 // Don't log for dark wake entry
2407 if (kSystemTransitionSleep
== _systemTransitionType
)
2408 tracePoint( kIOPMTracePointSleepApplications
);
2410 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2413 //******************************************************************************
2414 // askChangeDownDone
2416 // An opportunity for root domain to cancel the power transition,
2417 // possibily due to an assertion created by powerd in response to
2418 // kIOMessageCanSystemSleep.
2421 // full -> dark wake transition
2422 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
2423 // 2. askChangeDownDone()
2424 // dark -> sleep transition
2425 // 1. Notify powerd with kIOMessageCanSystemSleep
2426 // 2. askChangeDownDone()
2429 // full -> dark wake transition
2430 // 1. Notify powerd with kIOMessageCanSystemSleep
2431 // 2. askChangeDownDone()
2432 // dark -> sleep transition
2433 // 1. Notify powerd with kIOMessageCanSystemSleep
2434 // 2. askChangeDownDone()
2435 //******************************************************************************
2437 void IOPMrootDomain::askChangeDownDone(
2438 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2440 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2441 *inOutChangeFlags
, *cancel
,
2442 _systemTransitionType
,
2443 _currentCapability
, _pendingCapability
);
2445 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2447 // Dark->Sleep transition.
2448 // Check if there are any deny sleep assertions.
2449 // lastSleepReason already set by handleOurPowerChangeStart()
2451 if (!checkSystemCanSleep(lastSleepReason
))
2453 // Cancel dark wake to sleep transition.
2454 // Must re-scan assertions upon entering dark wake.
2457 DLOG("cancel dark->sleep\n");
2462 //******************************************************************************
2463 // systemDidNotSleep
2465 // Work common to both canceled or aborted sleep.
2466 //******************************************************************************
2468 void IOPMrootDomain::systemDidNotSleep( void )
2474 // stay awake for at least idleSeconds
2475 startIdleSleepTimer(idleSeconds
);
2480 if (sleepSlider
&& !userIsActive
)
2482 // Manually start the idle sleep timer besides waiting for
2483 // the user to become inactive.
2484 startIdleSleepTimer( kIdleSleepRetryInterval
);
2488 preventTransitionToUserActive(false);
2489 IOService::setAdvisoryTickleEnable( true );
2492 //******************************************************************************
2495 // Notify registered applications and kernel clients that we are not dropping
2498 // We override the superclass implementation so we can send a different message
2499 // type to the client or application being notified.
2501 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2502 //******************************************************************************
2504 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2506 DLOG("tellNoChangeDown %u->%u\n",
2507 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2509 // Sleep canceled, clear the sleep trace point.
2510 tracePoint(kIOPMTracePointSystemUp
);
2512 systemDidNotSleep();
2513 return tellClients( kIOMessageSystemWillNotSleep
);
2516 //******************************************************************************
2519 // Notify registered applications and kernel clients that we are raising power.
2521 // We override the superclass implementation so we can send a different message
2522 // type to the client or application being notified.
2523 //******************************************************************************
2525 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2528 DLOG("tellChangeUp %u->%u\n",
2529 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2531 ignoreTellChangeDown
= false;
2533 if ( stateNum
== ON_STATE
)
2535 // Direct callout into OSKext so it can disable kext unloads
2536 // during sleep/wake to prevent deadlocks.
2537 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2539 // Notify platform that sleep was cancelled or resumed.
2540 getPlatform()->callPlatformFunction(
2541 sleepMessagePEFunction
, false,
2542 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2545 if (getPowerState() == ON_STATE
)
2547 // this is a quick wake from aborted sleep
2548 systemDidNotSleep();
2549 tellClients( kIOMessageSystemWillPowerOn
);
2553 tracePoint( kIOPMTracePointWakeApplications
);
2554 tellClients( kIOMessageSystemHasPoweredOn
);
2558 //******************************************************************************
2559 // sysPowerDownHandler
2561 // Perform a vfs sync before system sleep.
2562 //******************************************************************************
2564 IOReturn
IOPMrootDomain::sysPowerDownHandler(
2565 void * target
, void * refCon
,
2566 UInt32 messageType
, IOService
* service
,
2567 void * messageArgs
, vm_size_t argSize
)
2571 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
2574 return kIOReturnUnsupported
;
2576 if (messageType
== kIOMessageSystemWillSleep
)
2579 uint32_t mem_only
= 0;
2580 IOPowerStateChangeNotification
*notify
=
2581 (IOPowerStateChangeNotification
*)messageArgs
;
2583 PE_parse_boot_argn("swd_mem_only", &mem_only
, sizeof(mem_only
));
2584 if ((mem_only
!= 1) && (gRootDomain
->sleepWakeDebugIsWdogEnabled()))
2586 notify
->returnValue
= 30 * 1000 * 1000;
2588 gRootDomain
->hibDebugSetupEntry
,
2589 (thread_call_param_t
)(uintptr_t) notify
->powerRef
);
2593 else if (messageType
== kIOMessageSystemCapabilityChange
)
2595 IOPMSystemCapabilityChangeParameters
* params
=
2596 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
2598 // Interested applications have been notified of an impending power
2599 // change and have acked (when applicable).
2600 // This is our chance to save whatever state we can before powering
2602 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2605 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2606 params
->fromCapabilities
, params
->toCapabilities
,
2607 params
->changeFlags
);
2609 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
2610 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
2611 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2613 // We will ack within 20 seconds
2614 params
->maxWaitForReply
= 20 * 1000 * 1000;
2616 gRootDomain
->evaluateSystemSleepPolicyEarly();
2618 // add in time we could spend freeing pages
2619 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
2621 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
2623 DLOG("sysPowerDownHandler max wait %d s\n",
2624 (int) (params
->maxWaitForReply
/ 1000 / 1000));
2627 // Notify platform that sleep has begun, after the early
2628 // sleep policy evaluation.
2629 getPlatform()->callPlatformFunction(
2630 sleepMessagePEFunction
, false,
2631 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
2634 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2636 // Purposely delay the ack and hope that shutdown occurs quickly.
2637 // Another option is not to schedule the thread and wait for
2639 AbsoluteTime deadline
;
2640 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2641 thread_call_enter1_delayed(
2642 gRootDomain
->diskSyncCalloutEntry
,
2643 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
2648 gRootDomain
->diskSyncCalloutEntry
,
2649 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
2652 if ((params
->changeFlags
& kIOPMSystemCapabilityDidChange
) &&
2653 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) &&
2654 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2657 // We will ack within 110 seconds
2658 params
->maxWaitForReply
= 110 * 1000 * 1000;
2661 gRootDomain
->diskSyncCalloutEntry
,
2662 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
2665 ret
= kIOReturnSuccess
;
2671 //******************************************************************************
2672 // handleQueueSleepWakeUUID
2674 // Called from IOPMrootDomain when we're initiating a sleep,
2675 // or indirectly from PM configd when PM decides to clear the UUID.
2676 // PM clears the UUID several minutes after successful wake from sleep,
2677 // so that we might associate App spindumps with the immediately previous
2680 // @param obj has a retain on it. We're responsible for releasing that retain.
2681 //******************************************************************************
2683 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
2685 OSString
*str
= NULL
;
2687 if (kOSBooleanFalse
== obj
)
2689 handlePublishSleepWakeUUID(NULL
);
2691 else if ((str
= OSDynamicCast(OSString
, obj
)))
2693 // This branch caches the UUID for an upcoming sleep/wake
2694 if (queuedSleepWakeUUIDString
) {
2695 queuedSleepWakeUUIDString
->release();
2696 queuedSleepWakeUUIDString
= NULL
;
2698 queuedSleepWakeUUIDString
= str
;
2699 queuedSleepWakeUUIDString
->retain();
2701 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
2710 //******************************************************************************
2711 // handlePublishSleepWakeUUID
2713 // Called from IOPMrootDomain when we're initiating a sleep,
2714 // or indirectly from PM configd when PM decides to clear the UUID.
2715 // PM clears the UUID several minutes after successful wake from sleep,
2716 // so that we might associate App spindumps with the immediately previous
2718 //******************************************************************************
2720 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
2725 * Clear the current UUID
2727 if (gSleepWakeUUIDIsSet
)
2729 DLOG("SleepWake UUID cleared\n");
2731 gSleepWakeUUIDIsSet
= false;
2733 removeProperty(kIOPMSleepWakeUUIDKey
);
2734 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
2738 * Optionally, publish a new UUID
2740 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
2742 OSString
*publishThisUUID
= NULL
;
2744 publishThisUUID
= queuedSleepWakeUUIDString
;
2745 publishThisUUID
->retain();
2747 if (publishThisUUID
)
2749 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
2750 publishThisUUID
->release();
2753 gSleepWakeUUIDIsSet
= true;
2754 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
2756 queuedSleepWakeUUIDString
->release();
2757 queuedSleepWakeUUIDString
= NULL
;
2761 //******************************************************************************
2762 // initializeBootSessionUUID
2764 // Initialize the boot session uuid at boot up and sets it into registry.
2765 //******************************************************************************
2767 void IOPMrootDomain::initializeBootSessionUUID(void)
2770 uuid_string_t new_uuid_string
;
2772 uuid_generate(new_uuid
);
2773 uuid_unparse_upper(new_uuid
, new_uuid_string
);
2774 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
2776 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
2779 //******************************************************************************
2780 // changePowerStateTo & changePowerStateToPriv
2782 // Override of these methods for logging purposes.
2783 //******************************************************************************
2785 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
2787 DLOG("changePowerStateTo(%lu)\n", ordinal
);
2789 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
2790 return kIOReturnUnsupported
;
2792 return super::changePowerStateTo(ordinal
);
2795 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
2797 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
2799 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
2800 return kIOReturnUnsupported
;
2802 return super::changePowerStateToPriv(ordinal
);
2805 //******************************************************************************
2808 //******************************************************************************
2810 bool IOPMrootDomain::activitySinceSleep(void)
2812 return (userActivityCount
!= userActivityAtSleep
);
2815 bool IOPMrootDomain::abortHibernation(void)
2817 bool ret
= activitySinceSleep();
2819 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
2821 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
2822 hibernateAborted
= true;
2828 hibernate_should_abort(void)
2831 return (gRootDomain
->abortHibernation());
2836 //******************************************************************************
2837 // willNotifyPowerChildren
2839 // Called after all interested drivers have all acknowledged the power change,
2840 // but before any power children is informed. Dispatched though a thread call,
2841 // so it is safe to perform work that might block on a sleeping disk. PM state
2842 // machine (not thread) will block w/o timeout until this function returns.
2843 //******************************************************************************
2845 void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
2848 if (SLEEP_STATE
== newPowerState
)
2850 IOHibernateSystemSleep();
2851 IOHibernateIOKitSleep();
2856 //******************************************************************************
2857 // sleepOnClamshellClosed
2859 // contains the logic to determine if the system should sleep when the clamshell
2861 //******************************************************************************
2863 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
2865 if (!clamshellExists
)
2868 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
2869 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
2871 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
);
2874 void IOPMrootDomain::sendClientClamshellNotification( void )
2876 /* Only broadcast clamshell alert if clamshell exists. */
2877 if (!clamshellExists
)
2880 setProperty(kAppleClamshellStateKey
,
2881 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
2883 setProperty(kAppleClamshellCausesSleepKey
,
2884 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
2886 /* Argument to message is a bitfiel of
2887 * ( kClamshellStateBit | kClamshellSleepBit )
2889 messageClients(kIOPMMessageClamshellStateChange
,
2890 (void *)(uintptr_t) ( (clamshellClosed
? kClamshellStateBit
: 0)
2891 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
2894 //******************************************************************************
2895 // getSleepSupported
2898 //******************************************************************************
2900 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
2902 return( platformSleepSupport
);
2905 //******************************************************************************
2906 // setSleepSupported
2909 //******************************************************************************
2911 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
2913 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
2914 OSBitOrAtomic(flags
, &platformSleepSupport
);
2917 //******************************************************************************
2918 // setDisableClamShellSleep
2920 //******************************************************************************
2922 void IOPMrootDomain::setDisableClamShellSleep( bool val
)
2924 if (gIOPMWorkLoop
->inGate() == false) {
2926 gIOPMWorkLoop
->runAction(
2927 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
2934 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
2935 if ( clamshellSleepDisabled
!= val
)
2937 clamshellSleepDisabled
= val
;
2938 // If clamshellSleepDisabled is reset to 0, reevaluate if
2939 // system need to go to sleep due to clamshell state
2940 if ( !clamshellSleepDisabled
&& clamshellClosed
)
2941 handlePowerNotification(kLocalEvalClamshellCommand
);
2946 //******************************************************************************
2950 //******************************************************************************
2952 void IOPMrootDomain::wakeFromDoze( void )
2954 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
2960 //******************************************************************************
2963 // Adds a new feature to the supported features dictionary
2964 //******************************************************************************
2966 void IOPMrootDomain::publishFeature( const char * feature
)
2968 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
2971 //******************************************************************************
2972 // publishFeature (with supported power source specified)
2974 // Adds a new feature to the supported features dictionary
2975 //******************************************************************************
2977 void IOPMrootDomain::publishFeature(
2978 const char *feature
,
2979 uint32_t supportedWhere
,
2980 uint32_t *uniqueFeatureID
)
2982 static uint16_t next_feature_id
= 500;
2984 OSNumber
*new_feature_data
= NULL
;
2985 OSNumber
*existing_feature
= NULL
;
2986 OSArray
*existing_feature_arr
= NULL
;
2987 OSObject
*osObj
= NULL
;
2988 uint32_t feature_value
= 0;
2990 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
2992 if(!supportedWhere
) {
2993 // Feature isn't supported anywhere!
2997 if(next_feature_id
> 5000) {
2998 // Far, far too many features!
3002 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3004 OSDictionary
*features
=
3005 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3007 // Create new features dict if necessary
3008 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3009 features
= OSDictionary::withDictionary(features
);
3011 features
= OSDictionary::withCapacity(1);
3014 // Create OSNumber to track new feature
3016 next_feature_id
+= 1;
3017 if( uniqueFeatureID
) {
3018 // We don't really mind if the calling kext didn't give us a place
3019 // to stash their unique id. Many kexts don't plan to unload, and thus
3020 // have no need to remove themselves later.
3021 *uniqueFeatureID
= next_feature_id
;
3024 feature_value
= (uint32_t)next_feature_id
;
3025 feature_value
<<= 16;
3026 feature_value
+= supportedWhere
;
3028 new_feature_data
= OSNumber::withNumber(
3029 (unsigned long long)feature_value
, 32);
3031 // Does features object already exist?
3032 if( (osObj
= features
->getObject(feature
)) )
3034 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3036 // We need to create an OSArray to hold the now 2 elements.
3037 existing_feature_arr
= OSArray::withObjects(
3038 (const OSObject
**)&existing_feature
, 1, 2);
3039 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3041 // Add object to existing array
3042 existing_feature_arr
= OSArray::withArray(
3043 existing_feature_arr
,
3044 existing_feature_arr
->getCount() + 1);
3047 if (existing_feature_arr
)
3049 existing_feature_arr
->setObject(new_feature_data
);
3050 features
->setObject(feature
, existing_feature_arr
);
3051 existing_feature_arr
->release();
3052 existing_feature_arr
= 0;
3055 // The easy case: no previously existing features listed. We simply
3056 // set the OSNumber at key 'feature' and we're on our way.
3057 features
->setObject(feature
, new_feature_data
);
3060 new_feature_data
->release();
3062 setProperty(kRootDomainSupportedFeatures
, features
);
3064 features
->release();
3066 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3068 // Notify EnergySaver and all those in user space so they might
3069 // re-populate their feature specific UI
3070 if(pmPowerStateQueue
) {
3071 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3075 //******************************************************************************
3076 // removePublishedFeature
3078 // Removes previously published feature
3079 //******************************************************************************
3081 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3083 IOReturn ret
= kIOReturnError
;
3084 uint32_t feature_value
= 0;
3085 uint16_t feature_id
= 0;
3086 bool madeAChange
= false;
3088 OSSymbol
*dictKey
= NULL
;
3089 OSCollectionIterator
*dictIterator
= NULL
;
3090 OSArray
*arrayMember
= NULL
;
3091 OSNumber
*numberMember
= NULL
;
3092 OSObject
*osObj
= NULL
;
3093 OSNumber
*osNum
= NULL
;
3094 OSArray
*arrayMemberCopy
;
3096 if (kBadPMFeatureID
== removeFeatureID
)
3097 return kIOReturnNotFound
;
3099 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3101 OSDictionary
*features
=
3102 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3104 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3106 // Any modifications to the dictionary are made to the copy to prevent
3107 // races & crashes with userland clients. Dictionary updated
3108 // automically later.
3109 features
= OSDictionary::withDictionary(features
);
3112 ret
= kIOReturnNotFound
;
3116 // We iterate 'features' dictionary looking for an entry tagged
3117 // with 'removeFeatureID'. If found, we remove it from our tracking
3118 // structures and notify the OS via a general interest message.
3120 dictIterator
= OSCollectionIterator::withCollection(features
);
3125 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3127 osObj
= features
->getObject(dictKey
);
3129 // Each Feature is either tracked by an OSNumber
3130 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3132 feature_value
= numberMember
->unsigned32BitValue();
3133 feature_id
= (uint16_t)(feature_value
>> 16);
3135 if( feature_id
== (uint16_t)removeFeatureID
)
3138 features
->removeObject(dictKey
);
3143 // Or tracked by an OSArray of OSNumbers
3144 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3146 unsigned int arrayCount
= arrayMember
->getCount();
3148 for(unsigned int i
=0; i
<arrayCount
; i
++)
3150 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3155 feature_value
= osNum
->unsigned32BitValue();
3156 feature_id
= (uint16_t)(feature_value
>> 16);
3158 if( feature_id
== (uint16_t)removeFeatureID
)
3161 if( 1 == arrayCount
) {
3162 // If the array only contains one element, remove
3164 features
->removeObject(dictKey
);
3166 // Otherwise remove the element from a copy of the array.
3167 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3168 if (arrayMemberCopy
)
3170 arrayMemberCopy
->removeObject(i
);
3171 features
->setObject(dictKey
, arrayMemberCopy
);
3172 arrayMemberCopy
->release();
3183 dictIterator
->release();
3187 ret
= kIOReturnSuccess
;
3189 setProperty(kRootDomainSupportedFeatures
, features
);
3191 // Notify EnergySaver and all those in user space so they might
3192 // re-populate their feature specific UI
3193 if(pmPowerStateQueue
) {
3194 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3197 ret
= kIOReturnNotFound
;
3201 if(features
) features
->release();
3202 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3206 //******************************************************************************
3207 // publishPMSetting (private)
3209 // Should only be called by PMSettingObject to publish a PM Setting as a
3210 // supported feature.
3211 //******************************************************************************
3213 void IOPMrootDomain::publishPMSetting(
3214 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3216 if (noPublishPMSettings
&&
3217 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3219 // Setting found in noPublishPMSettings array
3220 *featureID
= kBadPMFeatureID
;
3225 feature
->getCStringNoCopy(), where
, featureID
);
3228 //******************************************************************************
3229 // setPMSetting (private)
3231 // Internal helper to relay PM settings changes from user space to individual
3232 // drivers. Should be called only by IOPMrootDomain::setProperties.
3233 //******************************************************************************
3235 IOReturn
IOPMrootDomain::setPMSetting(
3236 const OSSymbol
*type
,
3239 PMSettingCallEntry
*entries
= 0;
3240 OSArray
*chosen
= 0;
3241 const OSArray
*array
;
3242 PMSettingObject
*pmso
;
3243 thread_t thisThread
;
3244 int i
, j
, count
, capacity
;
3247 return kIOReturnBadArgument
;
3251 // Update settings dict so changes are visible from copyPMSetting().
3252 fPMSettingsDict
->setObject(type
, object
);
3254 // Prep all PMSetting objects with the given 'type' for callout.
3255 array
= (const OSArray
*) settingsCallbacks
->getObject(type
);
3256 if (!array
|| ((capacity
= array
->getCount()) == 0))
3259 // Array to retain PMSetting objects targeted for callout.
3260 chosen
= OSArray::withCapacity(capacity
);
3262 goto unlock_exit
; // error
3264 entries
= IONew(PMSettingCallEntry
, capacity
);
3266 goto unlock_exit
; // error
3267 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3269 thisThread
= current_thread();
3271 for (i
= 0, j
= 0; i
<capacity
; i
++)
3273 pmso
= (PMSettingObject
*) array
->getObject(i
);
3276 entries
[j
].thread
= thisThread
;
3277 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3278 chosen
->setObject(pmso
);
3287 // Call each pmso in the chosen array.
3288 for (i
=0; i
<count
; i
++)
3290 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3291 pmso
->dispatchPMSetting(type
, object
);
3295 for (i
=0; i
<count
; i
++)
3297 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3298 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3299 if (pmso
->waitThread
)
3301 PMSETTING_WAKEUP(pmso
);
3307 if (chosen
) chosen
->release();
3308 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3310 return kIOReturnSuccess
;
3313 //******************************************************************************
3314 // copyPMSetting (public)
3316 // Allows kexts to safely read setting values, without being subscribed to
3318 //******************************************************************************
3320 OSObject
* IOPMrootDomain::copyPMSetting(
3321 OSSymbol
*whichSetting
)
3323 OSObject
*obj
= NULL
;
3325 if(!whichSetting
) return NULL
;
3328 obj
= fPMSettingsDict
->getObject(whichSetting
);
3337 //******************************************************************************
3338 // registerPMSettingController (public)
3340 // direct wrapper to registerPMSettingController with uint32_t power source arg
3341 //******************************************************************************
3343 IOReturn
IOPMrootDomain::registerPMSettingController(
3344 const OSSymbol
* settings
[],
3345 IOPMSettingControllerCallback func
,
3350 return registerPMSettingController(
3352 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3353 func
, target
, refcon
, handle
);
3356 //******************************************************************************
3357 // registerPMSettingController (public)
3359 // Kexts may register for notifications when a particular setting is changed.
3360 // A list of settings is available in IOPM.h.
3362 // * settings - An OSArray containing OSSymbols. Caller should populate this
3363 // array with a list of settings caller wants notifications from.
3364 // * func - A C function callback of the type IOPMSettingControllerCallback
3365 // * target - caller may provide an OSObject *, which PM will pass as an
3366 // target to calls to "func"
3367 // * refcon - caller may provide an void *, which PM will pass as an
3368 // argument to calls to "func"
3369 // * handle - This is a return argument. We will populate this pointer upon
3370 // call success. Hold onto this and pass this argument to
3371 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3373 // kIOReturnSuccess on success
3374 //******************************************************************************
3376 IOReturn
IOPMrootDomain::registerPMSettingController(
3377 const OSSymbol
* settings
[],
3378 uint32_t supportedPowerSources
,
3379 IOPMSettingControllerCallback func
,
3384 PMSettingObject
*pmso
= NULL
;
3385 OSObject
*pmsh
= NULL
;
3386 OSArray
*list
= NULL
;
3389 if (NULL
== settings
||
3393 return kIOReturnBadArgument
;
3396 pmso
= PMSettingObject::pmSettingObject(
3397 (IOPMrootDomain
*) this, func
, target
,
3398 refcon
, supportedPowerSources
, settings
, &pmsh
);
3402 return kIOReturnInternalError
;
3406 for (i
=0; settings
[i
]; i
++)
3408 list
= (OSArray
*) settingsCallbacks
->getObject(settings
[i
]);
3410 // New array of callbacks for this setting
3411 list
= OSArray::withCapacity(1);
3412 settingsCallbacks
->setObject(settings
[i
], list
);
3416 // Add caller to the callback list
3417 list
->setObject(pmso
);
3421 // Return handle to the caller, the setting object is private.
3424 return kIOReturnSuccess
;
3427 //******************************************************************************
3428 // deregisterPMSettingObject (private)
3430 // Only called from PMSettingObject.
3431 //******************************************************************************
3433 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3435 thread_t thisThread
= current_thread();
3436 PMSettingCallEntry
*callEntry
;
3437 OSCollectionIterator
*iter
;
3445 pmso
->disabled
= true;
3447 // Wait for all callout threads to finish.
3450 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3452 if (callEntry
->thread
!= thisThread
)
3460 assert(0 == pmso
->waitThread
);
3461 pmso
->waitThread
= thisThread
;
3462 PMSETTING_WAIT(pmso
);
3463 pmso
->waitThread
= 0;
3467 // Search each PM settings array in the kernel.
3468 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3471 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3473 array
= (OSArray
*) settingsCallbacks
->getObject(sym
);
3474 index
= array
->getNextIndexOfObject(pmso
, 0);
3476 array
->removeObject(index
);
3487 //******************************************************************************
3488 // informCPUStateChange
3490 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3491 // running on battery, with the lid closed, etc.
3493 // informCPUStateChange is a no-op on non x86 systems
3494 // only x86 has explicit support in the IntelCPUPowerManagement kext
3495 //******************************************************************************
3497 void IOPMrootDomain::informCPUStateChange(
3501 #if defined(__i386__) || defined(__x86_64__)
3503 pmioctlVariableInfo_t varInfoStruct
;
3505 const char *varNameStr
= NULL
;
3506 int32_t *varIndex
= NULL
;
3508 if (kInformAC
== type
) {
3509 varNameStr
= kIOPMRootDomainBatPowerCString
;
3510 varIndex
= &idxPMCPULimitedPower
;
3511 } else if (kInformLid
== type
) {
3512 varNameStr
= kIOPMRootDomainLidCloseCString
;
3513 varIndex
= &idxPMCPUClamshell
;
3518 // Set the new value!
3519 // pmCPUControl will assign us a new ID if one doesn't exist yet
3520 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
3521 varInfoStruct
.varID
= *varIndex
;
3522 varInfoStruct
.varType
= vBool
;
3523 varInfoStruct
.varInitValue
= value
;
3524 varInfoStruct
.varCurValue
= value
;
3525 strncpy( (char *)varInfoStruct
.varName
,
3526 (const char *)varNameStr
,
3527 strlen(varNameStr
) + 1 );
3530 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
3532 // pmCPU only assigns numerical id's when a new varName is specified
3534 && (*varIndex
== kCPUUnknownIndex
))
3536 // pmCPUControl has assigned us a new variable ID.
3537 // Let's re-read the structure we just SET to learn that ID.
3538 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
3542 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3543 *varIndex
= varInfoStruct
.varID
;
3549 #endif /* __i386__ || __x86_64__ */
3553 // MARK: Deep Sleep Policy
3557 //******************************************************************************
3558 // evaluateSystemSleepPolicy
3559 //******************************************************************************
3561 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
3565 kIOPMSleepFlagHibernate
= 0x00000001,
3566 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
3569 struct IOPMSystemSleepPolicyEntry
3571 uint32_t factorMask
;
3572 uint32_t factorBits
;
3573 uint32_t sleepFlags
;
3574 uint32_t wakeEvents
;
3575 } __attribute__((packed
));
3577 struct IOPMSystemSleepPolicyTable
3581 uint16_t entryCount
;
3582 IOPMSystemSleepPolicyEntry entries
[];
3583 } __attribute__((packed
));
3586 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
3587 kIOPMSleepAttributeHibernateSleep
= 0x00000002
3591 getSleepTypeAttributes( uint32_t sleepType
)
3593 static const uint32_t sleepTypeAttributes
[ kIOPMSleepTypeLast
] =
3598 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
3599 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3600 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3601 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3605 if (sleepType
>= kIOPMSleepTypeLast
)
3608 return sleepTypeAttributes
[sleepType
];
3611 bool IOPMrootDomain::evaluateSystemSleepPolicy(
3612 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
3614 const IOPMSystemSleepPolicyTable
* pt
;
3615 OSObject
* prop
= 0;
3616 OSData
* policyData
;
3617 uint64_t currentFactors
= 0;
3618 uint32_t standbyDelay
= 0;
3619 uint32_t powerOffDelay
= 0;
3620 uint32_t powerOffTimer
= 0;
3622 bool standbyEnabled
;
3623 bool powerOffEnabled
;
3626 // Get platform's sleep policy table
3627 if (!gSleepPolicyHandler
)
3629 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
3630 if (!prop
) goto done
;
3633 // Fetch additional settings
3634 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
3635 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
3636 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
3637 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
3638 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
))
3639 powerOffTimer
= powerOffDelay
;
3641 DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
3642 sleepPhase
, standbyEnabled
, standbyDelay
,
3643 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
3645 // pmset level overrides
3646 if ((*hibMode
& kIOHibernateModeOn
) == 0)
3648 if (!gSleepPolicyHandler
)
3650 standbyEnabled
= false;
3651 powerOffEnabled
= false;
3654 else if (!(*hibMode
& kIOHibernateModeSleep
))
3656 // Force hibernate (i.e. mode 25)
3657 // If standby is enabled, force standy.
3658 // If poweroff is enabled, force poweroff.
3660 currentFactors
|= kIOPMSleepFactorStandbyForced
;
3661 else if (powerOffEnabled
)
3662 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
3664 currentFactors
|= kIOPMSleepFactorHibernateForced
;
3667 // Current factors based on environment and assertions
3668 if (sleepTimerMaintenance
)
3669 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3670 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
)
3671 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3672 if (!clamshellClosed
)
3673 currentFactors
|= kIOPMSleepFactorLidOpen
;
3674 if (acAdaptorConnected
)
3675 currentFactors
|= kIOPMSleepFactorACPower
;
3676 if (lowBatteryCondition
)
3677 currentFactors
|= kIOPMSleepFactorBatteryLow
;
3679 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
3680 if (!standbyEnabled
)
3681 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
3682 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
3683 kIOPMDriverAssertionLevelOff
)
3684 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
3685 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
3686 kIOPMDriverAssertionLevelOff
)
3687 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
3688 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
3689 kIOPMDriverAssertionLevelOff
)
3690 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
3691 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
3692 kIOPMDriverAssertionLevelOff
)
3693 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
3694 if (_scheduledAlarms
!= 0)
3695 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
3696 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
3697 kIOPMDriverAssertionLevelOff
)
3698 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
3699 #define TCPKEEPALIVE 1
3701 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
3702 kIOPMDriverAssertionLevelOff
)
3703 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
3705 if (!powerOffEnabled
)
3706 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
3708 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
3710 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
3711 if (darkWakeHibernateError
&& !CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
3712 currentFactors
|= kIOPMSleepFactorHibernateFailed
;
3714 DLOG("sleep factors 0x%llx\n", currentFactors
);
3716 if (gSleepPolicyHandler
)
3718 uint32_t savedHibernateMode
;
3721 if (!gSleepPolicyVars
)
3723 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
3724 if (!gSleepPolicyVars
)
3726 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
3728 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
3729 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
3730 gSleepPolicyVars
->currentCapability
= _currentCapability
;
3731 gSleepPolicyVars
->highestCapability
= _highestCapability
;
3732 gSleepPolicyVars
->sleepFactors
= currentFactors
;
3733 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
3734 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
3735 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
3736 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
3737 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
3738 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
3740 if (kIOPMSleepPhase0
== sleepPhase
)
3742 // preserve hibernateMode
3743 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
3744 gSleepPolicyVars
->hibernateMode
= *hibMode
;
3746 else if (kIOPMSleepPhase1
== sleepPhase
)
3748 // use original hibernateMode for phase2
3749 gSleepPolicyVars
->hibernateMode
= *hibMode
;
3752 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
3754 if (kIOPMSleepPhase0
== sleepPhase
)
3756 // restore hibernateMode
3757 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
3760 if ((result
!= kIOReturnSuccess
) ||
3761 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
3762 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
3763 (kIOPMSystemSleepParametersVersion
!= params
->version
))
3765 MSG("sleep policy handler error\n");
3769 if ((getSleepTypeAttributes(params
->sleepType
) &
3770 kIOPMSleepAttributeHibernateSetup
) &&
3771 ((*hibMode
& kIOHibernateModeOn
) == 0))
3773 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
3776 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
3777 params
->version
, params
->sleepType
, params
->sleepFlags
,
3778 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
3783 // Policy table is meaningless without standby enabled
3784 if (!standbyEnabled
)
3787 // Validate the sleep policy table
3788 policyData
= OSDynamicCast(OSData
, prop
);
3789 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
3792 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
3793 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
3794 (pt
->version
!= 1) || (0 == pt
->entryCount
))
3797 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
3798 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
3801 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
3803 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
3804 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
3806 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
3807 entry
->factorMask
, entry
->factorBits
,
3808 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
3812 DLOG("^ found match\n");
3815 params
->version
= kIOPMSystemSleepParametersVersion
;
3816 params
->reserved1
= 1;
3817 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
3818 params
->sleepType
= kIOPMSleepTypeStandby
;
3820 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
3822 params
->ecWakeEvents
= entry
->wakeEvents
;
3823 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
3825 if (kIOPMSleepPhase2
== sleepPhase
)
3827 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
3829 if (!_standbyTimerResetSeconds
||
3830 (now_secs
<= _standbyTimerResetSeconds
))
3832 // Reset standby timer adjustment
3833 _standbyTimerResetSeconds
= now_secs
;
3834 DLOG("standby delay %u, reset %u\n",
3835 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
3837 else if (standbyDelay
)
3839 // Shorten the standby delay timer
3840 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
3841 if (standbyDelay
> elapsed
)
3842 standbyDelay
-= elapsed
;
3844 standbyDelay
= 1; // must be > 0
3846 DLOG("standby delay %u, elapsed %u\n",
3847 standbyDelay
, (uint32_t) elapsed
);
3850 params
->ecWakeTimer
= standbyDelay
;
3852 else if (kIOPMSleepPhase2
== sleepPhase
)
3854 // A sleep that does not enable the sleep timer will reset
3855 // the standby delay adjustment.
3856 _standbyTimerResetSeconds
= 0;
3868 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
3870 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
3872 // Evaluate early (priority interest phase), before drivers sleep.
3874 DLOG("%s\n", __FUNCTION__
);
3875 removeProperty(kIOPMSystemSleepParametersKey
);
3877 // Full wake resets the standby timer delay adjustment
3878 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
3879 _standbyTimerResetSeconds
= 0;
3881 hibernateDisabled
= false;
3883 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
3885 // Save for late evaluation if sleep is aborted
3886 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
3888 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
3891 if (!hibernateRetry
&&
3892 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
3893 kIOPMSleepAttributeHibernateSetup
) == 0))
3895 // skip hibernate setup
3896 hibernateDisabled
= true;
3900 // Publish IOPMSystemSleepType
3901 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
3902 if (sleepType
== kIOPMSleepTypeInvalid
)
3905 sleepType
= kIOPMSleepTypeNormalSleep
;
3906 if (hibernateMode
& kIOHibernateModeOn
)
3907 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
3908 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
3910 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
3911 (gEarlySystemSleepParams
.ecPoweroffTimer
))
3913 // report the lowest possible sleep state
3914 sleepType
= kIOPMSleepTypePowerOff
;
3917 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
3920 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
3922 IOPMSystemSleepParameters params
;
3923 OSData
* paramsData
;
3925 // Evaluate sleep policy after sleeping drivers but before platform sleep.
3927 DLOG("%s\n", __FUNCTION__
);
3929 bzero(¶ms
, sizeof(params
));
3930 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
))
3932 if ((hibernateDisabled
|| hibernateAborted
) &&
3933 (getSleepTypeAttributes(params
.sleepType
) &
3934 kIOPMSleepAttributeHibernateSetup
))
3936 // Final evaluation picked a state requiring hibernation,
3937 // but hibernate setup was skipped. Arm a short sleep using
3938 // the early non-hibernate sleep parameters.
3939 // Set hibernateRetry flag to force hibernate setup on the
3942 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
3943 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
3944 params
.ecWakeTimer
= 1;
3945 hibernateRetry
= true;
3946 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
3947 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
);
3951 hibernateRetry
= false;
3954 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
3957 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
3958 paramsData
->release();
3961 if (getSleepTypeAttributes(params
.sleepType
) &
3962 kIOPMSleepAttributeHibernateSleep
)
3964 // Disable sleep to force hibernation
3965 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
3970 bool IOPMrootDomain::getHibernateSettings(
3971 uint32_t * hibernateModePtr
,
3972 uint32_t * hibernateFreeRatio
,
3973 uint32_t * hibernateFreeTime
)
3975 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
3976 // has updated the hibernateDisabled flag.
3978 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
3979 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
3980 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
3981 if (hibernateDisabled
)
3982 *hibernateModePtr
= 0;
3983 else if (gSleepPolicyHandler
)
3984 *hibernateModePtr
= hibernateMode
;
3985 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
3989 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
3991 OSObject
* optionsProp
;
3992 OSDictionary
* optionsDict
;
3997 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
3998 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4002 obj
= optionsDict
->getObject(key
);
4003 if (obj
) obj
->retain();
4007 obj
= copyProperty(key
);
4009 if (obj
&& (num
= OSDynamicCast(OSNumber
, obj
)))
4011 *option
= num
->unsigned32BitValue();
4018 optionsProp
->release();
4022 #endif /* HIBERNATION */
4024 IOReturn
IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
)
4027 IOPMSystemSleepParameters params
;
4028 uint32_t hibMode
= 0;
4031 if (gIOPMWorkLoop
->inGate() == false)
4033 IOReturn ret
= gIOPMWorkLoop
->runAction(
4034 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4035 &IOPMrootDomain::getSystemSleepType
),
4037 (void *) sleepType
);
4041 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4042 bzero(¶ms
, sizeof(params
));
4044 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4047 *sleepType
= params
.sleepType
;
4048 return kIOReturnSuccess
;
4052 return kIOReturnUnsupported
;
4056 // MARK: Shutdown and Restart
4058 //******************************************************************************
4059 // handlePlatformHaltRestart
4061 //******************************************************************************
4063 struct HaltRestartApplierContext
{
4064 IOPMrootDomain
* RootDomain
;
4065 unsigned long PowerState
;
4066 IOPMPowerFlags PowerFlags
;
4072 platformHaltRestartApplier( OSObject
* object
, void * context
)
4074 IOPowerStateChangeNotification notify
;
4075 HaltRestartApplierContext
* ctx
;
4076 AbsoluteTime startTime
;
4079 ctx
= (HaltRestartApplierContext
*) context
;
4081 memset(¬ify
, 0, sizeof(notify
));
4082 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
4083 notify
.returnValue
= 0;
4084 notify
.stateNumber
= ctx
->PowerState
;
4085 notify
.stateFlags
= ctx
->PowerFlags
;
4087 clock_get_uptime(&startTime
);
4088 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4089 deltaTime
= computeDeltaTimeMS(&startTime
);
4091 if ((deltaTime
> kPMHaltTimeoutMS
) ||
4092 (gIOKitDebug
& kIOLogPMRootDomain
))
4094 _IOServiceInterestNotifier
* notifier
;
4095 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4097 // IOService children of IOPMrootDomain are not instrumented.
4098 // Only IORootParent currently falls under that group.
4102 LOG("%s handler %p took %u ms\n",
4103 (ctx
->MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
4104 (ctx
->MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
4105 OBFUSCATE(notifier
->handler
), (uint32_t) deltaTime
);
4112 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4114 HaltRestartApplierContext ctx
;
4115 AbsoluteTime startTime
;
4118 memset(&ctx
, 0, sizeof(ctx
));
4119 ctx
.RootDomain
= this;
4121 clock_get_uptime(&startTime
);
4125 case kPEUPSDelayHaltCPU
:
4126 ctx
.PowerState
= OFF_STATE
;
4127 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
4131 ctx
.PowerState
= RESTART_STATE
;
4132 ctx
.MessageType
= kIOMessageSystemWillRestart
;
4136 ctx
.PowerState
= ON_STATE
;
4137 ctx
.MessageType
= kIOMessageSystemPagingOff
;
4138 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4140 IOHibernateSystemRestart();
4148 // Notify legacy clients
4149 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
4151 // For normal shutdown, turn off File Server Mode.
4152 if (kPEHaltCPU
== pe_type
)
4154 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4155 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4158 setPMSetting(setting
, num
);
4164 if (kPEPagingOff
!= pe_type
)
4166 // Notify in power tree order
4167 notifySystemShutdown(this, ctx
.MessageType
);
4170 IOCPURunPlatformHaltRestartActions(pe_type
);
4172 deltaTime
= computeDeltaTimeMS(&startTime
);
4173 LOG("%s all drivers took %u ms\n",
4174 (ctx
.MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
4175 (ctx
.MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
4176 (uint32_t) deltaTime
);
4179 //******************************************************************************
4182 //******************************************************************************
4184 IOReturn
IOPMrootDomain::shutdownSystem( void )
4186 return kIOReturnUnsupported
;
4189 //******************************************************************************
4192 //******************************************************************************
4194 IOReturn
IOPMrootDomain::restartSystem( void )
4196 return kIOReturnUnsupported
;
4200 // MARK: System Capability
4202 //******************************************************************************
4203 // tagPowerPlaneService
4205 // Running on PM work loop thread.
4206 //******************************************************************************
4208 void IOPMrootDomain::tagPowerPlaneService(
4209 IOService
* service
,
4210 IOPMActions
* actions
)
4213 bool isDisplayWrangler
;
4215 memset(actions
, 0, sizeof(*actions
));
4216 actions
->target
= this;
4218 if (service
== this)
4220 actions
->actionPowerChangeStart
=
4221 OSMemberFunctionCast(
4222 IOPMActionPowerChangeStart
, this,
4223 &IOPMrootDomain::handleOurPowerChangeStart
);
4225 actions
->actionPowerChangeDone
=
4226 OSMemberFunctionCast(
4227 IOPMActionPowerChangeDone
, this,
4228 &IOPMrootDomain::handleOurPowerChangeDone
);
4230 actions
->actionPowerChangeOverride
=
4231 OSMemberFunctionCast(
4232 IOPMActionPowerChangeOverride
, this,
4233 &IOPMrootDomain::overrideOurPowerChange
);
4238 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4239 if (isDisplayWrangler
)
4244 isDisplayWrangler
= false;
4247 #if defined(__i386__) || defined(__x86_64__)
4248 if (isDisplayWrangler
)
4249 flags
|= kPMActionsFlagIsDisplayWrangler
;
4250 if (service
->getProperty("IOPMStrictTreeOrder"))
4251 flags
|= kPMActionsFlagIsGraphicsDevice
;
4252 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4253 flags
|= kPMActionsFlagIsAudioDevice
;
4256 // Find the power connection object that is a child of the PCI host
4257 // bridge, and has a graphics/audio device attached below. Mark the
4258 // power branch for delayed child notifications.
4262 IORegistryEntry
* child
= service
;
4263 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4265 while (child
!= this)
4267 if ((parent
== pciHostBridgeDriver
) ||
4270 if (OSDynamicCast(IOPowerConnection
, child
))
4272 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4273 conn
->delayChildNotification
= true;
4278 parent
= child
->getParentEntry(gIOPowerPlane
);
4284 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4285 actions
->parameter
|= flags
;
4286 actions
->actionPowerChangeOverride
=
4287 OSMemberFunctionCast(
4288 IOPMActionPowerChangeOverride
, this,
4289 &IOPMrootDomain::overridePowerChangeForUIService
);
4291 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4293 actions
->actionActivityTickle
=
4294 OSMemberFunctionCast(
4295 IOPMActionActivityTickle
, this,
4296 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4298 actions
->actionUpdatePowerClient
=
4299 OSMemberFunctionCast(
4300 IOPMActionUpdatePowerClient
, this,
4301 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
4306 // Locate the first PCI host bridge for PMTrace.
4307 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4309 IOService
* provider
= service
->getProvider();
4310 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4311 provider
->inPlane(gIODTPlane
))
4313 pciHostBridgeDevice
= provider
;
4314 pciHostBridgeDriver
= service
;
4315 DLOG("PMTrace found PCI host bridge %s->%s\n",
4316 provider
->getName(), service
->getName());
4320 // Tag top-level PCI devices. The order of PMinit() call does not
4321 // change across boots and is used as the PCI bit number.
4322 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4324 // Would prefer to check built-in property, but tagPowerPlaneService()
4325 // is called before pciDevice->registerService().
4326 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4327 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4329 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4332 // Save the assigned bit for fast lookup.
4333 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4335 actions
->actionPowerChangeStart
=
4336 OSMemberFunctionCast(
4337 IOPMActionPowerChangeStart
, this,
4338 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4340 actions
->actionPowerChangeDone
=
4341 OSMemberFunctionCast(
4342 IOPMActionPowerChangeDone
, this,
4343 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4349 //******************************************************************************
4350 // PM actions for root domain
4351 //******************************************************************************
4353 void IOPMrootDomain::overrideOurPowerChange(
4354 IOService
* service
,
4355 IOPMActions
* actions
,
4356 IOPMPowerStateIndex
* inOutPowerState
,
4357 IOPMPowerChangeFlags
* inOutChangeFlags
,
4358 IOPMRequestTag requestTag
)
4360 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4361 uint32_t changeFlags
= *inOutChangeFlags
;
4362 uint32_t currentPowerState
= (uint32_t) getPowerState();
4364 if (changeFlags
& kIOPMParentInitiated
)
4366 // Root parent is permanently pegged at max power,
4367 // a parent initiated power change is unexpected.
4368 *inOutChangeFlags
|= kIOPMNotDone
;
4372 if (powerState
< currentPowerState
)
4374 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4376 // Root domain is dropping power state ON->SLEEP.
4377 // If system is in full wake, first enter dark wake by
4378 // converting the power drop to a capability change.
4379 // Once in dark wake, transition to sleep state ASAP.
4381 darkWakeToSleepASAP
= true;
4383 // Drop graphics and audio capability
4384 _desiredCapability
&= ~(
4385 kIOPMSystemCapabilityGraphics
|
4386 kIOPMSystemCapabilityAudio
);
4388 // Convert to capability change (ON->ON)
4389 *inOutPowerState
= ON_STATE
;
4390 *inOutChangeFlags
|= kIOPMSynchronize
;
4392 // Revert device desire from SLEEP to ON
4393 changePowerStateToPriv(ON_STATE
);
4397 // System is in dark wake, ok to drop power state.
4398 // Broadcast root powering down to entire tree.
4399 *inOutChangeFlags
|= kIOPMRootChangeDown
;
4402 else if (powerState
> currentPowerState
)
4404 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0)
4406 // Broadcast power up when waking from sleep, but not for the
4407 // initial power change at boot by checking for cpu capability.
4408 *inOutChangeFlags
|= kIOPMRootChangeUp
;
4413 void IOPMrootDomain::handleOurPowerChangeStart(
4414 IOService
* service
,
4415 IOPMActions
* actions
,
4416 IOPMPowerStateIndex powerState
,
4417 IOPMPowerChangeFlags
* inOutChangeFlags
,
4418 IOPMRequestTag requestTag
)
4420 uint32_t changeFlags
= *inOutChangeFlags
;
4421 uint32_t currentPowerState
= (uint32_t) getPowerState();
4422 uint32_t sleepReason
= requestTag
? requestTag
: kIOPMSleepReasonIdle
;
4423 bool publishSleepReason
= false;
4425 _systemTransitionType
= kSystemTransitionNone
;
4426 _systemMessageClientMask
= 0;
4427 capabilityLoss
= false;
4429 if (lowBatteryCondition
)
4431 // Low battery notification may arrive after the initial sleep request
4432 // has been queued. Override the sleep reason so powerd and others can
4433 // treat this as an emergency sleep.
4434 sleepReason
= kIOPMSleepReasonLowPower
;
4437 // 1. Explicit capability change.
4439 if (changeFlags
& kIOPMSynchronize
)
4441 if (powerState
== ON_STATE
)
4443 if (changeFlags
& kIOPMSyncNoChildNotify
)
4444 _systemTransitionType
= kSystemTransitionNewCapClient
;
4446 _systemTransitionType
= kSystemTransitionCapability
;
4450 // 2. Going to sleep (cancellation still possible).
4452 else if (powerState
< currentPowerState
)
4453 _systemTransitionType
= kSystemTransitionSleep
;
4455 // 3. Woke from (idle or demand) sleep.
4457 else if (!systemBooting
&&
4458 (changeFlags
& kIOPMSelfInitiated
) &&
4459 (powerState
> currentPowerState
))
4461 _systemTransitionType
= kSystemTransitionWake
;
4462 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4463 kIOPMSystemCapabilityNetwork
;
4465 // Early exit from dark wake to full (e.g. LID open)
4466 if (kFullWakeReasonNone
!= fullWakeReason
)
4468 _desiredCapability
|= (
4469 kIOPMSystemCapabilityGraphics
|
4470 kIOPMSystemCapabilityAudio
);
4473 IOHibernateSetWakeCapabilities(_desiredCapability
);
4477 // Update pending wake capability at the beginning of every
4478 // state transition (including synchronize). This will become
4479 // the current capability at the end of the transition.
4481 if (kSystemTransitionSleep
== _systemTransitionType
)
4483 _pendingCapability
= 0;
4484 capabilityLoss
= true;
4486 // Clear previous stats
4487 IOLockLock(pmStatsLock
);
4488 if (pmStatsAppResponses
)
4490 pmStatsAppResponses
->release();
4491 pmStatsAppResponses
= OSArray::withCapacity(5);
4493 IOLockUnlock(pmStatsLock
);
4496 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4498 _pendingCapability
= _desiredCapability
|
4499 kIOPMSystemCapabilityCPU
|
4500 kIOPMSystemCapabilityNetwork
;
4502 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4503 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4505 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4506 (_pendingCapability
== _currentCapability
))
4508 // Cancel the PM state change.
4509 _systemTransitionType
= kSystemTransitionNone
;
4510 *inOutChangeFlags
|= kIOPMNotDone
;
4512 if (__builtin_popcount(_pendingCapability
) <
4513 __builtin_popcount(_currentCapability
))
4514 capabilityLoss
= true;
4517 // 1. Capability change.
4519 if (kSystemTransitionCapability
== _systemTransitionType
)
4521 // Dark to Full transition.
4522 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4524 tracePoint( kIOPMTracePointDarkWakeExit
);
4526 willEnterFullWake();
4529 // Full to Dark transition.
4530 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4532 tracePoint( kIOPMTracePointDarkWakeEntry
);
4533 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4534 _systemMessageClientMask
= kSystemMessageClientPowerd
|
4535 kSystemMessageClientLegacyApp
;
4539 // Prevent user active transitions before notifying clients
4540 // that system will sleep.
4541 preventTransitionToUserActive(true);
4543 IOService::setAdvisoryTickleEnable( false );
4545 // Publish the sleep reason for full to dark wake
4546 publishSleepReason
= true;
4547 lastSleepReason
= fullToDarkReason
= sleepReason
;
4549 // Publish a UUID for the Sleep --> Wake cycle
4550 handlePublishSleepWakeUUID(true);
4556 else if (kSystemTransitionSleep
== _systemTransitionType
)
4558 // Beginning of a system sleep transition.
4559 // Cancellation is still possible.
4560 tracePoint( kIOPMTracePointSleepStarted
, sleepReason
);
4562 _systemMessageClientMask
= kSystemMessageClientAll
;
4563 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4564 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
4565 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4566 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
4568 // Record the reason for dark wake back to sleep
4569 // System may not have ever achieved full wake
4571 publishSleepReason
= true;
4572 lastSleepReason
= sleepReason
;
4577 else if (kSystemTransitionWake
== _systemTransitionType
)
4579 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
4580 // Clear stats about sleep
4582 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4584 willEnterFullWake();
4588 // Message powerd only
4589 _systemMessageClientMask
= kSystemMessageClientPowerd
;
4590 tellClients(kIOMessageSystemWillPowerOn
);
4594 // The only location where the sleep reason is published. At this point
4595 // sleep can still be cancelled, but sleep reason should be published
4596 // early for logging purposes.
4598 if (publishSleepReason
)
4600 static const char * IOPMSleepReasons
[] =
4602 kIOPMClamshellSleepKey
,
4603 kIOPMPowerButtonSleepKey
,
4604 kIOPMSoftwareSleepKey
,
4605 kIOPMOSSwitchHibernationKey
,
4607 kIOPMLowPowerSleepKey
,
4608 kIOPMThermalEmergencySleepKey
,
4609 kIOPMMaintenanceSleepKey
,
4610 kIOPMSleepServiceExitKey
,
4611 kIOPMDarkWakeThermalEmergencyKey
4614 // Record sleep cause in IORegistry
4615 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
4616 if (reasonIndex
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0])) {
4617 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
4618 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
4622 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
4623 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
4625 _systemStateGeneration
++;
4626 systemDarkWake
= false;
4628 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4630 currentPowerState
, (uint32_t) powerState
, *inOutChangeFlags
,
4631 _systemTransitionType
, _systemStateGeneration
,
4632 _systemMessageClientMask
,
4633 _desiredCapability
, _currentCapability
, _pendingCapability
);
4637 void IOPMrootDomain::handleOurPowerChangeDone(
4638 IOService
* service
,
4639 IOPMActions
* actions
,
4640 IOPMPowerStateIndex powerState
,
4641 IOPMPowerChangeFlags changeFlags
,
4642 IOPMRequestTag requestTag __unused
)
4644 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4646 _systemTransitionType
= kSystemTransitionNone
;
4650 if (_systemTransitionType
!= kSystemTransitionNone
)
4652 uint32_t currentPowerState
= (uint32_t) getPowerState();
4654 if (changeFlags
& kIOPMNotDone
)
4656 // Power down was cancelled or vetoed.
4657 _pendingCapability
= _currentCapability
;
4658 lastSleepReason
= 0;
4660 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
4661 CAP_CURRENT(kIOPMSystemCapabilityCPU
))
4663 pmPowerStateQueue
->submitPowerEvent(
4664 kPowerEventPolicyStimulus
,
4665 (void *) kStimulusDarkWakeReentry
,
4666 _systemStateGeneration
);
4669 // Revert device desire to max.
4670 changePowerStateToPriv(ON_STATE
);
4674 // Send message on dark wake to full wake promotion.
4675 // tellChangeUp() handles the normal SLEEP->ON case.
4677 if (kSystemTransitionCapability
== _systemTransitionType
)
4679 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4681 lastSleepReason
= 0; // stop logging wrangler tickles
4682 tellClients(kIOMessageSystemHasPoweredOn
);
4684 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4686 // Going dark, reset full wake state
4687 // userIsActive will be cleared by wrangler powering down
4688 wranglerTickled
= false;
4689 fullWakeReason
= kFullWakeReasonNone
;
4693 // Reset state after exiting from dark wake.
4695 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
4696 CAP_LOSS(kIOPMSystemCapabilityCPU
))
4698 darkWakeMaintenance
= false;
4699 darkWakeToSleepASAP
= false;
4700 pciCantSleepValid
= false;
4701 darkWakeSleepService
= false;
4703 if (CAP_LOSS(kIOPMSystemCapabilityCPU
))
4705 // Remove the influence of display power assertion
4706 // before next system wake.
4707 if (wrangler
) wrangler
->changePowerStateForRootDomain(
4708 kWranglerPowerStateMin
);
4709 removeProperty(gIOPMUserTriggeredFullWakeKey
);
4713 // Entered dark mode.
4715 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4716 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
4718 // Queue an evaluation of whether to remain in dark wake,
4719 // and for how long. This serves the purpose of draining
4720 // any assertions from the queue.
4722 pmPowerStateQueue
->submitPowerEvent(
4723 kPowerEventPolicyStimulus
,
4724 (void *) kStimulusDarkWakeEntry
,
4725 _systemStateGeneration
);
4729 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4730 "dcp %x:%x:%x, dbgtimer %u\n",
4731 currentPowerState
, (uint32_t) powerState
, changeFlags
,
4732 _systemTransitionType
, _systemStateGeneration
,
4733 _systemMessageClientMask
,
4734 _desiredCapability
, _currentCapability
, _pendingCapability
,
4735 _lastDebugWakeSeconds
);
4737 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4740 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
4741 if (clamshellExists
&& fullWakeThreadCall
&&
4742 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
4744 // Not the initial graphics full power, graphics won't
4745 // send a power notification to trigger a lid state
4748 AbsoluteTime deadline
;
4749 clock_interval_to_deadline(45, kSecondScale
, &deadline
);
4750 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
4754 else if (CAP_GAIN(kIOPMSystemCapabilityCPU
))
4757 // Update current system capability.
4758 if (_currentCapability
!= _pendingCapability
)
4759 _currentCapability
= _pendingCapability
;
4761 // Update highest system capability.
4763 _highestCapability
|= _currentCapability
;
4765 if (darkWakePostTickle
&&
4766 (kSystemTransitionWake
== _systemTransitionType
) &&
4767 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4768 kDarkWakeFlagHIDTickleLate
)
4770 darkWakePostTickle
= false;
4774 // Reset tracepoint at completion of capability change,
4775 // completion of wake transition, and aborted sleep transition.
4777 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
4778 (_systemTransitionType
== kSystemTransitionWake
) ||
4779 ((_systemTransitionType
== kSystemTransitionSleep
) &&
4780 (changeFlags
& kIOPMNotDone
)))
4782 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
4783 tracePoint( kIOPMTracePointSystemUp
, 0 );
4786 _systemTransitionType
= kSystemTransitionNone
;
4787 _systemMessageClientMask
= 0;
4789 logGraphicsClamp
= false;
4793 //******************************************************************************
4794 // PM actions for graphics and audio.
4795 //******************************************************************************
4797 void IOPMrootDomain::overridePowerChangeForUIService(
4798 IOService
* service
,
4799 IOPMActions
* actions
,
4800 IOPMPowerStateIndex
* inOutPowerState
,
4801 IOPMPowerChangeFlags
* inOutChangeFlags
)
4803 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4804 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
4806 if (kSystemTransitionNone
== _systemTransitionType
)
4808 // Not in midst of a system transition.
4809 // Do not modify power limit enable state.
4811 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4813 // Activate power limiter.
4815 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4816 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4817 (changeFlags
& kIOPMSynchronize
))
4819 actions
->parameter
|= kPMActionsFlagLimitPower
;
4821 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4822 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
4823 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
4824 (changeFlags
& kIOPMSynchronize
))
4826 actions
->parameter
|= kPMActionsFlagLimitPower
;
4828 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
4829 (_systemTransitionType
== kSystemTransitionSleep
))
4831 // For graphics devices, arm the limiter when entering
4832 // system sleep. Not when dropping to dark wake.
4833 actions
->parameter
|= kPMActionsFlagLimitPower
;
4836 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4838 DLOG("+ plimit %s %p\n",
4839 service
->getName(), OBFUSCATE(service
));
4844 // Remove power limit.
4846 if ((actions
->parameter
& (
4847 kPMActionsFlagIsDisplayWrangler
|
4848 kPMActionsFlagIsGraphicsDevice
)) &&
4849 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
4851 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4853 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4854 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
4856 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4859 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4861 DLOG("- plimit %s %p\n",
4862 service
->getName(), OBFUSCATE(service
));
4866 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4868 uint32_t maxPowerState
= (uint32_t)(-1);
4870 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
4872 // Enforce limit for system power/cap transitions.
4875 if ((service
->getPowerState() > maxPowerState
) &&
4876 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
4880 // Remove lingering effects of any tickle before entering
4881 // dark wake. It will take a new tickle to return to full
4882 // wake, so the existing tickle state is useless.
4884 if (changeFlags
& kIOPMDomainDidChange
)
4885 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
4887 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
4894 // Deny all self-initiated changes when power is limited.
4895 // Wrangler tickle should never defeat the limiter.
4897 maxPowerState
= service
->getPowerState();
4900 if (powerState
> maxPowerState
)
4902 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
4903 service
->getName(), OBFUSCATE(service
), powerState
, maxPowerState
,
4905 *inOutPowerState
= maxPowerState
;
4907 if (darkWakePostTickle
&&
4908 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4909 (changeFlags
& kIOPMDomainWillChange
) &&
4910 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4911 kDarkWakeFlagHIDTickleEarly
))
4913 darkWakePostTickle
= false;
4918 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
4920 if (logGraphicsClamp
)
4925 clock_get_uptime(&now
);
4926 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
4927 absolutetime_to_nanoseconds(now
, &nsec
);
4928 if (kIOLogPMRootDomain
& gIOKitDebug
)
4929 MSG("Graphics suppressed %u ms\n",
4930 ((int)((nsec
) / 1000000ULL)));
4932 graphicsSuppressed
= true;
4937 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
4938 IOService
* service
,
4939 IOPMActions
* actions
)
4942 // Warning: Not running in PM work loop context - don't modify state !!!
4943 // Trap tickle directed to IODisplayWrangler while running with graphics
4944 // capability suppressed.
4946 assert(service
== wrangler
);
4948 clock_get_uptime(&userActivityTime
);
4949 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
4950 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
4952 userActivityCount
++;
4953 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
4954 userActivityCount
, lastSleepReason
);
4957 if (!wranglerTickled
&&
4958 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
4960 DLOG("display wrangler tickled\n");
4961 if (kIOLogPMRootDomain
& gIOKitDebug
)
4962 OSReportWithBacktrace("Dark wake display tickle");
4963 if (pmPowerStateQueue
)
4965 pmPowerStateQueue
->submitPowerEvent(
4966 kPowerEventPolicyStimulus
,
4967 (void *) kStimulusDarkWakeActivityTickle
,
4968 true /* set wake type */ );
4974 void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
4975 IOService
* service
,
4976 IOPMActions
* actions
,
4977 const OSSymbol
* powerClient
,
4978 IOPMPowerStateIndex oldPowerState
,
4979 IOPMPowerStateIndex newPowerState
)
4982 assert(service
== wrangler
);
4984 // This function implements half of the user active detection
4985 // by monitoring changes to the display wrangler's device desire.
4987 // User becomes active when either:
4988 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
4989 // in max power state. This desire change in absence of a power state
4990 // change is detected within. This handles the case when user becomes
4991 // active while the display is already lit by setDisplayPowerOn().
4993 // 2. Power state change to max, and DeviceDesire is also at max.
4994 // Handled by displayWranglerNotification().
4996 // User becomes inactive when DeviceDesire drops to sleep state or below.
4998 DLOG("wrangler %s (ps %u, %u->%u)\n",
4999 powerClient
->getCStringNoCopy(),
5000 (uint32_t) service
->getPowerState(),
5001 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
5003 if (powerClient
== gIOPMPowerClientDevice
)
5005 if ((newPowerState
> oldPowerState
) &&
5006 (newPowerState
== kWranglerPowerStateMax
) &&
5007 (service
->getPowerState() == kWranglerPowerStateMax
))
5009 evaluatePolicy( kStimulusEnterUserActiveState
);
5012 if ((newPowerState
< oldPowerState
) &&
5013 (newPowerState
<= kWranglerPowerStateSleep
))
5015 evaluatePolicy( kStimulusLeaveUserActiveState
);
5021 //******************************************************************************
5022 // User active state management
5023 //******************************************************************************
5025 void IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
5028 _preventUserActive
= prevent
;
5029 if (wrangler
&& !_preventUserActive
)
5031 // Allowing transition to user active, but the wrangler may have
5032 // already powered ON in case of sleep cancel/revert. Poll the
5033 // same conditions checked for in displayWranglerNotification()
5034 // to bring the user active state up to date.
5036 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
5037 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5038 kWranglerPowerStateMax
))
5040 evaluatePolicy( kStimulusEnterUserActiveState
);
5046 //******************************************************************************
5047 // Approve usage of delayed child notification by PM.
5048 //******************************************************************************
5050 bool IOPMrootDomain::shouldDelayChildNotification(
5051 IOService
* service
)
5053 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5054 (kFullWakeReasonNone
== fullWakeReason
) &&
5055 (kSystemTransitionWake
== _systemTransitionType
))
5057 DLOG("%s: delay child notify\n", service
->getName());
5063 //******************************************************************************
5064 // PM actions for PCI device.
5065 //******************************************************************************
5067 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5068 IOService
* service
,
5069 IOPMActions
* actions
,
5070 IOPMPowerStateIndex powerState
,
5071 IOPMPowerChangeFlags
* inOutChangeFlags
)
5073 pmTracer
->tracePCIPowerChange(
5074 PMTraceWorker::kPowerChangeStart
,
5075 service
, *inOutChangeFlags
,
5076 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5079 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5080 IOService
* service
,
5081 IOPMActions
* actions
,
5082 IOPMPowerStateIndex powerState
,
5083 IOPMPowerChangeFlags changeFlags
)
5085 pmTracer
->tracePCIPowerChange(
5086 PMTraceWorker::kPowerChangeCompleted
,
5087 service
, changeFlags
,
5088 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5091 //******************************************************************************
5094 // Override IOService::registerInterest() to intercept special clients.
5095 //******************************************************************************
5097 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
5100 friend class IOPMrootDomain
;
5101 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
)
5104 uint32_t ackTimeoutCnt
;
5108 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
5110 IONotifier
* IOPMrootDomain::registerInterest(
5111 const OSSymbol
* typeOfInterest
,
5112 IOServiceInterestHandler handler
,
5113 void * target
, void * ref
)
5115 IOPMServiceInterestNotifier
*notifier
= 0;
5116 bool isSystemCapabilityClient
;
5117 bool isKernelCapabilityClient
;
5118 IOReturn rc
= kIOReturnError
;;
5120 isSystemCapabilityClient
=
5122 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5124 isKernelCapabilityClient
=
5126 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5128 if (isSystemCapabilityClient
)
5129 typeOfInterest
= gIOAppPowerStateInterest
;
5131 notifier
= new IOPMServiceInterestNotifier
;
5132 if (!notifier
) return NULL
;
5134 if (notifier
->init()) {
5135 rc
= super::registerInterestForNotifer(notifier
, typeOfInterest
, handler
, target
, ref
);
5137 if (rc
!= kIOReturnSuccess
) {
5138 notifier
->release();
5141 if (pmPowerStateQueue
)
5143 notifier
->ackTimeoutCnt
= 0;
5144 if (isSystemCapabilityClient
)
5147 if (pmPowerStateQueue
->submitPowerEvent(
5148 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5149 notifier
->release();
5152 if (isKernelCapabilityClient
)
5155 if (pmPowerStateQueue
->submitPowerEvent(
5156 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5157 notifier
->release();
5164 //******************************************************************************
5165 // systemMessageFilter
5167 //******************************************************************************
5169 bool IOPMrootDomain::systemMessageFilter(
5170 void * object
, void * arg1
, void * arg2
, void * arg3
)
5172 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5173 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5174 bool isCapClient
= false;
5178 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5179 (!isCapMsg
|| !_joinedCapabilityClients
||
5180 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
5183 // Capability change message for app and kernel clients.
5187 if ((context
->notifyType
== kNotifyPriority
) ||
5188 (context
->notifyType
== kNotifyCapabilityChangePriority
))
5191 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5192 (object
== (void *) systemCapabilityNotifier
))
5198 IOPMSystemCapabilityChangeParameters
* capArgs
=
5199 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5201 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5203 capArgs
->fromCapabilities
= 0;
5204 capArgs
->toCapabilities
= _currentCapability
;
5205 capArgs
->changeFlags
= 0;
5209 capArgs
->fromCapabilities
= _currentCapability
;
5210 capArgs
->toCapabilities
= _pendingCapability
;
5212 if (context
->isPreChange
)
5213 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5215 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5218 // Capability change messages only go to the PM configd plugin.
5219 // Wait for response post-change if capabilitiy is increasing.
5220 // Wait for response pre-change if capability is decreasing.
5222 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5223 ( (capabilityLoss
&& context
->isPreChange
) ||
5224 (!capabilityLoss
&& !context
->isPreChange
) ) )
5226 // app has not replied yet, wait for it
5227 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5234 // Capability client will always see kIOMessageCanSystemSleep,
5235 // even for demand sleep. It will also have a chance to veto
5236 // sleep one last time after all clients have responded to
5237 // kIOMessageSystemWillSleep
5239 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
5240 (kIOMessageSystemWillNotSleep
== context
->messageType
))
5242 if (object
== (OSObject
*) systemCapabilityNotifier
)
5248 // Not idle sleep, don't ask apps.
5249 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
5255 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
)
5257 if ((object
== (OSObject
*) systemCapabilityNotifier
) &&
5258 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
5259 (fullToDarkReason
== kIOPMSleepReasonIdle
))
5264 // Reject capability change messages for legacy clients.
5265 // Reject legacy system sleep messages for capability client.
5267 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
5272 // Filter system sleep messages.
5274 if ((context
->notifyType
== kNotifyApps
) &&
5275 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
))
5277 IOPMServiceInterestNotifier
*notify
;
5280 if ((notify
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
))
5283 if (notify
->ackTimeoutCnt
>= 3)
5284 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5286 *((OSObject
**) arg3
) = kOSBooleanTrue
;
5289 else if ((context
->notifyType
== kNotifyPriority
) &&
5290 (_systemMessageClientMask
& kSystemMessageClientKernel
))
5297 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
5299 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
5300 if (_joinedCapabilityClients
->getCount() == 0)
5302 DLOG("destroyed capability client set %p\n",
5303 OBFUSCATE(_joinedCapabilityClients
));
5304 _joinedCapabilityClients
->release();
5305 _joinedCapabilityClients
= 0;
5312 //******************************************************************************
5313 // setMaintenanceWakeCalendar
5315 //******************************************************************************
5317 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
5318 const IOPMCalendarStruct
* calendar
)
5324 return kIOReturnBadArgument
;
5326 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
5328 return kIOReturnNoMemory
;
5330 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
5331 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
5332 if (kIOReturnSuccess
== ret
)
5333 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
5335 if (kPMCalendarTypeSleepService
== calendar
->selector
)
5337 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
5338 if (kIOReturnSuccess
== ret
)
5339 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
5341 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
5348 // MARK: Display Wrangler
5350 //******************************************************************************
5351 // displayWranglerNotification
5353 // Handle the notification when the IODisplayWrangler changes power state.
5354 //******************************************************************************
5356 IOReturn
IOPMrootDomain::displayWranglerNotification(
5357 void * target
, void * refCon
,
5358 UInt32 messageType
, IOService
* service
,
5359 void * messageArgument
, vm_size_t argSize
)
5362 int displayPowerState
;
5363 IOPowerStateChangeNotification
* params
=
5364 (IOPowerStateChangeNotification
*) messageArgument
;
5366 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
5367 (messageType
!= kIOMessageDeviceHasPoweredOn
))
5368 return kIOReturnUnsupported
;
5372 return kIOReturnUnsupported
;
5374 displayPowerState
= params
->stateNumber
;
5375 DLOG("wrangler %s ps %d\n",
5376 getIOMessageString(messageType
), displayPowerState
);
5378 switch (messageType
) {
5379 case kIOMessageDeviceWillPowerOff
:
5380 // Display wrangler has dropped power due to display idle
5381 // or force system sleep.
5383 // 4 Display ON kWranglerPowerStateMax
5384 // 3 Display Dim kWranglerPowerStateDim
5385 // 2 Display Sleep kWranglerPowerStateSleep
5386 // 1 Not visible to user
5387 // 0 Not visible to user kWranglerPowerStateMin
5389 if (displayPowerState
<= kWranglerPowerStateSleep
)
5390 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
5393 case kIOMessageDeviceHasPoweredOn
:
5394 // Display wrangler has powered on due to user activity
5395 // or wake from sleep.
5397 if (kWranglerPowerStateMax
== displayPowerState
)
5399 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
5401 // See comment in handleUpdatePowerClientForDisplayWrangler
5402 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5403 kWranglerPowerStateMax
)
5405 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
5411 return kIOReturnUnsupported
;
5414 //******************************************************************************
5415 // displayWranglerMatchPublished
5417 // Receives a notification when the IODisplayWrangler is published.
5418 // When it's published we install a power state change handler.
5419 //******************************************************************************
5421 bool IOPMrootDomain::displayWranglerMatchPublished(
5424 IOService
* newService
,
5425 IONotifier
* notifier __unused
)
5428 // found the display wrangler, now install a handler
5429 if( !newService
->registerInterest( gIOGeneralInterest
,
5430 &displayWranglerNotification
, target
, 0) )
5438 #if defined(__i386__) || defined(__x86_64__)
5440 bool IOPMrootDomain::IONVRAMMatchPublished(
5443 IOService
* newService
,
5444 IONotifier
* notifier
)
5446 unsigned int len
= 0;
5447 IOPMrootDomain
*rd
= (IOPMrootDomain
*)target
;
5448 OSNumber
*statusCode
= NULL
;
5450 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey
, NULL
, &len
))
5452 statusCode
= OSDynamicCast(OSNumber
, rd
->getProperty(kIOPMSleepWakeFailureCodeKey
));
5453 if (statusCode
!= NULL
) {
5454 if (statusCode
->unsigned64BitValue() != 0) {
5455 rd
->swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
5456 MSG("System was rebooted due to Sleep/Wake failure\n");
5459 rd
->swd_flags
|= SWD_BOOT_BY_OSX_WDOG
;
5460 MSG("System was non-responsive and was rebooted by watchdog\n");
5464 rd
->swd_logBufMap
= rd
->sleepWakeDebugRetrieve();
5466 if (notifier
) notifier
->remove();
5471 bool IOPMrootDomain::IONVRAMMatchPublished(
5474 IOService
* newService
,
5475 IONotifier
* notifier __unused
)
5482 //******************************************************************************
5485 //******************************************************************************
5487 void IOPMrootDomain::reportUserInput( void )
5494 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
5497 wrangler
= (IOService
*) iter
->getNextObject();
5503 wrangler
->activityTickle(0,0);
5507 //******************************************************************************
5508 // latchDisplayWranglerTickle
5509 //******************************************************************************
5511 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
5516 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
5517 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
5518 !checkSystemCanSustainFullWake())
5520 // Currently in dark wake, and not transitioning to full wake.
5521 // Full wake is unsustainable, so latch the tickle to prevent
5522 // the display from lighting up momentarily.
5523 wranglerTickleLatched
= true;
5527 wranglerTickleLatched
= false;
5530 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
5532 wranglerTickleLatched
= false;
5534 pmPowerStateQueue
->submitPowerEvent(
5535 kPowerEventPolicyStimulus
,
5536 (void *) kStimulusDarkWakeActivityTickle
);
5539 return wranglerTickleLatched
;
5545 //******************************************************************************
5546 // setDisplayPowerOn
5548 // For root domain user client
5549 //******************************************************************************
5551 void IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
5553 if (checkSystemCanSustainFullWake())
5555 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
5556 (void *) 0, options
);
5563 //******************************************************************************
5566 // Notification on battery class IOPowerSource appearance
5567 //******************************************************************************
5569 bool IOPMrootDomain::batteryPublished(
5572 IOService
* resourceService
,
5573 IONotifier
* notifier __unused
)
5575 // rdar://2936060&4435589
5576 // All laptops have dimmable LCD displays
5577 // All laptops have batteries
5578 // So if this machine has a battery, publish the fact that the backlight
5579 // supports dimming.
5580 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
5586 // MARK: System PM Policy
5588 //******************************************************************************
5589 // checkSystemSleepAllowed
5591 //******************************************************************************
5593 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
5594 uint32_t sleepReason
)
5598 // Conditions that prevent idle and demand system sleep.
5601 if (userDisabledAllSleep
)
5603 err
= 1; // 1. user-space sleep kill switch
5607 if (systemBooting
|| systemShutdown
|| gWillShutdown
)
5609 err
= 2; // 2. restart or shutdown in progress
5616 // Conditions above pegs the system at full wake.
5617 // Conditions below prevent system sleep but does not prevent
5618 // dark wake, and must be called from gated context.
5621 err
= 3; // 3. config does not support sleep
5625 if (lowBatteryCondition
)
5627 break; // always sleep on low battery
5630 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
)
5632 break; // always sleep on dark wake thermal emergencies
5635 if (preventSystemSleepList
->getCount() != 0)
5637 err
= 4; // 4. child prevent system sleep clamp
5641 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
5642 kIOPMDriverAssertionLevelOn
)
5644 err
= 5; // 5. CPU assertion
5648 if (pciCantSleepValid
)
5650 if (pciCantSleepFlag
)
5651 err
= 6; // 6. PCI card does not support PM (cached)
5654 else if (sleepSupportedPEFunction
&&
5655 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5658 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
5659 ret
= getPlatform()->callPlatformFunction(
5660 sleepSupportedPEFunction
, false,
5661 NULL
, NULL
, NULL
, NULL
);
5662 pciCantSleepValid
= true;
5663 pciCantSleepFlag
= false;
5664 if ((platformSleepSupport
& kPCICantSleep
) ||
5665 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
5667 err
= 6; // 6. PCI card does not support PM
5668 pciCantSleepFlag
= true;
5677 DLOG("System sleep prevented by %d\n", err
);
5683 bool IOPMrootDomain::checkSystemSleepEnabled( void )
5685 return checkSystemSleepAllowed(0, 0);
5688 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
5691 return checkSystemSleepAllowed(1, sleepReason
);
5694 //******************************************************************************
5695 // checkSystemCanSustainFullWake
5696 //******************************************************************************
5698 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
5701 if (lowBatteryCondition
)
5703 // Low battery wake, or received a low battery notification
5704 // while system is awake. This condition will persist until
5705 // the following wake.
5709 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisabled
)
5711 // Graphics state is unknown and external display might not be probed.
5712 // Do not incorporate state that requires graphics to be in max power
5713 // such as desktopMode or clamshellDisabled.
5715 if (!acAdaptorConnected
)
5717 DLOG("full wake check: no AC\n");
5725 //******************************************************************************
5728 // Conditions that affect our wake/sleep decision has changed.
5729 // If conditions dictate that the system must remain awake, clamp power
5730 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
5731 // is TRUE, then remove the power clamp and allow the power state to drop
5733 //******************************************************************************
5735 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
5737 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
5738 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
);
5742 if ((sleepSlider
== 0) || !checkSystemSleepEnabled())
5744 changePowerStateToPriv(ON_STATE
);
5746 else if ( sleepASAP
)
5748 changePowerStateToPriv(SLEEP_STATE
);
5752 //******************************************************************************
5753 // dispatchPowerEvent
5755 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
5756 //******************************************************************************
5758 void IOPMrootDomain::dispatchPowerEvent(
5759 uint32_t event
, void * arg0
, uint64_t arg1
)
5761 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
5766 case kPowerEventFeatureChanged
:
5767 messageClients(kIOPMMessageFeatureChange
, this);
5770 case kPowerEventReceivedPowerNotification
:
5771 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
5774 case kPowerEventSystemBootCompleted
:
5777 systemBooting
= false;
5779 if (lowBatteryCondition
)
5781 privateSleepSystem (kIOPMSleepReasonLowPower
);
5783 // The rest is unnecessary since the system is expected
5784 // to sleep immediately. The following wake will update
5789 if (swd_flags
& SWD_VALID_LOGS
) {
5790 if (swd_flags
& SWD_LOGS_IN_MEM
) {
5791 sleepWakeDebugDumpFromMem(swd_logBufMap
);
5792 swd_logBufMap
->release();
5795 else if (swd_flags
& SWD_LOGS_IN_FILE
)
5796 sleepWakeDebugDumpFromFile();
5798 else if (swd_flags
& (SWD_BOOT_BY_SW_WDOG
|SWD_BOOT_BY_OSX_WDOG
)) {
5799 // If logs are invalid, write the failure code
5800 sleepWakeDebugDumpFromMem(NULL
);
5802 // If lid is closed, re-send lid closed notification
5803 // now that booting is complete.
5804 if ( clamshellClosed
)
5806 handlePowerNotification(kLocalEvalClamshellCommand
);
5808 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
5813 case kPowerEventSystemShutdown
:
5814 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
5816 /* We set systemShutdown = true during shutdown
5817 to prevent sleep at unexpected times while loginwindow is trying
5818 to shutdown apps and while the OS is trying to transition to
5821 Set to true during shutdown, as soon as loginwindow shows
5822 the "shutdown countdown dialog", through individual app
5823 termination, and through black screen kernel shutdown.
5825 systemShutdown
= true;
5828 A shutdown was initiated, but then the shutdown
5829 was cancelled, clearing systemShutdown to false here.
5831 systemShutdown
= false;
5835 case kPowerEventUserDisabledSleep
:
5836 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
5839 case kPowerEventRegisterSystemCapabilityClient
:
5840 if (systemCapabilityNotifier
)
5842 systemCapabilityNotifier
->release();
5843 systemCapabilityNotifier
= 0;
5847 systemCapabilityNotifier
= (IONotifier
*) arg0
;
5848 systemCapabilityNotifier
->retain();
5850 /* intentional fall-through */
5852 case kPowerEventRegisterKernelCapabilityClient
:
5853 if (!_joinedCapabilityClients
)
5854 _joinedCapabilityClients
= OSSet::withCapacity(8);
5857 IONotifier
* notify
= (IONotifier
*) arg0
;
5858 if (_joinedCapabilityClients
)
5860 _joinedCapabilityClients
->setObject(notify
);
5861 synchronizePowerTree( kIOPMSyncNoChildNotify
);
5867 case kPowerEventPolicyStimulus
:
5870 int stimulus
= (uintptr_t) arg0
;
5871 evaluatePolicy( stimulus
, (uint32_t) arg1
);
5875 case kPowerEventAssertionCreate
:
5877 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
5882 case kPowerEventAssertionRelease
:
5884 pmAssertions
->handleReleaseAssertion(arg1
);
5888 case kPowerEventAssertionSetLevel
:
5890 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
5894 case kPowerEventQueueSleepWakeUUID
:
5895 handleQueueSleepWakeUUID((OSObject
*)arg0
);
5897 case kPowerEventPublishSleepWakeUUID
:
5898 handlePublishSleepWakeUUID((bool)arg0
);
5901 case kPowerEventSetDisplayPowerOn
:
5902 if (!wrangler
) break;
5905 // Force wrangler to max power state. If system is in dark wake
5906 // this alone won't raise the wrangler's power state.
5908 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
5910 // System in dark wake, always requesting full wake should
5911 // not have any bad side-effects, even if the request fails.
5913 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
5915 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
5916 requestFullWake( kFullWakeReasonDisplayOn
);
5921 // Relenquish desire to power up display.
5922 // Must first transition to state 1 since wrangler doesn't
5923 // power off the displays at state 0. At state 0 the root
5924 // domain is removed from the wrangler's power client list.
5926 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
5927 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
5933 //******************************************************************************
5934 // systemPowerEventOccurred
5936 // The power controller is notifying us of a hardware-related power management
5937 // event that we must handle.
5939 // systemPowerEventOccurred covers the same functionality that
5940 // receivePowerNotification does; it simply provides a richer API for conveying
5941 // more information.
5942 //******************************************************************************
5944 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5945 const OSSymbol
*event
,
5948 IOReturn attempt
= kIOReturnSuccess
;
5949 OSNumber
*newNumber
= NULL
;
5952 return kIOReturnBadArgument
;
5954 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
5956 return kIOReturnInternalError
;
5958 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
5960 newNumber
->release();
5965 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5966 const OSSymbol
*event
,
5969 OSDictionary
*thermalsDict
= NULL
;
5970 bool shouldUpdate
= true;
5972 if (!event
|| !value
)
5973 return kIOReturnBadArgument
;
5976 // We reuse featuresDict Lock because it already exists and guards
5977 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
5978 // of stepping on that lock.
5979 if (featuresDictLock
) IOLockLock(featuresDictLock
);
5981 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
5983 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
5984 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
5986 thermalsDict
= OSDictionary::withCapacity(1);
5989 if (!thermalsDict
) {
5990 shouldUpdate
= false;
5994 thermalsDict
->setObject (event
, value
);
5996 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
5998 thermalsDict
->release();
6002 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
6005 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
6007 return kIOReturnSuccess
;
6010 //******************************************************************************
6011 // receivePowerNotification
6013 // The power controller is notifying us of a hardware-related power management
6014 // event that we must handle. This may be a result of an 'environment' interrupt
6015 // from the power mgt micro.
6016 //******************************************************************************
6018 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
6020 pmPowerStateQueue
->submitPowerEvent(
6021 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
6022 return kIOReturnSuccess
;
6025 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
6027 bool eval_clamshell
= false;
6032 * Local (IOPMrootDomain only) eval clamshell command
6034 if (msg
& kLocalEvalClamshellCommand
)
6036 eval_clamshell
= true;
6042 if (msg
& kIOPMOverTemp
)
6044 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6045 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
6049 * Sleep if system is in dark wake
6051 if (msg
& kIOPMDWOverTemp
)
6053 DLOG("DarkWake thermal limits message received!\n");
6055 // Inform cap client that we're going to sleep
6056 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
6063 if (msg
& kIOPMSleepNow
)
6065 privateSleepSystem (kIOPMSleepReasonSoftware
);
6071 if (msg
& kIOPMPowerEmergency
)
6073 lowBatteryCondition
= true;
6074 privateSleepSystem (kIOPMSleepReasonLowPower
);
6080 if (msg
& kIOPMClamshellOpened
)
6082 // Received clamshel open message from clamshell controlling driver
6083 // Update our internal state and tell general interest clients
6084 clamshellClosed
= false;
6085 clamshellExists
= true;
6087 // Don't issue a hid tickle when lid is open and polled on wake
6088 if (msg
& kIOPMSetValue
)
6090 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
6095 informCPUStateChange(kInformLid
, 0);
6097 // Tell general interest clients
6098 sendClientClamshellNotification();
6100 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
6101 || (lastSleepReason
== kIOPMSleepReasonIdle
)
6102 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
6103 if (aborting
) userActivityCount
++;
6104 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
6109 * Send the clamshell interest notification since the lid is closing.
6111 if (msg
& kIOPMClamshellClosed
)
6113 // Received clamshel open message from clamshell controlling driver
6114 // Update our internal state and tell general interest clients
6115 clamshellClosed
= true;
6116 clamshellExists
= true;
6119 informCPUStateChange(kInformLid
, 1);
6121 // Tell general interest clients
6122 sendClientClamshellNotification();
6124 // And set eval_clamshell = so we can attempt
6125 eval_clamshell
= true;
6129 * Set Desktop mode (sent from graphics)
6131 * -> reevaluate lid state
6133 if (msg
& kIOPMSetDesktopMode
)
6135 desktopMode
= (0 != (msg
& kIOPMSetValue
));
6136 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
6138 sendClientClamshellNotification();
6140 // Re-evaluate the lid state
6141 eval_clamshell
= true;
6145 * AC Adaptor connected
6147 * -> reevaluate lid state
6149 if (msg
& kIOPMSetACAdaptorConnected
)
6151 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
6152 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
6155 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
6157 // Tell BSD if AC is connected
6158 // 0 == external power source; 1 == on battery
6159 post_sys_powersource(acAdaptorConnected
? 0:1);
6161 sendClientClamshellNotification();
6163 // Re-evaluate the lid state
6164 eval_clamshell
= true;
6166 // Lack of AC may have latched a display wrangler tickle.
6167 // This mirrors the hardware's USB wake event latch, where a latched
6168 // USB wake event followed by an AC attach will trigger a full wake.
6169 latchDisplayWranglerTickle( false );
6172 // AC presence will reset the standy timer delay adjustment.
6173 _standbyTimerResetSeconds
= 0;
6175 if (!userIsActive
) {
6176 // Reset userActivityTime when power supply is changed(rdr 13789330)
6177 clock_get_uptime(&userActivityTime
);
6182 * Enable Clamshell (external display disappear)
6184 * -> reevaluate lid state
6186 if (msg
& kIOPMEnableClamshell
)
6188 // Re-evaluate the lid state
6189 // System should sleep on external display disappearance
6190 // in lid closed operation.
6191 if (true == clamshellDisabled
)
6193 eval_clamshell
= true;
6196 clamshellDisabled
= false;
6197 sendClientClamshellNotification();
6201 * Disable Clamshell (external display appeared)
6202 * We don't bother re-evaluating clamshell state. If the system is awake,
6203 * the lid is probably open.
6205 if (msg
& kIOPMDisableClamshell
)
6207 clamshellDisabled
= true;
6208 sendClientClamshellNotification();
6212 * Evaluate clamshell and SLEEP if appropiate
6214 if (eval_clamshell
&& clamshellClosed
)
6216 if (shouldSleepOnClamshellClosed())
6217 privateSleepSystem (kIOPMSleepReasonClamshell
);
6219 evaluatePolicy( kStimulusDarkWakeEvaluate
);
6225 if (msg
& kIOPMPowerButton
)
6227 if (!wranglerAsleep
)
6229 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
6230 // Check that power button sleep is enabled
6232 if( kOSBooleanTrue
!= getProperty(pbs
))
6233 privateSleepSystem (kIOPMSleepReasonPowerButton
);
6241 //******************************************************************************
6244 // Evaluate root-domain policy in response to external changes.
6245 //******************************************************************************
6247 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
6251 int idleSleepEnabled
: 1;
6252 int idleSleepDisabled
: 1;
6253 int displaySleep
: 1;
6254 int sleepDelayChanged
: 1;
6255 int evaluateDarkWake
: 1;
6256 int adjustPowerState
: 1;
6257 int userBecameInactive
: 1;
6262 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
6269 case kStimulusDisplayWranglerSleep
:
6270 if (!wranglerAsleep
)
6272 // first transition to wrangler sleep or lower
6273 wranglerAsleep
= true;
6274 flags
.bit
.displaySleep
= true;
6278 case kStimulusDisplayWranglerWake
:
6279 displayIdleForDemandSleep
= false;
6280 wranglerAsleep
= false;
6283 case kStimulusEnterUserActiveState
:
6284 if (_preventUserActive
)
6286 DLOG("user active dropped\n");
6291 userIsActive
= true;
6292 userWasActive
= true;
6294 // Stay awake after dropping demand for display power on
6295 if (kFullWakeReasonDisplayOn
== fullWakeReason
)
6296 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
6298 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
6299 messageClients(kIOPMMessageUserIsActiveChanged
);
6301 flags
.bit
.idleSleepDisabled
= true;
6304 case kStimulusLeaveUserActiveState
:
6307 userIsActive
= false;
6308 clock_get_uptime(&userBecameInactiveTime
);
6309 flags
.bit
.userBecameInactive
= true;
6311 setProperty(gIOPMUserIsActiveKey
, kOSBooleanFalse
);
6312 messageClients(kIOPMMessageUserIsActiveChanged
);
6316 case kStimulusAggressivenessChanged
:
6318 unsigned long minutesToIdleSleep
= 0;
6319 unsigned long minutesToDisplayDim
= 0;
6320 unsigned long minutesDelta
= 0;
6322 // Fetch latest display and system sleep slider values.
6323 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
6324 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
6325 DLOG("aggressiveness changed: system %u->%u, display %u\n",
6326 (uint32_t) sleepSlider
,
6327 (uint32_t) minutesToIdleSleep
,
6328 (uint32_t) minutesToDisplayDim
);
6330 DLOG("idle time -> %ld secs (ena %d)\n",
6331 idleSeconds
, (minutesToIdleSleep
!= 0));
6333 if (0x7fffffff == minutesToIdleSleep
)
6334 minutesToIdleSleep
= idleSeconds
;
6336 // How long to wait before sleeping the system once
6337 // the displays turns off is indicated by 'extraSleepDelay'.
6339 if ( minutesToIdleSleep
> minutesToDisplayDim
)
6340 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
6341 else if ( minutesToIdleSleep
== minutesToDisplayDim
)
6344 if ((sleepSlider
== 0) && (minutesToIdleSleep
!= 0))
6345 flags
.bit
.idleSleepEnabled
= true;
6347 if ((sleepSlider
!= 0) && (minutesToIdleSleep
== 0))
6348 flags
.bit
.idleSleepDisabled
= true;
6350 if (((minutesDelta
!= extraSleepDelay
) ||
6351 (userActivityTime
!= userActivityTime_prev
)) &&
6352 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
6353 flags
.bit
.sleepDelayChanged
= true;
6355 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
6356 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
6358 // Reconsider decision to remain in dark wake
6359 flags
.bit
.evaluateDarkWake
= true;
6362 sleepSlider
= minutesToIdleSleep
;
6363 extraSleepDelay
= minutesDelta
;
6364 userActivityTime_prev
= userActivityTime
;
6367 case kStimulusDemandSystemSleep
:
6368 displayIdleForDemandSleep
= true;
6369 if (wrangler
&& wranglerIdleSettings
)
6371 // Request wrangler idle only when demand sleep is triggered
6373 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6375 wrangler
->setProperties(wranglerIdleSettings
);
6376 DLOG("Requested wrangler idle\n");
6379 // arg = sleepReason
6380 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
6383 case kStimulusAllowSystemSleepChanged
:
6384 flags
.bit
.adjustPowerState
= true;
6387 case kStimulusDarkWakeActivityTickle
:
6388 // arg == true implies real and not self generated wrangler tickle.
6389 // Update wake type on PM work loop instead of the tickle thread to
6390 // eliminate the possibility of an early tickle clobbering the wake
6391 // type set by the platform driver.
6393 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
6395 if (false == wranglerTickled
)
6397 if (latchDisplayWranglerTickle(true))
6399 DLOG("latched tickle\n");
6403 wranglerTickled
= true;
6404 DLOG("Requesting full wake after dark wake activity tickle\n");
6405 requestFullWake( kFullWakeReasonLocalUser
);
6409 case kStimulusDarkWakeEntry
:
6410 case kStimulusDarkWakeReentry
:
6411 // Any system transitions since the last dark wake transition
6412 // will invalid the stimulus.
6414 if (arg
== _systemStateGeneration
)
6416 DLOG("dark wake entry\n");
6417 systemDarkWake
= true;
6419 // Keep wranglerAsleep an invariant when wrangler is absent
6421 wranglerAsleep
= true;
6423 if (kStimulusDarkWakeEntry
== stimulus
)
6425 clock_get_uptime(&userBecameInactiveTime
);
6426 flags
.bit
.evaluateDarkWake
= true;
6429 // Always accelerate disk spindown while in dark wake,
6430 // even if system does not support/allow sleep.
6432 cancelIdleSleepTimer();
6433 setQuickSpinDownTimeout();
6437 case kStimulusDarkWakeEvaluate
:
6440 flags
.bit
.evaluateDarkWake
= true;
6444 case kStimulusNoIdleSleepPreventers
:
6445 flags
.bit
.adjustPowerState
= true;
6448 } /* switch(stimulus) */
6450 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
))
6452 if (darkWakeToSleepASAP
||
6453 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
6455 uint32_t newSleepReason
;
6457 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6459 // System was previously in full wake. Sleep reason from
6460 // full to dark already recorded in fullToDarkReason.
6462 if (lowBatteryCondition
)
6463 newSleepReason
= kIOPMSleepReasonLowPower
;
6465 newSleepReason
= fullToDarkReason
;
6469 // In dark wake from system sleep.
6471 if (darkWakeSleepService
)
6472 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
6474 newSleepReason
= kIOPMSleepReasonMaintenance
;
6477 if (checkSystemCanSleep(newSleepReason
))
6479 privateSleepSystem(newSleepReason
);
6482 else // non-maintenance (network) dark wake
6484 if (checkSystemCanSleep(kIOPMSleepReasonIdle
))
6486 // Release power clamp, and wait for children idle.
6487 adjustPowerState(true);
6491 changePowerStateToPriv(ON_STATE
);
6498 // The rest are irrelevant while system is in dark wake.
6502 if ((flags
.bit
.displaySleep
) &&
6503 (kFullWakeReasonDisplayOn
== fullWakeReason
))
6505 // kIOPMSleepReasonMaintenance?
6506 changePowerStateWithOverrideTo( SLEEP_STATE
, kIOPMSleepReasonMaintenance
);
6509 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
)
6511 bool cancelQuickSpindown
= false;
6513 if (flags
.bit
.sleepDelayChanged
)
6515 // Cancel existing idle sleep timer and quick disk spindown.
6516 // New settings will be applied by the idleSleepEnabled flag
6517 // handler below if idle sleep is enabled.
6519 DLOG("extra sleep timer changed\n");
6520 cancelIdleSleepTimer();
6521 cancelQuickSpindown
= true;
6525 DLOG("user inactive\n");
6528 if (!userIsActive
&& sleepSlider
)
6530 startIdleSleepTimer(getTimeToIdleSleep());
6533 if (cancelQuickSpindown
)
6534 restoreUserSpinDownTimeout();
6537 if (flags
.bit
.idleSleepEnabled
)
6539 DLOG("idle sleep timer enabled\n");
6542 changePowerStateToPriv(ON_STATE
);
6545 startIdleSleepTimer( idleSeconds
);
6550 // Start idle timer if prefs now allow system sleep
6551 // and user is already inactive. Disk spindown is
6552 // accelerated upon timer expiration.
6556 startIdleSleepTimer(getTimeToIdleSleep());
6561 if (flags
.bit
.idleSleepDisabled
)
6563 DLOG("idle sleep timer disabled\n");
6564 cancelIdleSleepTimer();
6565 restoreUserSpinDownTimeout();
6569 if (flags
.bit
.adjustPowerState
)
6571 bool sleepASAP
= false;
6573 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
6577 changePowerStateToPriv(ON_STATE
);
6580 // stay awake for at least idleSeconds
6581 startIdleSleepTimer(idleSeconds
);
6584 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
6590 adjustPowerState(sleepASAP
);
6594 //******************************************************************************
6597 // Request transition from dark wake to full wake
6598 //******************************************************************************
6600 void IOPMrootDomain::requestFullWake( FullWakeReason reason
)
6602 uint32_t options
= 0;
6603 IOService
* pciRoot
= 0;
6604 bool promotion
= false;
6606 // System must be in dark wake and a valid reason for entering full wake
6607 if ((kFullWakeReasonNone
== reason
) ||
6608 (kFullWakeReasonNone
!= fullWakeReason
) ||
6609 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)))
6614 // Will clear reason upon exit from full wake
6615 fullWakeReason
= reason
;
6617 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
6618 kIOPMSystemCapabilityAudio
);
6620 if ((kSystemTransitionWake
== _systemTransitionType
) &&
6621 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6622 !graphicsSuppressed
)
6624 // Promote to full wake while waking up to dark wake due to tickle.
6625 // PM will hold off notifying the graphics subsystem about system wake
6626 // as late as possible, so if a HID tickle does arrive, graphics can
6627 // power up on this same wake cycle. The latency to power up graphics
6628 // on the next cycle can be huge on some systems. However, once any
6629 // graphics suppression has taken effect, it is too late. All other
6630 // graphics devices must be similarly suppressed. But the delay till
6631 // the following cycle should be short.
6633 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
6634 kIOPMSystemCapabilityAudio
);
6636 // Immediately bring up audio and graphics
6637 pciRoot
= pciHostBridgeDriver
;
6638 willEnterFullWake();
6642 // Unsafe to cancel once graphics was powered.
6643 // If system woke from dark wake, the return to sleep can
6644 // be cancelled. "awake -> dark -> sleep" transition
6645 // can be canceled also, during the "dark --> sleep" phase
6646 // *prior* to driver power down.
6647 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
6648 _pendingCapability
== 0) {
6649 options
|= kIOPMSyncCancelPowerDown
;
6652 synchronizePowerTree(options
, pciRoot
);
6653 if (kFullWakeReasonLocalUser
== fullWakeReason
)
6655 // IOGraphics doesn't light the display even though graphics is
6656 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
6657 // So, do an explicit activity tickle
6659 wrangler
->activityTickle(0,0);
6662 // Log a timestamp for the initial full wake request.
6663 // System may not always honor this full wake request.
6664 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6669 clock_get_uptime(&now
);
6670 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
6671 absolutetime_to_nanoseconds(now
, &nsec
);
6672 MSG("full wake %s (reason %u) %u ms\n",
6673 promotion
? "promotion" : "request",
6674 fullWakeReason
, ((int)((nsec
) / 1000000ULL)));
6678 //******************************************************************************
6679 // willEnterFullWake
6681 // System will enter full wake from sleep, from dark wake, or from dark
6682 // wake promotion. This function aggregate things that are in common to
6683 // all three full wake transitions.
6685 // Assumptions: fullWakeReason was updated
6686 //******************************************************************************
6688 void IOPMrootDomain::willEnterFullWake( void )
6690 hibernateRetry
= false;
6691 sleepToStandby
= false;
6692 sleepTimerMaintenance
= false;
6694 _systemMessageClientMask
= kSystemMessageClientPowerd
|
6695 kSystemMessageClientLegacyApp
;
6697 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
6699 // Initial graphics full power
6700 _systemMessageClientMask
|= kSystemMessageClientKernel
;
6702 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
6703 setProperty(gIOPMUserTriggeredFullWakeKey
,
6704 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
6705 kOSBooleanTrue
: kOSBooleanFalse
);
6708 IOHibernateSetWakeCapabilities(_pendingCapability
);
6711 IOService::setAdvisoryTickleEnable( true );
6712 tellClients(kIOMessageSystemWillPowerOn
);
6713 preventTransitionToUserActive(false);
6716 //******************************************************************************
6717 // fullWakeDelayedWork
6719 // System has already entered full wake. Invoked by a delayed thread call.
6720 //******************************************************************************
6722 void IOPMrootDomain::fullWakeDelayedWork( void )
6724 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
6725 // Not gated, don't modify state
6726 if ((kSystemTransitionNone
== _systemTransitionType
) &&
6727 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6729 receivePowerNotification( kLocalEvalClamshellCommand
);
6734 //******************************************************************************
6735 // evaluateAssertions
6737 //******************************************************************************
6738 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
6740 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
6742 messageClients(kIOPMMessageDriverAssertionsChanged
);
6744 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
6747 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
6749 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
6750 wrangler
->setIgnoreIdleTimer( value
);
6754 if (changedBits
& kIOPMDriverAssertionCPUBit
)
6755 evaluatePolicy(kStimulusDarkWakeEvaluate
);
6757 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
6758 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
6760 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
6761 updatePreventIdleSleepList(this, true);
6764 DLOG("Driver assertion ReservedBit7 dropped\n");
6765 updatePreventIdleSleepList(this, false);
6773 //******************************************************************************
6776 //******************************************************************************
6778 void IOPMrootDomain::pmStatsRecordEvent(
6780 AbsoluteTime timestamp
)
6782 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
6783 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
6786 OSData
*publishPMStats
= NULL
;
6788 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
6790 absolutetime_to_nanoseconds(timestamp
, &nsec
);
6792 switch (eventIndex
) {
6793 case kIOPMStatsHibernateImageWrite
:
6795 gPMStats
.hibWrite
.start
= nsec
;
6797 gPMStats
.hibWrite
.stop
= nsec
;
6800 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
6801 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
6804 case kIOPMStatsHibernateImageRead
:
6806 gPMStats
.hibRead
.start
= nsec
;
6808 gPMStats
.hibRead
.stop
= nsec
;
6811 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
6812 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
6814 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
6815 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
6816 publishPMStats
->release();
6817 bzero(&gPMStats
, sizeof(gPMStats
));
6824 * Appends a record of the application response to
6825 * IOPMrootDomain::pmStatsAppResponses
6827 void IOPMrootDomain::pmStatsRecordApplicationResponse(
6828 const OSSymbol
*response
,
6834 IOPMPowerStateIndex powerState
)
6836 OSDictionary
*responseDescription
= NULL
;
6837 OSNumber
*delayNum
= NULL
;
6838 OSNumber
*powerCaps
= NULL
;
6839 OSNumber
*pidNum
= NULL
;
6840 OSNumber
*msgNum
= NULL
;
6841 const OSSymbol
*appname
;
6842 const OSSymbol
*sleep
= NULL
, *wake
= NULL
;
6843 IOPMServiceInterestNotifier
*notify
= 0;
6845 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
)))
6847 if (response
->isEqualTo(gIOPMStatsApplicationResponseTimedOut
))
6848 notify
->ackTimeoutCnt
++;
6850 notify
->ackTimeoutCnt
= 0;
6854 if (response
->isEqualTo(gIOPMStatsApplicationResponsePrompt
) ||
6855 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
))
6859 responseDescription
= OSDictionary::withCapacity(5);
6860 if (responseDescription
)
6863 responseDescription
->setObject(_statsResponseTypeKey
, response
);
6866 msgNum
= OSNumber::withNumber(messageType
, 32);
6868 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
6872 if (name
&& (strlen(name
) > 0))
6874 appname
= OSSymbol::withCString(name
);
6876 responseDescription
->setObject(_statsNameKey
, appname
);
6881 if (app_pid
!= -1) {
6882 pidNum
= OSNumber::withNumber(app_pid
, 32);
6884 responseDescription
->setObject(_statsPIDKey
, pidNum
);
6889 delayNum
= OSNumber::withNumber(delay_ms
, 32);
6891 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
6892 delayNum
->release();
6895 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
6896 powerCaps
= OSNumber::withNumber(powerState
, 32);
6898 #if !defined(__i386__) && !defined(__x86_64__)
6899 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
6901 powerState
, delay_ms
);
6906 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
6909 responseDescription
->setObject(_statsPowerCapsKey
, powerCaps
);
6910 powerCaps
->release();
6913 sleep
= OSSymbol::withCString("Sleep");
6914 wake
= OSSymbol::withCString("Wake");
6915 if (_systemTransitionType
== kSystemTransitionSleep
) {
6916 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
6918 else if (_systemTransitionType
== kSystemTransitionWake
) {
6919 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
6921 else if (_systemTransitionType
== kSystemTransitionCapability
) {
6922 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
6923 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
6924 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
6925 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
6927 if (sleep
) sleep
->release();
6928 if (wake
) wake
->release();
6932 IOLockLock(pmStatsLock
);
6933 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
6934 pmStatsAppResponses
->setObject(responseDescription
);
6936 IOLockUnlock(pmStatsLock
);
6938 responseDescription
->release();
6945 // MARK: PMTraceWorker
6947 //******************************************************************************
6948 // TracePoint support
6950 //******************************************************************************
6952 #define kIOPMRegisterNVRAMTracePointHandlerKey \
6953 "IOPMRegisterNVRAMTracePointHandler"
6955 IOReturn
IOPMrootDomain::callPlatformFunction(
6956 const OSSymbol
* functionName
,
6957 bool waitForFunction
,
6958 void * param1
, void * param2
,
6959 void * param3
, void * param4
)
6961 if (pmTracer
&& functionName
&&
6962 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
6963 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
6965 uint32_t tracePointPhases
, tracePointPCI
;
6966 uint64_t statusCode
;
6968 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
6969 pmTracer
->tracePointTarget
= (void *) param2
;
6970 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
6971 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
6972 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
6973 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
6975 MSG("Sleep failure code 0x%08x 0x%08x\n",
6976 tracePointPCI
, tracePointPhases
);
6978 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
6979 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
6981 return kIOReturnSuccess
;
6984 else if (functionName
&&
6985 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
6987 if (gSleepPolicyHandler
)
6988 return kIOReturnExclusiveAccess
;
6990 return kIOReturnBadArgument
;
6991 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
6992 gSleepPolicyTarget
= (void *) param2
;
6993 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
6994 return kIOReturnSuccess
;
6998 return super::callPlatformFunction(
6999 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
7002 void IOPMrootDomain::tracePoint( uint8_t point
)
7004 if (systemBooting
) return;
7006 if (kIOPMTracePointWakeCapabilityClients
== point
)
7007 acceptSystemWakeEvents(false);
7009 PMDebug(kPMLogSleepWakeTracePoint
, point
, 0);
7010 pmTracer
->tracePoint(point
);
7013 void IOPMrootDomain::tracePoint( uint8_t point
, uint8_t data
)
7015 if (systemBooting
) return;
7017 PMDebug(kPMLogSleepWakeTracePoint
, point
, data
);
7018 pmTracer
->tracePoint(point
, data
);
7021 void IOPMrootDomain::traceDetail( uint32_t detail
)
7024 pmTracer
->traceDetail( detail
);
7028 IOReturn
IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
7029 IOReportConfigureAction action
,
7034 if (action
!= kIOReportGetDimensions
) goto exit
;
7036 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7037 if ( (channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
7038 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
7039 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
) ) {
7040 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
7045 return super::configureReport(channelList
, action
, result
, destination
);
7049 IOReturn
IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
7050 IOReportUpdateAction action
,
7056 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
7057 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
7061 if (action
!= kIOReportCopyChannelData
) goto exit
;
7063 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7064 ch_id
= channelList
->channels
[cnt
].channel_id
;
7066 if ((ch_id
== kSleepCntChID
) ||
7067 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
7068 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
7072 if (ch_id
== kSleepCntChID
)
7073 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
7074 else if (ch_id
== kDarkWkCntChID
)
7075 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
7076 else if (ch_id
== kUserWkCntChID
)
7077 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
7079 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
7080 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
7081 dest
->appendBytes(data2cpy
, size2cpy
);
7085 return super::updateReport(channelList
, action
, result
, destination
);
7089 //******************************************************************************
7090 // PMTraceWorker Class
7092 //******************************************************************************
7095 #define super OSObject
7096 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
7098 #define kPMBestGuessPCIDevicesCount 25
7099 #define kPMMaxRTCBitfieldSize 32
7101 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
7105 me
= OSTypeAlloc( PMTraceWorker
);
7106 if (!me
|| !me
->init())
7111 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
));
7113 // Note that we cannot instantiate the PCI device -> bit mappings here, since
7114 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
7115 // this dictionary lazily.
7117 me
->pciDeviceBitMappings
= NULL
;
7118 me
->pciMappingLock
= IOLockAlloc();
7119 me
->tracePhase
= kIOPMTracePointSystemUp
;
7120 me
->loginWindowPhase
= 0;
7121 me
->traceData32
= 0;
7125 void PMTraceWorker::RTC_TRACE(void)
7127 if (tracePointHandler
&& tracePointTarget
)
7131 wordA
= (tracePhase
<< 24) | (loginWindowPhase
<< 16) |
7134 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
7135 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
7139 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
7141 const OSSymbol
* deviceName
;
7144 IOLockLock(pciMappingLock
);
7146 if (!pciDeviceBitMappings
)
7148 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
7149 if (!pciDeviceBitMappings
)
7153 // Check for bitmask overflow.
7154 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
7157 if ((deviceName
= pciDevice
->copyName()) &&
7158 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
7159 pciDeviceBitMappings
->setObject(deviceName
))
7161 index
= pciDeviceBitMappings
->getCount() - 1;
7162 _LOG("PMTrace PCI array: set object %s => %d\n",
7163 deviceName
->getCStringNoCopy(), index
);
7166 deviceName
->release();
7167 if (!addedToRegistry
&& (index
>= 0))
7168 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
7171 IOLockUnlock(pciMappingLock
);
7175 bool PMTraceWorker::serialize(OSSerialize
*s
) const
7178 if (pciDeviceBitMappings
)
7180 IOLockLock(pciMappingLock
);
7181 ok
= pciDeviceBitMappings
->serialize(s
);
7182 IOLockUnlock(pciMappingLock
);
7187 void PMTraceWorker::tracePoint(uint8_t phase
)
7189 // clear trace detail when phase begins
7190 if (tracePhase
!= phase
)
7195 DLOG("trace point 0x%02x\n", tracePhase
);
7199 void PMTraceWorker::tracePoint(uint8_t phase
, uint8_t data8
)
7201 // clear trace detail when phase begins
7202 if (tracePhase
!= phase
)
7208 DLOG("trace point 0x%02x 0x%02x\n", tracePhase
, traceData8
);
7212 void PMTraceWorker::traceDetail(uint32_t detail
)
7214 if (kIOPMTracePointSleepPriorityClients
!= tracePhase
)
7217 traceData32
= detail
;
7218 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7223 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
7225 loginWindowPhase
= phase
;
7227 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
7231 void PMTraceWorker::tracePCIPowerChange(
7232 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
7235 uint32_t expectedFlag
;
7237 // Ignore PCI changes outside of system sleep/wake.
7238 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
7239 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
7242 // Only record the WillChange transition when going to sleep,
7243 // and the DidChange on the way up.
7244 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
7245 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
7246 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
7247 if (changeFlags
!= expectedFlag
)
7250 // Mark this device off in our bitfield
7251 if (bitNum
< kPMMaxRTCBitfieldSize
)
7253 bitMask
= (1 << bitNum
);
7255 if (kPowerChangeStart
== type
)
7257 traceData32
|= bitMask
;
7258 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
7259 service
->getName(), bitNum
, bitMask
, traceData32
);
7263 traceData32
&= ~bitMask
;
7264 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
7265 service
->getName(), bitNum
, bitMask
, traceData32
);
7268 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7273 uint64_t PMTraceWorker::getPMStatusCode( )
7275 return (((uint64_t)traceData32
<< 32) | (tracePhase
<< 24) |
7276 (loginWindowPhase
<< 16) | (traceData8
<< 8));
7281 // MARK: PMHaltWorker
7283 //******************************************************************************
7284 // PMHaltWorker Class
7286 //******************************************************************************
7288 static unsigned int gPMHaltBusyCount
;
7289 static unsigned int gPMHaltIdleCount
;
7290 static int gPMHaltDepth
;
7291 static unsigned long gPMHaltEvent
;
7292 static IOLock
* gPMHaltLock
= 0;
7293 static OSArray
* gPMHaltArray
= 0;
7294 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
7296 PMHaltWorker
* PMHaltWorker::worker( void )
7302 me
= OSTypeAlloc( PMHaltWorker
);
7303 if (!me
|| !me
->init())
7306 me
->lock
= IOLockAlloc();
7310 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
7311 me
->retain(); // thread holds extra retain
7312 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
7317 thread_deallocate(thread
);
7322 if (me
) me
->release();
7326 void PMHaltWorker::free( void )
7328 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
7334 return OSObject::free();
7337 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
7339 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
7341 IOLockLock( gPMHaltLock
);
7343 me
->depth
= gPMHaltDepth
;
7344 IOLockUnlock( gPMHaltLock
);
7346 while (me
->depth
>= 0)
7348 PMHaltWorker::work( me
);
7350 IOLockLock( gPMHaltLock
);
7351 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
7353 // This is the last thread to finish work on this level,
7354 // inform everyone to start working on next lower level.
7356 me
->depth
= gPMHaltDepth
;
7357 gPMHaltIdleCount
= 0;
7358 thread_wakeup((event_t
) &gPMHaltIdleCount
);
7362 // One or more threads are still working on this level,
7363 // this thread must wait.
7364 me
->depth
= gPMHaltDepth
- 1;
7366 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
7367 } while (me
->depth
!= gPMHaltDepth
);
7369 IOLockUnlock( gPMHaltLock
);
7372 // No more work to do, terminate thread
7373 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
7374 thread_wakeup( &gPMHaltDepth
);
7378 void PMHaltWorker::work( PMHaltWorker
* me
)
7380 IOService
* service
;
7382 AbsoluteTime startTime
;
7391 // Claim an unit of work from the shared pool
7392 IOLockLock( gPMHaltLock
);
7393 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
7396 service
= (IOService
*)inner
->getAnyObject();
7400 inner
->removeObject(service
);
7403 IOLockUnlock( gPMHaltLock
);
7405 break; // no more work at this depth
7407 clock_get_uptime(&startTime
);
7409 if (!service
->isInactive() &&
7410 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
7412 IOLockLock(me
->lock
);
7413 me
->startTime
= startTime
;
7414 me
->service
= service
;
7415 me
->timeout
= false;
7416 IOLockUnlock(me
->lock
);
7418 service
->systemWillShutdown( gPMHaltEvent
);
7420 // Wait for driver acknowledgement
7421 IOLockLock(me
->lock
);
7422 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
7424 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
7427 timeout
= me
->timeout
;
7428 IOLockUnlock(me
->lock
);
7431 deltaTime
= computeDeltaTimeMS(&startTime
);
7432 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
7433 (gIOKitDebug
& kIOLogPMRootDomain
))
7435 LOG("%s driver %s (%p) took %u ms\n",
7436 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
7437 "PowerOff" : "Restart",
7438 service
->getName(), OBFUSCATE(service
),
7439 (uint32_t) deltaTime
);
7447 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
7450 AbsoluteTime startTime
;
7451 AbsoluteTime endTime
;
7455 IOLockLock(me
->lock
);
7456 if (me
->service
&& !me
->timeout
)
7458 startTime
= me
->startTime
;
7460 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
7462 SUB_ABSOLUTETIME(&endTime
, &startTime
);
7463 absolutetime_to_nanoseconds(endTime
, &nano
);
7465 if (nano
> 3000000000ULL)
7468 MSG("%s still waiting on %s\n",
7469 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
7470 "PowerOff" : "Restart",
7471 me
->service
->getName());
7474 IOLockUnlock(me
->lock
);
7478 //******************************************************************************
7479 // acknowledgeSystemWillShutdown
7481 // Acknowledgement from drivers that they have prepared for shutdown/restart.
7482 //******************************************************************************
7484 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
7486 PMHaltWorker
* worker
;
7492 //DLOG("%s acknowledged\n", from->getName());
7493 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
7496 worker
= (PMHaltWorker
*) prop
;
7497 IOLockLock(worker
->lock
);
7498 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
7499 thread_wakeup((event_t
) worker
);
7500 IOLockUnlock(worker
->lock
);
7505 DLOG("%s acknowledged without worker property\n",
7511 //******************************************************************************
7512 // notifySystemShutdown
7514 // Notify all objects in PM tree that system will shutdown or restart
7515 //******************************************************************************
7518 notifySystemShutdown( IOService
* root
, unsigned long event
)
7520 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
7521 IORegistryIterator
* iter
;
7522 IORegistryEntry
* entry
;
7525 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
7526 AbsoluteTime deadline
;
7527 unsigned int totalNodes
= 0;
7529 unsigned int rootDepth
;
7530 unsigned int numWorkers
;
7536 DLOG("%s event = %lx\n", __FUNCTION__
, event
);
7538 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
7540 // Iterate the entire PM tree starting from root
7542 rootDepth
= root
->getDepth( gIOPowerPlane
);
7543 if (!rootDepth
) goto done
;
7545 // debug - for repeated test runs
7546 while (PMHaltWorker::metaClass
->getInstanceCount())
7551 gPMHaltArray
= OSArray::withCapacity(40);
7552 if (!gPMHaltArray
) goto done
;
7555 gPMHaltArray
->flushCollection();
7559 gPMHaltLock
= IOLockAlloc();
7560 if (!gPMHaltLock
) goto done
;
7563 if (!gPMHaltClientAcknowledgeKey
)
7565 gPMHaltClientAcknowledgeKey
=
7566 OSSymbol::withCStringNoCopy("PMShutdown");
7567 if (!gPMHaltClientAcknowledgeKey
) goto done
;
7570 gPMHaltEvent
= event
;
7572 // Depth-first walk of PM plane
7574 iter
= IORegistryIterator::iterateOver(
7575 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
7579 while ((entry
= iter
->getNextObject()))
7581 node
= OSDynamicCast(IOService
, entry
);
7586 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
7589 depth
= node
->getDepth( gIOPowerPlane
);
7590 if (depth
<= rootDepth
)
7595 // adjust to zero based depth
7596 depth
-= (rootDepth
+ 1);
7598 // gPMHaltArray is an array of containers, each container
7599 // refers to nodes with the same depth.
7601 count
= gPMHaltArray
->getCount();
7602 while (depth
>= count
)
7604 // expand array and insert placeholders
7605 gPMHaltArray
->setObject(PLACEHOLDER
);
7608 count
= gPMHaltArray
->getCount();
7611 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
7612 if (inner
== PLACEHOLDER
)
7614 inner
= OSSet::withCapacity(40);
7617 gPMHaltArray
->replaceObject(depth
, inner
);
7622 // PM nodes that appear more than once in the tree will have
7623 // the same depth, OSSet will refuse to add the node twice.
7625 ok
= inner
->setObject(node
);
7628 DLOG("Skipped PM node %s\n", node
->getName());
7634 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
7637 if (inner
!= PLACEHOLDER
)
7638 count
= inner
->getCount();
7639 DLOG("Nodes at depth %u = %u\n", i
, count
);
7642 // strip placeholders (not all depths are populated)
7644 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
7646 if (inner
== PLACEHOLDER
)
7648 gPMHaltArray
->removeObject(i
);
7651 count
= inner
->getCount();
7652 if (count
> numWorkers
)
7654 totalNodes
+= count
;
7658 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
7661 gPMHaltBusyCount
= 0;
7662 gPMHaltIdleCount
= 0;
7663 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
7665 // Create multiple workers (and threads)
7667 if (numWorkers
> kPMHaltMaxWorkers
)
7668 numWorkers
= kPMHaltMaxWorkers
;
7670 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
7671 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
7673 for (unsigned int i
= 0; i
< numWorkers
; i
++)
7674 workers
[i
] = PMHaltWorker::worker();
7676 // Wait for workers to exhaust all available work
7678 IOLockLock(gPMHaltLock
);
7679 while (gPMHaltDepth
>= 0)
7681 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
7683 waitResult
= IOLockSleepDeadline(
7684 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
7685 if (THREAD_TIMED_OUT
== waitResult
)
7688 clock_get_uptime(&now
);
7690 IOLockUnlock(gPMHaltLock
);
7691 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
7694 PMHaltWorker::checkTimeout(workers
[i
], &now
);
7696 IOLockLock(gPMHaltLock
);
7699 IOLockUnlock(gPMHaltLock
);
7701 // Release all workers
7703 for (unsigned int i
= 0; i
< numWorkers
; i
++)
7706 workers
[i
]->release();
7707 // worker also retained by it's own thread
7711 DLOG("%s done\n", __FUNCTION__
);
7716 // MARK: Kernel Assertion
7718 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7720 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
7721 IOPMDriverAssertionType whichAssertionBits
,
7722 IOPMDriverAssertionLevel assertionLevel
,
7723 IOService
*ownerService
,
7724 const char *ownerDescription
)
7727 IOPMDriverAssertionID newAssertion
;
7732 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
7734 if (kIOReturnSuccess
== ret
)
7735 return newAssertion
;
7740 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
7743 return kIOReturnInternalError
;
7745 return pmAssertions
->releaseAssertion(releaseAssertion
);
7749 IOReturn
IOPMrootDomain::setPMAssertionLevel(
7750 IOPMDriverAssertionID assertionID
,
7751 IOPMDriverAssertionLevel assertionLevel
)
7753 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
7756 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
7758 IOPMDriverAssertionType sysLevels
;
7760 if (!pmAssertions
|| whichAssertion
== 0)
7761 return kIOPMDriverAssertionLevelOff
;
7763 sysLevels
= pmAssertions
->getActivatedAssertions();
7765 // Check that every bit set in argument 'whichAssertion' is asserted
7766 // in the aggregate bits.
7767 if ((sysLevels
& whichAssertion
) == whichAssertion
)
7768 return kIOPMDriverAssertionLevelOn
;
7770 return kIOPMDriverAssertionLevelOff
;
7773 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
7776 return kIOReturnNotFound
;
7778 return pmAssertions
->setUserAssertionLevels(inLevels
);
7781 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
7785 pmAssertions
->publishProperties();
7787 return( IOService::serializeProperties(s
) );
7790 OSObject
* IOPMrootDomain::copyProperty( const char * aKey
) const
7792 OSObject
*obj
= NULL
;
7793 obj
= IOService::copyProperty(aKey
);
7795 if (obj
) return obj
;
7797 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
7798 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
7799 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
)
7800 return OSBoolean::withBoolean(true);
7802 return OSBoolean::withBoolean(false);
7806 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
7807 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
7808 if (swd_flags
& SWD_VALID_LOGS
)
7809 return OSBoolean::withBoolean(true);
7811 return OSBoolean::withBoolean(false);
7816 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
7817 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
7818 * issued by DisplayWrangler on darkwake.
7820 if (!strcmp(aKey
, "DesktopMode")) {
7822 return OSBoolean::withBoolean(true);
7824 return OSBoolean::withBoolean(false);
7826 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
7827 if (displayIdleForDemandSleep
) {
7828 return OSBoolean::withBoolean(true);
7831 return OSBoolean::withBoolean(false);
7835 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
))
7837 OSArray
* array
= 0;
7839 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount())
7840 array
= OSArray::withArray(_systemWakeEventsArray
);
7845 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
))
7847 OSArray
* array
= 0;
7848 IOLockLock(pmStatsLock
);
7849 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
7850 array
= OSArray::withArray(pmStatsAppResponses
);
7851 pmStatsAppResponses
->flushCollection();
7853 IOLockUnlock(pmStatsLock
);
7861 // MARK: Wake Event Reporting
7863 void IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
7866 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
7870 //******************************************************************************
7871 // acceptSystemWakeEvents
7873 // Private control for the acceptance of driver wake event claims.
7874 //******************************************************************************
7876 void IOPMrootDomain::acceptSystemWakeEvents( bool accept
)
7878 bool logWakeReason
= false;
7883 gWakeReasonString
[0] = '\0';
7884 if (!_systemWakeEventsArray
)
7885 _systemWakeEventsArray
= OSArray::withCapacity(4);
7886 if ((_acceptSystemWakeEvents
= (_systemWakeEventsArray
!= 0)))
7887 _systemWakeEventsArray
->flushCollection();
7891 _acceptSystemWakeEvents
= false;
7896 MSG("system wake events:%s\n", gWakeReasonString
);
7899 //******************************************************************************
7900 // claimSystemWakeEvent
7902 // For a driver to claim a device is the source/conduit of a system wake event.
7903 //******************************************************************************
7905 void IOPMrootDomain::claimSystemWakeEvent(
7908 const char * reason
,
7909 OSObject
* details
)
7911 const OSSymbol
* deviceName
= 0;
7912 OSNumber
* deviceRegId
= 0;
7913 OSNumber
* claimTime
= 0;
7914 OSData
* flagsData
= 0;
7915 OSString
* reasonString
= 0;
7916 OSDictionary
* d
= 0;
7920 pmEventTimeStamp(×tamp
);
7922 if (!device
|| !reason
) return;
7924 deviceName
= device
->copyName(gIOServicePlane
);
7925 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
7926 claimTime
= OSNumber::withNumber(timestamp
, 64);
7927 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
7928 reasonString
= OSString::withCString(reason
);
7929 d
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
7930 if (!deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
)
7933 d
->setObject(gIONameKey
, deviceName
);
7934 d
->setObject(gIORegistryEntryIDKey
, deviceRegId
);
7935 d
->setObject(kIOPMWakeEventTimeKey
, claimTime
);
7936 d
->setObject(kIOPMWakeEventFlagsKey
, flagsData
);
7937 d
->setObject(kIOPMWakeEventReasonKey
, reasonString
);
7939 d
->setObject(kIOPMWakeEventDetailsKey
, details
);
7942 if (!gWakeReasonSysctlRegistered
)
7944 // Lazy registration until the platform driver stops registering
7946 gWakeReasonSysctlRegistered
= true;
7948 if (_acceptSystemWakeEvents
)
7950 ok
= _systemWakeEventsArray
->setObject(d
);
7951 if (gWakeReasonString
[0] != '\0')
7952 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
7953 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
7958 if (deviceName
) deviceName
->release();
7959 if (deviceRegId
) deviceRegId
->release();
7960 if (claimTime
) claimTime
->release();
7961 if (flagsData
) flagsData
->release();
7962 if (reasonString
) reasonString
->release();
7963 if (d
) d
->release();
7966 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7969 // MARK: PMSettingHandle
7971 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
7973 void PMSettingHandle::free( void )
7977 pmso
->clientHandleFreed();
7986 // MARK: PMSettingObject
7989 #define super OSObject
7990 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
7993 * Static constructor/initializer for PMSettingObject
7995 PMSettingObject
*PMSettingObject::pmSettingObject(
7996 IOPMrootDomain
*parent_arg
,
7997 IOPMSettingControllerCallback handler_arg
,
7998 OSObject
*target_arg
,
7999 uintptr_t refcon_arg
,
8000 uint32_t supportedPowerSources
,
8001 const OSSymbol
* settings
[],
8002 OSObject
**handle_obj
)
8004 uint32_t settingCount
= 0;
8005 PMSettingObject
*pmso
= 0;
8006 PMSettingHandle
*pmsh
= 0;
8008 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
8011 // count OSSymbol entries in NULL terminated settings array
8012 while (settings
[settingCount
]) {
8015 if (0 == settingCount
)
8018 pmso
= new PMSettingObject
;
8019 if (!pmso
|| !pmso
->init())
8022 pmsh
= new PMSettingHandle
;
8023 if (!pmsh
|| !pmsh
->init())
8026 queue_init(&pmso
->calloutQueue
);
8027 pmso
->parent
= parent_arg
;
8028 pmso
->func
= handler_arg
;
8029 pmso
->target
= target_arg
;
8030 pmso
->refcon
= refcon_arg
;
8031 pmso
->settingCount
= settingCount
;
8033 pmso
->retain(); // handle holds a retain on pmso
8037 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
8038 if (pmso
->publishedFeatureID
) {
8039 for (unsigned int i
=0; i
<settingCount
; i
++) {
8040 // Since there is now at least one listener to this setting, publish
8041 // PM root domain support for it.
8042 parent_arg
->publishPMSetting( settings
[i
],
8043 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
8051 if (pmso
) pmso
->release();
8052 if (pmsh
) pmsh
->release();
8056 void PMSettingObject::free( void )
8058 if (publishedFeatureID
) {
8059 for (uint32_t i
=0; i
<settingCount
; i
++) {
8060 if (publishedFeatureID
[i
]) {
8061 parent
->removePublishedFeature( publishedFeatureID
[i
] );
8065 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
8071 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
8073 (*func
)(target
, type
, object
, refcon
);
8076 void PMSettingObject::clientHandleFreed( void )
8078 parent
->deregisterPMSettingObject(this);
8082 // MARK: PMAssertionsTracker
8084 //*********************************************************************************
8085 //*********************************************************************************
8086 //*********************************************************************************
8087 // class PMAssertionsTracker Implementation
8089 #define kAssertUniqueIDStart 500
8091 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
8093 PMAssertionsTracker
*myself
;
8095 myself
= new PMAssertionsTracker
;
8099 myself
->owner
= rootDomain
;
8100 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
8101 myself
->assertionsArray
= OSArray::withCapacity(5);
8102 myself
->assertionsKernel
= 0;
8103 myself
->assertionsUser
= 0;
8104 myself
->assertionsCombined
= 0;
8105 myself
->assertionsArrayLock
= IOLockAlloc();
8106 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
8108 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
8116 * - Update assertionsKernel to reflect the state of all
8117 * assertions in the kernel.
8118 * - Update assertionsCombined to reflect both kernel & user space.
8120 void PMAssertionsTracker::tabulate(void)
8124 PMAssertStruct
*_a
= NULL
;
8127 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
8128 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
8132 assertionsKernel
= 0;
8133 assertionsCombined
= 0;
8135 if (!assertionsArray
)
8138 if ((count
= assertionsArray
->getCount()))
8140 for (i
=0; i
<count
; i
++)
8142 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8145 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8146 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
8147 assertionsKernel
|= _a
->assertionBits
;
8152 tabulateProducerCount
++;
8153 assertionsCombined
= assertionsKernel
| assertionsUser
;
8155 if ((assertionsKernel
!= oldKernel
) ||
8156 (assertionsCombined
!= oldCombined
))
8158 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
8162 void PMAssertionsTracker::publishProperties( void )
8164 OSArray
*assertionsSummary
= NULL
;
8166 if (tabulateConsumerCount
!= tabulateProducerCount
)
8168 IOLockLock(assertionsArrayLock
);
8170 tabulateConsumerCount
= tabulateProducerCount
;
8172 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8174 assertionsSummary
= copyAssertionsArray();
8175 if (assertionsSummary
)
8177 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
8178 assertionsSummary
->release();
8182 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
8185 /* Publish the IOPMrootDomain property "DriverPMAssertions"
8187 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
8189 IOLockUnlock(assertionsArrayLock
);
8193 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
8195 PMAssertStruct
*_a
= NULL
;
8202 && (count
= assertionsArray
->getCount()))
8204 for (i
=0; i
<count
; i
++)
8206 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8209 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8210 if (_a
&& (_id
== _a
->id
)) {
8227 /* PMAssertionsTracker::handleCreateAssertion
8228 * Perform assertion work on the PM workloop. Do not call directly.
8230 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
8236 IOLockLock(assertionsArrayLock
);
8237 assertionsArray
->setObject(newAssertion
);
8238 IOLockUnlock(assertionsArrayLock
);
8239 newAssertion
->release();
8243 return kIOReturnSuccess
;
8246 /* PMAssertionsTracker::createAssertion
8247 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
8250 IOReturn
PMAssertionsTracker::createAssertion(
8251 IOPMDriverAssertionType which
,
8252 IOPMDriverAssertionLevel level
,
8253 IOService
*serviceID
,
8254 const char *whoItIs
,
8255 IOPMDriverAssertionID
*outID
)
8257 OSData
*dataStore
= NULL
;
8258 PMAssertStruct track
;
8260 // Warning: trillions and trillions of created assertions may overflow the unique ID.
8261 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
8262 track
.level
= level
;
8263 track
.assertionBits
= which
;
8264 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
):0;
8265 track
.ownerService
= serviceID
;
8266 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
8267 track
.modifiedTime
= 0;
8268 pmEventTimeStamp(&track
.createdTime
);
8270 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
8273 if (track
.ownerString
)
8274 track
.ownerString
->release();
8275 return kIOReturnNoMemory
;
8280 if (owner
&& owner
->pmPowerStateQueue
) {
8281 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
8284 return kIOReturnSuccess
;
8287 /* PMAssertionsTracker::handleReleaseAssertion
8288 * Runs in PM workloop. Do not call directly.
8290 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
8291 IOPMDriverAssertionID _id
)
8296 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
8299 return kIOReturnNotFound
;
8301 IOLockLock(assertionsArrayLock
);
8302 if (assertStruct
->ownerString
)
8303 assertStruct
->ownerString
->release();
8305 assertionsArray
->removeObject(index
);
8306 IOLockUnlock(assertionsArrayLock
);
8309 return kIOReturnSuccess
;
8312 /* PMAssertionsTracker::releaseAssertion
8313 * Releases an assertion and affects system behavior if appropiate.
8314 * Actual work happens on PM workloop.
8316 IOReturn
PMAssertionsTracker::releaseAssertion(
8317 IOPMDriverAssertionID _id
)
8319 if (owner
&& owner
->pmPowerStateQueue
) {
8320 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
8322 return kIOReturnSuccess
;
8325 /* PMAssertionsTracker::handleSetAssertionLevel
8326 * Runs in PM workloop. Do not call directly.
8328 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
8329 IOPMDriverAssertionID _id
,
8330 IOPMDriverAssertionLevel _level
)
8332 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
8336 if (!assertStruct
) {
8337 return kIOReturnNotFound
;
8340 IOLockLock(assertionsArrayLock
);
8341 pmEventTimeStamp(&assertStruct
->modifiedTime
);
8342 assertStruct
->level
= _level
;
8343 IOLockUnlock(assertionsArrayLock
);
8346 return kIOReturnSuccess
;
8349 /* PMAssertionsTracker::setAssertionLevel
8351 IOReturn
PMAssertionsTracker::setAssertionLevel(
8352 IOPMDriverAssertionID _id
,
8353 IOPMDriverAssertionLevel _level
)
8355 if (owner
&& owner
->pmPowerStateQueue
) {
8356 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
8357 (void *)(uintptr_t)_level
, _id
);
8360 return kIOReturnSuccess
;
8363 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
8365 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
8369 if (new_user_levels
!= assertionsUser
)
8371 assertionsUser
= new_user_levels
;
8372 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
8376 return kIOReturnSuccess
;
8379 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
8380 IOPMDriverAssertionType new_user_levels
)
8382 if (gIOPMWorkLoop
) {
8383 gIOPMWorkLoop
->runAction(
8384 OSMemberFunctionCast(
8387 &PMAssertionsTracker::handleSetUserAssertionLevels
),
8389 (void *) &new_user_levels
, 0, 0, 0);
8392 return kIOReturnSuccess
;
8396 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
8400 OSArray
*outArray
= NULL
;
8402 if (!assertionsArray
||
8403 (0 == (count
= assertionsArray
->getCount())) ||
8404 (NULL
== (outArray
= OSArray::withCapacity(count
))))
8409 for (i
=0; i
<count
; i
++)
8411 PMAssertStruct
*_a
= NULL
;
8413 OSDictionary
*details
= NULL
;
8415 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8416 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
8418 OSNumber
*_n
= NULL
;
8420 details
= OSDictionary::withCapacity(7);
8424 outArray
->setObject(details
);
8427 _n
= OSNumber::withNumber(_a
->id
, 64);
8429 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
8432 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
8434 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
8437 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
8439 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
8442 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
8444 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
);
8447 _n
= OSNumber::withNumber(_a
->level
, 64);
8449 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
8452 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
8454 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
8458 if (_a
->ownerString
) {
8459 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
8468 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
8470 return assertionsCombined
;
8473 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
8474 IOPMDriverAssertionType type
)
8476 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
8478 return kIOPMDriverAssertionLevelOn
;
8480 return kIOPMDriverAssertionLevelOff
;
8484 //*********************************************************************************
8485 //*********************************************************************************
8486 //*********************************************************************************
8489 static void pmEventTimeStamp(uint64_t *recordTS
)
8497 // We assume tsec fits into 32 bits; 32 bits holds enough
8498 // seconds for 136 years since the epoch in 1970.
8499 clock_get_calendar_microtime(&tsec
, &tusec
);
8502 // Pack the sec & microsec calendar time into a uint64_t, for fun.
8504 *recordTS
|= (uint32_t)tusec
;
8505 *recordTS
|= ((uint64_t)tsec
<< 32);
8511 // MARK: IORootParent
8513 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8515 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
8517 // The reason that root domain needs a root parent is to facilitate demand
8518 // sleep, since a power change from the root parent cannot be vetoed.
8520 // The above statement is no longer true since root domain now performs
8521 // demand sleep using overrides. But root parent remains to avoid changing
8522 // the power tree stacking. Root parent is parked at the max power state.
8525 static IOPMPowerState patriarchPowerStates
[2] =
8527 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
8528 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
8531 void IORootParent::initialize( void )
8535 bool IORootParent::start( IOService
* nub
)
8537 IOService::start(nub
);
8538 attachToParent( getRegistryRoot(), gIOPowerPlane
);
8540 registerPowerDriver(this, patriarchPowerStates
, 2);
8545 void IORootParent::shutDownSystem( void )
8549 void IORootParent::restartSystem( void )
8553 void IORootParent::sleepSystem( void )
8557 void IORootParent::dozeSystem( void )
8561 void IORootParent::sleepToDoze( void )
8565 void IORootParent::wakeSystem( void )
8569 OSObject
* IORootParent::copyProperty( const char * aKey
) const
8571 return (IOService::copyProperty(aKey
));
8575 #if defined(__i386__) || defined(__x86_64__)
8576 IOReturn
IOPMrootDomain::restartWithStackshot()
8578 if ((swd_flags
& SWD_WDOG_ENABLED
) == 0)
8579 return kIOReturnError
;
8581 takeStackshot(true, true);
8583 return kIOReturnSuccess
;
8586 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
8588 takeStackshot(wdogTrigger
, false);
8591 void IOPMrootDomain::takeStackshot(bool wdogTrigger
, bool isOSXWatchdog
)
8593 swd_hdr
* hdr
= NULL
;
8595 uint32_t wdog_panic
= 0;
8602 uint32_t bytesRemaining
;
8604 OSString
* UUIDstring
= NULL
;
8606 IOMemoryMap
* logBufMap
= NULL
;
8608 swd_stackshot_hdr
*stackshotHdr
= NULL
;
8609 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
8613 if (PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
)) &&
8614 (wdog_panic
== 1)) {
8615 // If boot-arg is set to panic on sleep/wake hang, call panic
8616 panic("Sleep/Wake hang detected\n");
8619 else if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
8620 // If current boot is due to this watch dog trigger restart in previous boot,
8621 // then don't trigger again until at least 1 successful sleep & wake.
8622 sleepCnt
= displayWakeCnt
= 1;
8623 if (!(sleepCnt
&& displayWakeCnt
)) {
8624 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
8625 PEHaltRestart(kPEHaltCPU
);
8632 if (sleepWakeDebugIsWdogEnabled() == false)
8635 if (swd_buffer
== NULL
) {
8636 sleepWakeDebugMemAlloc();
8637 if (swd_buffer
== NULL
) return;
8640 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
8644 hdr
= (swd_hdr
*)swd_buffer
;
8645 memset(hdr
->UUID
, 0x20, sizeof(hdr
->UUID
));
8646 if ((UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
8648 if (wdogTrigger
|| (!UUIDstring
->isEqualTo(hdr
->UUID
))) {
8649 const char *str
= UUIDstring
->getCStringNoCopy();
8650 snprintf(hdr
->UUID
, sizeof(hdr
->UUID
), "UUID: %s", str
);
8653 DLOG("Data for current UUID already exists\n");
8658 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
8659 bytesRemaining
= SWD_BUF_SIZE
- hdr
->spindump_offset
;
8661 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
8662 hdr
->is_osx_watchdog
= isOSXWatchdog
;
8664 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
8666 while (bytesRemaining
> sizeof(swd_stackshot_hdr
)) {
8668 stackshotHdr
= (swd_stackshot_hdr
*)dstAddr
;
8669 stackshotHdr
->magic
= SWD_STACKSHOTHDR_MAGIC
;
8670 stackshotHdr
->size
= 0;
8671 bytesRemaining
-= sizeof(swd_stackshot_hdr
);
8672 dstAddr
+= sizeof(swd_stackshot_hdr
);
8674 if (isOSXWatchdog
) {
8676 size
= bytesRemaining
;
8677 flags
= STACKSHOT_SAVE_LOADINFO
| STACKSHOT_SAVE_KEXT_LOADINFO
;
8679 else if (cnt
== 0) {
8681 * Take stackshot of all process on first sample. Size is restricted
8682 * to SWD_INITIAL_STACK_SIZE
8685 size
= (bytesRemaining
> SWD_INITIAL_STACK_SIZE
) ? SWD_INITIAL_STACK_SIZE
: bytesRemaining
;
8686 flags
= STACKSHOT_SAVE_LOADINFO
| STACKSHOT_SAVE_KEXT_LOADINFO
|STACKSHOT_SAVE_KERNEL_FRAMES_ONLY
;
8689 /* Take sample of kernel threads only */
8691 size
= bytesRemaining
;
8695 stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, &stackshotHdr
->size
);
8697 dstAddr
+= stackshotHdr
->size
;
8698 bytesRemaining
-= stackshotHdr
->size
;
8700 DLOG("Sample: %d size: %d bytesRemaining: %d\n", cnt
, stackshotHdr
->size
, bytesRemaining
);
8701 if ((stackshotHdr
->size
== 0) || (++cnt
== 10))
8703 IOSleep(10); // 10 ms
8706 hdr
->spindump_size
= (SWD_BUF_SIZE
- bytesRemaining
- hdr
->spindump_offset
);
8709 memset(hdr
->cps
, 0x20, sizeof(hdr
->cps
));
8710 snprintf(hdr
->cps
, sizeof(hdr
->cps
), "\ncps: %d", ((IOService
*)this)->getPowerState());
8711 code
= pmTracer
->getPMStatusCode();
8712 memset(hdr
->PMStatusCode
, 0x20, sizeof(hdr
->PMStatusCode
));
8713 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: %08x %08x",
8714 (uint32_t)((code
>> 32) & 0xffffffff), (uint32_t)(code
& 0xffffffff));
8715 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
8716 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
8719 data
[0] = round_page(sizeof(swd_hdr
) + hdr
->spindump_size
);
8720 /* Header & rootdomain log is constantly changing and is not covered by CRC */
8721 data
[1] = hdr
->crc
= crc32(0, ((char*)swd_buffer
+hdr
->spindump_offset
), hdr
->spindump_size
);
8722 data
[2] = kvtophys((vm_offset_t
)swd_buffer
);
8723 len
= sizeof(addr64_t
)*3;
8724 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
8725 data
[0], data
[1], data
[2]);
8727 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey
, data
, len
) == false)
8729 DLOG("Failed to update nvram boot-args\n");
8735 gRootDomain
->swd_lock
= 0;
8738 IOLog("Restarting to collect Sleep wake debug logs\n");
8739 PEHaltRestart(kPERestartCPU
);
8742 logBufMap
= sleepWakeDebugRetrieve();
8744 sleepWakeDebugDumpFromMem(logBufMap
);
8745 logBufMap
->release();
8751 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
8753 vm_size_t size
= SWD_BUF_SIZE
;
8755 swd_hdr
*hdr
= NULL
;
8757 IOBufferMemoryDescriptor
*memDesc
= NULL
;
8760 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
8763 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
8766 // Try allocating above 4GB. If that fails, try at 2GB
8767 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
8768 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
8769 size
, 0xFFFFFFFF00000000ULL
);
8771 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
8772 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
8773 size
, 0xFFFFFFFF10000000ULL
);
8776 if (memDesc
== NULL
)
8778 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
8783 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
8784 memset(hdr
, 0, sizeof(swd_hdr
));
8786 hdr
->signature
= SWD_HDR_SIGNATURE
;
8787 hdr
->alloc_size
= size
;
8789 hdr
->spindump_offset
= sizeof(swd_hdr
);
8790 swd_buffer
= (void *)hdr
;
8791 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
8794 gRootDomain
->swd_lock
= 0;
8797 void IOPMrootDomain::sleepWakeDebugEnableWdog()
8799 swd_flags
|= SWD_WDOG_ENABLED
;
8801 sleepWakeDebugMemAlloc();
8804 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
8806 return ((swd_flags
& SWD_WDOG_ENABLED
) &&
8807 !systemBooting
&& !systemShutdown
);
8810 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
8812 struct vnode
*vp
= NULL
;
8813 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
8814 kauth_cred_t cred
= vfs_context_ucred(ctx
);
8815 struct vnode_attr va
;
8816 errno_t error
= EIO
;
8818 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
8819 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
8821 IOLog("Failed to open the file %s\n", name
);
8825 VATTR_WANTED(&va
, va_nlink
);
8826 /* Don't dump to non-regular files or files with links. */
8827 if (vp
->v_type
!= VREG
||
8828 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
8829 IOLog("Bailing as this is not a regular file\n");
8833 VATTR_SET(&va
, va_data_size
, 0);
8834 vnode_setattr(vp
, &va
, ctx
);
8837 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
8838 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, vfs_context_proc(ctx
));
8840 IOLog("Failed to save sleep wake log. err 0x%x\n", error
);
8842 DLOG("Saved %d bytes to file %s\n",len
, name
);
8845 if (vp
) vnode_close(vp
, FWRITE
, ctx
);
8846 if (ctx
) vfs_context_rele(ctx
);
8852 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
8853 struct vnode
*srcVp
,
8854 vfs_context_t srcCtx
,
8855 char *tmpBuf
, uint64_t tmpBufSize
,
8857 const char *dstFname
,
8861 struct vnode
*vp
= NULL
;
8862 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
8863 struct vnode_attr va
;
8864 errno_t error
= EIO
;
8865 uint64_t bytesToRead
, bytesToWrite
;
8866 uint64_t readFileOffset
, writeFileOffset
, srcDataOffset
;
8867 uint32_t newcrc
= 0;
8869 if (vnode_open(dstFname
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
8870 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
8872 DLOG("Failed to open the file %s\n", dstFname
);
8876 VATTR_WANTED(&va
, va_nlink
);
8877 /* Don't dump to non-regular files or files with links. */
8878 if (vp
->v_type
!= VREG
||
8879 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
8880 DLOG("Bailing as this is not a regular file\n");
8884 VATTR_SET(&va
, va_data_size
, 0);
8885 vnode_setattr(vp
, &va
, ctx
);
8887 writeFileOffset
= 0;
8889 bytesToRead
= (round_page(numBytes
) > tmpBufSize
) ? tmpBufSize
: round_page(numBytes
);
8890 readFileOffset
= trunc_page(srcOffset
);
8892 DLOG("Read file (numBytes:0x%llx)\n", bytesToRead
);
8893 error
= vn_rdwr(UIO_READ
, srcVp
, tmpBuf
, bytesToRead
, readFileOffset
,
8894 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
8895 vfs_context_ucred(srcCtx
), (int *) 0,
8896 vfs_context_proc(srcCtx
));
8898 DLOG("Failed to read file(numBytes:0x%llx)\n", bytesToRead
);
8902 srcDataOffset
= (uint64_t)tmpBuf
+ (srcOffset
- readFileOffset
);
8903 bytesToWrite
= bytesToRead
- (srcOffset
- readFileOffset
);
8904 if (bytesToWrite
> numBytes
) bytesToWrite
= numBytes
;
8907 newcrc
= crc32(newcrc
, (void *)srcDataOffset
, bytesToWrite
);
8909 error
= vn_rdwr(UIO_WRITE
, vp
, (char *)srcDataOffset
, bytesToWrite
, writeFileOffset
,
8910 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
8911 vfs_context_ucred(ctx
), (int *) 0,
8912 vfs_context_proc(ctx
));
8914 DLOG("Failed to write file(numBytes:0x%llx)\n", bytesToWrite
);
8918 writeFileOffset
+= bytesToWrite
;
8919 numBytes
-= bytesToWrite
;
8920 srcOffset
+= bytesToWrite
;
8923 if (crc
!= newcrc
) {
8924 swd_stackshot_hdr
*shdr
= (swd_stackshot_hdr
*)tmpBuf
;;
8926 /* Set statckshot size to 0 if crc doesn't match */
8927 shdr
->magic
= SWD_STACKSHOTHDR_MAGIC
;
8930 assert(tmpBufSize
> sizeof(swd_stackshot_hdr
));
8931 bytesToWrite
= round_page(sizeof(swd_stackshot_hdr
));
8932 vn_rdwr(UIO_WRITE
, vp
, (char *)tmpBuf
, bytesToWrite
, 0,
8933 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
8934 vfs_context_ucred(ctx
), (int *) 0,
8935 vfs_context_proc(ctx
));
8937 DLOG("CRC check failed. expected:0x%x actual:0x%x\n", crc
, newcrc
);
8942 error
= vnode_close(vp
, FWRITE
, ctx
);
8943 DLOG("vnode_close returned 0x%x\n", error
);
8945 if (ctx
) vfs_context_rele(ctx
);
8953 void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
8957 char hibernateFilename
[MAXPATHLEN
+1];
8958 char PMStatusCode
[100];
8960 swd_hdr
*hdr
= NULL
;
8961 uint32_t stacksSize
, logSize
;
8962 uint64_t tmpBufSize
;
8963 uint64_t hdrOffset
, stacksOffset
, logOffset
;
8964 errno_t error
= EIO
;
8965 OSObject
*obj
= NULL
;
8966 OSString
*str
= NULL
;
8967 OSNumber
*failStat
= NULL
;
8968 struct vnode
*vp
= NULL
;
8969 vfs_context_t ctx
= NULL
;
8971 struct vnode_attr va
;
8972 IOBufferMemoryDescriptor
*tmpBufDesc
= NULL
;
8973 IOHibernateImageHeader
*imageHdr
;
8975 DLOG("sleepWakeDebugDumpFromFile\n");
8976 if ((swd_flags
& SWD_LOGS_IN_FILE
) == 0)
8979 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
8983 hibernateFilename
[0] = 0;
8984 if ((obj
= copyProperty(kIOHibernateFileKey
)))
8986 if ((str
= OSDynamicCast(OSString
, obj
)))
8987 strlcpy(hibernateFilename
, str
->getCStringNoCopy(),
8988 sizeof(hibernateFilename
));
8991 if (!hibernateFilename
[0]) {
8992 DMSG("sleepWakeDebugDumpFromFile: Failed to hib file name\n");
8995 DLOG("sleepWakeDebugDumpFromFile: Hib file name %s\n", hibernateFilename
);
8997 /* Allocate a temp buffer to copy data between files */
8998 tmpBufSize
= 2*4096;
8999 tmpBufDesc
= IOBufferMemoryDescriptor::
9000 inTaskWithOptions(kernel_task
, kIODirectionOutIn
| kIOMemoryMapperNone
,
9001 tmpBufSize
, PAGE_SIZE
);
9004 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
9008 tmpBuf
= tmpBufDesc
->getBytesNoCopy();
9010 ctx
= vfs_context_create(vfs_context_current());
9011 if (vnode_open(hibernateFilename
, (FREAD
| O_NOFOLLOW
), 0,
9012 VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9014 DMSG("sleepWakeDebugDumpFromFile: Failed to open the hibernate file %s\n", hibernateFilename
);
9018 VATTR_WANTED(&va
, va_nlink
);
9019 VATTR_WANTED(&va
, va_data_alloc
);
9020 if (vp
->v_type
!= VREG
||
9021 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9022 DMSG("sleepWakeDebugDumpFromFile: Bailing as this is not a regular file\n");
9026 /* Read the sleepimage file header */
9027 rc
= vn_rdwr(UIO_READ
, vp
, (char *)tmpBuf
, round_page(sizeof(IOHibernateImageHeader
)), 0,
9028 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9029 vfs_context_ucred(ctx
), (int *) 0,
9030 vfs_context_proc(ctx
));
9032 DMSG("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d)\n", round_page(sizeof(IOHibernateImageHeader
)), rc
);
9036 imageHdr
= ((IOHibernateImageHeader
*)tmpBuf
);
9037 if (imageHdr
->signature
!= kIOHibernateHeaderDebugDataSignature
) {
9038 DMSG("sleepWakeDebugDumpFromFile: File header has unexpected value 0x%x\n", imageHdr
->signature
);
9042 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
9043 hdrOffset
= imageHdr
->deviceBlockSize
;
9044 if (hdrOffset
+ sizeof(swd_hdr
) >= va
.va_data_alloc
) {
9045 DMSG("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx)\n", va
.va_data_alloc
);
9049 DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
));
9050 /* Read the sleep/wake debug header(swd_hdr) */
9051 rc
= vn_rdwr(UIO_READ
, vp
, (char *)tmpBuf
, round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
),
9052 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9053 vfs_context_ucred(ctx
), (int *) 0,
9054 vfs_context_proc(ctx
));
9056 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %lu. rc=%d\n",
9057 round_page(sizeof(swd_hdr
)), rc
);
9061 hdr
= (swd_hdr
*)((char *)tmpBuf
+ (hdrOffset
- trunc_page(hdrOffset
)));
9062 if ((hdr
->signature
!= SWD_HDR_SIGNATURE
) || (hdr
->alloc_size
> SWD_BUF_SIZE
) ||
9063 (hdr
->spindump_offset
> SWD_BUF_SIZE
) || (hdr
->spindump_size
> SWD_BUF_SIZE
)) {
9064 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
9065 hdr
->signature
, hdr
->alloc_size
, hdr
->spindump_offset
, hdr
->spindump_size
);
9068 stacksSize
= hdr
->spindump_size
;
9070 /* Get stacks & log offsets in the image file */
9071 stacksOffset
= hdrOffset
+ hdr
->spindump_offset
;
9072 logOffset
= hdrOffset
+ offsetof(swd_hdr
, UUID
);
9073 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9075 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, stacksOffset
,
9076 getDumpStackFilename(hdr
), stacksSize
, hdr
->crc
);
9077 if (error
== EFAULT
) {
9078 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
9081 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, logOffset
,
9082 getDumpLogFilename(hdr
), logSize
, 0);
9084 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error
);
9089 // Write just the SleepWakeLog.dump with failure code
9092 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9093 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
9094 fcode
= failStat
->unsigned64BitValue();
9095 fname
= kSleepWakeLogFilename
;
9098 fname
= kAppleOSXWatchdogLogFilename
;
9100 memset(PMStatusCode
, 0x20, sizeof(PMStatusCode
)); // Fill with spaces
9101 PMStatusCode
[sizeof(PMStatusCode
)-1] = 0xa; // And an end-of-line at the end
9102 snprintf(PMStatusCode
, sizeof(PMStatusCode
)-1, "Code: 0x%llx", fcode
);
9103 sleepWakeDebugSaveFile(fname
, PMStatusCode
, sizeof(PMStatusCode
));
9105 gRootDomain
->swd_lock
= 0;
9107 if (vp
) vnode_close(vp
, FREAD
, ctx
);
9108 if (ctx
) vfs_context_rele(ctx
);
9109 if (tmpBufDesc
) tmpBufDesc
->release();
9113 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*logBufMap
)
9115 IOVirtualAddress srcBuf
= NULL
;
9116 char *stackBuf
= NULL
, *logOffset
= NULL
;
9119 errno_t error
= EIO
;
9120 uint64_t bufSize
= 0;
9121 swd_hdr
*hdr
= NULL
;
9122 char PMStatusCode
[100];
9123 OSNumber
*failStat
= NULL
;
9125 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9128 if ((logBufMap
== 0) || ( (srcBuf
= logBufMap
->getVirtualAddress()) == 0) )
9130 DLOG("Nothing saved to dump to file\n");
9134 hdr
= (swd_hdr
*)srcBuf
;
9135 bufSize
= logBufMap
->getLength();
9136 if (bufSize
<= sizeof(swd_hdr
))
9138 IOLog("SleepWake log buffer contents are invalid\n");
9142 stackBuf
= (char*)hdr
+hdr
->spindump_offset
;
9144 error
= sleepWakeDebugSaveFile(getDumpStackFilename(hdr
), stackBuf
, hdr
->spindump_size
);
9145 if (error
) goto exit
;
9147 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
9148 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9150 error
= sleepWakeDebugSaveFile(getDumpLogFilename(hdr
), logOffset
, logSize
);
9151 if (error
) goto exit
;
9153 hdr
->spindump_size
= 0;
9158 // Write just the SleepWakeLog.dump with failure code
9160 const char *sname
, *lname
;
9161 swd_stackshot_hdr shdr
;
9163 /* Try writing an empty stacks file */
9164 shdr
.magic
= SWD_STACKSHOTHDR_MAGIC
;
9168 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9169 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
9170 fcode
= failStat
->unsigned64BitValue();
9171 lname
= kSleepWakeLogFilename
;
9172 sname
= kSleepWakeStackFilename
;
9175 lname
= kAppleOSXWatchdogLogFilename
;
9176 sname
= kAppleOSXWatchdogStackFilename
;
9179 sleepWakeDebugSaveFile(sname
, (char*)(&shdr
), sizeof(shdr
));
9180 memset(PMStatusCode
, 0x20, sizeof(PMStatusCode
)); // Fill with spaces
9181 PMStatusCode
[sizeof(PMStatusCode
)-1] = 0xa; // And an end-of-line at the end
9182 snprintf(PMStatusCode
, sizeof(PMStatusCode
)-1, "Code: 0x%llx", fcode
);
9183 sleepWakeDebugSaveFile(lname
, PMStatusCode
, sizeof(PMStatusCode
));
9185 gRootDomain
->swd_lock
= 0;
9188 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
9190 IOVirtualAddress vaddr
= NULL
;
9191 IOMemoryDescriptor
* desc
= NULL
;
9192 IOMemoryMap
* logBufMap
= NULL
;
9196 uint64_t bufSize
= 0;
9198 uint64_t newcrc
= 0;
9200 swd_hdr
*hdr
= NULL
;
9205 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9208 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey
, 0, &len
)) {
9209 DLOG("No sleepWakeDebug note to read\n");
9213 if (len
== strlen("sleepimage")) {
9215 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, str
, &len
);
9217 if (!strncmp((char*)str
, "sleepimage", strlen("sleepimage"))) {
9218 DLOG("sleepWakeDebugRetrieve: in file logs\n");
9219 swd_flags
|= SWD_LOGS_IN_FILE
|SWD_VALID_LOGS
;
9223 else if (len
== sizeof(addr64_t
)*3)
9224 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, data
, &len
);
9226 DLOG("Invalid sleepWakeDebug note length(%d)\n", len
);
9232 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
9233 data
[0], data
[1], data
[2]);
9234 DLOG("sleepWakeDebugRetrieve: in mem logs\n");
9238 if ( (bufSize
<= sizeof(swd_hdr
)) ||(bufSize
> SWD_BUF_SIZE
) || (crc
== 0) )
9240 IOLog("SleepWake log buffer contents are invalid\n");
9244 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
9245 bufSize
, crc
, paddr
);
9248 desc
= IOMemoryDescriptor::withAddressRange( paddr
, bufSize
,
9249 kIODirectionOutIn
| kIOMemoryMapperNone
, NULL
);
9252 IOLog("Fail to map SleepWake log buffer\n");
9256 logBufMap
= desc
->map();
9258 vaddr
= logBufMap
->getVirtualAddress();
9261 if ( (logBufMap
->getLength() <= sizeof(swd_hdr
)) || (vaddr
== NULL
) ) {
9262 IOLog("Fail to map SleepWake log buffer\n");
9266 hdr
= (swd_hdr
*)vaddr
;
9267 if (hdr
->spindump_offset
+hdr
->spindump_size
> bufSize
)
9269 IOLog("SleepWake log buffer contents are invalid\n");
9274 newcrc
= crc32(0, (void *)((char*)vaddr
+hdr
->spindump_offset
),
9275 hdr
->spindump_size
);
9276 if (newcrc
!= crc
) {
9277 IOLog("SleepWake log buffer contents are invalid\n");
9282 swd_flags
|= SWD_LOGS_IN_MEM
| SWD_VALID_LOGS
;
9286 PERemoveNVRAMProperty(kIOSleepWakeDebugKey
);
9288 if (logBufMap
) logBufMap
->release();
9291 if (desc
) desc
->release();
9292 gRootDomain
->swd_lock
= 0;
9299 void IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
9303 void IOPMrootDomain::takeStackshot(bool restart
, bool isOSXWatchdog
)
9305 #pragma unused(restart)
9306 #pragma unused(isOSXWatchdog)
9309 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9312 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*map
)
9315 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
9316 struct vnode
*srcVp
,
9317 vfs_context_t srcCtx
,
9318 char *tmpBuf
, uint64_t tmpBufSize
,
9320 const char *dstFname
,
9327 void IOPMrootDomain::sleepWakeDebugDumpFromFile()
9331 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
9336 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9340 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9345 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)