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/IOKitDebug.h>
36 #include <IOKit/IOTimeStamp.h>
37 #include <IOKit/pwr_mgt/IOPMlog.h>
38 #include <IOKit/pwr_mgt/RootDomain.h>
39 #include <IOKit/pwr_mgt/IOPMPrivate.h>
40 #include <IOKit/IODeviceTreeSupport.h>
41 #include <IOKit/IOMessage.h>
42 #include <IOKit/IOReturn.h>
43 #include "RootDomainUserClient.h"
44 #include "IOKit/pwr_mgt/IOPowerConnection.h"
45 #include "IOPMPowerStateQueue.h"
46 #include <IOKit/IOCatalogue.h>
48 #include <IOKit/IOHibernatePrivate.h>
50 #include <console/video_console.h>
51 #include <sys/syslog.h>
52 #include <sys/sysctl.h>
54 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
55 #include "IOServicePMPrivate.h"
58 #include <mach/shared_region.h>
61 #if defined(__i386__) || defined(__x86_64__)
63 #include "IOPMrootDomainInternal.h"
67 #define kIOPMrootDomainClass "IOPMrootDomain"
68 #define LOG_PREFIX "PMRD: "
71 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
74 do { kprintf(LOG_PREFIX x); } while (false)
76 #define DLOG(x...) do { \
77 if (kIOLogPMRootDomain & gIOKitDebug) \
78 kprintf(LOG_PREFIX x); } while (false)
82 #define DARK_WAKE_DEBUG 1
83 #define SUSPEND_PM_NOTIFICATIONS_DEBUG 1
85 #define CHECK_THREAD_CONTEXT
86 #ifdef CHECK_THREAD_CONTEXT
87 static IOWorkLoop
* gIOPMWorkLoop
= 0;
88 #define ASSERT_GATED() \
90 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
91 panic("RootDomain: not inside PM gate"); \
95 #define ASSERT_GATED()
96 #endif /* CHECK_THREAD_CONTEXT */
99 (((_pendingCapability & (c)) == 0) && \
100 ((_currentCapability & (c)) != 0))
102 #define CAP_GAIN(c) \
103 (((_currentCapability & (c)) == 0) && \
104 ((_pendingCapability & (c)) != 0))
106 #define CAP_CHANGE(c) \
107 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
109 #define CAP_CURRENT(c) \
110 ((_currentCapability & (c)) != 0)
112 #define CAP_HIGHEST(c) \
113 ((_highestCapability & (c)) != 0)
115 #define DARK_TO_FULL_EVALUATE_CLAMSHELL 0
117 // Event types for IOPMPowerStateQueue::submitPowerEvent()
119 kPowerEventFeatureChanged
= 1, // 1
120 kPowerEventReceivedPowerNotification
, // 2
121 kPowerEventSystemBootCompleted
, // 3
122 kPowerEventSystemShutdown
, // 4
123 kPowerEventUserDisabledSleep
, // 5
124 kPowerEventRegisterSystemCapabilityClient
, // 6
125 kPowerEventRegisterKernelCapabilityClient
, // 7
126 kPowerEventPolicyStimulus
, // 8
127 kPowerEventAssertionCreate
, // 9
128 kPowerEventAssertionRelease
, // 10
129 kPowerEventAssertionSetLevel
, // 11
130 kPowerEventQueueSleepWakeUUID
, // 12
131 kPowerEventPublishSleepWakeUUID
, // 13
132 kPowerEventSuspendClient
// 14
135 // For evaluatePolicy()
136 // List of stimuli that affects the root domain policy.
138 kStimulusDisplayWranglerSleep
, // 0
139 kStimulusDisplayWranglerWake
, // 1
140 kStimulusAggressivenessChanged
, // 2
141 kStimulusDemandSystemSleep
, // 3
142 kStimulusAllowSystemSleepChanged
, // 4
143 kStimulusDarkWakeActivityTickle
, // 5
144 kStimulusDarkWakeEntry
, // 6
145 kStimulusDarkWakeReentry
, // 7
146 kStimulusDarkWakeEvaluate
, // 8
147 kStimulusNoIdleSleepPreventers
// 9
151 IOReturn
OSKextSystemSleepOrWake( UInt32
);
154 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
155 static void notifySystemShutdown( IOService
* root
, unsigned long event
);
156 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
157 static void pmEventTimeStamp(uint64_t *recordTS
);
159 // "IOPMSetSleepSupported" callPlatformFunction name
160 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
161 static const OSSymbol
*sleepMessagePEFunction
= NULL
;
163 #define kIOSleepSupportedKey "IOSleepSupported"
164 #define kIOPMSystemCapabilitiesKey "System Capabilities"
166 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
167 | kIOPMSupportedOnBatt \
168 | kIOPMSupportedOnUPS)
172 // not idle around autowake time, secs
173 kAutoWakePreWindow
= 45,
174 kAutoWakePostWindow
= 15
177 #define kLocalEvalClamshellCommand (1 << 15)
187 #define ON_POWER kIOPMPowerOn
188 #define RESTART_POWER kIOPMRestart
189 #define SLEEP_POWER kIOPMAuxPowerOn
191 static IOPMPowerState ourPowerStates
[NUM_POWER_STATES
] =
193 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
194 {1, kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
, 0,0,0,0,0,0,0,0},
195 {1, kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
, 0,0,0,0,0,0,0,0},
196 {1, kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
, 0,0,0,0,0,0,0,0}
199 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
200 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
201 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
202 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
203 #define kIOPMRootDomainWakeTypeUser "User"
204 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
205 #define kIOPMRootDomainWakeTypeNetwork "Network"
206 #define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
208 // Special interest that entitles the interested client from receiving
209 // all system messages. Only used by powerd.
211 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
213 #define kPMSuspendedNotificationClients "PMSuspendedNotificationClients"
218 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
219 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
221 #define kAggressivesMinValue 1
224 kAggressivesStateBusy
= 0x01,
225 kAggressivesStateQuickSpindown
= 0x02
228 struct AggressivesRecord
{
234 struct AggressivesRequest
{
240 AggressivesRecord record
;
245 kAggressivesRequestTypeService
= 1,
246 kAggressivesRequestTypeRecord
250 kAggressivesOptionSynchronous
= 0x00000001,
251 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
252 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
253 kAggressivesOptionQuickSpindownMask
= 0x00000300
257 kAggressivesRecordFlagModified
= 0x00000001,
258 kAggressivesRecordFlagMinValue
= 0x00000002
263 kDarkWakeFlagHIDTickleEarly
= 0x01, // hid tickle before gfx suppression
264 kDarkWakeFlagHIDTickleLate
= 0x02, // hid tickle after gfx suppression
265 kDarkWakeFlagHIDTickleNone
= 0x03, // hid tickle is not posted
266 kDarkWakeFlagHIDTickleMask
= 0x03,
267 kDarkWakeFlagIgnoreDiskIOInDark
= 0x04, // ignore disk idle in DW
268 kDarkWakeFlagIgnoreDiskIOAlways
= 0x08, // always ignore disk idle
269 kDarkWakeFlagIgnoreDiskIOMask
= 0x0C,
270 kDarkWakeFlagAlarmIsDark
= 0x0100
273 static IOPMrootDomain
* gRootDomain
;
274 static IONotifier
* gSysPowerDownNotifier
= 0;
275 static UInt32 gSleepOrShutdownPending
= 0;
276 static UInt32 gWillShutdown
= 0;
277 static UInt32 gPagingOff
= 0;
278 static UInt32 gSleepWakeUUIDIsSet
= false;
279 static uint32_t gAggressivesState
= 0;
280 static uint32_t gDarkWakeFlags
= kDarkWakeFlagHIDTickleNone
| kDarkWakeFlagIgnoreDiskIOAlways
;
281 static PMStatsStruct gPMStats
;
283 struct timeval gIOLastSleepTime
;
284 struct timeval gIOLastWakeTime
;
286 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
287 #define kCPUUnknownIndex 9999999
294 const OSSymbol
*gIOPMStatsApplicationResponseTimedOut
;
295 const OSSymbol
*gIOPMStatsApplicationResponseCancel
;
296 const OSSymbol
*gIOPMStatsApplicationResponseSlow
;
298 #define kBadPMFeatureID 0
302 * Opaque handle passed to clients of registerPMSettingController()
304 class PMSettingHandle
: public OSObject
306 OSDeclareFinalStructors( PMSettingHandle
)
307 friend class PMSettingObject
;
310 PMSettingObject
*pmso
;
316 * Internal object to track each PM setting controller
318 class PMSettingObject
: public OSObject
320 OSDeclareFinalStructors( PMSettingObject
)
321 friend class IOPMrootDomain
;
324 queue_head_t calloutQueue
;
326 IOPMrootDomain
*parent
;
327 PMSettingHandle
*pmsh
;
328 IOPMSettingControllerCallback func
;
331 uint32_t *publishedFeatureID
;
332 uint32_t settingCount
;
338 static PMSettingObject
*pmSettingObject(
339 IOPMrootDomain
*parent_arg
,
340 IOPMSettingControllerCallback handler_arg
,
341 OSObject
*target_arg
,
342 uintptr_t refcon_arg
,
343 uint32_t supportedPowerSources
,
344 const OSSymbol
*settings
[],
345 OSObject
**handle_obj
);
347 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
348 void clientHandleFreed(void);
351 struct PMSettingCallEntry
{
356 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
357 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
358 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
359 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
361 //*********************************************************************************
362 //*********************************************************************************
363 //*********************************************************************************
365 /* @class IOPMTimeline
366 * @astract Tracks & records PM activity.
367 * @discussion Intended for use only as a helper-class to IOPMrootDomain.
368 * Do not subclass or directly invoke iOPMTimeline
370 class IOPMTimeline
: public OSObject
372 OSDeclareDefaultStructors( IOPMTimeline
);
375 static IOPMTimeline
* timeline(IOPMrootDomain
*root_domain
);
377 bool setProperties(OSDictionary
*d
);
378 OSDictionary
*copyInfoDictionary(void);
380 IOReturn
recordSystemPowerEvent( PMEventDetails
*details
);
382 IOReturn
recordDetailedPowerEvent( PMEventDetails
*details
);
384 IOMemoryDescriptor
*getPMTraceMemoryDescriptor();
386 uint32_t getNumEventsLoggedThisPeriod();
387 void setNumEventsLoggedThisPeriod(uint32_t newCount
);
388 bool isSleepCycleInProgress();
389 void setSleepCycleInProgressFlag(bool flag
);
394 void setEventsTrackedCount(uint32_t newTracked
);
395 void setEventsRecordingLevel(uint32_t eventsTrackedBits
);
396 static uint32_t _atomicIndexIncrement(uint32_t *index
, uint32_t limit
);
399 kPMTimelineRecordTardyDrivers
= 1 << 0,
400 kPMTmielineRecordSystemEvents
= 1 << 1,
401 kPMTimelineRecordAllDrivers
= 1 << 2,
402 kPMTimelineRecordOff
= 0,
403 kPMTimelineRecordDefault
= 3,
404 kPMTimelineRecordDebug
= 7
407 // eventsRecordingLevel is a bitfield defining which PM driver events will get logged
408 // into the PM buffer.
409 uint32_t eventsRecordingLevel
;
411 // pmTraceMemoryDescriptor represents the memory block that IOPMTimeLine records PM trace points into.
412 IOBufferMemoryDescriptor
*pmTraceMemoryDescriptor
;
414 // Pointer to starting address in pmTraceMemoryDescriptor
415 IOPMSystemEventRecord
*traceBuffer
;
416 IOPMTraceBufferHeader
*hdr
;
418 uint16_t systemState
;
421 IOPMrootDomain
*owner
;
423 uint32_t numEventsLoggedThisPeriod
;
424 bool sleepCycleInProgress
;
427 OSDefineMetaClassAndStructors( IOPMTimeline
, OSObject
)
431 * Internal helper object for logging trace points to RTC
432 * IOPMrootDomain and only IOPMrootDomain should instantiate
433 * exactly one of these.
436 typedef void (*IOPMTracePointHandler
)(
437 void * target
, uint32_t code
, uint32_t data
);
439 class PMTraceWorker
: public OSObject
441 OSDeclareDefaultStructors(PMTraceWorker
)
443 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
445 static PMTraceWorker
*tracer( IOPMrootDomain
* );
446 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
447 void tracePoint(uint8_t phase
);
448 void tracePoint(uint8_t phase
, uint8_t data8
);
449 void traceDetail(uint32_t detail
);
450 void traceLoginWindowPhase(uint8_t phase
);
451 int recordTopLevelPCIDevice(IOService
*);
452 void RTC_TRACE(void);
453 virtual bool serialize(OSSerialize
*s
) const;
455 IOPMTracePointHandler tracePointHandler
;
456 void * tracePointTarget
;
458 IOPMrootDomain
*owner
;
459 IOLock
*pciMappingLock
;
460 OSArray
*pciDeviceBitMappings
;
462 uint8_t addedToRegistry
;
464 uint8_t loginWindowPhase
;
466 uint32_t traceData32
;
470 * PMAssertionsTracker
471 * Tracks kernel and user space PM assertions
473 class PMAssertionsTracker
: public OSObject
475 OSDeclareFinalStructors(PMAssertionsTracker
)
477 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
479 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
480 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
481 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
482 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
484 OSArray
*copyAssertionsArray(void);
485 IOPMDriverAssertionType
getActivatedAssertions(void);
486 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
488 IOReturn
handleCreateAssertion(OSData
*);
489 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
490 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
491 IOReturn
handleSetUserAssertionLevels(void * arg0
);
492 void publishProperties(void);
496 IOPMDriverAssertionID id
;
497 IOPMDriverAssertionType assertionBits
;
498 uint64_t createdTime
;
499 uint64_t modifiedTime
;
500 const OSSymbol
*ownerString
;
501 IOService
*ownerService
;
502 IOPMDriverAssertionLevel level
;
505 uint32_t tabulateProducerCount
;
506 uint32_t tabulateConsumerCount
;
508 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
511 IOPMrootDomain
*owner
;
512 OSArray
*assertionsArray
;
513 IOLock
*assertionsArrayLock
;
514 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8))); /* aligned for atomic access */
515 IOPMDriverAssertionType assertionsKernel
;
516 IOPMDriverAssertionType assertionsUser
;
517 IOPMDriverAssertionType assertionsCombined
;
520 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
524 * Internal helper object for Shutdown/Restart notifications.
526 #define kPMHaltMaxWorkers 8
527 #define kPMHaltTimeoutMS 100
529 class PMHaltWorker
: public OSObject
531 OSDeclareFinalStructors( PMHaltWorker
)
534 IOService
* service
; // service being worked on
535 AbsoluteTime startTime
; // time when work started
536 int depth
; // work on nubs at this PM-tree depth
537 int visits
; // number of nodes visited (debug)
539 bool timeout
; // service took too long
541 static PMHaltWorker
* worker( void );
542 static void main( void * arg
, wait_result_t waitResult
);
543 static void work( PMHaltWorker
* me
);
544 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
545 virtual void free( void );
548 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
551 #define super IOService
552 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
554 static void IOPMRootDomainWillShutdown(void)
556 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
558 OSKext::willShutdown();
559 for (int i
= 0; i
< 100; i
++)
561 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
569 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
571 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
574 IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
576 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
579 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
581 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
584 IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
586 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
589 IOReturn
rootDomainRestart ( void )
591 return gRootDomain
->restartSystem();
594 IOReturn
rootDomainShutdown ( void )
596 return gRootDomain
->shutdownSystem();
599 void IOSystemShutdownNotification(void)
601 IOPMRootDomainWillShutdown();
602 if (OSCompareAndSwap(0, 1, &gPagingOff
))
605 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
610 int sync_internal(void);
614 A device is always in the highest power state which satisfies its driver,
615 its policy-maker, and any power children it has, but within the constraint
616 of the power state provided by its parent. The driver expresses its desire by
617 calling changePowerStateTo(), the policy-maker expresses its desire by calling
618 changePowerStateToPriv(), and the children express their desires by calling
619 requestPowerDomainState().
621 The Root Power Domain owns the policy for idle and demand sleep for the system.
622 It is a power-managed IOService just like the others in the system.
623 It implements several power states which map to what we see as Sleep and On.
625 The sleep policy is as follows:
626 1. Sleep is prevented if the case is open so that nobody will think the machine
627 is off and plug/unplug cards.
628 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
629 3. System cannot Sleep if some object in the tree is in a power state marked
630 kIOPMPreventSystemSleep.
632 These three conditions are enforced using the "driver clamp" by calling
633 changePowerStateTo(). For example, if the case is opened,
634 changePowerStateTo(ON_STATE) is called to hold the system on regardless
635 of the desires of the children of the root or the state of the other clamp.
637 Demand Sleep is initiated by pressing the front panel power button, closing
638 the clamshell, or selecting the menu item. In this case the root's parent
639 actually initiates the power state change so that the root domain has no
640 choice and does not give applications the opportunity to veto the change.
642 Idle Sleep occurs if no objects in the tree are in a state marked
643 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
644 the root on, so it sets the "policy-maker clamp" by calling
645 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
646 This timer is set for the difference between the sleep timeout slider and the
647 display dim timeout slider. When the timer expires, it releases its clamp and
648 now nothing is holding it awake, so it falls asleep.
650 Demand sleep is prevented when the system is booting. When preferences are
651 transmitted by the loginwindow at the end of boot, a flag is cleared,
652 and this allows subsequent Demand Sleep.
655 //******************************************************************************
657 IOPMrootDomain
* IOPMrootDomain::construct( void )
659 IOPMrootDomain
*root
;
661 root
= new IOPMrootDomain
;
668 //******************************************************************************
670 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
672 IOService
* rootDomain
= (IOService
*) p0
;
673 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
674 uint32_t powerState
= rootDomain
->getPowerState();
676 DLOG("disk_sync_callout ps=%u\n", powerState
);
678 if (ON_STATE
== powerState
)
681 IOHibernateSystemSleep();
688 IOHibernateSystemPostWake();
692 rootDomain
->allowPowerChange(notifyRef
);
693 DLOG("disk_sync_callout finish\n");
696 //******************************************************************************
698 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
)
700 AbsoluteTime endTime
;
703 clock_get_uptime(&endTime
);
704 if (CMP_ABSOLUTETIME(&endTime
, startTime
) > 0)
706 SUB_ABSOLUTETIME(&endTime
, startTime
);
707 absolutetime_to_nanoseconds(endTime
, &nano
);
710 return (UInt32
)(nano
/ 1000000ULL);
713 //******************************************************************************
716 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
718 struct timeval
*swt
= (struct timeval
*)arg1
;
719 struct proc
*p
= req
->p
;
722 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
723 } else if(proc_is64bit(p
)) {
724 struct user64_timeval t
;
725 t
.tv_sec
= swt
->tv_sec
;
726 t
.tv_usec
= swt
->tv_usec
;
727 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
729 struct user32_timeval t
;
730 t
.tv_sec
= swt
->tv_sec
;
731 t
.tv_usec
= swt
->tv_usec
;
732 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
736 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
737 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
738 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
740 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
741 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
742 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
747 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
749 int new_value
, changed
;
750 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
752 if (!gWillShutdown
&& (new_value
== 1)) {
753 IOPMRootDomainWillShutdown();
760 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
761 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
762 0, 0, sysctl_willshutdown
, "I", "");
767 sysctl_progressmeterenable
768 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
771 int new_value
, changed
;
773 error
= sysctl_io_number(req
, vc_progress_meter_enable
, sizeof(int), &new_value
, &changed
);
776 vc_enable_progressmeter(new_value
);
783 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
786 int new_value
, changed
;
788 error
= sysctl_io_number(req
, vc_progress_meter_value
, sizeof(int), &new_value
, &changed
);
791 vc_set_progressmeter(new_value
);
796 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
797 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
798 0, 0, sysctl_progressmeterenable
, "I", "");
800 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
801 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
802 0, 0, sysctl_progressmeter
, "I", "");
806 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
808 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
809 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
810 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
811 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
812 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
814 //******************************************************************************
817 //******************************************************************************
819 #define kRootDomainSettingsCount 17
821 bool IOPMrootDomain::start( IOService
* nub
)
823 OSIterator
*psIterator
;
824 OSDictionary
*tmpDict
;
825 IORootParent
* patriarch
;
830 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
831 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
832 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
833 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
834 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
836 gIOPMStatsApplicationResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
837 gIOPMStatsApplicationResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
838 gIOPMStatsApplicationResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
840 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
841 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
843 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
845 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
846 gIOPMSettingAutoWakeSecondsKey
,
847 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
848 OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
),
849 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
850 gIOPMSettingDebugWakeRelativeKey
,
851 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
852 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
853 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
854 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
855 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
856 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
857 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
858 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
859 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
860 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
861 gIOPMSettingSilentRunningKey
864 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
866 queue_init(&aggressivesQueue
);
867 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
868 aggressivesData
= OSData::withCapacity(
869 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
871 featuresDictLock
= IOLockAlloc();
872 settingsCtrlLock
= IOLockAlloc();
873 setPMRootDomain(this);
875 extraSleepTimer
= thread_call_allocate(
876 idleSleepTimerExpired
,
877 (thread_call_param_t
) this);
879 diskSyncCalloutEntry
= thread_call_allocate(
881 (thread_call_param_t
) this);
883 setProperty(kIOSleepSupportedKey
, true);
885 bzero(&gPMStats
, sizeof(gPMStats
));
887 pmTracer
= PMTraceWorker::tracer(this);
889 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
891 userDisabledAllSleep
= false;
892 systemBooting
= true;
894 idleSleepTimerPending
= false;
896 clamshellClosed
= false;
897 clamshellExists
= false;
898 clamshellDisabled
= true;
899 acAdaptorConnected
= true;
901 // Set the default system capabilities at boot.
902 _currentCapability
= kIOPMSystemCapabilityCPU
|
903 kIOPMSystemCapabilityGraphics
|
904 kIOPMSystemCapabilityAudio
|
905 kIOPMSystemCapabilityNetwork
;
907 _pendingCapability
= _currentCapability
;
908 _desiredCapability
= _currentCapability
;
909 _highestCapability
= _currentCapability
;
910 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
912 queuedSleepWakeUUIDString
= NULL
;
913 pmStatsAppResponses
= OSArray::withCapacity(5);
914 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
915 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
916 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
917 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
918 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
920 idxPMCPUClamshell
= kCPUUnknownIndex
;
921 idxPMCPULimitedPower
= kCPUUnknownIndex
;
923 tmpDict
= OSDictionary::withCapacity(1);
924 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
927 settingsCallbacks
= OSDictionary::withCapacity(1);
929 // Create a list of the valid PM settings that we'll relay to
930 // interested clients in setProperties() => setPMSetting()
931 allowedPMSettings
= OSArray::withObjects(
932 (const OSObject
**)settingsArr
,
933 kRootDomainSettingsCount
,
936 // List of PM settings that should not automatically publish itself
937 // as a feature when registered by a listener.
938 noPublishPMSettings
= OSArray::withObjects(
939 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
941 fPMSettingsDict
= OSDictionary::withCapacity(5);
942 preventIdleSleepList
= OSSet::withCapacity(8);
943 preventSystemSleepList
= OSSet::withCapacity(2);
945 PMinit(); // creates gIOPMWorkLoop
947 // Create IOPMPowerStateQueue used to queue external power
948 // events, and to handle those events on the PM work loop.
949 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
950 this, OSMemberFunctionCast(IOEventSource::Action
, this,
951 &IOPMrootDomain::dispatchPowerEvent
));
952 getPMworkloop()->addEventSource(pmPowerStateQueue
);
953 #ifdef CHECK_THREAD_CONTEXT
954 gIOPMWorkLoop
= getPMworkloop();
957 // create our power parent
958 patriarch
= new IORootParent
;
960 patriarch
->attach(this);
961 patriarch
->start(this);
962 patriarch
->addPowerChild(this);
964 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
965 changePowerStateToPriv(ON_STATE
);
967 if (gIOKitDebug
& (kIOLogDriverPower1
| kIOLogDriverPower2
))
969 // Setup our PM logging & recording code
970 timeline
= IOPMTimeline::timeline(this);
972 OSDictionary
*tlInfo
= timeline
->copyInfoDictionary();
976 setProperty(kIOPMTimelineDictionaryKey
, tlInfo
);
982 // install power change handler
983 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
986 // Register for a notification when IODisplayWrangler is published
987 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
989 _displayWranglerNotifier
= addMatchingNotification(
990 gIOPublishNotification
, tmpDict
,
991 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
997 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
998 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
999 ucClassName
->release();
1001 // IOBacklightDisplay can take a long time to load at boot, or it may
1002 // not load at all if you're booting with clamshell closed. We publish
1003 // 'DisplayDims' here redundantly to get it published early and at all.
1004 psIterator
= getMatchingServices( serviceMatching("IOPMPowerSource") );
1005 if( psIterator
&& psIterator
->getNextObject() )
1007 // There's at least one battery on the system, so we publish
1008 // 'DisplayDims' support for the LCD.
1009 publishFeature("DisplayDims");
1012 psIterator
->release();
1016 pmSuspendedCapacity
= pmSuspendedSize
= 0;
1017 pmSuspendedPIDS
= NULL
;
1020 sysctl_register_oid(&sysctl__kern_sleeptime
);
1021 sysctl_register_oid(&sysctl__kern_waketime
);
1022 sysctl_register_oid(&sysctl__kern_willshutdown
);
1023 #if !CONFIG_EMBEDDED
1024 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1025 sysctl_register_oid(&sysctl__kern_progressmeter
);
1026 #endif /* !CONFIG_EMBEDDED */
1029 IOHibernateSystemInit(this);
1032 registerService(); // let clients find us
1040 void IOPMrootDomain::handleSuspendPMNotificationClient(uint32_t pid
, bool doSuspend
)
1047 if (!pmSuspendedPIDS
) {
1048 pmSuspendedCapacity
= 8;
1049 pmSuspendedSize
= pmSuspendedCapacity
* sizeof(PMNotifySuspendedStruct
);
1050 pmSuspendedPIDS
= (PMNotifySuspendedStruct
*)IOMalloc(pmSuspendedSize
);
1051 bzero(pmSuspendedPIDS
, pmSuspendedSize
);
1054 /* Find the existing pid in the existing array */
1056 for (i
=0; i
< pmSuspendedCapacity
; i
++) {
1057 if (pmSuspendedPIDS
[i
].pid
== pid
) {
1065 /* Find an unused slot in the suspended pids table. */
1067 for (i
=0; i
< pmSuspendedCapacity
; i
++) {
1068 if (pmSuspendedPIDS
[i
].refcount
== 0) {
1073 if (pmSuspendedCapacity
== i
)
1075 /* GROW if necessary */
1077 PMNotifySuspendedStruct
*newSuspended
= NULL
;
1078 pmSuspendedCapacity
*= 2;
1079 pmSuspendedSize
= pmSuspendedCapacity
* sizeof(PMNotifySuspendedStruct
);
1080 newSuspended
= (PMNotifySuspendedStruct
*)IOMalloc(pmSuspendedSize
);
1082 bzero(newSuspended
, pmSuspendedSize
);
1083 bcopy(pmSuspendedPIDS
, newSuspended
, pmSuspendedSize
/2);
1084 IOFree(pmSuspendedPIDS
, pmSuspendedSize
/2);
1086 pmSuspendedPIDS
= newSuspended
;
1090 pmSuspendedPIDS
[index
].pid
= pid
;
1094 pmSuspendedPIDS
[index
].refcount
++;
1096 pmSuspendedPIDS
[index
].refcount
--;
1100 * Publish array of suspended pids in IOPMrootDomain
1102 OSArray
*publish
= OSArray::withCapacity(pmSuspendedCapacity
);
1104 for (i
=0; i
<pmSuspendedCapacity
; i
++)
1106 if (pmSuspendedPIDS
[i
].refcount
> 0) {
1107 OSDictionary
*suspended
= OSDictionary::withCapacity(2);
1110 n
= OSNumber::withNumber(pmSuspendedPIDS
[i
].pid
, 32);
1111 suspended
->setObject("pid", n
);
1114 n
= OSNumber::withNumber(pmSuspendedPIDS
[i
].refcount
, 32);
1115 suspended
->setObject("refcount", n
);
1118 publish
->setObject(suspended
);
1119 suspended
->release();
1124 if (0 != publish
->getCount()) {
1125 setProperty(kPMSuspendedNotificationClients
, publish
);
1127 removeProperty(kPMSuspendedNotificationClients
);
1135 bool IOPMrootDomain::pmNotificationIsSuspended(uint32_t pid
)
1139 for (index
=0; index
< pmSuspendedCapacity
; index
++) {
1140 if (pmSuspendedPIDS
[index
].pid
== pid
) {
1141 return pmSuspendedPIDS
[index
].refcount
> 0;
1149 void IOPMrootDomain::suspendPMNotificationsForPID(uint32_t pid
, bool doSuspend
)
1151 if(pmPowerStateQueue
) {
1152 pmPowerStateQueue
->submitPowerEvent(kPowerEventSuspendClient
, (void *)pid
, (uint64_t)doSuspend
);
1157 //******************************************************************************
1160 // Receive a setProperty call
1161 // The "System Boot" property means the system is completely booted.
1162 //******************************************************************************
1164 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1166 IOReturn return_value
= kIOReturnSuccess
;
1167 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1175 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1176 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1177 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1178 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1179 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1180 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1181 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1182 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1183 const OSSymbol
*loginwindow_tracepoint_string
= OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey
);
1184 const OSSymbol
*pmTimelineLogging_string
= OSSymbol::withCString(kIOPMTimelineDictionaryKey
);
1186 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1187 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1188 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1189 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1191 #if SUSPEND_PM_NOTIFICATIONS_DEBUG
1192 const OSSymbol
*suspendPMClient_string
= OSSymbol::withCString(kPMSuspendedNotificationClients
);
1197 return_value
= kIOReturnBadArgument
;
1201 if ((b
= OSDynamicCast(OSBoolean
, dict
->getObject(publish_simulated_battery_string
))))
1203 publishResource(publish_simulated_battery_string
, kOSBooleanTrue
);
1206 if ((n
= OSDynamicCast(OSNumber
, dict
->getObject(idle_seconds_string
))))
1208 setProperty(idle_seconds_string
, n
);
1209 idleSeconds
= n
->unsigned32BitValue();
1212 if (boot_complete_string
&& dict
->getObject(boot_complete_string
))
1214 pmPowerStateQueue
->submitPowerEvent( kPowerEventSystemBootCompleted
);
1217 if( battery_warning_disabled_string
&& dict
->getObject(battery_warning_disabled_string
))
1219 setProperty( battery_warning_disabled_string
, dict
->getObject(battery_warning_disabled_string
));
1222 if (pmTimelineLogging_string
&& (d
= OSDynamicCast(OSDictionary
, dict
->getObject(pmTimelineLogging_string
))))
1224 if (timeline
&& timeline
->setProperties(d
))
1226 OSDictionary
*tlInfo
= timeline
->copyInfoDictionary();
1228 setProperty(kIOPMTimelineDictionaryKey
, tlInfo
);
1234 if( sys_shutdown_string
&& (b
= OSDynamicCast(OSBoolean
, dict
->getObject(sys_shutdown_string
))))
1236 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1239 if( stall_halt_string
&& (b
= OSDynamicCast(OSBoolean
, dict
->getObject(stall_halt_string
))) )
1241 setProperty(stall_halt_string
, b
);
1245 if ( hibernatemode_string
1246 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatemode_string
))))
1248 setProperty(hibernatemode_string
, n
);
1250 if ( hibernatefreeratio_string
1251 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatefreeratio_string
))))
1253 setProperty(hibernatefreeratio_string
, n
);
1255 if ( hibernatefreetime_string
1256 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatefreetime_string
))))
1258 setProperty(hibernatefreetime_string
, n
);
1261 if ( hibernatefile_string
1262 && (str
= OSDynamicCast(OSString
, dict
->getObject(hibernatefile_string
))))
1264 setProperty(hibernatefile_string
, str
);
1268 if( sleepdisabled_string
1269 && (b
= OSDynamicCast(OSBoolean
, dict
->getObject(sleepdisabled_string
))) )
1271 setProperty(sleepdisabled_string
, b
);
1272 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1274 if (ondeck_sleepwake_uuid_string
1275 && (obj
= dict
->getObject(ondeck_sleepwake_uuid_string
)))
1277 if(pmPowerStateQueue
) {
1279 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1284 if (loginwindow_tracepoint_string
1285 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(loginwindow_tracepoint_string
)))
1288 pmTracer
->traceLoginWindowPhase( n
->unsigned8BitValue() );
1291 if ((b
= OSDynamicCast(OSBoolean
, dict
->getObject(kIOPMDeepSleepEnabledKey
))))
1293 setProperty(kIOPMDeepSleepEnabledKey
, b
);
1295 if ((n
= OSDynamicCast(OSNumber
, dict
->getObject(kIOPMDeepSleepDelayKey
))))
1297 setProperty(kIOPMDeepSleepDelayKey
, n
);
1300 #if SUSPEND_PM_NOTIFICATIONS_DEBUG
1301 if ((n
= OSDynamicCast(OSNumber
, dict
->getObject(suspendPMClient_string
))))
1303 // Toggle the suspended status for pid n.
1304 uint32_t pid_int
= n
->unsigned32BitValue();
1305 suspendPMNotificationsForPID(pid_int
, !pmNotificationIsSuspended(pid_int
));
1309 if ((b
= OSDynamicCast(OSBoolean
, dict
->getObject(kIOPMDestroyFVKeyOnStandbyKey
))))
1311 setProperty(kIOPMDestroyFVKeyOnStandbyKey
, b
);
1314 // Relay our allowed PM settings onto our registered PM clients
1315 for(i
= 0; i
< allowedPMSettings
->getCount(); i
++) {
1317 type
= (OSSymbol
*)allowedPMSettings
->getObject(i
);
1320 obj
= dict
->getObject(type
);
1323 if ((gIOPMSettingAutoWakeSecondsKey
== type
) && ((n
= OSDynamicCast(OSNumber
, obj
))))
1325 UInt32 rsecs
= n
->unsigned32BitValue();
1327 autoWakeStart
= autoWakeEnd
= 0;
1330 AbsoluteTime deadline
;
1331 clock_interval_to_deadline(rsecs
+ kAutoWakePostWindow
, kSecondScale
, &deadline
);
1332 autoWakeEnd
= AbsoluteTime_to_scalar(&deadline
);
1333 if (rsecs
> kAutoWakePreWindow
)
1334 rsecs
-= kAutoWakePreWindow
;
1337 clock_interval_to_deadline(rsecs
, kSecondScale
, &deadline
);
1338 autoWakeStart
= AbsoluteTime_to_scalar(&deadline
);
1341 if (gIOPMSettingDebugWakeRelativeKey
== type
)
1343 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1344 _debugWakeSeconds
= n
->unsigned32BitValue();
1346 _debugWakeSeconds
= 0;
1349 return_value
= setPMSetting(type
, obj
);
1351 if(kIOReturnSuccess
!= return_value
) goto exit
;
1355 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1356 if(boot_complete_string
) boot_complete_string
->release();
1357 if(sys_shutdown_string
) sys_shutdown_string
->release();
1358 if(stall_halt_string
) stall_halt_string
->release();
1359 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1360 if(idle_seconds_string
) idle_seconds_string
->release();
1361 if(sleepdisabled_string
) sleepdisabled_string
->release();
1362 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1363 if(loginwindow_tracepoint_string
) loginwindow_tracepoint_string
->release();
1364 if(pmTimelineLogging_string
) pmTimelineLogging_string
->release();
1366 if(hibernatemode_string
) hibernatemode_string
->release();
1367 if(hibernatefile_string
) hibernatefile_string
->release();
1368 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1369 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1371 #if SUSPEND_PM_NOTIFICATIONS_DEBUG
1372 if(suspendPMClient_string
) suspendPMClient_string
->release();
1374 return return_value
;
1378 // MARK: Aggressiveness
1380 //******************************************************************************
1381 // setAggressiveness
1383 // Override IOService::setAggressiveness()
1384 //******************************************************************************
1386 IOReturn
IOPMrootDomain::setAggressiveness(
1388 unsigned long value
)
1390 return setAggressiveness( type
, value
, 0 );
1394 * Private setAggressiveness() with an internal options argument.
1396 IOReturn
IOPMrootDomain::setAggressiveness(
1398 unsigned long value
,
1399 IOOptionBits options
)
1401 AggressivesRequest
* entry
;
1402 AggressivesRequest
* request
;
1405 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1406 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1408 request
= IONew(AggressivesRequest
, 1);
1410 return kIOReturnNoMemory
;
1412 memset(request
, 0, sizeof(*request
));
1413 request
->options
= options
;
1414 request
->dataType
= kAggressivesRequestTypeRecord
;
1415 request
->data
.record
.type
= (uint32_t) type
;
1416 request
->data
.record
.value
= (uint32_t) value
;
1420 // Update disk quick spindown flag used by getAggressiveness().
1421 // Never merge requests with quick spindown flags set.
1423 if (options
& kAggressivesOptionQuickSpindownEnable
)
1424 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1425 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1426 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1429 // Coalesce requests with identical aggressives types.
1430 // Deal with callers that calls us too "aggressively".
1432 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1434 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1435 (entry
->data
.record
.type
== type
) &&
1436 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1438 entry
->data
.record
.value
= value
;
1447 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1450 AGGRESSIVES_UNLOCK();
1453 IODelete(request
, AggressivesRequest
, 1);
1455 if (options
& kAggressivesOptionSynchronous
)
1456 handleAggressivesRequests(); // not truly synchronous
1458 thread_call_enter(aggressivesThreadCall
);
1460 return kIOReturnSuccess
;
1463 //******************************************************************************
1464 // getAggressiveness
1466 // Override IOService::setAggressiveness()
1467 // Fetch the aggressiveness factor with the given type.
1468 //******************************************************************************
1470 IOReturn
IOPMrootDomain::getAggressiveness (
1472 unsigned long * outLevel
)
1478 return kIOReturnBadArgument
;
1482 // Disk quick spindown in effect, report value = 1
1484 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1485 (type
== kPMMinutesToSpinDown
))
1487 value
= kAggressivesMinValue
;
1491 // Consult the pending request queue.
1495 AggressivesRequest
* entry
;
1497 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1499 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1500 (entry
->data
.record
.type
== type
) &&
1501 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1503 value
= entry
->data
.record
.value
;
1510 // Consult the backend records.
1512 if (!source
&& aggressivesData
)
1514 AggressivesRecord
* record
;
1517 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1518 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1520 for (i
= 0; i
< count
; i
++, record
++)
1522 if (record
->type
== type
)
1524 value
= record
->value
;
1531 AGGRESSIVES_UNLOCK();
1535 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1536 source
, (uint32_t) type
, value
);
1537 *outLevel
= (unsigned long) value
;
1538 return kIOReturnSuccess
;
1542 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1543 *outLevel
= 0; // default return = 0, driver may not check for error
1544 return kIOReturnInvalid
;
1548 //******************************************************************************
1549 // joinAggressiveness
1551 // Request from IOService to join future aggressiveness broadcasts.
1552 //******************************************************************************
1554 IOReturn
IOPMrootDomain::joinAggressiveness(
1555 IOService
* service
)
1557 AggressivesRequest
* request
;
1559 if (!service
|| (service
== this))
1560 return kIOReturnBadArgument
;
1562 DLOG("joinAggressiveness %s %p\n", service
->getName(), service
);
1564 request
= IONew(AggressivesRequest
, 1);
1566 return kIOReturnNoMemory
;
1568 service
->retain(); // released by synchronizeAggressives()
1570 memset(request
, 0, sizeof(*request
));
1571 request
->dataType
= kAggressivesRequestTypeService
;
1572 request
->data
.service
= service
;
1575 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1576 AGGRESSIVES_UNLOCK();
1578 thread_call_enter(aggressivesThreadCall
);
1580 return kIOReturnSuccess
;
1583 //******************************************************************************
1584 // handleAggressivesRequests
1586 // Backend thread processes all incoming aggressiveness requests in the queue.
1587 //******************************************************************************
1590 handleAggressivesFunction(
1591 thread_call_param_t param1
,
1592 thread_call_param_t param2
)
1596 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1600 void IOPMrootDomain::handleAggressivesRequests( void )
1602 AggressivesRecord
* start
;
1603 AggressivesRecord
* record
;
1604 AggressivesRequest
* request
;
1605 queue_head_t joinedQueue
;
1609 bool pingSelf
= false;
1613 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1614 queue_empty(&aggressivesQueue
))
1617 gAggressivesState
|= kAggressivesStateBusy
;
1618 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1619 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1624 queue_init(&joinedQueue
);
1628 // Remove request from the incoming queue in FIFO order.
1629 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1630 switch (request
->dataType
)
1632 case kAggressivesRequestTypeRecord
:
1633 // Update existing record if found.
1635 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1637 if (record
->type
== request
->data
.record
.type
)
1641 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1643 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1646 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1647 kAggressivesRecordFlagModified
);
1648 DLOG("disk spindown accelerated, was %u min\n",
1652 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1654 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1657 record
->flags
|= kAggressivesRecordFlagModified
;
1658 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1659 DLOG("disk spindown restored to %u min\n",
1663 else if (record
->value
!= request
->data
.record
.value
)
1665 record
->value
= request
->data
.record
.value
;
1666 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1669 record
->flags
|= kAggressivesRecordFlagModified
;
1676 // No matching record, append a new record.
1678 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1680 AggressivesRecord newRecord
;
1682 newRecord
.flags
= kAggressivesRecordFlagModified
;
1683 newRecord
.type
= request
->data
.record
.type
;
1684 newRecord
.value
= request
->data
.record
.value
;
1685 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1687 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1688 DLOG("disk spindown accelerated\n");
1691 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1693 // OSData may have switched to another (larger) buffer.
1694 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1695 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1699 // Finished processing the request, release it.
1700 IODelete(request
, AggressivesRequest
, 1);
1703 case kAggressivesRequestTypeService
:
1704 // synchronizeAggressives() will free request.
1705 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1709 panic("bad aggressives request type %x\n", request
->dataType
);
1712 } while (!queue_empty(&aggressivesQueue
));
1714 // Release the lock to perform work, with busy flag set.
1715 if (!queue_empty(&joinedQueue
) || broadcast
)
1717 AGGRESSIVES_UNLOCK();
1718 if (!queue_empty(&joinedQueue
))
1719 synchronizeAggressives(&joinedQueue
, start
, count
);
1721 broadcastAggressives(start
, count
);
1725 // Remove the modified flag from all records.
1726 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1728 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1729 ((record
->type
== kPMMinutesToDim
) ||
1730 (record
->type
== kPMMinutesToSleep
)))
1733 record
->flags
&= ~kAggressivesRecordFlagModified
;
1736 // Check the incoming queue again since new entries may have been
1737 // added while lock was released above.
1739 } while (!queue_empty(&aggressivesQueue
));
1741 gAggressivesState
&= ~kAggressivesStateBusy
;
1744 AGGRESSIVES_UNLOCK();
1746 // Root domain is interested in system and display sleep slider changes.
1747 // Submit a power event to handle those changes on the PM work loop.
1749 if (pingSelf
&& pmPowerStateQueue
) {
1750 pmPowerStateQueue
->submitPowerEvent(
1751 kPowerEventPolicyStimulus
,
1752 (void *) kStimulusAggressivenessChanged
);
1756 //******************************************************************************
1757 // synchronizeAggressives
1759 // Push all known aggressiveness records to one or more IOService.
1760 //******************************************************************************
1762 void IOPMrootDomain::synchronizeAggressives(
1763 queue_head_t
* joinedQueue
,
1764 const AggressivesRecord
* array
,
1767 IOService
* service
;
1768 AggressivesRequest
* request
;
1769 const AggressivesRecord
* record
;
1770 IOPMDriverCallEntry callEntry
;
1774 while (!queue_empty(joinedQueue
))
1776 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1777 if (request
->dataType
== kAggressivesRequestTypeService
)
1778 service
= request
->data
.service
;
1782 IODelete(request
, AggressivesRequest
, 1);
1787 if (service
->assertPMDriverCall(&callEntry
))
1789 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1791 value
= record
->value
;
1792 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1793 value
= kAggressivesMinValue
;
1795 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1796 record
->type
, value
, service
->getName());
1797 service
->setAggressiveness(record
->type
, value
);
1799 service
->deassertPMDriverCall(&callEntry
);
1801 service
->release(); // retained by joinAggressiveness()
1806 //******************************************************************************
1807 // broadcastAggressives
1809 // Traverse PM tree and call setAggressiveness() for records that have changed.
1810 //******************************************************************************
1812 void IOPMrootDomain::broadcastAggressives(
1813 const AggressivesRecord
* array
,
1816 IORegistryIterator
* iter
;
1817 IORegistryEntry
* entry
;
1818 IOPowerConnection
* connect
;
1819 IOService
* service
;
1820 const AggressivesRecord
* record
;
1821 IOPMDriverCallEntry callEntry
;
1825 iter
= IORegistryIterator::iterateOver(
1826 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1832 while ((entry
= iter
->getNextObject()))
1834 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1835 if (!connect
|| !connect
->getReadyFlag())
1838 if ((service
= (IOService
*) connect
->copyChildEntry(gIOPowerPlane
)))
1840 if (service
->assertPMDriverCall(&callEntry
))
1842 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1844 if (record
->flags
& kAggressivesRecordFlagModified
)
1846 value
= record
->value
;
1847 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1848 value
= kAggressivesMinValue
;
1849 _LOG("broadcastAggressives %x = %u to %s\n",
1850 record
->type
, value
, service
->getName());
1851 service
->setAggressiveness(record
->type
, value
);
1854 service
->deassertPMDriverCall(&callEntry
);
1860 while (!entry
&& !iter
->isValid());
1866 // MARK: System Sleep
1868 //******************************************************************************
1869 // startIdleSleepTimer
1871 //******************************************************************************
1873 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1875 AbsoluteTime deadline
;
1880 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1881 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1882 idleSleepTimerPending
= true;
1886 thread_call_enter(extraSleepTimer
);
1888 DLOG("idle timer set for %u seconds\n", inSeconds
);
1891 //******************************************************************************
1892 // cancelIdleSleepTimer
1894 //******************************************************************************
1896 void IOPMrootDomain::cancelIdleSleepTimer( void )
1899 if (idleSleepTimerPending
)
1901 DLOG("idle timer cancelled\n");
1902 thread_call_cancel(extraSleepTimer
);
1903 idleSleepTimerPending
= false;
1907 //******************************************************************************
1908 // idleSleepTimerExpired
1910 //******************************************************************************
1912 static void idleSleepTimerExpired(
1913 thread_call_param_t us
, thread_call_param_t
)
1915 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
1918 //******************************************************************************
1919 // handleSleepTimerExpiration
1921 // The time between the sleep idle timeout and the next longest one has elapsed.
1922 // It's time to sleep. Start that by removing the clamp that's holding us awake.
1923 //******************************************************************************
1925 void IOPMrootDomain::handleSleepTimerExpiration( void )
1927 if (!getPMworkloop()->inGate())
1929 getPMworkloop()->runAction(
1930 OSMemberFunctionCast(IOWorkLoop::Action
, this,
1931 &IOPMrootDomain::handleSleepTimerExpiration
),
1938 DLOG("sleep timer expired\n");
1941 idleSleepTimerPending
= false;
1943 clock_get_uptime(&time
);
1944 if ((AbsoluteTime_to_scalar(&time
) > autoWakeStart
) &&
1945 (AbsoluteTime_to_scalar(&time
) < autoWakeEnd
))
1947 thread_call_enter_delayed(extraSleepTimer
, *((AbsoluteTime
*) &autoWakeEnd
));
1951 setQuickSpinDownTimeout();
1952 adjustPowerState(true);
1955 //******************************************************************************
1956 // setQuickSpinDownTimeout
1958 //******************************************************************************
1960 void IOPMrootDomain::setQuickSpinDownTimeout( void )
1964 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
1967 //******************************************************************************
1968 // restoreUserSpinDownTimeout
1970 //******************************************************************************
1972 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
1976 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
1979 //******************************************************************************
1982 //******************************************************************************
1985 IOReturn
IOPMrootDomain::sleepSystem( void )
1987 return sleepSystemOptions(NULL
);
1991 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
1993 /* sleepSystem is a public function, and may be called by any kernel driver.
1994 * And that's bad - drivers should sleep the system by calling
1995 * receivePowerNotification() instead. Drivers should not use sleepSystem.
1997 * Note that user space app calls to IOPMSleepSystem() will also travel
1998 * this code path and thus be correctly identified as software sleeps.
2001 if (options
&& options
->getObject("OSSwitch"))
2003 // Log specific sleep cause for OS Switch hibernation
2004 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2006 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2011 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2013 static const char * IOPMSleepReasons
[] = {
2015 kIOPMClamshellSleepKey
,
2016 kIOPMPowerButtonSleepKey
,
2017 kIOPMSoftwareSleepKey
,
2018 kIOPMOSSwitchHibernationKey
,
2020 kIOPMLowPowerSleepKey
,
2021 kIOPMThermalEmergencySleepKey
,
2022 kIOPMMaintenanceSleepKey
,
2023 kIOPMSleepServiceExitKey
,
2024 kIOPMDarkWakeThermalEmergencyKey
2027 PMEventDetails
*details
;
2029 if (!checkSystemCanSleep())
2031 // Record why the system couldn't sleep
2032 details
= PMEventDetails::eventDetails(kIOPMEventTypeSleep
, NULL
,
2033 sleepReason
, kIOReturnNotPermitted
);
2035 recordAndReleasePMEvent( details
);
2036 return kIOReturnNotPermitted
;
2039 if (kIOPMSleepReasonDarkWakeThermalEmergency
== sleepReason
)
2040 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
2043 timeline
->setSleepCycleInProgressFlag(true);
2045 // Time to publish a UUID for the Sleep --> Wake cycle
2046 if(pmPowerStateQueue
) {
2047 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishSleepWakeUUID
, (void *)true);
2050 // Log the beginning of system sleep.
2051 details
= PMEventDetails::eventDetails(kIOPMEventTypeSleep
, NULL
,
2052 sleepReason
, kIOReturnSuccess
);
2054 recordAndReleasePMEvent( details
);
2056 // Record sleep cause in IORegistry
2057 lastSleepReason
= sleepReason
;
2058 sleepReason
-= (kIOPMSleepReasonClamshell
- 1);
2059 if (sleepReason
&& (sleepReason
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0]))) {
2060 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[sleepReason
]);
2063 if (pmPowerStateQueue
)
2064 pmPowerStateQueue
->submitPowerEvent(
2065 kPowerEventPolicyStimulus
,
2066 (void *) kStimulusDemandSystemSleep
);
2068 return kIOReturnSuccess
;
2071 IOReturn
IOPMrootDomain::recordPMEventGated(PMEventDetails
*record
)
2073 // If we don't have a place to log to, we can't actually
2074 // log anything. Chances are, the person who is asking us to do
2075 // the PM logging has forgotten to set the right bootflags
2077 return kIOReturnSuccess
;
2079 if(gIOPMWorkLoop
->inGate() == false) {
2081 IOReturn ret
= gIOPMWorkLoop
->runAction(
2082 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::recordPMEventGated
),
2089 // Now that we're guaranteed to be running in gate ...
2091 // Check the validity of the argument we are given
2093 return kIOReturnBadArgument
;
2095 // Record a driver event, or a system event
2096 if(record
->eventClassifier
== kIOPMEventClassDriverEvent
2097 || record
->eventClassifier
== kIOPMEventClassSystemEvent
)
2098 return this->recordPMEvent(record
);
2101 return kIOReturnBadArgument
;
2105 IOReturn
IOPMrootDomain::recordAndReleasePMEventGated(PMEventDetails
*record
)
2107 IOReturn ret
= kIOReturnBadArgument
;
2111 ret
= recordPMEventGated(record
);
2118 //******************************************************************************
2121 // This overrides powerChangeDone in IOService.
2122 //******************************************************************************
2124 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2126 PMEventDetails
*details
;
2129 DLOG("PowerChangeDone: %u->%u\n",
2130 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2132 switch ( getPowerState() )
2135 if (previousPowerState
!= ON_STATE
)
2138 details
= PMEventDetails::eventDetails(
2139 kIOPMEventTypeSleepDone
,
2144 recordAndReleasePMEvent( details
);
2146 // re-enable this timer for next sleep
2147 cancelIdleSleepTimer();
2150 clock_usec_t microsecs
;
2151 clock_get_calendar_microtime(&secs
, µsecs
);
2153 gIOLastSleepTime
.tv_sec
= secs
;
2154 gIOLastSleepTime
.tv_usec
= microsecs
;
2155 gIOLastWakeTime
.tv_sec
= 0;
2156 gIOLastWakeTime
.tv_usec
= 0;
2159 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2161 IOHibernateSystemHasSlept();
2163 evaluateSystemSleepPolicyFinal();
2165 LOG("System Sleep\n");
2168 getPlatform()->sleepKernel();
2170 // The CPU(s) are off at this point,
2171 // Code will resume execution here upon wake.
2173 clock_get_uptime(&systemWakeTime
);
2176 IOHibernateSystemWake();
2179 // sleep transition complete
2180 gSleepOrShutdownPending
= 0;
2182 // trip the reset of the calendar clock
2183 clock_wakeup_calendar();
2186 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2190 getPlatform()->PMLog(kIOPMrootDomainClass
, kPMLogSystemWake
, 0, 0);
2191 lowBatteryCondition
= false;
2192 lastSleepReason
= 0;
2194 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2195 _debugWakeSeconds
= 0;
2197 // And start logging the wake event here
2198 // TODO: Publish the wakeReason string as an integer
2199 details
= PMEventDetails::eventDetails(
2205 recordAndReleasePMEvent( details
);
2211 #if defined(__i386__) || defined(__x86_64__)
2212 wranglerTickled
= false;
2213 graphicsSuppressed
= false;
2214 darkWakePostTickle
= false;
2215 logGraphicsClamp
= true;
2216 logWranglerTickle
= true;
2217 sleepTimerMaintenance
= false;
2218 wranglerTickleLatched
= false;
2219 darkWakeThermalAlarm
= false;
2220 darkWakeThermalEmergency
= false;
2222 OSString
* wakeType
= OSDynamicCast(
2223 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2224 OSString
* wakeReason
= OSDynamicCast(
2225 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2227 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2229 lowBatteryCondition
= true;
2230 darkWakeMaintenance
= true;
2231 darkWakeToSleepASAP
= true;
2233 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2235 OSNumber
* hibOptions
= OSDynamicCast(
2236 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2238 if (hibernateAborted
|| ((hibOptions
&&
2239 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2241 // Hibernate aborted, or EFI brought up graphics
2242 wranglerTickled
= true;
2246 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2247 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2249 // User wake or RTC alarm
2250 wranglerTickled
= true;
2254 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2256 // SMC standby timer trumps SleepX
2257 darkWakeMaintenance
= true;
2258 darkWakeToSleepASAP
= true;
2259 sleepTimerMaintenance
= true;
2262 if ((_lastDebugWakeSeconds
!= 0) &&
2263 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2265 // SleepX before maintenance
2266 wranglerTickled
= true;
2270 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2272 darkWakeMaintenance
= true;
2273 darkWakeToSleepASAP
= true;
2277 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2279 darkWakeToSleepASAP
= true;
2280 // darkWakeMaintenance = true; // ????
2281 darkWakeSleepService
= true;
2285 // Unidentified wake source, resume to full wake if debug
2286 // alarm is pending.
2288 if (_lastDebugWakeSeconds
&&
2289 (!wakeReason
|| wakeReason
->isEqualTo("")))
2290 wranglerTickled
= true;
2292 darkWakeToSleepASAP
= true;
2298 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2300 darkWakeMaintenance
= true;
2301 darkWakeToSleepASAP
= true;
2302 sleepTimerMaintenance
= true;
2304 else if (hibernateAborted
|| !wakeType
||
2305 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2306 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2308 // Post a HID tickle immediately - except for RTC maintenance wake.
2309 wranglerTickled
= true;
2313 darkWakeMaintenance
= true;
2314 darkWakeToSleepASAP
= true;
2318 if (wranglerTickled
)
2320 else if (!darkWakeMaintenance
)
2322 // Early/late tickle for non-maintenance wake.
2323 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2324 kDarkWakeFlagHIDTickleEarly
) ||
2325 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2326 kDarkWakeFlagHIDTickleLate
))
2328 darkWakePostTickle
= true;
2331 #else /* !__i386__ && !__x86_64__ */
2332 // stay awake for at least 30 seconds
2333 wranglerTickled
= true;
2334 startIdleSleepTimer(30);
2337 changePowerStateToPriv(ON_STATE
);
2341 if (previousPowerState
!= ON_STATE
)
2343 details
= PMEventDetails::eventDetails(
2344 kIOPMEventTypeWakeDone
,
2349 recordAndReleasePMEvent( details
);
2355 //******************************************************************************
2356 // requestPowerDomainState
2358 // Extend implementation in IOService. Running on PM work loop thread.
2359 //******************************************************************************
2361 IOReturn
IOPMrootDomain::requestPowerDomainState (
2362 IOPMPowerFlags childDesire
,
2363 IOPowerConnection
* childConnection
,
2364 unsigned long specification
)
2366 // Idle and system sleep prevention flags affects driver desire.
2367 // Children desire are irrelevant so they are cleared.
2369 return super::requestPowerDomainState(0, childConnection
, specification
);
2372 //******************************************************************************
2373 // updatePreventIdleSleepList
2375 // Called by IOService on PM work loop.
2376 //******************************************************************************
2378 void IOPMrootDomain::updatePreventIdleSleepList(
2379 IOService
* service
, bool addNotRemove
)
2381 unsigned int oldCount
, newCount
;
2385 // Disregard disk I/O (anything besides the display wrangler)
2386 // as a factor preventing idle sleep,except in the case of legacy disk I/O
2388 if ((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOAlways
) &&
2389 addNotRemove
&& (service
!= wrangler
) && (service
!= this))
2394 oldCount
= preventIdleSleepList
->getCount();
2397 preventIdleSleepList
->setObject(service
);
2398 DLOG("prevent idle sleep list: %s+ (%u)\n",
2399 service
->getName(), preventIdleSleepList
->getCount());
2401 else if (preventIdleSleepList
->member(service
))
2403 preventIdleSleepList
->removeObject(service
);
2404 DLOG("prevent idle sleep list: %s- (%u)\n",
2405 service
->getName(), preventIdleSleepList
->getCount());
2407 newCount
= preventIdleSleepList
->getCount();
2409 if ((oldCount
== 0) && (newCount
!= 0))
2411 // Driver added to empty prevent list.
2412 // Update the driver desire to prevent idle sleep.
2413 // Driver desire does not prevent demand sleep.
2415 changePowerStateTo(ON_STATE
);
2417 else if ((oldCount
!= 0) && (newCount
== 0))
2419 // Last driver removed from prevent list.
2420 // Drop the driver clamp to allow idle sleep.
2422 changePowerStateTo(SLEEP_STATE
);
2423 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2427 //******************************************************************************
2428 // preventSystemSleepListUpdate
2430 // Called by IOService on PM work loop.
2431 //******************************************************************************
2433 void IOPMrootDomain::updatePreventSystemSleepList(
2434 IOService
* service
, bool addNotRemove
)
2436 unsigned int oldCount
;
2439 if (this == service
)
2442 oldCount
= preventSystemSleepList
->getCount();
2445 preventSystemSleepList
->setObject(service
);
2446 DLOG("prevent system sleep list: %s+ (%u)\n",
2447 service
->getName(), preventSystemSleepList
->getCount());
2449 else if (preventSystemSleepList
->member(service
))
2451 preventSystemSleepList
->removeObject(service
);
2452 DLOG("prevent system sleep list: %s- (%u)\n",
2453 service
->getName(), preventSystemSleepList
->getCount());
2455 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2457 // Lost all system sleep preventers.
2458 // Send stimulus if system sleep was blocked, and is in dark wake.
2459 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2464 //******************************************************************************
2467 // Override the superclass implementation to send a different message type.
2468 //******************************************************************************
2470 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2472 DLOG("tellChangeDown %u->%u\n",
2473 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2475 if (SLEEP_STATE
== stateNum
)
2477 if (!ignoreTellChangeDown
)
2478 tracePoint( kIOPMTracePointSleepApplications
);
2480 tracePoint( kIOPMTracePointSleepPriorityClients
);
2483 if ((SLEEP_STATE
== stateNum
) && !ignoreTellChangeDown
)
2485 userActivityAtSleep
= userActivityCount
;
2486 hibernateAborted
= false;
2487 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2489 // Direct callout into OSKext so it can disable kext unloads
2490 // during sleep/wake to prevent deadlocks.
2491 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2493 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2495 // Notify platform that sleep has begun
2496 getPlatform()->callPlatformFunction(
2497 sleepMessagePEFunction
, false,
2498 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
2501 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2502 // But tellClientsWithResponse() must be called for both.
2503 ignoreTellChangeDown
= true;
2506 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2509 //******************************************************************************
2512 // Override the superclass implementation to send a different message type.
2513 // This must be idle sleep since we don't ask during any other power change.
2514 //******************************************************************************
2516 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2518 DLOG("askChangeDown %u->%u\n",
2519 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2521 // Don't log for dark wake entry
2522 if (kSystemTransitionSleep
== _systemTransitionType
)
2523 tracePoint( kIOPMTracePointSleepApplications
);
2525 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2528 //******************************************************************************
2529 // askChangeDownDone
2531 // Called by PM after all apps have responded to kIOMessageCanSystemSleep.
2532 // pmconfigd may create a deny sleep assertion before ack'ing.
2533 //******************************************************************************
2535 void IOPMrootDomain::askChangeDownDone(
2536 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2538 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2539 *inOutChangeFlags
, *cancel
,
2540 _systemTransitionType
,
2541 _currentCapability
, _pendingCapability
);
2543 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2545 // Dark->Sleep transition.
2546 // Check if there are any deny sleep assertions.
2547 // Full->Dark transition is never cancelled.
2549 if (!checkSystemCanSleep(true))
2551 // Cancel dark wake to sleep transition.
2552 // Must re-scan assertions upon entering dark wake.
2555 DLOG("cancel dark->sleep\n");
2560 //******************************************************************************
2563 // Notify registered applications and kernel clients that we are not dropping
2566 // We override the superclass implementation so we can send a different message
2567 // type to the client or application being notified.
2569 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2570 //******************************************************************************
2572 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2574 DLOG("tellNoChangeDown %u->%u\n",
2575 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2577 // Sleep canceled, clear the sleep trace point.
2578 tracePoint(kIOPMTracePointSystemUp
);
2580 if (idleSeconds
&& !wrangler
)
2582 // stay awake for at least idleSeconds
2583 startIdleSleepTimer(idleSeconds
);
2585 return tellClients( kIOMessageSystemWillNotSleep
);
2588 //******************************************************************************
2591 // Notify registered applications and kernel clients that we are raising power.
2593 // We override the superclass implementation so we can send a different message
2594 // type to the client or application being notified.
2595 //******************************************************************************
2597 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2600 DLOG("tellChangeUp %u->%u\n",
2601 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2603 ignoreTellChangeDown
= false;
2605 if ( stateNum
== ON_STATE
)
2607 // Direct callout into OSKext so it can disable kext unloads
2608 // during sleep/wake to prevent deadlocks.
2609 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2611 // Notify platform that sleep was cancelled or resumed.
2612 getPlatform()->callPlatformFunction(
2613 sleepMessagePEFunction
, false,
2614 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2617 if (getPowerState() == ON_STATE
)
2619 // this is a quick wake from aborted sleep
2620 if (idleSeconds
&& !wrangler
)
2622 // stay awake for at least idleSeconds
2623 startIdleSleepTimer(idleSeconds
);
2625 tellClients( kIOMessageSystemWillPowerOn
);
2628 tracePoint( kIOPMTracePointWakeApplications
);
2630 if (pmStatsAppResponses
)
2632 setProperty(kIOPMSleepStatisticsAppsKey
, pmStatsAppResponses
);
2633 pmStatsAppResponses
->release();
2634 pmStatsAppResponses
= OSArray::withCapacity(5);
2637 tellClients( kIOMessageSystemHasPoweredOn
);
2641 //******************************************************************************
2642 // sysPowerDownHandler
2644 // Perform a vfs sync before system sleep.
2645 //******************************************************************************
2647 IOReturn
IOPMrootDomain::sysPowerDownHandler(
2648 void * target
, void * refCon
,
2649 UInt32 messageType
, IOService
* service
,
2650 void * messageArgs
, vm_size_t argSize
)
2654 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
2657 return kIOReturnUnsupported
;
2659 if (messageType
== kIOMessageSystemCapabilityChange
)
2661 IOPMSystemCapabilityChangeParameters
* params
=
2662 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
2664 // Interested applications have been notified of an impending power
2665 // change and have acked (when applicable).
2666 // This is our chance to save whatever state we can before powering
2668 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2671 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2672 params
->fromCapabilities
, params
->toCapabilities
,
2673 params
->changeFlags
);
2675 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
2676 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
2677 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2679 // We will ack within 20 seconds
2680 params
->maxWaitForReply
= 20 * 1000 * 1000;
2682 gRootDomain
->evaluateSystemSleepPolicyEarly();
2684 // add in time we could spend freeing pages
2685 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
2687 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
2689 DLOG("sysPowerDownHandler timeout %d s\n", (int) (params
->maxWaitForReply
/ 1000 / 1000));
2692 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2694 // Purposely delay the ack and hope that shutdown occurs quickly.
2695 // Another option is not to schedule the thread and wait for
2697 AbsoluteTime deadline
;
2698 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2699 thread_call_enter1_delayed(
2700 gRootDomain
->diskSyncCalloutEntry
,
2701 (thread_call_param_t
) params
->notifyRef
,
2706 gRootDomain
->diskSyncCalloutEntry
,
2707 (thread_call_param_t
) params
->notifyRef
);
2711 if ((params
->changeFlags
& kIOPMSystemCapabilityDidChange
) &&
2712 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) &&
2713 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2715 // We will ack within 110 seconds
2716 params
->maxWaitForReply
= 110 * 1000 * 1000;
2719 gRootDomain
->diskSyncCalloutEntry
,
2720 (thread_call_param_t
) params
->notifyRef
);
2723 ret
= kIOReturnSuccess
;
2729 //******************************************************************************
2730 // handleQueueSleepWakeUUID
2732 // Called from IOPMrootDomain when we're initiating a sleep,
2733 // or indirectly from PM configd when PM decides to clear the UUID.
2734 // PM clears the UUID several minutes after successful wake from sleep,
2735 // so that we might associate App spindumps with the immediately previous
2738 // @param obj has a retain on it. We're responsible for releasing that retain.
2739 //******************************************************************************
2741 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
2743 OSString
*str
= NULL
;
2745 if (kOSBooleanFalse
== obj
)
2747 handlePublishSleepWakeUUID(NULL
);
2749 else if ((str
= OSDynamicCast(OSString
, obj
)))
2751 // This branch caches the UUID for an upcoming sleep/wake
2752 if (queuedSleepWakeUUIDString
) {
2753 queuedSleepWakeUUIDString
->release();
2754 queuedSleepWakeUUIDString
= NULL
;
2756 queuedSleepWakeUUIDString
= str
;
2757 queuedSleepWakeUUIDString
->retain();
2759 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
2768 //******************************************************************************
2769 // handlePublishSleepWakeUUID
2771 // Called from IOPMrootDomain when we're initiating a sleep,
2772 // or indirectly from PM configd when PM decides to clear the UUID.
2773 // PM clears the UUID several minutes after successful wake from sleep,
2774 // so that we might associate App spindumps with the immediately previous
2776 //******************************************************************************
2778 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
2783 * Clear the current UUID
2785 if (gSleepWakeUUIDIsSet
)
2787 DLOG("SleepWake UUID cleared\n");
2789 OSString
*UUIDstring
= NULL
;
2792 (UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))))
2794 PMEventDetails
*details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDClear
,
2795 UUIDstring
->getCStringNoCopy(), NULL
, 0);
2797 timeline
->recordSystemPowerEvent( details
);
2800 timeline
->setNumEventsLoggedThisPeriod(0);
2803 gSleepWakeUUIDIsSet
= false;
2805 removeProperty(kIOPMSleepWakeUUIDKey
);
2806 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
2810 * Optionally, publish a new UUID
2812 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
2814 OSString
*publishThisUUID
= NULL
;
2816 publishThisUUID
= queuedSleepWakeUUIDString
;
2817 publishThisUUID
->retain();
2820 PMEventDetails
*details
;
2821 details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDSet
,
2822 publishThisUUID
->getCStringNoCopy(), NULL
, 0);
2824 timeline
->recordSystemPowerEvent( details
);
2829 if (publishThisUUID
)
2831 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
2832 publishThisUUID
->release();
2835 gSleepWakeUUIDIsSet
= true;
2836 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
2838 queuedSleepWakeUUIDString
->release();
2839 queuedSleepWakeUUIDString
= NULL
;
2843 //******************************************************************************
2844 // changePowerStateTo & changePowerStateToPriv
2846 // Override of these methods for logging purposes.
2847 //******************************************************************************
2849 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
2851 DLOG("changePowerStateTo(%lu)\n", ordinal
);
2853 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
2854 return kIOReturnUnsupported
;
2856 return super::changePowerStateTo(ordinal
);
2859 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
2861 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
2863 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
2864 return kIOReturnUnsupported
;
2866 return super::changePowerStateToPriv(ordinal
);
2869 //******************************************************************************
2872 //******************************************************************************
2874 bool IOPMrootDomain::activitySinceSleep(void)
2876 return (userActivityCount
!= userActivityAtSleep
);
2879 bool IOPMrootDomain::abortHibernation(void)
2881 bool ret
= activitySinceSleep();
2883 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
2885 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
2886 hibernateAborted
= true;
2892 hibernate_should_abort(void)
2895 return (gRootDomain
->abortHibernation());
2900 //******************************************************************************
2901 // sleepOnClamshellClosed
2903 // contains the logic to determine if the system should sleep when the clamshell
2905 //******************************************************************************
2907 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
2909 if (!clamshellExists
)
2912 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d\n",
2913 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
);
2915 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) );
2918 void IOPMrootDomain::sendClientClamshellNotification( void )
2920 /* Only broadcast clamshell alert if clamshell exists. */
2921 if (!clamshellExists
)
2924 setProperty(kAppleClamshellStateKey
,
2925 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
2927 setProperty(kAppleClamshellCausesSleepKey
,
2928 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
2930 /* Argument to message is a bitfiel of
2931 * ( kClamshellStateBit | kClamshellSleepBit )
2933 messageClients(kIOPMMessageClamshellStateChange
,
2934 (void *) ( (clamshellClosed
? kClamshellStateBit
: 0)
2935 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
2938 //******************************************************************************
2939 // getSleepSupported
2942 //******************************************************************************
2944 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
2946 return( platformSleepSupport
);
2949 //******************************************************************************
2950 // setSleepSupported
2953 //******************************************************************************
2955 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
2957 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
2958 OSBitOrAtomic(flags
, &platformSleepSupport
);
2961 //******************************************************************************
2965 //******************************************************************************
2967 void IOPMrootDomain::wakeFromDoze( void )
2969 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
2975 //******************************************************************************
2978 // Adds a new feature to the supported features dictionary
2979 //******************************************************************************
2981 void IOPMrootDomain::publishFeature( const char * feature
)
2983 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
2986 //******************************************************************************
2987 // publishFeature (with supported power source specified)
2989 // Adds a new feature to the supported features dictionary
2990 //******************************************************************************
2992 void IOPMrootDomain::publishFeature(
2993 const char *feature
,
2994 uint32_t supportedWhere
,
2995 uint32_t *uniqueFeatureID
)
2997 static uint16_t next_feature_id
= 500;
2999 OSNumber
*new_feature_data
= NULL
;
3000 OSNumber
*existing_feature
= NULL
;
3001 OSArray
*existing_feature_arr
= NULL
;
3002 OSObject
*osObj
= NULL
;
3003 uint32_t feature_value
= 0;
3005 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3007 if(!supportedWhere
) {
3008 // Feature isn't supported anywhere!
3012 if(next_feature_id
> 5000) {
3013 // Far, far too many features!
3017 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3019 OSDictionary
*features
=
3020 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3022 // Create new features dict if necessary
3023 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3024 features
= OSDictionary::withDictionary(features
);
3026 features
= OSDictionary::withCapacity(1);
3029 // Create OSNumber to track new feature
3031 next_feature_id
+= 1;
3032 if( uniqueFeatureID
) {
3033 // We don't really mind if the calling kext didn't give us a place
3034 // to stash their unique id. Many kexts don't plan to unload, and thus
3035 // have no need to remove themselves later.
3036 *uniqueFeatureID
= next_feature_id
;
3039 feature_value
= (uint32_t)next_feature_id
;
3040 feature_value
<<= 16;
3041 feature_value
+= supportedWhere
;
3043 new_feature_data
= OSNumber::withNumber(
3044 (unsigned long long)feature_value
, 32);
3046 // Does features object already exist?
3047 if( (osObj
= features
->getObject(feature
)) )
3049 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3051 // We need to create an OSArray to hold the now 2 elements.
3052 existing_feature_arr
= OSArray::withObjects(
3053 (const OSObject
**)&existing_feature
, 1, 2);
3054 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3056 // Add object to existing array
3057 existing_feature_arr
= OSArray::withArray(
3058 existing_feature_arr
,
3059 existing_feature_arr
->getCount() + 1);
3062 if (existing_feature_arr
)
3064 existing_feature_arr
->setObject(new_feature_data
);
3065 features
->setObject(feature
, existing_feature_arr
);
3066 existing_feature_arr
->release();
3067 existing_feature_arr
= 0;
3070 // The easy case: no previously existing features listed. We simply
3071 // set the OSNumber at key 'feature' and we're on our way.
3072 features
->setObject(feature
, new_feature_data
);
3075 new_feature_data
->release();
3077 setProperty(kRootDomainSupportedFeatures
, features
);
3079 features
->release();
3081 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3083 // Notify EnergySaver and all those in user space so they might
3084 // re-populate their feature specific UI
3085 if(pmPowerStateQueue
) {
3086 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3090 //******************************************************************************
3091 // removePublishedFeature
3093 // Removes previously published feature
3094 //******************************************************************************
3096 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3098 IOReturn ret
= kIOReturnError
;
3099 uint32_t feature_value
= 0;
3100 uint16_t feature_id
= 0;
3101 bool madeAChange
= false;
3103 OSSymbol
*dictKey
= NULL
;
3104 OSCollectionIterator
*dictIterator
= NULL
;
3105 OSArray
*arrayMember
= NULL
;
3106 OSNumber
*numberMember
= NULL
;
3107 OSObject
*osObj
= NULL
;
3108 OSNumber
*osNum
= NULL
;
3109 OSArray
*arrayMemberCopy
;
3111 if (kBadPMFeatureID
== removeFeatureID
)
3112 return kIOReturnNotFound
;
3114 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3116 OSDictionary
*features
=
3117 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3119 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3121 // Any modifications to the dictionary are made to the copy to prevent
3122 // races & crashes with userland clients. Dictionary updated
3123 // automically later.
3124 features
= OSDictionary::withDictionary(features
);
3127 ret
= kIOReturnNotFound
;
3131 // We iterate 'features' dictionary looking for an entry tagged
3132 // with 'removeFeatureID'. If found, we remove it from our tracking
3133 // structures and notify the OS via a general interest message.
3135 dictIterator
= OSCollectionIterator::withCollection(features
);
3140 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3142 osObj
= features
->getObject(dictKey
);
3144 // Each Feature is either tracked by an OSNumber
3145 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3147 feature_value
= numberMember
->unsigned32BitValue();
3148 feature_id
= (uint16_t)(feature_value
>> 16);
3150 if( feature_id
== (uint16_t)removeFeatureID
)
3153 features
->removeObject(dictKey
);
3158 // Or tracked by an OSArray of OSNumbers
3159 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3161 unsigned int arrayCount
= arrayMember
->getCount();
3163 for(unsigned int i
=0; i
<arrayCount
; i
++)
3165 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3170 feature_value
= osNum
->unsigned32BitValue();
3171 feature_id
= (uint16_t)(feature_value
>> 16);
3173 if( feature_id
== (uint16_t)removeFeatureID
)
3176 if( 1 == arrayCount
) {
3177 // If the array only contains one element, remove
3179 features
->removeObject(dictKey
);
3181 // Otherwise remove the element from a copy of the array.
3182 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3183 if (arrayMemberCopy
)
3185 arrayMemberCopy
->removeObject(i
);
3186 features
->setObject(dictKey
, arrayMemberCopy
);
3187 arrayMemberCopy
->release();
3198 dictIterator
->release();
3202 ret
= kIOReturnSuccess
;
3204 setProperty(kRootDomainSupportedFeatures
, features
);
3206 // Notify EnergySaver and all those in user space so they might
3207 // re-populate their feature specific UI
3208 if(pmPowerStateQueue
) {
3209 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3212 ret
= kIOReturnNotFound
;
3216 if(features
) features
->release();
3217 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3221 //******************************************************************************
3222 // publishPMSetting (private)
3224 // Should only be called by PMSettingObject to publish a PM Setting as a
3225 // supported feature.
3226 //******************************************************************************
3228 void IOPMrootDomain::publishPMSetting(
3229 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3231 if (noPublishPMSettings
&&
3232 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3234 // Setting found in noPublishPMSettings array
3235 *featureID
= kBadPMFeatureID
;
3240 feature
->getCStringNoCopy(), where
, featureID
);
3243 //******************************************************************************
3244 // setPMSetting (private)
3246 // Internal helper to relay PM settings changes from user space to individual
3247 // drivers. Should be called only by IOPMrootDomain::setProperties.
3248 //******************************************************************************
3250 IOReturn
IOPMrootDomain::setPMSetting(
3251 const OSSymbol
*type
,
3254 PMSettingCallEntry
*entries
= 0;
3255 OSArray
*chosen
= 0;
3256 const OSArray
*array
;
3257 PMSettingObject
*pmso
;
3258 thread_t thisThread
;
3259 int i
, j
, count
, capacity
;
3262 return kIOReturnBadArgument
;
3266 // Update settings dict so changes are visible from copyPMSetting().
3267 fPMSettingsDict
->setObject(type
, object
);
3269 // Prep all PMSetting objects with the given 'type' for callout.
3270 array
= (const OSArray
*) settingsCallbacks
->getObject(type
);
3271 if (!array
|| ((capacity
= array
->getCount()) == 0))
3274 // Array to retain PMSetting objects targeted for callout.
3275 chosen
= OSArray::withCapacity(capacity
);
3277 goto unlock_exit
; // error
3279 entries
= IONew(PMSettingCallEntry
, capacity
);
3281 goto unlock_exit
; // error
3282 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3284 thisThread
= current_thread();
3286 for (i
= 0, j
= 0; i
<capacity
; i
++)
3288 pmso
= (PMSettingObject
*) array
->getObject(i
);
3291 entries
[j
].thread
= thisThread
;
3292 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3293 chosen
->setObject(pmso
);
3302 // Call each pmso in the chosen array.
3303 for (i
=0; i
<count
; i
++)
3305 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3306 pmso
->dispatchPMSetting(type
, object
);
3310 for (i
=0; i
<count
; i
++)
3312 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3313 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3314 if (pmso
->waitThread
)
3316 PMSETTING_WAKEUP(pmso
);
3322 if (chosen
) chosen
->release();
3323 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3325 return kIOReturnSuccess
;
3328 //******************************************************************************
3329 // copyPMSetting (public)
3331 // Allows kexts to safely read setting values, without being subscribed to
3333 //******************************************************************************
3335 OSObject
* IOPMrootDomain::copyPMSetting(
3336 OSSymbol
*whichSetting
)
3338 OSObject
*obj
= NULL
;
3340 if(!whichSetting
) return NULL
;
3343 obj
= fPMSettingsDict
->getObject(whichSetting
);
3352 //******************************************************************************
3353 // registerPMSettingController (public)
3355 // direct wrapper to registerPMSettingController with uint32_t power source arg
3356 //******************************************************************************
3358 IOReturn
IOPMrootDomain::registerPMSettingController(
3359 const OSSymbol
* settings
[],
3360 IOPMSettingControllerCallback func
,
3365 return registerPMSettingController(
3367 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3368 func
, target
, refcon
, handle
);
3371 //******************************************************************************
3372 // registerPMSettingController (public)
3374 // Kexts may register for notifications when a particular setting is changed.
3375 // A list of settings is available in IOPM.h.
3377 // * settings - An OSArray containing OSSymbols. Caller should populate this
3378 // array with a list of settings caller wants notifications from.
3379 // * func - A C function callback of the type IOPMSettingControllerCallback
3380 // * target - caller may provide an OSObject *, which PM will pass as an
3381 // target to calls to "func"
3382 // * refcon - caller may provide an void *, which PM will pass as an
3383 // argument to calls to "func"
3384 // * handle - This is a return argument. We will populate this pointer upon
3385 // call success. Hold onto this and pass this argument to
3386 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3388 // kIOReturnSuccess on success
3389 //******************************************************************************
3391 IOReturn
IOPMrootDomain::registerPMSettingController(
3392 const OSSymbol
* settings
[],
3393 uint32_t supportedPowerSources
,
3394 IOPMSettingControllerCallback func
,
3399 PMSettingObject
*pmso
= NULL
;
3400 OSObject
*pmsh
= NULL
;
3401 OSArray
*list
= NULL
;
3404 if (NULL
== settings
||
3408 return kIOReturnBadArgument
;
3411 pmso
= PMSettingObject::pmSettingObject(
3412 (IOPMrootDomain
*) this, func
, target
,
3413 refcon
, supportedPowerSources
, settings
, &pmsh
);
3417 return kIOReturnInternalError
;
3421 for (i
=0; settings
[i
]; i
++)
3423 list
= (OSArray
*) settingsCallbacks
->getObject(settings
[i
]);
3425 // New array of callbacks for this setting
3426 list
= OSArray::withCapacity(1);
3427 settingsCallbacks
->setObject(settings
[i
], list
);
3431 // Add caller to the callback list
3432 list
->setObject(pmso
);
3436 // Return handle to the caller, the setting object is private.
3439 return kIOReturnSuccess
;
3442 //******************************************************************************
3443 // deregisterPMSettingObject (private)
3445 // Only called from PMSettingObject.
3446 //******************************************************************************
3448 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3450 thread_t thisThread
= current_thread();
3451 PMSettingCallEntry
*callEntry
;
3452 OSCollectionIterator
*iter
;
3460 pmso
->disabled
= true;
3462 // Wait for all callout threads to finish.
3465 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3467 if (callEntry
->thread
!= thisThread
)
3475 assert(0 == pmso
->waitThread
);
3476 pmso
->waitThread
= thisThread
;
3477 PMSETTING_WAIT(pmso
);
3478 pmso
->waitThread
= 0;
3482 // Search each PM settings array in the kernel.
3483 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3486 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3488 array
= (OSArray
*) settingsCallbacks
->getObject(sym
);
3489 index
= array
->getNextIndexOfObject(pmso
, 0);
3491 array
->removeObject(index
);
3502 //******************************************************************************
3503 // informCPUStateChange
3505 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3506 // running on battery, with the lid closed, etc.
3508 // informCPUStateChange is a no-op on non x86 systems
3509 // only x86 has explicit support in the IntelCPUPowerManagement kext
3510 //******************************************************************************
3512 void IOPMrootDomain::informCPUStateChange(
3516 #if defined(__i386__) || defined(__x86_64__)
3518 pmioctlVariableInfo_t varInfoStruct
;
3520 const char *varNameStr
= NULL
;
3521 int32_t *varIndex
= NULL
;
3523 if (kInformAC
== type
) {
3524 varNameStr
= kIOPMRootDomainBatPowerCString
;
3525 varIndex
= &idxPMCPULimitedPower
;
3526 } else if (kInformLid
== type
) {
3527 varNameStr
= kIOPMRootDomainLidCloseCString
;
3528 varIndex
= &idxPMCPUClamshell
;
3533 // Set the new value!
3534 // pmCPUControl will assign us a new ID if one doesn't exist yet
3535 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
3536 varInfoStruct
.varID
= *varIndex
;
3537 varInfoStruct
.varType
= vBool
;
3538 varInfoStruct
.varInitValue
= value
;
3539 varInfoStruct
.varCurValue
= value
;
3540 strncpy( (char *)varInfoStruct
.varName
,
3541 (const char *)varNameStr
,
3542 strlen(varNameStr
) + 1 );
3545 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
3547 // pmCPU only assigns numerical id's when a new varName is specified
3549 && (*varIndex
== kCPUUnknownIndex
))
3551 // pmCPUControl has assigned us a new variable ID.
3552 // Let's re-read the structure we just SET to learn that ID.
3553 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
3557 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3558 *varIndex
= varInfoStruct
.varID
;
3564 #endif /* __i386__ || __x86_64__ */
3568 // MARK: Deep Sleep Policy
3572 //******************************************************************************
3573 // evaluateSystemSleepPolicy
3574 //******************************************************************************
3576 struct IOPMSystemSleepPolicyEntry
3578 uint32_t factorMask
;
3579 uint32_t factorBits
;
3580 uint32_t sleepFlags
;
3581 uint32_t wakeEvents
;
3584 struct IOPMSystemSleepPolicyTable
3586 uint8_t signature
[4];
3588 uint16_t entryCount
;
3589 IOPMSystemSleepPolicyEntry entries
[];
3593 kIOPMSleepFactorSleepTimerWake
= 0x00000001,
3594 kIOPMSleepFactorLidOpen
= 0x00000002,
3595 kIOPMSleepFactorACPower
= 0x00000004,
3596 kIOPMSleepFactorLowBattery
= 0x00000008,
3597 kIOPMSleepFactorDeepSleepNoDelay
= 0x00000010,
3598 kIOPMSleepFactorDeepSleepDemand
= 0x00000020,
3599 kIOPMSleepFactorDeepSleepDisable
= 0x00000040,
3600 kIOPMSleepFactorUSBExternalDevice
= 0x00000080,
3601 kIOPMSleepFactorBluetoothHIDDevice
= 0x00000100,
3602 kIOPMSleepFactorExternalMediaMounted
= 0x00000200,
3603 kIOPMSleepFactorDriverAssertBit5
= 0x00000400, /* Reserved for ThunderBolt */
3604 kIOPMSleepFactorDriverAssertBit6
= 0x00000800,
3605 kIOPMSleepFactorDriverAssertBit7
= 0x00001000 /* Reserved for legacy I/O */
3609 kSleepPhaseEarly
, kSleepPhaseFinal
3612 bool IOPMrootDomain::evaluateSystemSleepPolicy( IOPMSystemSleepParameters
* p
, int sleepPhase
)
3614 const IOPMSystemSleepPolicyTable
* pt
;
3615 OSObject
* prop
= 0;
3616 OSData
* policyData
;
3617 uint32_t currentFactors
;
3618 uint32_t deepSleepDelay
= 0;
3619 bool success
= false;
3621 if (getProperty(kIOPMDeepSleepEnabledKey
) != kOSBooleanTrue
)
3624 getSleepOption(kIOPMDeepSleepDelayKey
, &deepSleepDelay
);
3626 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
3630 policyData
= OSDynamicCast(OSData
, prop
);
3632 (policyData
->getLength() < sizeof(IOPMSystemSleepPolicyTable
)))
3637 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
3638 if ((pt
->signature
[0] != 'S') ||
3639 (pt
->signature
[1] != 'L') ||
3640 (pt
->signature
[2] != 'P') ||
3641 (pt
->signature
[3] != 'T') ||
3642 (pt
->version
!= 1) ||
3643 (pt
->entryCount
== 0))
3648 if ((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
3649 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
))
3655 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
3656 kIOPMDriverAssertionLevelOff
)
3657 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
3658 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
3659 kIOPMDriverAssertionLevelOff
)
3660 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
3661 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
3662 kIOPMDriverAssertionLevelOff
)
3663 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
3664 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) != /* AssertionBit5 = Thunderbolt */
3665 kIOPMDriverAssertionLevelOff
)
3666 currentFactors
|= kIOPMSleepFactorDriverAssertBit5
;
3667 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit7
) !=
3668 kIOPMDriverAssertionLevelOff
)
3669 currentFactors
|= kIOPMSleepFactorDriverAssertBit7
;
3670 if (0 == deepSleepDelay
)
3671 currentFactors
|= kIOPMSleepFactorDeepSleepNoDelay
;
3672 if (!clamshellClosed
)
3673 currentFactors
|= kIOPMSleepFactorLidOpen
;
3674 if (acAdaptorConnected
)
3675 currentFactors
|= kIOPMSleepFactorACPower
;
3676 if (lowBatteryCondition
)
3677 currentFactors
|= kIOPMSleepFactorLowBattery
;
3678 if (sleepTimerMaintenance
)
3679 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3682 if ((hibernateMode
& kIOHibernateModeOn
) == 0)
3683 currentFactors
|= kIOPMSleepFactorDeepSleepDisable
;
3684 else if ((hibernateMode
& kIOHibernateModeSleep
) == 0)
3685 currentFactors
|= kIOPMSleepFactorDeepSleepDemand
;
3687 DLOG("Sleep policy %u entries, current factors 0x%x\n",
3688 pt
->entryCount
, currentFactors
);
3690 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
3692 const IOPMSystemSleepPolicyEntry
* policyEntry
= &pt
->entries
[i
];
3694 DLOG("factor mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x\n",
3695 policyEntry
->factorMask
, policyEntry
->factorBits
,
3696 policyEntry
->sleepFlags
, policyEntry
->wakeEvents
);
3698 if ((currentFactors
^ policyEntry
->factorBits
) & policyEntry
->factorMask
)
3699 continue; // mismatch, try next
3704 p
->sleepFlags
= policyEntry
->sleepFlags
;
3706 p
->wakeEvents
= policyEntry
->wakeEvents
;
3707 if (p
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
3709 if (kSleepPhaseFinal
== sleepPhase
)
3711 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
3713 if (!_standbyTimerResetSeconds
||
3714 (now_secs
<= _standbyTimerResetSeconds
))
3716 // Reset standby timer adjustment
3717 _standbyTimerResetSeconds
= now_secs
;
3718 DLOG("standby delay %u, reset %u\n",
3719 deepSleepDelay
, (uint32_t) _standbyTimerResetSeconds
);
3721 else if (deepSleepDelay
)
3723 // Shorten the standby delay timer
3724 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
3725 if (deepSleepDelay
> elapsed
)
3726 deepSleepDelay
-= elapsed
;
3728 deepSleepDelay
= 1; // must be > 0
3730 DLOG("standby delay %u, elapsed %u\n",
3731 deepSleepDelay
, (uint32_t) elapsed
);
3734 p
->sleepTimer
= deepSleepDelay
;
3736 else if (kSleepPhaseFinal
== sleepPhase
)
3738 // A sleep that does not enable the sleep timer will reset
3739 // the standby delay adjustment.
3740 _standbyTimerResetSeconds
= 0;
3744 DLOG("matched policy entry %u\n", i
);
3756 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
3758 IOPMSystemSleepParameters params
;
3760 // Evaluate sleep policy before driver sleep phase.
3762 DLOG("%s\n", __FUNCTION__
);
3763 removeProperty(kIOPMSystemSleepParametersKey
);
3765 // Full wake resets the standby timer delay adjustment
3766 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
3767 _standbyTimerResetSeconds
= 0;
3769 hibernateDisabled
= false;
3771 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
3773 if (!hibernateNoDefeat
&&
3774 evaluateSystemSleepPolicy(¶ms
, kSleepPhaseEarly
) &&
3775 ((params
.sleepFlags
& kIOPMSleepFlagHibernate
) == 0))
3777 hibernateDisabled
= true;
3781 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
3783 IOPMSystemSleepParameters params
;
3784 OSData
* paramsData
;
3786 // Evaluate sleep policy after drivers but before platform sleep.
3788 DLOG("%s\n", __FUNCTION__
);
3790 if (evaluateSystemSleepPolicy(¶ms
, kSleepPhaseFinal
))
3792 if ((hibernateDisabled
|| hibernateAborted
) &&
3793 (params
.sleepFlags
& kIOPMSleepFlagHibernate
))
3795 // Should hibernate but unable to or aborted.
3796 // Arm timer for a short sleep and retry or wake fully.
3798 params
.sleepFlags
&= ~kIOPMSleepFlagHibernate
;
3799 params
.sleepFlags
|= kIOPMSleepFlagSleepTimerEnable
;
3800 params
.sleepTimer
= 1;
3801 hibernateNoDefeat
= true;
3802 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
3803 params
.sleepTimer
, hibernateDisabled
, hibernateAborted
);
3806 hibernateNoDefeat
= false;
3808 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
3811 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
3812 paramsData
->release();
3815 if (params
.sleepFlags
& kIOPMSleepFlagHibernate
)
3818 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
3823 bool IOPMrootDomain::getHibernateSettings(
3824 uint32_t * hibernateMode
,
3825 uint32_t * hibernateFreeRatio
,
3826 uint32_t * hibernateFreeTime
)
3828 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateMode
);
3829 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
3830 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
3831 if (hibernateDisabled
)
3833 DLOG("hibernateMode 0x%x\n", *hibernateMode
);
3837 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
3839 OSObject
* optionsProp
;
3840 OSDictionary
* optionsDict
;
3845 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
3846 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
3850 obj
= optionsDict
->getObject(key
);
3851 if (obj
) obj
->retain();
3855 obj
= copyProperty(key
);
3857 if (obj
&& (num
= OSDynamicCast(OSNumber
, obj
)))
3859 *option
= num
->unsigned32BitValue();
3866 optionsProp
->release();
3870 #endif /* HIBERNATION */
3873 // MARK: Shutdown and Restart
3875 //******************************************************************************
3876 // handlePlatformHaltRestart
3878 //******************************************************************************
3880 struct HaltRestartApplierContext
{
3881 IOPMrootDomain
* RootDomain
;
3882 unsigned long PowerState
;
3883 IOPMPowerFlags PowerFlags
;
3889 platformHaltRestartApplier( OSObject
* object
, void * context
)
3891 IOPowerStateChangeNotification notify
;
3892 HaltRestartApplierContext
* ctx
;
3893 AbsoluteTime startTime
;
3896 ctx
= (HaltRestartApplierContext
*) context
;
3898 memset(¬ify
, 0, sizeof(notify
));
3899 notify
.powerRef
= (void *)ctx
->Counter
;
3900 notify
.returnValue
= 0;
3901 notify
.stateNumber
= ctx
->PowerState
;
3902 notify
.stateFlags
= ctx
->PowerFlags
;
3904 clock_get_uptime(&startTime
);
3905 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
3906 deltaTime
= computeDeltaTimeMS(&startTime
);
3908 if ((deltaTime
> kPMHaltTimeoutMS
) ||
3909 (gIOKitDebug
& kIOLogPMRootDomain
))
3911 _IOServiceInterestNotifier
* notifier
;
3912 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
3914 // IOService children of IOPMrootDomain are not instrumented.
3915 // Only IORootParent currently falls under that group.
3919 LOG("%s handler %p took %u ms\n",
3920 (ctx
->MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
3921 (ctx
->MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
3922 notifier
->handler
, (uint32_t) deltaTime
);
3929 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
3931 HaltRestartApplierContext ctx
;
3932 AbsoluteTime startTime
;
3935 memset(&ctx
, 0, sizeof(ctx
));
3936 ctx
.RootDomain
= this;
3938 clock_get_uptime(&startTime
);
3942 case kPEUPSDelayHaltCPU
:
3943 ctx
.PowerState
= OFF_STATE
;
3944 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
3948 ctx
.PowerState
= RESTART_STATE
;
3949 ctx
.MessageType
= kIOMessageSystemWillRestart
;
3953 ctx
.PowerState
= ON_STATE
;
3954 ctx
.MessageType
= kIOMessageSystemPagingOff
;
3955 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
3962 // Notify legacy clients
3963 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
3965 // For normal shutdown, turn off File Server Mode.
3966 if (kPEHaltCPU
== pe_type
)
3968 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
3969 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
3972 setPMSetting(setting
, num
);
3978 if (kPEPagingOff
!= pe_type
)
3980 // Notify in power tree order
3981 notifySystemShutdown(this, ctx
.MessageType
);
3984 deltaTime
= computeDeltaTimeMS(&startTime
);
3985 LOG("%s all drivers took %u ms\n",
3986 (ctx
.MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
3987 (ctx
.MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
3988 (uint32_t) deltaTime
);
3991 //******************************************************************************
3994 //******************************************************************************
3996 IOReturn
IOPMrootDomain::shutdownSystem( void )
3998 return kIOReturnUnsupported
;
4001 //******************************************************************************
4004 //******************************************************************************
4006 IOReturn
IOPMrootDomain::restartSystem( void )
4008 return kIOReturnUnsupported
;
4012 // MARK: System Capability
4014 //******************************************************************************
4015 // tagPowerPlaneService
4017 // Running on PM work loop thread.
4018 //******************************************************************************
4020 void IOPMrootDomain::tagPowerPlaneService(
4021 IOService
* service
,
4022 IOPMActions
* actions
)
4025 bool isDisplayWrangler
;
4027 memset(actions
, 0, sizeof(*actions
));
4028 actions
->target
= this;
4030 if (service
== this)
4032 actions
->actionPowerChangeStart
=
4033 OSMemberFunctionCast(
4034 IOPMActionPowerChangeStart
, this,
4035 &IOPMrootDomain::handleOurPowerChangeStart
);
4037 actions
->actionPowerChangeDone
=
4038 OSMemberFunctionCast(
4039 IOPMActionPowerChangeDone
, this,
4040 &IOPMrootDomain::handleOurPowerChangeDone
);
4042 actions
->actionPowerChangeOverride
=
4043 OSMemberFunctionCast(
4044 IOPMActionPowerChangeOverride
, this,
4045 &IOPMrootDomain::overrideOurPowerChange
);
4050 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4051 if (isDisplayWrangler
)
4056 isDisplayWrangler
= false;
4059 #if defined(__i386__) || defined(__x86_64__)
4060 if (isDisplayWrangler
)
4061 flags
|= kPMActionsFlagIsDisplayWrangler
;
4062 if (service
->getProperty("IOPMStrictTreeOrder"))
4063 flags
|= kPMActionsFlagIsGraphicsDevice
;
4064 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4065 flags
|= kPMActionsFlagIsAudioDevice
;
4068 // Find the power connection object that is a child of the PCI host
4069 // bridge, and has a graphics/audio device attached below. Mark the
4070 // power branch for delayed child notifications.
4074 IORegistryEntry
* child
= service
;
4075 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4077 while (child
!= this)
4079 if ((parent
== pciHostBridgeDriver
) ||
4082 if (OSDynamicCast(IOPowerConnection
, child
))
4084 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4085 conn
->delayChildNotification
= true;
4090 parent
= child
->getParentEntry(gIOPowerPlane
);
4096 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4097 actions
->parameter
|= flags
;
4098 actions
->actionPowerChangeOverride
=
4099 OSMemberFunctionCast(
4100 IOPMActionPowerChangeOverride
, this,
4101 &IOPMrootDomain::overridePowerChangeForUIService
);
4103 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4105 actions
->actionActivityTickle
=
4106 OSMemberFunctionCast(
4107 IOPMActionActivityTickle
, this,
4108 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4113 // Locate the first PCI host bridge for PMTrace.
4114 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4116 IOService
* provider
= service
->getProvider();
4117 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4118 provider
->inPlane(gIODTPlane
))
4120 pciHostBridgeDevice
= provider
;
4121 pciHostBridgeDriver
= service
;
4122 DLOG("PMTrace found PCI host bridge %s->%s\n",
4123 provider
->getName(), service
->getName());
4127 // Tag top-level PCI devices. The order of PMinit() call does not
4128 // change across boots and is used as the PCI bit number.
4129 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4131 // Would prefer to check built-in property, but tagPowerPlaneService()
4132 // is called before pciDevice->registerService().
4133 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4134 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4136 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4139 // Save the assigned bit for fast lookup.
4140 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4142 actions
->actionPowerChangeStart
=
4143 OSMemberFunctionCast(
4144 IOPMActionPowerChangeStart
, this,
4145 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4147 actions
->actionPowerChangeDone
=
4148 OSMemberFunctionCast(
4149 IOPMActionPowerChangeDone
, this,
4150 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4156 //******************************************************************************
4157 // PM actions for root domain
4158 //******************************************************************************
4160 void IOPMrootDomain::overrideOurPowerChange(
4161 IOService
* service
,
4162 IOPMActions
* actions
,
4163 unsigned long * inOutPowerState
,
4164 uint32_t * inOutChangeFlags
)
4166 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4167 uint32_t changeFlags
= *inOutChangeFlags
;
4168 uint32_t currentPowerState
= (uint32_t) getPowerState();
4170 if ((currentPowerState
== powerState
) ||
4171 (changeFlags
& kIOPMParentInitiated
))
4173 // FIXME: cancel any parent change (unexpected)
4174 // Root parent is permanently pegged at max power,
4175 // kIOPMParentInitiated is unexpected.
4179 if (powerState
< currentPowerState
)
4181 if ((changeFlags
& kIOPMSkipAskPowerDown
) == 0)
4183 /* Convenient place to run any code at idle sleep time
4184 * IOPMrootDomain initiates an idle sleep here
4186 * Set last sleep cause accordingly.
4188 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishSleepWakeUUID
, (void *)true);
4190 lastSleepReason
= kIOPMSleepReasonIdle
;
4191 setProperty(kRootDomainSleepReasonKey
, kIOPMIdleSleepKey
);
4193 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4195 // Root domain is dropping power state ON->SLEEP.
4196 // If system is in full wake, first drop to dark wake.
4198 darkWakeToSleepASAP
= true;
4200 // Drop graphics capability.
4201 // No transition if system is already in dark wake.
4203 _desiredCapability
&= ~(
4204 kIOPMSystemCapabilityGraphics
|
4205 kIOPMSystemCapabilityAudio
);
4207 *inOutPowerState
= ON_STATE
;
4208 *inOutChangeFlags
|= kIOPMSynchronize
;
4210 // Revert device desire from SLEEP->ON.
4211 changePowerStateToPriv(ON_STATE
);
4216 void IOPMrootDomain::handleOurPowerChangeStart(
4217 IOService
* service
,
4218 IOPMActions
* actions
,
4219 uint32_t powerState
,
4220 uint32_t * inOutChangeFlags
)
4222 uint32_t changeFlags
= *inOutChangeFlags
;
4223 uint32_t currentPowerState
= (uint32_t) getPowerState();
4225 _systemTransitionType
= kSystemTransitionNone
;
4226 _systemMessageClientMask
= 0;
4227 capabilityLoss
= false;
4229 // 1. Explicit capability change.
4231 if (changeFlags
& kIOPMSynchronize
)
4233 if (powerState
== ON_STATE
)
4235 if (changeFlags
& kIOPMSyncNoChildNotify
)
4236 _systemTransitionType
= kSystemTransitionNewCapClient
;
4238 _systemTransitionType
= kSystemTransitionCapability
;
4242 // 2. Going to sleep (cancellation still possible).
4244 else if (powerState
< currentPowerState
)
4245 _systemTransitionType
= kSystemTransitionSleep
;
4247 // 3. Woke from (idle or demand) sleep.
4249 else if (!systemBooting
&&
4250 (changeFlags
& kIOPMSelfInitiated
) &&
4251 (powerState
> currentPowerState
))
4253 _systemTransitionType
= kSystemTransitionWake
;
4254 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4255 kIOPMSystemCapabilityNetwork
;
4257 // Check for early HID events (e.g. LID open)
4258 if (wranglerTickled
)
4260 _desiredCapability
|= (
4261 kIOPMSystemCapabilityGraphics
|
4262 kIOPMSystemCapabilityAudio
);
4266 // Update pending wake capability at the beginning of every
4267 // state transition (including synchronize). This will become
4268 // the current capability at the end of the transition.
4270 if (kSystemTransitionSleep
== _systemTransitionType
)
4272 _pendingCapability
= 0;
4273 capabilityLoss
= true;
4275 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4277 _pendingCapability
= _desiredCapability
|
4278 kIOPMSystemCapabilityCPU
|
4279 kIOPMSystemCapabilityNetwork
;
4281 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4282 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4284 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4285 (_pendingCapability
== _currentCapability
))
4287 // Cancel the PM state change.
4288 _systemTransitionType
= kSystemTransitionNone
;
4289 *inOutChangeFlags
|= kIOPMNotDone
;
4291 if (__builtin_popcount(_pendingCapability
) <
4292 __builtin_popcount(_currentCapability
))
4293 capabilityLoss
= true;
4294 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4295 rejectWranglerTickle
= true;
4298 // 1. Capability change.
4300 if (kSystemTransitionCapability
== _systemTransitionType
)
4302 // Dark to Full transition.
4303 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4305 tracePoint( kIOPMTracePointDarkWakeExit
);
4306 wranglerSleepIgnored
= false;
4307 sleepTimerMaintenance
= false;
4308 hibernateNoDefeat
= false;
4309 _systemMessageClientMask
= kSystemMessageClientUser
;
4310 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4311 _systemMessageClientMask
|= kSystemMessageClientKernel
;
4313 tellClients(kIOMessageSystemWillPowerOn
);
4316 // Full to Dark transition.
4317 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4319 tracePoint( kIOPMTracePointDarkWakeEntry
);
4320 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4321 _systemMessageClientMask
= kSystemMessageClientUser
;
4327 else if (kSystemTransitionSleep
== _systemTransitionType
)
4329 // Beginning of a system sleep transition.
4330 // Cancellation is still possible.
4331 tracePoint( kIOPMTracePointSleepStarted
, lastSleepReason
);
4333 _systemMessageClientMask
= kSystemMessageClientAll
;
4334 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4335 _systemMessageClientMask
&= ~kSystemMessageClientApp
;
4336 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4337 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
4339 // Optimization to ignore wrangler power down thus skipping
4340 // the disk spindown and arming the idle timer for demand sleep.
4342 if (changeFlags
& kIOPMIgnoreChildren
)
4344 wranglerSleepIgnored
= true;
4347 logWranglerTickle
= false;
4352 else if (kSystemTransitionWake
== _systemTransitionType
)
4354 wranglerSleepIgnored
= false;
4356 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4358 _systemMessageClientMask
= kSystemMessageClientAll
;
4362 _systemMessageClientMask
= kSystemMessageClientConfigd
;
4365 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
4366 tellClients(kIOMessageSystemWillPowerOn
);
4369 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
4370 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
4372 _systemStateGeneration
++;
4373 systemDarkWake
= false;
4375 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4377 currentPowerState
, powerState
, *inOutChangeFlags
,
4378 _systemTransitionType
, _systemStateGeneration
,
4379 _systemMessageClientMask
,
4380 _desiredCapability
, _currentCapability
, _pendingCapability
);
4384 void IOPMrootDomain::handleOurPowerChangeDone(
4385 IOService
* service
,
4386 IOPMActions
* actions
,
4387 uint32_t powerState
,
4388 uint32_t changeFlags
)
4390 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4392 _systemTransitionType
= kSystemTransitionNone
;
4396 if (_systemTransitionType
!= kSystemTransitionNone
)
4398 uint32_t currentPowerState
= (uint32_t) getPowerState();
4400 if (changeFlags
& kIOPMNotDone
)
4402 // Power down was cancelled or vetoed.
4403 _pendingCapability
= _currentCapability
;
4404 lastSleepReason
= 0;
4406 if (((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4407 (_currentCapability
& kIOPMSystemCapabilityCPU
))
4409 pmPowerStateQueue
->submitPowerEvent(
4410 kPowerEventPolicyStimulus
,
4411 (void *) kStimulusDarkWakeReentry
,
4412 _systemStateGeneration
);
4415 // Revert device desire to max.
4416 changePowerStateToPriv(ON_STATE
);
4420 // Send message on dark wake to full wake promotion.
4421 // tellChangeUp() handles the normal SLEEP->ON case.
4423 if (kSystemTransitionCapability
== _systemTransitionType
)
4425 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4427 tellClients(kIOMessageSystemHasPoweredOn
);
4428 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
4429 // Re-evaluate clamshell state ourselves when graphics
4430 // will not get kIOMessageSystemHasPoweredOn.
4432 if (clamshellClosed
&&
4433 ((_systemMessageClientMask
& kSystemMessageClientKernel
) == 0))
4435 receivePowerNotification( kLocalEvalClamshellCommand
);
4439 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4440 wranglerTickled
= false;
4443 // Reset state after exiting from dark wake.
4445 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
4446 CAP_LOSS(kIOPMSystemCapabilityCPU
))
4448 darkWakeMaintenance
= false;
4449 darkWakeToSleepASAP
= false;
4450 pciCantSleepValid
= false;
4451 rejectWranglerTickle
= false;
4452 darkWakeSleepService
= false;
4455 // Entered dark mode.
4457 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4458 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
4460 if (((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOInDark
) == 0) &&
4461 (kSystemTransitionWake
== _systemTransitionType
) &&
4462 (_lastDebugWakeSeconds
== 0))
4464 OSObject
* prop
= copyProperty(kIOPMRootDomainWakeTypeKey
);
4467 OSString
* wakeType
= OSDynamicCast(OSString
, prop
);
4469 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeNetwork
))
4471 // Woke from network and entered dark wake.
4472 if (darkWakeToSleepASAP
)
4474 DLOG("cleared darkWakeToSleepASAP\n");
4475 darkWakeToSleepASAP
= false;
4482 // Queue an evaluation of whether to remain in dark wake,
4483 // and for how long. This serves the purpose of draining
4484 // any assertions from the queue.
4486 pmPowerStateQueue
->submitPowerEvent(
4487 kPowerEventPolicyStimulus
,
4488 (void *) kStimulusDarkWakeEntry
,
4489 _systemStateGeneration
);
4493 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4494 "dcp %x:%x:%x, dbgtimer %u\n",
4495 currentPowerState
, powerState
, changeFlags
,
4496 _systemTransitionType
, _systemStateGeneration
,
4497 _systemMessageClientMask
,
4498 _desiredCapability
, _currentCapability
, _pendingCapability
,
4499 _lastDebugWakeSeconds
);
4501 // Update current system capability.
4503 if (_currentCapability
!= _pendingCapability
)
4504 _currentCapability
= _pendingCapability
;
4506 // Update highest system capability.
4508 if (!CAP_CURRENT(kIOPMSystemCapabilityCPU
))
4509 _highestCapability
= 0; // reset at sleep state
4511 _highestCapability
|= _currentCapability
;
4513 if (darkWakePostTickle
&&
4514 (kSystemTransitionWake
== _systemTransitionType
) &&
4515 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4516 kDarkWakeFlagHIDTickleLate
)
4518 darkWakePostTickle
= false;
4522 // Reset tracepoint at completion of capability change,
4523 // completion of wake transition, and aborted sleep transition.
4525 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
4526 (_systemTransitionType
== kSystemTransitionWake
) ||
4527 ((_systemTransitionType
== kSystemTransitionSleep
) &&
4528 (changeFlags
& kIOPMNotDone
)))
4530 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
4531 tracePoint( kIOPMTracePointSystemUp
, 0 );
4533 // kIOPMDWOverTemp notification handling was postponed
4534 if (darkWakeThermalAlarm
)
4536 if (!wranglerTickled
&& !darkWakeThermalEmergency
&&
4537 CAP_CURRENT(kIOPMSystemCapabilityCPU
) &&
4538 !CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4540 darkWakeThermalEmergency
= true;
4541 privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
4542 MSG("DarkWake thermal limits breached. Going to sleep!\n");
4544 darkWakeThermalAlarm
= false;
4548 _systemTransitionType
= kSystemTransitionNone
;
4549 _systemMessageClientMask
= 0;
4551 logGraphicsClamp
= false;
4555 //******************************************************************************
4556 // PM actions for graphics and audio.
4557 //******************************************************************************
4559 void IOPMrootDomain::overridePowerChangeForUIService(
4560 IOService
* service
,
4561 IOPMActions
* actions
,
4562 unsigned long * inOutPowerState
,
4563 uint32_t * inOutChangeFlags
)
4565 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4566 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
4568 if (kSystemTransitionNone
== _systemTransitionType
)
4570 // Not in midst of a system transition.
4571 // Do not modify power limit enable state.
4573 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4575 // Activate power limiter.
4577 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4578 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4579 (changeFlags
& kIOPMSynchronize
))
4581 actions
->parameter
|= kPMActionsFlagLimitPower
;
4583 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4584 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
4585 (changeFlags
& kIOPMSynchronize
))
4587 actions
->parameter
|= kPMActionsFlagLimitPower
;
4589 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
4590 (_systemTransitionType
== kSystemTransitionSleep
))
4592 // For graphics devices, arm the limiter when entering
4593 // system sleep. Not when dropping to dark wake.
4594 actions
->parameter
|= kPMActionsFlagLimitPower
;
4597 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4599 DLOG("+ plimit %s %p\n",
4600 service
->getName(), service
);
4605 // Remove power limit.
4607 if ((actions
->parameter
& (
4608 kPMActionsFlagIsDisplayWrangler
|
4609 kPMActionsFlagIsGraphicsDevice
)) &&
4610 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
4612 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4614 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4615 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
4617 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4620 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4622 DLOG("- plimit %s %p\n",
4623 service
->getName(), service
);
4627 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4629 uint32_t maxPowerState
= (uint32_t)(-1);
4631 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
4633 // Enforce limit for system power/cap transitions.
4636 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4637 (service
->getPowerState() > 0))
4639 // Forces a 3->1 transition sequence
4640 if (changeFlags
& kIOPMDomainWillChange
)
4648 // Deny all self-initiated changes when power is limited.
4649 // Wrangler tickle should never defeat the limiter.
4651 maxPowerState
= service
->getPowerState();
4654 if (powerState
> maxPowerState
)
4656 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
4657 service
->getName(), service
, powerState
, maxPowerState
,
4659 *inOutPowerState
= maxPowerState
;
4661 if (darkWakePostTickle
&&
4662 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4663 (changeFlags
& kIOPMDomainWillChange
) &&
4664 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4665 kDarkWakeFlagHIDTickleEarly
))
4667 darkWakePostTickle
= false;
4672 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
4674 if (logGraphicsClamp
)
4679 clock_get_uptime(&now
);
4680 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
4681 absolutetime_to_nanoseconds(now
, &nsec
);
4682 MSG("Graphics suppressed %u ms\n",
4683 ((int)((nsec
) / 1000000ULL)));
4685 graphicsSuppressed
= true;
4690 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
4691 IOService
* service
,
4692 IOPMActions
* actions
)
4694 // Warning: Not running in PM work loop context - don't modify state !!!
4695 // Trap tickle directed to IODisplayWrangler while running with graphics
4696 // capability suppressed.
4698 assert(service
== wrangler
);
4700 if (service
== wrangler
)
4702 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
4703 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
4705 userActivityCount
++;
4706 DLOG("display wrangler tickled1 %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
4710 if (!wranglerTickled
&&
4711 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
4713 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
4714 DLOG("display wrangler tickled\n");
4715 if (kIOLogPMRootDomain
& gIOKitDebug
)
4716 OSReportWithBacktrace("Dark wake display tickle");
4717 if (pmPowerStateQueue
)
4719 pmPowerStateQueue
->submitPowerEvent(
4720 kPowerEventPolicyStimulus
,
4721 (void *) kStimulusDarkWakeActivityTickle
);
4726 //******************************************************************************
4727 // Approve usage of delayed child notification by PM.
4728 //******************************************************************************
4730 bool IOPMrootDomain::shouldDelayChildNotification(
4731 IOService
* service
)
4733 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
4735 (kSystemTransitionWake
== _systemTransitionType
))
4737 DLOG("%s: delay child notify\n", service
->getName());
4743 //******************************************************************************
4744 // PM actions for PCI device.
4745 //******************************************************************************
4747 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
4748 IOService
* service
,
4749 IOPMActions
* actions
,
4750 uint32_t powerState
,
4751 uint32_t * inOutChangeFlags
)
4753 pmTracer
->tracePCIPowerChange(
4754 PMTraceWorker::kPowerChangeStart
,
4755 service
, *inOutChangeFlags
,
4756 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
4759 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
4760 IOService
* service
,
4761 IOPMActions
* actions
,
4762 uint32_t powerState
,
4763 uint32_t changeFlags
)
4765 pmTracer
->tracePCIPowerChange(
4766 PMTraceWorker::kPowerChangeCompleted
,
4767 service
, changeFlags
,
4768 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
4771 //******************************************************************************
4774 // Override IOService::registerInterest() to intercept special clients.
4775 //******************************************************************************
4777 IONotifier
* IOPMrootDomain::registerInterest(
4778 const OSSymbol
* typeOfInterest
,
4779 IOServiceInterestHandler handler
,
4780 void * target
, void * ref
)
4782 IONotifier
* notifier
;
4783 bool isSystemCapabilityClient
;
4784 bool isKernelCapabilityClient
;
4786 isSystemCapabilityClient
=
4788 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
4790 isKernelCapabilityClient
=
4792 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
4794 if (isSystemCapabilityClient
)
4795 typeOfInterest
= gIOAppPowerStateInterest
;
4797 notifier
= super::registerInterest(typeOfInterest
, handler
, target
, ref
);
4798 if (notifier
&& pmPowerStateQueue
)
4800 if (isSystemCapabilityClient
)
4803 if (pmPowerStateQueue
->submitPowerEvent(
4804 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
4805 notifier
->release();
4808 if (isKernelCapabilityClient
)
4811 if (pmPowerStateQueue
->submitPowerEvent(
4812 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
4813 notifier
->release();
4820 //******************************************************************************
4821 // systemMessageFilter
4823 //******************************************************************************
4825 bool IOPMrootDomain::systemMessageFilter(
4826 void * object
, void * arg1
, void * arg2
, void * arg3
)
4828 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
4829 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
4830 bool isCapClient
= false;
4834 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
4835 (!isCapMsg
|| !_joinedCapabilityClients
||
4836 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
4839 // Capability change message for app and kernel clients.
4843 if ((context
->notifyType
== kNotifyPriority
) ||
4844 (context
->notifyType
== kNotifyCapabilityChangePriority
))
4847 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
4848 (object
== (void *) systemCapabilityNotifier
))
4854 IOPMSystemCapabilityChangeParameters
* capArgs
=
4855 (IOPMSystemCapabilityChangeParameters
*) arg2
;
4857 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4859 capArgs
->fromCapabilities
= 0;
4860 capArgs
->toCapabilities
= _currentCapability
;
4861 capArgs
->changeFlags
= 0;
4865 capArgs
->fromCapabilities
= _currentCapability
;
4866 capArgs
->toCapabilities
= _pendingCapability
;
4868 if (context
->isPreChange
)
4869 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
4871 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
4874 // Capability change messages only go to the PM configd plugin.
4875 // Wait for response post-change if capabilitiy is increasing.
4876 // Wait for response pre-change if capability is decreasing.
4878 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
4879 ( (capabilityLoss
&& context
->isPreChange
) ||
4880 (!capabilityLoss
&& !context
->isPreChange
) ) )
4882 // app has not replied yet, wait for it
4883 *((OSObject
**) arg3
) = kOSBooleanFalse
;
4890 // Capability client will always see kIOMessageCanSystemSleep,
4891 // even for demand sleep.
4893 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
4894 (kIOMessageSystemWillNotSleep
== context
->messageType
))
4896 if (object
== (OSObject
*) systemCapabilityNotifier
)
4902 // Not idle sleep, don't ask apps.
4903 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
4909 // Reject capability change messages for legacy clients.
4910 // Reject legacy system sleep messages for capability client.
4912 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
4917 // Filter system sleep messages.
4919 if ((context
->notifyType
== kNotifyApps
) &&
4920 (_systemMessageClientMask
& kSystemMessageClientApp
))
4924 else if ((context
->notifyType
== kNotifyPriority
) &&
4925 (_systemMessageClientMask
& kSystemMessageClientKernel
))
4932 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
4934 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
4935 if (_joinedCapabilityClients
->getCount() == 0)
4937 DLOG("destroyed capability client set %p\n",
4938 _joinedCapabilityClients
);
4939 _joinedCapabilityClients
->release();
4940 _joinedCapabilityClients
= 0;
4947 //******************************************************************************
4948 // setMaintenanceWakeCalendar
4950 //******************************************************************************
4952 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
4953 const IOPMCalendarStruct
* calendar
)
4959 return kIOReturnBadArgument
;
4961 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
4963 return kIOReturnNoMemory
;
4965 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
4966 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
4968 if (kPMCalendarTypeSleepService
== calendar
->selector
)
4970 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
4979 // MARK: Display Wrangler
4981 //******************************************************************************
4982 // displayWranglerNotification
4984 // Handle the notification when the IODisplayWrangler changes power state.
4985 //******************************************************************************
4987 IOReturn
IOPMrootDomain::displayWranglerNotification(
4988 void * target
, void * refCon
,
4989 UInt32 messageType
, IOService
* service
,
4990 void * messageArgument
, vm_size_t argSize
)
4993 int displayPowerState
;
4994 IOPowerStateChangeNotification
* params
=
4995 (IOPowerStateChangeNotification
*) messageArgument
;
4997 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
4998 (messageType
!= kIOMessageDeviceHasPoweredOn
))
4999 return kIOReturnUnsupported
;
5003 return kIOReturnUnsupported
;
5005 displayPowerState
= params
->stateNumber
;
5006 DLOG("DisplayWrangler message 0x%x, power state %d\n",
5007 (uint32_t) messageType
, displayPowerState
);
5009 switch (messageType
) {
5010 case kIOMessageDeviceWillPowerOff
:
5012 // Display wrangler has dropped power due to display idle
5013 // or force system sleep.
5018 // 1 Not visible to user
5019 // 0 Not visible to user
5021 if (displayPowerState
> 2)
5024 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
5027 case kIOMessageDeviceHasPoweredOn
:
5029 // Display wrangler has powered on due to user activity
5030 // or wake from sleep.
5032 if ( 4 != displayPowerState
)
5035 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
5039 return kIOReturnUnsupported
;
5042 //******************************************************************************
5043 // displayWranglerMatchPublished
5045 // Receives a notification when the IODisplayWrangler is published.
5046 // When it's published we install a power state change handler.
5047 //******************************************************************************
5049 bool IOPMrootDomain::displayWranglerMatchPublished(
5052 IOService
* newService
,
5053 IONotifier
* notifier __unused
)
5056 // found the display wrangler, now install a handler
5057 if( !newService
->registerInterest( gIOGeneralInterest
,
5058 &displayWranglerNotification
, target
, 0) )
5066 //******************************************************************************
5069 //******************************************************************************
5071 void IOPMrootDomain::reportUserInput( void )
5078 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
5081 wrangler
= (IOService
*) iter
->getNextObject();
5087 wrangler
->activityTickle(0,0);
5091 //******************************************************************************
5092 // blockDisplayWranglerTickle
5093 //******************************************************************************
5095 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
5100 // Not too late to prevent the display from lighting up
5101 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
5102 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
5103 !checkSystemCanSustainFullWake())
5105 wranglerTickleLatched
= true;
5109 wranglerTickleLatched
= false;
5112 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
5114 wranglerTickleLatched
= false;
5116 pmPowerStateQueue
->submitPowerEvent(
5117 kPowerEventPolicyStimulus
,
5118 (void *) kStimulusDarkWakeActivityTickle
);
5121 return wranglerTickleLatched
;
5130 //******************************************************************************
5133 // Notification on battery class IOPowerSource appearance
5134 //******************************************************************************
5136 bool IOPMrootDomain::batteryPublished(
5139 IOService
* resourceService
,
5140 IONotifier
* notifier __unused
)
5142 // rdar://2936060&4435589
5143 // All laptops have dimmable LCD displays
5144 // All laptops have batteries
5145 // So if this machine has a battery, publish the fact that the backlight
5146 // supports dimming.
5147 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
5153 // MARK: System PM Policy
5155 //******************************************************************************
5156 // checkSystemCanSleep
5158 //******************************************************************************
5160 bool IOPMrootDomain::checkSystemCanSleep( IOOptionBits options
)
5164 // Conditions that prevent idle and demand system sleep.
5167 if (userDisabledAllSleep
)
5169 err
= 1; // 1. user-space sleep kill switch
5173 if (systemBooting
|| systemShutdown
)
5175 err
= 2; // 2. restart or shutdown in progress
5182 // Conditions above pegs the system at full wake.
5183 // Conditions below prevent system sleep but does not prevent
5184 // dark wake, and must be called from gated context.
5187 err
= 3; // 3. config does not support sleep
5191 if (lowBatteryCondition
)
5193 break; // always sleep on low battery
5196 if(darkWakeThermalEmergency
)
5198 break; // always sleep on dark wake thermal emergencies
5201 if (preventSystemSleepList
->getCount() != 0)
5203 err
= 4; // 4. child prevent system sleep clamp
5207 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
5208 kIOPMDriverAssertionLevelOn
)
5210 err
= 5; // 5. CPU assertion
5214 if (pciCantSleepValid
)
5216 if (pciCantSleepFlag
)
5217 err
= 6; // 6. PCI card does not support PM (cached)
5220 else if (sleepSupportedPEFunction
&&
5221 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5224 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
5225 ret
= getPlatform()->callPlatformFunction(
5226 sleepSupportedPEFunction
, false,
5227 NULL
, NULL
, NULL
, NULL
);
5228 pciCantSleepValid
= true;
5229 pciCantSleepFlag
= false;
5230 if ((platformSleepSupport
& kPCICantSleep
) ||
5231 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
5233 err
= 6; // 6. PCI card does not support PM
5234 pciCantSleepFlag
= true;
5243 DLOG("System sleep prevented by %d\n", err
);
5249 //******************************************************************************
5250 // checkSystemCanSustainFullWake
5251 //******************************************************************************
5253 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
5256 if (lowBatteryCondition
)
5258 // Low battery wake, or received a low battery notification
5259 // while system is awake.
5263 if (clamshellExists
&& clamshellClosed
&& !acAdaptorConnected
)
5265 // Lid closed on battery power
5272 //******************************************************************************
5275 // Conditions that affect our wake/sleep decision has changed.
5276 // If conditions dictate that the system must remain awake, clamp power
5277 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
5278 // is TRUE, then remove the power clamp and allow the power state to drop
5280 //******************************************************************************
5282 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
5284 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
5285 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
);
5289 if ((sleepSlider
== 0) || !checkSystemCanSleep())
5291 changePowerStateToPriv(ON_STATE
);
5293 else if ( sleepASAP
)
5295 changePowerStateToPriv(SLEEP_STATE
);
5299 //******************************************************************************
5300 // dispatchPowerEvent
5302 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
5303 //******************************************************************************
5305 void IOPMrootDomain::dispatchPowerEvent(
5306 uint32_t event
, void * arg0
, uint64_t arg1
)
5308 DLOG("power event %u args %p 0x%llx\n", event
, arg0
, arg1
);
5313 case kPowerEventFeatureChanged
:
5314 messageClients(kIOPMMessageFeatureChange
, this);
5317 case kPowerEventReceivedPowerNotification
:
5318 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
5321 case kPowerEventSystemBootCompleted
:
5324 systemBooting
= false;
5326 // If lid is closed, re-send lid closed notification
5327 // now that booting is complete.
5328 if ( clamshellClosed
)
5330 handlePowerNotification(kLocalEvalClamshellCommand
);
5332 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
5336 case kPowerEventSystemShutdown
:
5337 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
5339 /* We set systemShutdown = true during shutdown
5340 to prevent sleep at unexpected times while loginwindow is trying
5341 to shutdown apps and while the OS is trying to transition to
5344 Set to true during shutdown, as soon as loginwindow shows
5345 the "shutdown countdown dialog", through individual app
5346 termination, and through black screen kernel shutdown.
5348 systemShutdown
= true;
5351 A shutdown was initiated, but then the shutdown
5352 was cancelled, clearing systemShutdown to false here.
5354 systemShutdown
= false;
5358 case kPowerEventUserDisabledSleep
:
5359 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
5362 case kPowerEventRegisterSystemCapabilityClient
:
5363 if (systemCapabilityNotifier
)
5365 systemCapabilityNotifier
->release();
5366 systemCapabilityNotifier
= 0;
5370 systemCapabilityNotifier
= (IONotifier
*) arg0
;
5371 systemCapabilityNotifier
->retain();
5373 /* intentional fall-through */
5375 case kPowerEventRegisterKernelCapabilityClient
:
5376 if (!_joinedCapabilityClients
)
5377 _joinedCapabilityClients
= OSSet::withCapacity(8);
5380 IONotifier
* notify
= (IONotifier
*) arg0
;
5381 if (_joinedCapabilityClients
)
5383 _joinedCapabilityClients
->setObject(notify
);
5384 synchronizePowerTree( kIOPMSyncNoChildNotify
);
5390 case kPowerEventPolicyStimulus
:
5393 int stimulus
= (uintptr_t) arg0
;
5394 evaluatePolicy( stimulus
, (uint32_t) arg1
);
5398 case kPowerEventAssertionCreate
:
5400 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
5405 case kPowerEventAssertionRelease
:
5407 pmAssertions
->handleReleaseAssertion(arg1
);
5411 case kPowerEventAssertionSetLevel
:
5413 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
5417 case kPowerEventQueueSleepWakeUUID
:
5418 handleQueueSleepWakeUUID((OSObject
*)arg0
);
5420 case kPowerEventPublishSleepWakeUUID
:
5421 handlePublishSleepWakeUUID((bool)arg0
);
5423 case kPowerEventSuspendClient
:
5424 handleSuspendPMNotificationClient((uintptr_t)arg0
, (bool)arg1
);
5429 //******************************************************************************
5430 // systemPowerEventOccurred
5432 // The power controller is notifying us of a hardware-related power management
5433 // event that we must handle.
5435 // systemPowerEventOccurred covers the same functionality that
5436 // receivePowerNotification does; it simply provides a richer API for conveying
5437 // more information.
5438 //******************************************************************************
5440 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5441 const OSSymbol
*event
,
5444 IOReturn attempt
= kIOReturnSuccess
;
5445 OSNumber
*newNumber
= NULL
;
5448 return kIOReturnBadArgument
;
5450 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
5452 return kIOReturnInternalError
;
5454 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
5456 newNumber
->release();
5461 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5462 const OSSymbol
*event
,
5465 OSDictionary
*thermalsDict
= NULL
;
5466 bool shouldUpdate
= true;
5468 if (!event
|| !value
)
5469 return kIOReturnBadArgument
;
5472 // We reuse featuresDict Lock because it already exists and guards
5473 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
5474 // of stepping on that lock.
5475 if (featuresDictLock
) IOLockLock(featuresDictLock
);
5477 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
5479 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
5480 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
5482 thermalsDict
= OSDictionary::withCapacity(1);
5485 if (!thermalsDict
) {
5486 shouldUpdate
= false;
5490 thermalsDict
->setObject (event
, value
);
5492 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
5494 thermalsDict
->release();
5498 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
5501 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
5503 return kIOReturnSuccess
;
5506 //******************************************************************************
5507 // receivePowerNotification
5509 // The power controller is notifying us of a hardware-related power management
5510 // event that we must handle. This may be a result of an 'environment' interrupt
5511 // from the power mgt micro.
5512 //******************************************************************************
5514 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
5516 pmPowerStateQueue
->submitPowerEvent(
5517 kPowerEventReceivedPowerNotification
, (void *) msg
);
5518 return kIOReturnSuccess
;
5521 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
5523 bool eval_clamshell
= false;
5528 * Local (IOPMrootDomain only) eval clamshell command
5530 if (msg
& kLocalEvalClamshellCommand
)
5532 eval_clamshell
= true;
5538 if (msg
& kIOPMOverTemp
)
5540 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
5541 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
5544 if (msg
& kIOPMDWOverTemp
)
5546 if (!CAP_CURRENT(kIOPMSystemCapabilityCPU
) ||
5547 (_systemTransitionType
== kSystemTransitionSleep
) ||
5548 (_systemTransitionType
== kSystemTransitionWake
) ||
5549 (_systemTransitionType
== kSystemTransitionCapability
))
5551 // During early wake or when system capability is changing,
5552 // set flag and take action at end of transition.
5553 darkWakeThermalAlarm
= true;
5555 else if (!wranglerTickled
&& !darkWakeThermalEmergency
&&
5556 !CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
5558 // System in steady state and in dark wake
5559 darkWakeThermalEmergency
= true;
5560 privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
5561 MSG("DarkWake thermal limits breached. Going to sleep!\n");
5568 if (msg
& kIOPMSleepNow
)
5570 privateSleepSystem (kIOPMSleepReasonSoftware
);
5576 if (msg
& kIOPMPowerEmergency
)
5578 lowBatteryCondition
= true;
5579 privateSleepSystem (kIOPMSleepReasonLowPower
);
5585 if (msg
& kIOPMClamshellOpened
)
5587 // Received clamshel open message from clamshell controlling driver
5588 // Update our internal state and tell general interest clients
5589 clamshellClosed
= false;
5590 clamshellExists
= true;
5592 // Don't issue a hid tickle when lid is open and polled on wake
5593 if (msg
& kIOPMSetValue
)
5595 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
5600 informCPUStateChange(kInformLid
, 0);
5602 // Tell general interest clients
5603 sendClientClamshellNotification();
5605 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
5606 || (lastSleepReason
== kIOPMSleepReasonIdle
)
5607 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
5608 if (aborting
) userActivityCount
++;
5609 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
5614 * Send the clamshell interest notification since the lid is closing.
5616 if (msg
& kIOPMClamshellClosed
)
5618 // Received clamshel open message from clamshell controlling driver
5619 // Update our internal state and tell general interest clients
5620 clamshellClosed
= true;
5621 clamshellExists
= true;
5624 informCPUStateChange(kInformLid
, 1);
5626 // Tell general interest clients
5627 sendClientClamshellNotification();
5629 // And set eval_clamshell = so we can attempt
5630 eval_clamshell
= true;
5634 * Set Desktop mode (sent from graphics)
5636 * -> reevaluate lid state
5638 if (msg
& kIOPMSetDesktopMode
)
5640 desktopMode
= (0 != (msg
& kIOPMSetValue
));
5641 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
5643 sendClientClamshellNotification();
5645 // Re-evaluate the lid state
5646 if( clamshellClosed
)
5648 eval_clamshell
= true;
5653 * AC Adaptor connected
5655 * -> reevaluate lid state
5657 if (msg
& kIOPMSetACAdaptorConnected
)
5659 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
5660 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
5663 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
5665 // Tell BSD if AC is connected
5666 // 0 == external power source; 1 == on battery
5667 post_sys_powersource(acAdaptorConnected
? 0:1);
5669 sendClientClamshellNotification();
5671 // Re-evaluate the lid state
5672 if( clamshellClosed
)
5674 eval_clamshell
= true;
5677 // Lack of AC may have latched a display wrangler tickle.
5678 // This mirrors the hardware's USB wake event latch, where a latched
5679 // USB wake event followed by an AC attach will trigger a full wake.
5680 latchDisplayWranglerTickle( false );
5683 // AC presence will reset the standy timer delay adjustment.
5684 _standbyTimerResetSeconds
= 0;
5689 * Enable Clamshell (external display disappear)
5691 * -> reevaluate lid state
5693 if (msg
& kIOPMEnableClamshell
)
5695 // Re-evaluate the lid state
5696 // System should sleep on external display disappearance
5697 // in lid closed operation.
5698 if( clamshellClosed
&& (true == clamshellDisabled
) )
5700 eval_clamshell
= true;
5703 clamshellDisabled
= false;
5705 sendClientClamshellNotification();
5709 * Disable Clamshell (external display appeared)
5710 * We don't bother re-evaluating clamshell state. If the system is awake,
5711 * the lid is probably open.
5713 if (msg
& kIOPMDisableClamshell
)
5715 clamshellDisabled
= true;
5717 sendClientClamshellNotification();
5721 * Evaluate clamshell and SLEEP if appropiate
5723 if ( eval_clamshell
&& shouldSleepOnClamshellClosed() )
5727 privateSleepSystem (kIOPMSleepReasonClamshell
);
5729 else if ( eval_clamshell
)
5731 evaluatePolicy( kStimulusDarkWakeEvaluate
);
5737 if (msg
& kIOPMPowerButton
)
5739 if (!wranglerAsleep
)
5741 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
5742 // Check that power button sleep is enabled
5744 if( kOSBooleanTrue
!= getProperty(pbs
))
5745 privateSleepSystem (kIOPMSleepReasonPowerButton
);
5753 //******************************************************************************
5756 // Evaluate root-domain policy in response to external changes.
5757 //******************************************************************************
5759 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
5763 int idleSleepEnabled
: 1;
5764 int idleSleepDisabled
: 1;
5765 int displaySleep
: 1;
5766 int sleepDelayChanged
: 1;
5767 int evaluateDarkWake
: 1;
5768 int adjustPowerState
: 1;
5773 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
5780 case kStimulusDisplayWranglerSleep
:
5781 if (!wranglerAsleep
)
5783 wranglerAsleep
= true;
5784 clock_get_uptime(&wranglerSleepTime
);
5785 flags
.bit
.displaySleep
= true;
5789 case kStimulusDisplayWranglerWake
:
5790 wranglerAsleep
= false;
5791 flags
.bit
.idleSleepDisabled
= true;
5794 case kStimulusAggressivenessChanged
:
5796 unsigned long minutesToIdleSleep
= 0;
5797 unsigned long minutesToDisplayDim
= 0;
5798 unsigned long minutesDelta
= 0;
5800 // Fetch latest display and system sleep slider values.
5801 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
5802 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
5803 DLOG("aggressiveness changed: system %u->%u, display %u\n",
5804 (uint32_t) sleepSlider
,
5805 (uint32_t) minutesToIdleSleep
,
5806 (uint32_t) minutesToDisplayDim
);
5808 DLOG("idle time -> %ld secs (ena %d)\n",
5809 idleSeconds
, (minutesToIdleSleep
!= 0));
5811 if (0x7fffffff == minutesToIdleSleep
)
5812 minutesToIdleSleep
= idleSeconds
;
5814 // How long to wait before sleeping the system once
5815 // the displays turns off is indicated by 'extraSleepDelay'.
5817 if ( minutesToIdleSleep
> minutesToDisplayDim
)
5818 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
5819 else if( minutesToIdleSleep
== minutesToDisplayDim
)
5822 if ((sleepSlider
== 0) && (minutesToIdleSleep
!= 0))
5823 flags
.bit
.idleSleepEnabled
= true;
5825 if ((sleepSlider
!= 0) && (minutesToIdleSleep
== 0))
5826 flags
.bit
.idleSleepDisabled
= true;
5828 if ((minutesDelta
!= extraSleepDelay
) &&
5829 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
5830 flags
.bit
.sleepDelayChanged
= true;
5832 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
5833 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
5835 // Reconsider decision to remain in dark wake
5836 flags
.bit
.evaluateDarkWake
= true;
5839 sleepSlider
= minutesToIdleSleep
;
5840 extraSleepDelay
= minutesDelta
;
5843 case kStimulusDemandSystemSleep
:
5844 changePowerStateWithOverrideTo( SLEEP_STATE
);
5847 case kStimulusAllowSystemSleepChanged
:
5848 flags
.bit
.adjustPowerState
= true;
5851 case kStimulusDarkWakeActivityTickle
:
5852 if (false == wranglerTickled
)
5854 uint32_t options
= 0;
5855 IOService
* pciRoot
= 0;
5857 if (rejectWranglerTickle
)
5859 DLOG("rejected tickle, type %u capability %x:%x\n",
5860 _systemTransitionType
,
5861 _currentCapability
, _pendingCapability
);
5865 if (latchDisplayWranglerTickle(true))
5867 DLOG("latched tickle\n");
5871 _desiredCapability
|=
5872 (kIOPMSystemCapabilityGraphics
|
5873 kIOPMSystemCapabilityAudio
);
5875 if ((kSystemTransitionWake
== _systemTransitionType
) &&
5876 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
5877 !graphicsSuppressed
)
5879 DLOG("Promoting to full wake\n");
5881 // Elevate to full wake while waking up to dark wake.
5882 // PM will hold off notifying the graphics subsystem about
5883 // system wake as late as possible, so if a HID event does
5884 // arrive, we can turn on graphics on this wake cycle, and
5885 // not have to wait till the following cycle. That latency
5886 // can be huge on some systems. However, once any graphics
5887 // suppression has taken effect, it is too late. All other
5888 // graphics devices must be similarly suppressed. But the
5889 // delay till the following cycle should be very short.
5891 _pendingCapability
|=
5892 (kIOPMSystemCapabilityGraphics
|
5893 kIOPMSystemCapabilityAudio
);
5895 // Immediately bring up audio and graphics.
5896 pciRoot
= pciHostBridgeDriver
;
5898 // Notify clients about full wake.
5899 _systemMessageClientMask
= kSystemMessageClientAll
;
5900 tellClients(kIOMessageSystemWillPowerOn
);
5903 // Unsafe to cancel once graphics was powered.
5904 // If system woke from dark wake, the return to sleep can
5905 // be cancelled. But "awake -> dark -> sleep" transition
5906 // cannot be cancelled.
5908 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
5909 options
|= kIOPMSyncCancelPowerDown
;
5912 synchronizePowerTree( options
, pciRoot
);
5913 wranglerTickled
= true;
5914 // IOGraphics doesn't lit the display even though graphics
5915 // is enanbled in kIOMessageSystemCapabilityChange message(radar 9502104)
5916 // So, do an explicit activity tickle
5918 wrangler
->activityTickle(0,0);
5920 if (logWranglerTickle
)
5925 clock_get_uptime(&now
);
5926 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
5927 absolutetime_to_nanoseconds(now
, &nsec
);
5928 MSG("HID tickle %u ms\n",
5929 ((int)((nsec
) / 1000000ULL)));
5930 logWranglerTickle
= false;
5935 case kStimulusDarkWakeEntry
:
5936 case kStimulusDarkWakeReentry
:
5937 // Any system transitions since the last dark wake transition
5938 // will invalid the stimulus.
5940 if (arg
== _systemStateGeneration
)
5942 DLOG("dark wake entry\n");
5943 systemDarkWake
= true;
5944 wranglerAsleep
= true;
5945 clock_get_uptime(&wranglerSleepTime
);
5947 // Always accelerate disk spindown while in dark wake,
5948 // even if system does not support/allow sleep.
5950 cancelIdleSleepTimer();
5951 setQuickSpinDownTimeout();
5952 flags
.bit
.evaluateDarkWake
= true;
5956 case kStimulusDarkWakeEvaluate
:
5959 flags
.bit
.evaluateDarkWake
= true;
5961 #if !DARK_TO_FULL_EVALUATE_CLAMSHELL
5964 // Not through kLocalEvalClamshellCommand to avoid loop.
5965 if (clamshellClosed
&& shouldSleepOnClamshellClosed() &&
5966 checkSystemCanSleep(true))
5968 privateSleepSystem( kIOPMSleepReasonClamshell
);
5974 case kStimulusNoIdleSleepPreventers
:
5975 flags
.bit
.adjustPowerState
= true;
5978 } /* switch(stimulus) */
5980 if (flags
.bit
.evaluateDarkWake
&& !wranglerTickled
)
5982 if (darkWakeToSleepASAP
||
5983 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
5985 // System currently in dark wake, and no children and
5986 // assertion prevent system sleep.
5988 if (checkSystemCanSleep(true))
5990 if (lowBatteryCondition
)
5992 lastSleepReason
= kIOPMSleepReasonLowPower
;
5993 setProperty(kRootDomainSleepReasonKey
, kIOPMLowPowerSleepKey
);
5995 else if (darkWakeMaintenance
)
5997 lastSleepReason
= kIOPMSleepReasonMaintenance
;
5998 setProperty(kRootDomainSleepReasonKey
, kIOPMMaintenanceSleepKey
);
6000 else if (darkWakeSleepService
)
6002 lastSleepReason
= kIOPMSleepReasonSleepServiceExit
;
6003 setProperty(kRootDomainSleepReasonKey
, kIOPMSleepServiceExitKey
);
6005 changePowerStateWithOverrideTo( SLEEP_STATE
);
6009 // Parked in dark wake, a tickle will return to full wake
6010 rejectWranglerTickle
= false;
6013 else // non-maintenance (network) dark wake
6015 if (checkSystemCanSleep(true))
6017 // Release power clamp, and wait for children idle.
6018 adjustPowerState(true);
6022 changePowerStateToPriv(ON_STATE
);
6024 rejectWranglerTickle
= false;
6030 // The rest are irrelevant while system is in dark wake.
6034 if (flags
.bit
.displaySleep
|| flags
.bit
.sleepDelayChanged
)
6036 bool cancelQuickSpindown
= false;
6038 if (flags
.bit
.sleepDelayChanged
)
6040 DLOG("extra sleep timer changed\n");
6041 cancelIdleSleepTimer();
6042 cancelQuickSpindown
= true;
6046 DLOG("display sleep\n");
6049 if (wranglerAsleep
&& !wranglerSleepIgnored
)
6051 if ( extraSleepDelay
)
6053 // Start a timer here if the System Sleep timer is greater
6054 // than the Display Sleep timer.
6056 startIdleSleepTimer(gRootDomain
->extraSleepDelay
* 60);
6058 else if ( sleepSlider
)
6060 // Accelerate disk spindown if system sleep and display sleep
6061 // sliders are set to the same value (e.g. both set to 5 min),
6062 // and display is about to go dark. Check the system sleep is
6063 // not set to never sleep. Disk sleep setting is ignored.
6065 setQuickSpinDownTimeout();
6066 cancelQuickSpindown
= false;
6070 if (cancelQuickSpindown
)
6071 restoreUserSpinDownTimeout();
6074 if (flags
.bit
.idleSleepEnabled
)
6076 DLOG("idle sleep timer enabled\n");
6079 changePowerStateToPriv(ON_STATE
);
6082 startIdleSleepTimer( idleSeconds
);
6087 // Start idle sleep timer if wrangler went to sleep
6088 // while system sleep was disabled. Disk spindown is
6089 // accelerated upon timer expiration.
6095 uint32_t minutesSinceDisplaySleep
= 0;
6096 uint32_t sleepDelay
= 0;
6098 clock_get_uptime(&now
);
6099 if (CMP_ABSOLUTETIME(&now
, &wranglerSleepTime
) > 0)
6101 SUB_ABSOLUTETIME(&now
, &wranglerSleepTime
);
6102 absolutetime_to_nanoseconds(now
, &nanos
);
6103 minutesSinceDisplaySleep
= nanos
/ (60000000000ULL);
6106 if (extraSleepDelay
> minutesSinceDisplaySleep
)
6108 sleepDelay
= extraSleepDelay
- minutesSinceDisplaySleep
;
6111 startIdleSleepTimer(sleepDelay
* 60);
6112 DLOG("display slept %u min, set idle timer to %u min\n",
6113 minutesSinceDisplaySleep
, sleepDelay
);
6118 if (flags
.bit
.idleSleepDisabled
)
6120 DLOG("idle sleep timer disabled\n");
6121 cancelIdleSleepTimer();
6122 restoreUserSpinDownTimeout();
6126 if (flags
.bit
.adjustPowerState
)
6128 bool sleepASAP
= false;
6130 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
6134 changePowerStateToPriv(ON_STATE
);
6137 // stay awake for at least idleSeconds
6138 startIdleSleepTimer(idleSeconds
);
6141 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
6148 lastSleepReason
= kIOPMSleepReasonIdle
;
6149 setProperty(kRootDomainSleepReasonKey
, kIOPMIdleSleepKey
);
6152 adjustPowerState(sleepASAP
);
6156 //******************************************************************************
6157 // evaluateAssertions
6159 //******************************************************************************
6160 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
6162 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
6164 messageClients(kIOPMMessageDriverAssertionsChanged
);
6166 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
6169 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
6171 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
6172 wrangler
->setIgnoreIdleTimer( value
);
6176 if (changedBits
& kIOPMDriverAssertionCPUBit
)
6177 evaluatePolicy(kStimulusDarkWakeEvaluate
);
6179 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
6180 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
6182 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
6183 updatePreventIdleSleepList(this, true);
6186 DLOG("Driver assertion ReservedBit7 dropped\n");
6187 updatePreventIdleSleepList(this, false);
6196 //******************************************************************************
6199 //******************************************************************************
6201 void IOPMrootDomain::pmStatsRecordEvent(
6203 AbsoluteTime timestamp
)
6205 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
6206 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
6209 OSData
*publishPMStats
= NULL
;
6211 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
6213 absolutetime_to_nanoseconds(timestamp
, &nsec
);
6215 switch (eventIndex
) {
6216 case kIOPMStatsHibernateImageWrite
:
6218 gPMStats
.hibWrite
.start
= nsec
;
6220 gPMStats
.hibWrite
.stop
= nsec
;
6223 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
6224 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
6227 case kIOPMStatsHibernateImageRead
:
6229 gPMStats
.hibRead
.start
= nsec
;
6231 gPMStats
.hibRead
.stop
= nsec
;
6234 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
6235 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
6237 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
6238 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
6239 publishPMStats
->release();
6240 bzero(&gPMStats
, sizeof(gPMStats
));
6247 * Appends a record of the application response to
6248 * IOPMrootDomain::pmStatsAppResponses
6250 void IOPMrootDomain::pmStatsRecordApplicationResponse(
6251 const OSSymbol
*response
,
6257 OSDictionary
*responseDescription
= NULL
;
6258 OSNumber
*delayNum
= NULL
;
6259 OSNumber
*pidNum
= NULL
;
6260 OSNumber
*msgNum
= NULL
;
6261 const OSSymbol
*appname
;
6262 const OSSymbol
*entryName
;
6263 OSObject
*entryType
;
6266 if (!pmStatsAppResponses
|| pmStatsAppResponses
->getCount() > 50)
6270 while ((responseDescription
= (OSDictionary
*) pmStatsAppResponses
->getObject(i
++)))
6272 entryType
= responseDescription
->getObject(_statsResponseTypeKey
);
6273 entryName
= (OSSymbol
*) responseDescription
->getObject(_statsNameKey
);
6274 if (entryName
&& (entryType
== response
) && entryName
->isEqualTo(name
))
6276 OSNumber
* entryValue
;
6277 entryValue
= (OSNumber
*) responseDescription
->getObject(_statsTimeMSKey
);
6278 if (entryValue
&& (entryValue
->unsigned32BitValue() < delay_ms
))
6279 entryValue
->setValue(delay_ms
);
6284 responseDescription
= OSDictionary::withCapacity(5);
6285 if (responseDescription
)
6288 responseDescription
->setObject(_statsResponseTypeKey
, response
);
6291 if (messageType
!= 0) {
6292 msgNum
= OSNumber::withNumber(messageType
, 32);
6294 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
6299 if (name
&& (strlen(name
) > 0))
6301 appname
= OSSymbol::withCString(name
);
6303 responseDescription
->setObject(_statsNameKey
, appname
);
6308 if (app_pid
!= -1) {
6309 pidNum
= OSNumber::withNumber(app_pid
, 32);
6311 responseDescription
->setObject(_statsPIDKey
, pidNum
);
6316 delayNum
= OSNumber::withNumber(delay_ms
, 32);
6318 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
6319 delayNum
->release();
6322 if (pmStatsAppResponses
) {
6323 pmStatsAppResponses
->setObject(responseDescription
);
6326 responseDescription
->release();
6332 // MARK: PMTraceWorker
6334 //******************************************************************************
6335 // TracePoint support
6337 //******************************************************************************
6339 #define kIOPMRegisterNVRAMTracePointHandlerKey \
6340 "IOPMRegisterNVRAMTracePointHandler"
6342 IOReturn
IOPMrootDomain::callPlatformFunction(
6343 const OSSymbol
* functionName
,
6344 bool waitForFunction
,
6345 void * param1
, void * param2
,
6346 void * param3
, void * param4
)
6348 if (pmTracer
&& functionName
&&
6349 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
6350 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
6352 uint32_t tracePointPhases
, tracePointPCI
;
6353 uint64_t statusCode
;
6355 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
6356 pmTracer
->tracePointTarget
= (void *) param2
;
6357 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
6358 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
6359 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
6360 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
6362 MSG("Sleep failure code 0x%08x 0x%08x\n",
6363 tracePointPCI
, tracePointPhases
);
6365 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
6366 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
6368 return kIOReturnSuccess
;
6371 return super::callPlatformFunction(
6372 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
6375 void IOPMrootDomain::tracePoint( uint8_t point
)
6377 if (systemBooting
) return;
6379 pmTracer
->tracePoint(point
);
6382 if (kIOPMTracePointSleepPowerPlaneDrivers
== point
) IOHibernateIOKitSleep();
6386 void IOPMrootDomain::tracePoint( uint8_t point
, uint8_t data
)
6389 pmTracer
->tracePoint(point
, data
);
6392 void IOPMrootDomain::traceDetail( uint32_t detail
)
6395 pmTracer
->traceDetail( detail
);
6398 //******************************************************************************
6399 // PMTraceWorker Class
6401 //******************************************************************************
6404 #define super OSObject
6405 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
6407 #define kPMBestGuessPCIDevicesCount 25
6408 #define kPMMaxRTCBitfieldSize 32
6410 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
6414 me
= OSTypeAlloc( PMTraceWorker
);
6415 if (!me
|| !me
->init())
6420 DLOG("PMTraceWorker %p\n", me
);
6422 // Note that we cannot instantiate the PCI device -> bit mappings here, since
6423 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
6424 // this dictionary lazily.
6426 me
->pciDeviceBitMappings
= NULL
;
6427 me
->pciMappingLock
= IOLockAlloc();
6428 me
->tracePhase
= kIOPMTracePointSystemUp
;
6429 me
->loginWindowPhase
= 0;
6430 me
->traceData32
= 0;
6434 void PMTraceWorker::RTC_TRACE(void)
6436 if (tracePointHandler
&& tracePointTarget
)
6440 wordA
= (tracePhase
<< 24) | (loginWindowPhase
<< 16) |
6443 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
6444 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
6448 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
6450 const OSSymbol
* deviceName
;
6453 IOLockLock(pciMappingLock
);
6455 if (!pciDeviceBitMappings
)
6457 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
6458 if (!pciDeviceBitMappings
)
6462 // Check for bitmask overflow.
6463 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
6466 if ((deviceName
= pciDevice
->copyName()) &&
6467 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
6468 pciDeviceBitMappings
->setObject(deviceName
))
6470 index
= pciDeviceBitMappings
->getCount() - 1;
6471 _LOG("PMTrace PCI array: set object %s => %d\n",
6472 deviceName
->getCStringNoCopy(), index
);
6475 deviceName
->release();
6476 if (!addedToRegistry
&& (index
>= 0))
6477 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
6480 IOLockUnlock(pciMappingLock
);
6484 bool PMTraceWorker::serialize(OSSerialize
*s
) const
6487 if (pciDeviceBitMappings
)
6489 IOLockLock(pciMappingLock
);
6490 ok
= pciDeviceBitMappings
->serialize(s
);
6491 IOLockUnlock(pciMappingLock
);
6496 void PMTraceWorker::tracePoint(uint8_t phase
)
6498 // clear trace detail when phase begins
6499 if (tracePhase
!= phase
)
6504 DLOG("trace point 0x%02x\n", tracePhase
);
6508 void PMTraceWorker::tracePoint(uint8_t phase
, uint8_t data8
)
6510 // clear trace detail when phase begins
6511 if (tracePhase
!= phase
)
6517 DLOG("trace point 0x%02x 0x%02x\n", tracePhase
, traceData8
);
6521 void PMTraceWorker::traceDetail(uint32_t detail
)
6523 if (kIOPMTracePointSleepPriorityClients
!= tracePhase
)
6526 traceData32
= detail
;
6527 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
6532 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
6534 loginWindowPhase
= phase
;
6536 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
6540 void PMTraceWorker::tracePCIPowerChange(
6541 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
6544 uint32_t expectedFlag
;
6546 // Ignore PCI changes outside of system sleep/wake.
6547 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
6548 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
6551 // Only record the WillChange transition when going to sleep,
6552 // and the DidChange on the way up.
6553 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
6554 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
6555 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
6556 if (changeFlags
!= expectedFlag
)
6559 // Mark this device off in our bitfield
6560 if (bitNum
< kPMMaxRTCBitfieldSize
)
6562 bitMask
= (1 << bitNum
);
6564 if (kPowerChangeStart
== type
)
6566 traceData32
|= bitMask
;
6567 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
6568 service
->getName(), bitNum
, bitMask
, traceData32
);
6572 traceData32
&= ~bitMask
;
6573 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
6574 service
->getName(), bitNum
, bitMask
, traceData32
);
6582 // MARK: PMHaltWorker
6584 //******************************************************************************
6585 // PMHaltWorker Class
6587 //******************************************************************************
6589 static unsigned int gPMHaltBusyCount
;
6590 static unsigned int gPMHaltIdleCount
;
6591 static int gPMHaltDepth
;
6592 static unsigned long gPMHaltEvent
;
6593 static IOLock
* gPMHaltLock
= 0;
6594 static OSArray
* gPMHaltArray
= 0;
6595 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
6597 PMHaltWorker
* PMHaltWorker::worker( void )
6603 me
= OSTypeAlloc( PMHaltWorker
);
6604 if (!me
|| !me
->init())
6607 me
->lock
= IOLockAlloc();
6611 DLOG("PMHaltWorker %p\n", me
);
6612 me
->retain(); // thread holds extra retain
6613 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
6618 thread_deallocate(thread
);
6623 if (me
) me
->release();
6627 void PMHaltWorker::free( void )
6629 DLOG("PMHaltWorker free %p\n", this);
6635 return OSObject::free();
6638 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
6640 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
6642 IOLockLock( gPMHaltLock
);
6644 me
->depth
= gPMHaltDepth
;
6645 IOLockUnlock( gPMHaltLock
);
6647 while (me
->depth
>= 0)
6649 PMHaltWorker::work( me
);
6651 IOLockLock( gPMHaltLock
);
6652 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
6654 // This is the last thread to finish work on this level,
6655 // inform everyone to start working on next lower level.
6657 me
->depth
= gPMHaltDepth
;
6658 gPMHaltIdleCount
= 0;
6659 thread_wakeup((event_t
) &gPMHaltIdleCount
);
6663 // One or more threads are still working on this level,
6664 // this thread must wait.
6665 me
->depth
= gPMHaltDepth
- 1;
6667 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
6668 } while (me
->depth
!= gPMHaltDepth
);
6670 IOLockUnlock( gPMHaltLock
);
6673 // No more work to do, terminate thread
6674 DLOG("All done for worker: %p (visits = %u)\n", me
, me
->visits
);
6675 thread_wakeup( &gPMHaltDepth
);
6679 void PMHaltWorker::work( PMHaltWorker
* me
)
6681 IOService
* service
;
6683 AbsoluteTime startTime
;
6692 // Claim an unit of work from the shared pool
6693 IOLockLock( gPMHaltLock
);
6694 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
6697 service
= (IOService
*)inner
->getAnyObject();
6701 inner
->removeObject(service
);
6704 IOLockUnlock( gPMHaltLock
);
6706 break; // no more work at this depth
6708 clock_get_uptime(&startTime
);
6710 if (!service
->isInactive() &&
6711 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
6713 IOLockLock(me
->lock
);
6714 me
->startTime
= startTime
;
6715 me
->service
= service
;
6716 me
->timeout
= false;
6717 IOLockUnlock(me
->lock
);
6719 service
->systemWillShutdown( gPMHaltEvent
);
6721 // Wait for driver acknowledgement
6722 IOLockLock(me
->lock
);
6723 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
6725 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
6728 timeout
= me
->timeout
;
6729 IOLockUnlock(me
->lock
);
6732 deltaTime
= computeDeltaTimeMS(&startTime
);
6733 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
6734 (gIOKitDebug
& kIOLogPMRootDomain
))
6736 LOG("%s driver %s (%p) took %u ms\n",
6737 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
6738 "PowerOff" : "Restart",
6739 service
->getName(), service
,
6740 (uint32_t) deltaTime
);
6748 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
6751 AbsoluteTime startTime
;
6752 AbsoluteTime endTime
;
6756 IOLockLock(me
->lock
);
6757 if (me
->service
&& !me
->timeout
)
6759 startTime
= me
->startTime
;
6761 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
6763 SUB_ABSOLUTETIME(&endTime
, &startTime
);
6764 absolutetime_to_nanoseconds(endTime
, &nano
);
6766 if (nano
> 3000000000ULL)
6769 MSG("%s still waiting on %s\n",
6770 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
6771 "PowerOff" : "Restart",
6772 me
->service
->getName());
6775 IOLockUnlock(me
->lock
);
6779 //******************************************************************************
6780 // acknowledgeSystemWillShutdown
6782 // Acknowledgement from drivers that they have prepared for shutdown/restart.
6783 //******************************************************************************
6785 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
6787 PMHaltWorker
* worker
;
6793 //DLOG("%s acknowledged\n", from->getName());
6794 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
6797 worker
= (PMHaltWorker
*) prop
;
6798 IOLockLock(worker
->lock
);
6799 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
6800 thread_wakeup((event_t
) worker
);
6801 IOLockUnlock(worker
->lock
);
6806 DLOG("%s acknowledged without worker property\n",
6812 //******************************************************************************
6813 // notifySystemShutdown
6815 // Notify all objects in PM tree that system will shutdown or restart
6816 //******************************************************************************
6819 notifySystemShutdown( IOService
* root
, unsigned long event
)
6821 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
6822 IORegistryIterator
* iter
;
6823 IORegistryEntry
* entry
;
6826 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
6827 AbsoluteTime deadline
;
6828 unsigned int totalNodes
= 0;
6830 unsigned int rootDepth
;
6831 unsigned int numWorkers
;
6837 DLOG("%s event = %lx\n", __FUNCTION__
, event
);
6839 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
6841 // Iterate the entire PM tree starting from root
6843 rootDepth
= root
->getDepth( gIOPowerPlane
);
6844 if (!rootDepth
) goto done
;
6846 // debug - for repeated test runs
6847 while (PMHaltWorker::metaClass
->getInstanceCount())
6852 gPMHaltArray
= OSArray::withCapacity(40);
6853 if (!gPMHaltArray
) goto done
;
6856 gPMHaltArray
->flushCollection();
6860 gPMHaltLock
= IOLockAlloc();
6861 if (!gPMHaltLock
) goto done
;
6864 if (!gPMHaltClientAcknowledgeKey
)
6866 gPMHaltClientAcknowledgeKey
=
6867 OSSymbol::withCStringNoCopy("PMShutdown");
6868 if (!gPMHaltClientAcknowledgeKey
) goto done
;
6871 gPMHaltEvent
= event
;
6873 // Depth-first walk of PM plane
6875 iter
= IORegistryIterator::iterateOver(
6876 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
6880 while ((entry
= iter
->getNextObject()))
6882 node
= OSDynamicCast(IOService
, entry
);
6887 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
6890 depth
= node
->getDepth( gIOPowerPlane
);
6891 if (depth
<= rootDepth
)
6896 // adjust to zero based depth
6897 depth
-= (rootDepth
+ 1);
6899 // gPMHaltArray is an array of containers, each container
6900 // refers to nodes with the same depth.
6902 count
= gPMHaltArray
->getCount();
6903 while (depth
>= count
)
6905 // expand array and insert placeholders
6906 gPMHaltArray
->setObject(PLACEHOLDER
);
6909 count
= gPMHaltArray
->getCount();
6912 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
6913 if (inner
== PLACEHOLDER
)
6915 inner
= OSSet::withCapacity(40);
6918 gPMHaltArray
->replaceObject(depth
, inner
);
6923 // PM nodes that appear more than once in the tree will have
6924 // the same depth, OSSet will refuse to add the node twice.
6926 ok
= inner
->setObject(node
);
6929 DLOG("Skipped PM node %s\n", node
->getName());
6935 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
6938 if (inner
!= PLACEHOLDER
)
6939 count
= inner
->getCount();
6940 DLOG("Nodes at depth %u = %u\n", i
, count
);
6943 // strip placeholders (not all depths are populated)
6945 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
6947 if (inner
== PLACEHOLDER
)
6949 gPMHaltArray
->removeObject(i
);
6952 count
= inner
->getCount();
6953 if (count
> numWorkers
)
6955 totalNodes
+= count
;
6959 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
6962 gPMHaltBusyCount
= 0;
6963 gPMHaltIdleCount
= 0;
6964 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
6966 // Create multiple workers (and threads)
6968 if (numWorkers
> kPMHaltMaxWorkers
)
6969 numWorkers
= kPMHaltMaxWorkers
;
6971 DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
6972 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
6974 for (unsigned int i
= 0; i
< numWorkers
; i
++)
6975 workers
[i
] = PMHaltWorker::worker();
6977 // Wait for workers to exhaust all available work
6979 IOLockLock(gPMHaltLock
);
6980 while (gPMHaltDepth
>= 0)
6982 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
6984 waitResult
= IOLockSleepDeadline(
6985 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
6986 if (THREAD_TIMED_OUT
== waitResult
)
6989 clock_get_uptime(&now
);
6991 IOLockUnlock(gPMHaltLock
);
6992 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
6995 PMHaltWorker::checkTimeout(workers
[i
], &now
);
6997 IOLockLock(gPMHaltLock
);
7000 IOLockUnlock(gPMHaltLock
);
7002 // Release all workers
7004 for (unsigned int i
= 0; i
< numWorkers
; i
++)
7007 workers
[i
]->release();
7008 // worker also retained by it's own thread
7012 DLOG("%s done\n", __FUNCTION__
);
7016 //*********************************************************************************
7017 // Sleep/Wake logging
7019 //*********************************************************************************
7021 IOMemoryDescriptor
*IOPMrootDomain::getPMTraceMemoryDescriptor(void)
7024 return timeline
->getPMTraceMemoryDescriptor();
7029 // Forwards external reports of detailed events to IOPMTimeline
7030 IOReturn
IOPMrootDomain::recordPMEvent(PMEventDetails
*details
)
7032 if (timeline
&& details
) {
7036 // Record a detailed driver power change event, or...
7037 if(details
->eventClassifier
== kIOPMEventClassDriverEvent
) {
7038 rc
= timeline
->recordDetailedPowerEvent( details
);
7041 // Record a system power management event
7042 else if(details
->eventClassifier
== kIOPMEventClassSystemEvent
) {
7043 rc
= timeline
->recordSystemPowerEvent( details
);
7046 return kIOReturnBadArgument
;
7049 // If we get to record this message, then we've reached the
7050 // end of another successful Sleep --> Wake cycle
7051 // At this point, we pat ourselves in the back and allow
7052 // our Sleep --> Wake UUID to be published
7053 if(details
->eventType
== kIOPMEventTypeWakeDone
) {
7054 timeline
->setSleepCycleInProgressFlag(false);
7058 // Check if its time to clear the timeline buffer
7059 if(getProperty(kIOPMSleepWakeUUIDKey)
7060 && timeline->isSleepCycleInProgress() == false
7061 && timeline->getNumEventsLoggedThisPeriod() > 500) {
7063 // Clear the old UUID
7064 if(pmPowerStateQueue) {
7065 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)false );
7072 return kIOReturnNotReady
;
7075 IOReturn
IOPMrootDomain::recordAndReleasePMEvent(PMEventDetails
*details
)
7077 IOReturn ret
= kIOReturnBadArgument
;
7081 ret
= recordPMEvent(details
);
7088 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7090 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
7091 IOPMDriverAssertionType whichAssertionBits
,
7092 IOPMDriverAssertionLevel assertionLevel
,
7093 IOService
*ownerService
,
7094 const char *ownerDescription
)
7097 IOPMDriverAssertionID newAssertion
;
7102 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
7104 if (kIOReturnSuccess
== ret
)
7105 return newAssertion
;
7110 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
7113 return kIOReturnInternalError
;
7115 return pmAssertions
->releaseAssertion(releaseAssertion
);
7118 IOReturn
IOPMrootDomain::setPMAssertionLevel(
7119 IOPMDriverAssertionID assertionID
,
7120 IOPMDriverAssertionLevel assertionLevel
)
7122 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
7125 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
7127 IOPMDriverAssertionType sysLevels
;
7129 if (!pmAssertions
|| whichAssertion
== 0)
7130 return kIOPMDriverAssertionLevelOff
;
7132 sysLevels
= pmAssertions
->getActivatedAssertions();
7134 // Check that every bit set in argument 'whichAssertion' is asserted
7135 // in the aggregate bits.
7136 if ((sysLevels
& whichAssertion
) == whichAssertion
)
7137 return kIOPMDriverAssertionLevelOn
;
7139 return kIOPMDriverAssertionLevelOff
;
7142 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
7145 return kIOReturnNotFound
;
7147 return pmAssertions
->setUserAssertionLevels(inLevels
);
7150 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
7154 pmAssertions
->publishProperties();
7156 return( IOService::serializeProperties(s
) );
7159 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7162 // MARK: PMSettingHandle
7164 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
7166 void PMSettingHandle::free( void )
7170 pmso
->clientHandleFreed();
7179 // MARK: PMSettingObject
7182 #define super OSObject
7183 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
7186 * Static constructor/initializer for PMSettingObject
7188 PMSettingObject
*PMSettingObject::pmSettingObject(
7189 IOPMrootDomain
*parent_arg
,
7190 IOPMSettingControllerCallback handler_arg
,
7191 OSObject
*target_arg
,
7192 uintptr_t refcon_arg
,
7193 uint32_t supportedPowerSources
,
7194 const OSSymbol
* settings
[],
7195 OSObject
**handle_obj
)
7197 uint32_t settingCount
= 0;
7198 PMSettingObject
*pmso
= 0;
7199 PMSettingHandle
*pmsh
= 0;
7201 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
7204 // count OSSymbol entries in NULL terminated settings array
7205 while (settings
[settingCount
]) {
7208 if (0 == settingCount
)
7211 pmso
= new PMSettingObject
;
7212 if (!pmso
|| !pmso
->init())
7215 pmsh
= new PMSettingHandle
;
7216 if (!pmsh
|| !pmsh
->init())
7219 queue_init(&pmso
->calloutQueue
);
7220 pmso
->parent
= parent_arg
;
7221 pmso
->func
= handler_arg
;
7222 pmso
->target
= target_arg
;
7223 pmso
->refcon
= refcon_arg
;
7224 pmso
->settingCount
= settingCount
;
7226 pmso
->retain(); // handle holds a retain on pmso
7230 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
7231 if (pmso
->publishedFeatureID
) {
7232 for (unsigned int i
=0; i
<settingCount
; i
++) {
7233 // Since there is now at least one listener to this setting, publish
7234 // PM root domain support for it.
7235 parent_arg
->publishPMSetting( settings
[i
],
7236 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
7244 if (pmso
) pmso
->release();
7245 if (pmsh
) pmsh
->release();
7249 void PMSettingObject::free( void )
7251 if (publishedFeatureID
) {
7252 for (uint32_t i
=0; i
<settingCount
; i
++) {
7253 if (publishedFeatureID
[i
]) {
7254 parent
->removePublishedFeature( publishedFeatureID
[i
] );
7258 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
7264 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
7266 (*func
)(target
, type
, object
, refcon
);
7269 void PMSettingObject::clientHandleFreed( void )
7271 parent
->deregisterPMSettingObject(this);
7275 // MARK: IOPMTimeline
7278 #define super OSObject
7280 //*********************************************************************************
7281 //*********************************************************************************
7282 //*********************************************************************************
7284 IOPMTimeline
*IOPMTimeline::timeline(IOPMrootDomain
*root_domain
)
7286 IOPMTimeline
*myself
;
7291 myself
= new IOPMTimeline
;
7294 myself
->owner
= root_domain
;
7301 bool IOPMTimeline::init(void)
7303 if (!super::init()) {
7307 logLock
= IOLockAlloc();
7309 // Fresh timeline, no events logged yet
7310 this->numEventsLoggedThisPeriod
= 0;
7311 this->sleepCycleInProgress
= false;
7313 //this->setEventsRecordingLevel(1); // TODO
7314 this->setEventsTrackedCount(kIOPMDefaultSystemEventsTracked
);
7319 void IOPMTimeline::free(void)
7321 if (pmTraceMemoryDescriptor
) {
7322 pmTraceMemoryDescriptor
->release();
7323 pmTraceMemoryDescriptor
= NULL
;
7326 IOLockFree(logLock
);
7331 IOMemoryDescriptor
*IOPMTimeline::getPMTraceMemoryDescriptor()
7333 return pmTraceMemoryDescriptor
;
7336 //*********************************************************************************
7337 //*********************************************************************************
7338 //*********************************************************************************
7340 bool IOPMTimeline::setProperties(OSDictionary
*d
)
7343 OSBoolean
*b
= NULL
;
7344 bool changed
= false;
7346 /* Changes size of detailed events buffer */
7347 n
= (OSNumber
*)d
->getObject(kIOPMTimelineSystemNumberTrackedKey
);
7348 if (OSDynamicCast(OSNumber
, n
))
7351 this->setEventsTrackedCount(n
->unsigned32BitValue());
7355 /* enables or disables system events */
7356 b
= (OSBoolean
*)d
->getObject(kIOPMTimelineEnabledKey
);
7360 this->setEventsRecordingLevel((int)(kOSBooleanTrue
== b
));
7366 //*********************************************************************************
7367 //*********************************************************************************
7368 //*********************************************************************************
7370 OSDictionary
*IOPMTimeline::copyInfoDictionary(void)
7372 OSDictionary
*out
= OSDictionary::withCapacity(3);
7378 n
= OSNumber::withNumber(hdr
->sizeEntries
, 32);
7379 out
->setObject(kIOPMTimelineSystemNumberTrackedKey
, n
);
7382 n
= OSNumber::withNumber(hdr
->sizeBytes
, 32);
7383 out
->setObject(kIOPMTimelineSystemBufferSizeKey
, n
);
7387 out
->setObject(kIOPMTimelineEnabledKey
, eventsRecordingLevel
? kOSBooleanTrue
: kOSBooleanFalse
);
7392 //*********************************************************************************
7393 //*********************************************************************************
7394 //*********************************************************************************
7396 /* IOPMTimeline::recordSystemPowerEvent()
7398 * Expected "type" arguments are listed in IOPMPrivate.h under enum "SystemEventTypes"
7399 * Type arguments include "system events", and "Intermediate events"
7401 * - System Events have paired "start" and "stop" events.
7402 * - A start event shall be followed by a stop event.
7403 * - Any number of Intermediate Events may fall between the
7404 * start and stop events.
7405 * - Intermediate events are meaningless outside the bounds of a system event's
7406 * start & stoup routines.
7407 * - It's invalid to record a Start event without a following Stop event; e.g. two
7408 * Start events without an intervenining Stop event is invalid.
7411 * - The first recorded system event shall be preceded by an entry with type == 0
7412 * - IOPMTimeline may choose not to record intermediate events while there's not
7413 * a system event in process.
7415 IOReturn
IOPMTimeline::recordSystemPowerEvent( PMEventDetails
*details
)
7417 static bool wakeDonePending
= true;
7418 IOPMSystemEventRecord
*record_to
= NULL
;
7419 OSString
*swUUIDKey
= NULL
;
7420 uint32_t useIndex
= 0;
7423 return kIOReturnBadArgument
;
7426 return kIOReturnNotReady
;
7428 if (details
->eventType
== kIOPMEventTypeWakeDone
)
7430 if(!wakeDonePending
)
7431 return kIOReturnBadArgument
;
7434 IOLockLock(logLock
);
7436 if (details
->eventType
== kIOPMEventTypeWake
) {
7437 wakeDonePending
= true;
7438 } else if (details
->eventType
== kIOPMEventTypeWakeDone
) {
7439 wakeDonePending
= false;
7442 systemState
= details
->eventType
;
7444 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
7446 // The entry immediately after the latest entry (and thus
7447 // immediately before the first entry) shall have a type 0.
7448 if (useIndex
+ 1 >= hdr
->sizeEntries
) {
7449 traceBuffer
[useIndex
+ 1].eventType
= 0;
7451 traceBuffer
[0].eventType
= 0;
7454 record_to
= &traceBuffer
[useIndex
];
7455 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
7458 record_to
->eventType
= details
->eventType
;
7459 record_to
->eventReason
= details
->reason
;
7460 record_to
->eventResult
= details
->result
;
7461 pmEventTimeStamp(&record_to
->timestamp
);
7463 // If caller doesn't provide a UUID, we'll use the UUID that's posted
7464 // on IOPMrootDomain under key kIOPMSleepWakeUUIDKey
7465 if (!details
->uuid
) {
7466 swUUIDKey
= OSDynamicCast(OSString
, owner
->copyProperty(kIOPMSleepWakeUUIDKey
));
7469 details
->uuid
= swUUIDKey
->getCStringNoCopy();
7473 strncpy(record_to
->uuid
, details
->uuid
, kMaxPMStringLength
);
7476 swUUIDKey
->release();
7478 numEventsLoggedThisPeriod
++;
7481 IOLockUnlock(logLock
);
7483 return kIOReturnSuccess
;
7487 //*********************************************************************************
7488 //*********************************************************************************
7489 //*********************************************************************************
7491 IOReturn
IOPMTimeline::recordDetailedPowerEvent( PMEventDetails
*details
)
7493 IOPMSystemEventRecord
*record_to
= NULL
;
7496 if (!details
->eventType
|| !details
->ownerName
)
7497 return kIOReturnBadArgument
;
7499 IOLockLock(logLock
);
7501 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
7503 record_to
= (IOPMSystemEventRecord
*)&traceBuffer
[useIndex
];
7504 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
7507 record_to
->eventType
= details
->eventType
;
7508 if (details
->ownerName
&& (strlen(details
->ownerName
) > 1)) {
7509 strlcpy( record_to
->ownerName
,
7511 sizeof(record_to
->ownerName
));
7514 record_to
->ownerDisambiguateID
= details
->ownerUnique
;
7516 if (details
->interestName
&& (strlen(details
->interestName
) > 1)) {
7517 strlcpy(record_to
->interestName
,
7518 details
->interestName
,
7519 sizeof(record_to
->interestName
));
7522 record_to
->oldState
= details
->oldState
;
7523 record_to
->newState
= details
->newState
;
7524 record_to
->eventResult
= details
->result
;
7525 record_to
->elapsedTimeUS
= details
->elapsedTimeUS
;
7526 pmEventTimeStamp(&record_to
->timestamp
);
7528 numEventsLoggedThisPeriod
++;
7531 IOLockUnlock(logLock
);
7532 return kIOReturnSuccess
;
7535 uint32_t IOPMTimeline::getNumEventsLoggedThisPeriod() {
7536 return this->numEventsLoggedThisPeriod
;
7539 void IOPMTimeline::setNumEventsLoggedThisPeriod(uint32_t newCount
) {
7540 this->numEventsLoggedThisPeriod
= newCount
;
7543 bool IOPMTimeline::isSleepCycleInProgress() {
7544 return this->sleepCycleInProgress
;
7547 void IOPMTimeline::setSleepCycleInProgressFlag(bool flag
) {
7548 this->sleepCycleInProgress
= flag
;
7550 //*********************************************************************************
7551 //*********************************************************************************
7552 //*********************************************************************************
7554 void IOPMTimeline::setEventsTrackedCount(uint32_t newTracked
)
7556 size_t make_buf_size
= 0;
7558 make_buf_size
= sizeof(IOPMTraceBufferHeader
) + (newTracked
* sizeof(IOPMSystemEventRecord
));
7560 IOLockLock(logLock
);
7562 if (pmTraceMemoryDescriptor
) {
7563 pmTraceMemoryDescriptor
->release();
7564 pmTraceMemoryDescriptor
= NULL
;
7570 if (0 == newTracked
)
7572 IOLog("IOPMrootDomain -> erased buffer.\n");
7576 pmTraceMemoryDescriptor
= IOBufferMemoryDescriptor::withOptions(
7577 kIOMemoryKernelUserShared
| kIODirectionIn
, make_buf_size
);
7579 if (!pmTraceMemoryDescriptor
)
7581 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns NULL\n", (int)make_buf_size
);
7585 pmTraceMemoryDescriptor
->prepare(kIODirectionIn
);
7587 // Header occupies the first sizeof(IOPMTraceBufferHeader) bytes
7588 hdr
= (IOPMTraceBufferHeader
*)pmTraceMemoryDescriptor
->getBytesNoCopy();
7590 // Recorded events occupy the remaining bulk of the buffer
7591 traceBuffer
= (IOPMSystemEventRecord
*)((uint8_t *)hdr
+ sizeof(IOPMTraceBufferHeader
));
7593 bzero(hdr
, make_buf_size
);
7595 hdr
->sizeBytes
= make_buf_size
;
7596 hdr
->sizeEntries
= newTracked
;
7598 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns bufferMB with address 0x%08x\n", (int)make_buf_size
, (unsigned int)(uintptr_t)traceBuffer
);
7601 IOLockUnlock(logLock
);
7604 //*********************************************************************************
7605 //*********************************************************************************
7606 //*********************************************************************************
7608 void IOPMTimeline::setEventsRecordingLevel(uint32_t eventsTrackedBits
)
7617 /* static helper to IOPMTimeline
7619 uint32_t IOPMTimeline::_atomicIndexIncrement(uint32_t *index
, uint32_t limit
)
7629 inc_index
= (was_index
+1)%limit
;
7630 } while (!OSCompareAndSwap(was_index
, inc_index
, index
));
7636 // MARK: PMAssertionsTracker
7638 //*********************************************************************************
7639 //*********************************************************************************
7640 //*********************************************************************************
7641 // class PMAssertionsTracker Implementation
7643 #define kAssertUniqueIDStart 500
7645 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
7647 PMAssertionsTracker
*myself
;
7649 myself
= new PMAssertionsTracker
;
7653 myself
->owner
= rootDomain
;
7654 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
7655 myself
->assertionsArray
= OSArray::withCapacity(5);
7656 myself
->assertionsKernel
= 0;
7657 myself
->assertionsUser
= 0;
7658 myself
->assertionsCombined
= 0;
7659 myself
->assertionsArrayLock
= IOLockAlloc();
7660 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
7662 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
7670 * - Update assertionsKernel to reflect the state of all
7671 * assertions in the kernel.
7672 * - Update assertionsCombined to reflect both kernel & user space.
7674 void PMAssertionsTracker::tabulate(void)
7678 PMAssertStruct
*_a
= NULL
;
7681 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
7682 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
7686 assertionsKernel
= 0;
7687 assertionsCombined
= 0;
7689 if (!assertionsArray
)
7692 if ((count
= assertionsArray
->getCount()))
7694 for (i
=0; i
<count
; i
++)
7696 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7699 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
7700 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
7701 assertionsKernel
|= _a
->assertionBits
;
7706 tabulateProducerCount
++;
7707 assertionsCombined
= assertionsKernel
| assertionsUser
;
7709 if ((assertionsKernel
!= oldKernel
) ||
7710 (assertionsCombined
!= oldCombined
))
7712 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
7716 void PMAssertionsTracker::publishProperties( void )
7718 OSArray
*assertionsSummary
= NULL
;
7720 if (tabulateConsumerCount
!= tabulateProducerCount
)
7722 IOLockLock(assertionsArrayLock
);
7724 tabulateConsumerCount
= tabulateProducerCount
;
7726 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
7728 assertionsSummary
= copyAssertionsArray();
7729 if (assertionsSummary
)
7731 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
7732 assertionsSummary
->release();
7736 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
7739 /* Publish the IOPMrootDomain property "DriverPMAssertions"
7741 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
7743 IOLockUnlock(assertionsArrayLock
);
7747 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
7749 PMAssertStruct
*_a
= NULL
;
7756 && (count
= assertionsArray
->getCount()))
7758 for (i
=0; i
<count
; i
++)
7760 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7763 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
7764 if (_a
&& (_id
== _a
->id
)) {
7781 /* PMAssertionsTracker::handleCreateAssertion
7782 * Perform assertion work on the PM workloop. Do not call directly.
7784 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
7790 IOLockLock(assertionsArrayLock
);
7791 assertionsArray
->setObject(newAssertion
);
7792 IOLockUnlock(assertionsArrayLock
);
7793 newAssertion
->release();
7797 return kIOReturnSuccess
;
7800 /* PMAssertionsTracker::createAssertion
7801 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
7804 IOReturn
PMAssertionsTracker::createAssertion(
7805 IOPMDriverAssertionType which
,
7806 IOPMDriverAssertionLevel level
,
7807 IOService
*serviceID
,
7808 const char *whoItIs
,
7809 IOPMDriverAssertionID
*outID
)
7811 OSData
*dataStore
= NULL
;
7812 PMAssertStruct track
;
7814 // Warning: trillions and trillions of created assertions may overflow the unique ID.
7815 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
7816 track
.level
= level
;
7817 track
.assertionBits
= which
;
7818 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
) : 0;
7819 track
.ownerService
= serviceID
;
7820 track
.modifiedTime
= 0;
7821 pmEventTimeStamp(&track
.createdTime
);
7823 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
7826 if (track
.ownerString
)
7827 track
.ownerString
->release();
7828 return kIOReturnNoMemory
;
7833 if (owner
&& owner
->pmPowerStateQueue
) {
7834 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
7837 return kIOReturnSuccess
;
7840 /* PMAssertionsTracker::handleReleaseAssertion
7841 * Runs in PM workloop. Do not call directly.
7843 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
7844 IOPMDriverAssertionID _id
)
7849 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
7852 return kIOReturnNotFound
;
7854 IOLockLock(assertionsArrayLock
);
7855 if (assertStruct
->ownerString
)
7856 assertStruct
->ownerString
->release();
7858 assertionsArray
->removeObject(index
);
7859 IOLockUnlock(assertionsArrayLock
);
7862 return kIOReturnSuccess
;
7865 /* PMAssertionsTracker::releaseAssertion
7866 * Releases an assertion and affects system behavior if appropiate.
7867 * Actual work happens on PM workloop.
7869 IOReturn
PMAssertionsTracker::releaseAssertion(
7870 IOPMDriverAssertionID _id
)
7872 if (owner
&& owner
->pmPowerStateQueue
) {
7873 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
7875 return kIOReturnSuccess
;
7878 /* PMAssertionsTracker::handleSetAssertionLevel
7879 * Runs in PM workloop. Do not call directly.
7881 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
7882 IOPMDriverAssertionID _id
,
7883 IOPMDriverAssertionLevel _level
)
7885 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
7889 if (!assertStruct
) {
7890 return kIOReturnNotFound
;
7893 IOLockLock(assertionsArrayLock
);
7894 pmEventTimeStamp(&assertStruct
->modifiedTime
);
7895 assertStruct
->level
= _level
;
7896 IOLockUnlock(assertionsArrayLock
);
7899 return kIOReturnSuccess
;
7902 /* PMAssertionsTracker::setAssertionLevel
7904 IOReturn
PMAssertionsTracker::setAssertionLevel(
7905 IOPMDriverAssertionID _id
,
7906 IOPMDriverAssertionLevel _level
)
7908 if (owner
&& owner
->pmPowerStateQueue
) {
7909 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
7910 (void *)_level
, _id
);
7913 return kIOReturnSuccess
;
7916 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
7918 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
7922 if (new_user_levels
!= assertionsUser
)
7924 assertionsUser
= new_user_levels
;
7925 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
7929 return kIOReturnSuccess
;
7932 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
7933 IOPMDriverAssertionType new_user_levels
)
7935 if (gIOPMWorkLoop
) {
7936 gIOPMWorkLoop
->runAction(
7937 OSMemberFunctionCast(
7940 &PMAssertionsTracker::handleSetUserAssertionLevels
),
7942 (void *) &new_user_levels
, 0, 0, 0);
7945 return kIOReturnSuccess
;
7949 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
7953 OSArray
*outArray
= NULL
;
7955 if (!assertionsArray
||
7956 (0 == (count
= assertionsArray
->getCount())) ||
7957 (NULL
== (outArray
= OSArray::withCapacity(count
))))
7962 for (i
=0; i
<count
; i
++)
7964 PMAssertStruct
*_a
= NULL
;
7966 OSDictionary
*details
= NULL
;
7968 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7969 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
7971 OSNumber
*_n
= NULL
;
7973 details
= OSDictionary::withCapacity(7);
7977 outArray
->setObject(details
);
7980 _n
= OSNumber::withNumber(_a
->id
, 64);
7982 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
7985 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
7987 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
7990 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
7992 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
7995 _n
= OSNumber::withNumber((uintptr_t)_a
->ownerService
, 64);
7997 details
->setObject(kIOPMDriverAssertionOwnerServiceKey
, _n
);
8000 _n
= OSNumber::withNumber(_a
->level
, 64);
8002 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
8005 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
8007 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
8011 if (_a
->ownerString
) {
8012 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
8021 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
8023 return assertionsCombined
;
8026 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
8027 IOPMDriverAssertionType type
)
8029 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
8031 return kIOPMDriverAssertionLevelOn
;
8033 return kIOPMDriverAssertionLevelOff
;
8037 //*********************************************************************************
8038 //*********************************************************************************
8039 //*********************************************************************************
8042 static void pmEventTimeStamp(uint64_t *recordTS
)
8050 // We assume tsec fits into 32 bits; 32 bits holds enough
8051 // seconds for 136 years since the epoch in 1970.
8052 clock_get_calendar_microtime(&tsec
, &tusec
);
8055 // Pack the sec & microsec calendar time into a uint64_t, for fun.
8057 *recordTS
|= (uint32_t)tusec
;
8058 *recordTS
|= ((uint64_t)tsec
<< 32);
8064 // MARK: IORootParent
8066 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8068 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
8070 // The reason that root domain needs a root parent is to facilitate demand
8071 // sleep, since a power change from the root parent cannot be vetoed.
8073 // The above statement is no longer true since root domain now performs
8074 // demand sleep using overrides. But root parent remains to avoid changing
8075 // the power tree stacking. Root parent is parked at the max power state.
8078 static IOPMPowerState patriarchPowerStates
[2] =
8080 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
8081 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
8084 void IORootParent::initialize( void )
8088 bool IORootParent::start( IOService
* nub
)
8090 IOService::start(nub
);
8091 attachToParent( getRegistryRoot(), gIOPowerPlane
);
8093 registerPowerDriver(this, patriarchPowerStates
, 2);
8098 void IORootParent::shutDownSystem( void )
8102 void IORootParent::restartSystem( void )
8106 void IORootParent::sleepSystem( void )
8110 void IORootParent::dozeSystem( void )
8114 void IORootParent::sleepToDoze( void )
8118 void IORootParent::wakeSystem( void )
8122 OSObject
* IORootParent::copyProperty( const char * aKey
) const
8124 return (IOService::copyProperty(aKey
));