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 CHECK_THREAD_CONTEXT
83 #ifdef CHECK_THREAD_CONTEXT
84 static IOWorkLoop
* gIOPMWorkLoop
= 0;
85 #define ASSERT_GATED() \
87 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
88 panic("RootDomain: not inside PM gate"); \
92 #define ASSERT_GATED()
93 #endif /* CHECK_THREAD_CONTEXT */
96 (((_pendingCapability & (c)) == 0) && \
97 ((_currentCapability & (c)) != 0))
100 (((_currentCapability & (c)) == 0) && \
101 ((_pendingCapability & (c)) != 0))
103 #define CAP_CHANGE(c) \
104 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
106 #define CAP_CURRENT(c) \
107 ((_currentCapability & (c)) != 0)
109 #define CAP_HIGHEST(c) \
110 ((_highestCapability & (c)) != 0)
112 #define DARK_TO_FULL_EVALUATE_CLAMSHELL 0
114 // Event types for IOPMPowerStateQueue::submitPowerEvent()
116 kPowerEventFeatureChanged
= 1, // 1
117 kPowerEventReceivedPowerNotification
, // 2
118 kPowerEventSystemBootCompleted
, // 3
119 kPowerEventSystemShutdown
, // 4
120 kPowerEventUserDisabledSleep
, // 5
121 kPowerEventRegisterSystemCapabilityClient
, // 6
122 kPowerEventRegisterKernelCapabilityClient
, // 7
123 kPowerEventPolicyStimulus
, // 8
124 kPowerEventAssertionCreate
, // 9
125 kPowerEventAssertionRelease
, // 10
126 kPowerEventAssertionSetLevel
, // 11
127 kPowerEventQueueSleepWakeUUID
, // 12
128 kPowerEventPublishSleepWakeUUID
// 13
131 // For evaluatePolicy()
132 // List of stimuli that affects the root domain policy.
134 kStimulusDisplayWranglerSleep
, // 0
135 kStimulusDisplayWranglerWake
, // 1
136 kStimulusAggressivenessChanged
, // 2
137 kStimulusDemandSystemSleep
, // 3
138 kStimulusAllowSystemSleepChanged
, // 4
139 kStimulusDarkWakeActivityTickle
, // 5
140 kStimulusDarkWakeEntry
, // 6
141 kStimulusDarkWakeReentry
, // 7
142 kStimulusDarkWakeEvaluate
// 8
146 IOReturn
OSKextSystemSleepOrWake( UInt32
);
149 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
150 static void notifySystemShutdown( IOService
* root
, unsigned long event
);
151 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
152 static void pmEventTimeStamp(uint64_t *recordTS
);
154 // "IOPMSetSleepSupported" callPlatformFunction name
155 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
156 static const OSSymbol
*sleepMessagePEFunction
= NULL
;
158 #define kIOSleepSupportedKey "IOSleepSupported"
159 #define kIOPMSystemCapabilitiesKey "System Capabilities"
161 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
162 | kIOPMSupportedOnBatt \
163 | kIOPMSupportedOnUPS)
167 // not idle around autowake time, secs
168 kAutoWakePreWindow
= 45,
169 kAutoWakePostWindow
= 15
172 #define kLocalEvalClamshellCommand (1 << 15)
182 #define ON_POWER kIOPMPowerOn
183 #define RESTART_POWER kIOPMRestart
184 #define SLEEP_POWER kIOPMAuxPowerOn
186 static IOPMPowerState ourPowerStates
[NUM_POWER_STATES
] =
188 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
189 {1, kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
, 0,0,0,0,0,0,0,0},
190 {1, kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
, 0,0,0,0,0,0,0,0},
191 {1, kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
, 0,0,0,0,0,0,0,0}
194 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
195 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
196 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
197 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
198 #define kIOPMRootDomainWakeTypeUser "User"
199 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
200 #define kIOPMRootDomainWakeTypeNetwork "Network"
202 // Special interest that entitles the interested client from receiving
203 // all system messages. Only used by powerd.
205 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
210 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
211 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
213 #define kAggressivesMinValue 1
216 kAggressivesStateBusy
= 0x01,
217 kAggressivesStateQuickSpindown
= 0x02
220 struct AggressivesRecord
{
226 struct AggressivesRequest
{
232 AggressivesRecord record
;
237 kAggressivesRequestTypeService
= 1,
238 kAggressivesRequestTypeRecord
242 kAggressivesOptionSynchronous
= 0x00000001,
243 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
244 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
245 kAggressivesOptionQuickSpindownMask
= 0x00000300
249 kAggressivesRecordFlagModified
= 0x00000001,
250 kAggressivesRecordFlagMinValue
= 0x00000002
255 kDarkWakeFlagHIDTickleEarly
= 0x01, // hid tickle before gfx suppression
256 kDarkWakeFlagHIDTickleLate
= 0x02, // hid tickle after gfx suppression
257 kDarkWakeFlagHIDTickleNone
= 0x03, // hid tickle is not posted
258 kDarkWakeFlagHIDTickleMask
= 0x03,
259 kDarkWakeFlagIgnoreDiskIOInDark
= 0x04, // ignore disk idle in DW
260 kDarkWakeFlagIgnoreDiskIOAlways
= 0x08, // always ignore disk idle
261 kDarkWakeFlagIgnoreDiskIOMask
= 0x0C,
262 kDarkWakeFlagAlarmIsDark
= 0x0100
265 static IOPMrootDomain
* gRootDomain
;
266 static IONotifier
* gSysPowerDownNotifier
= 0;
267 static UInt32 gSleepOrShutdownPending
= 0;
268 static UInt32 gWillShutdown
= 0;
269 static UInt32 gPagingOff
= 0;
270 static UInt32 gSleepWakeUUIDIsSet
= false;
271 static uint32_t gAggressivesState
= 0;
272 static uint32_t gDarkWakeFlags
= kDarkWakeFlagHIDTickleNone
;
273 static bool gRAMDiskImageBoot
= false;
275 struct timeval gIOLastSleepTime
;
276 struct timeval gIOLastWakeTime
;
278 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
279 #define kCPUUnknownIndex 9999999
286 const OSSymbol
*gIOPMStatsApplicationResponseTimedOut
;
287 const OSSymbol
*gIOPMStatsApplicationResponseCancel
;
288 const OSSymbol
*gIOPMStatsApplicationResponseSlow
;
290 #define kBadPMFeatureID 0
294 * Opaque handle passed to clients of registerPMSettingController()
296 class PMSettingHandle
: public OSObject
298 OSDeclareFinalStructors( PMSettingHandle
)
299 friend class PMSettingObject
;
302 PMSettingObject
*pmso
;
308 * Internal object to track each PM setting controller
310 class PMSettingObject
: public OSObject
312 OSDeclareFinalStructors( PMSettingObject
)
313 friend class IOPMrootDomain
;
316 queue_head_t calloutQueue
;
318 IOPMrootDomain
*parent
;
319 PMSettingHandle
*pmsh
;
320 IOPMSettingControllerCallback func
;
323 uint32_t *publishedFeatureID
;
324 uint32_t settingCount
;
330 static PMSettingObject
*pmSettingObject(
331 IOPMrootDomain
*parent_arg
,
332 IOPMSettingControllerCallback handler_arg
,
333 OSObject
*target_arg
,
334 uintptr_t refcon_arg
,
335 uint32_t supportedPowerSources
,
336 const OSSymbol
*settings
[],
337 OSObject
**handle_obj
);
339 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
340 void clientHandleFreed(void);
343 struct PMSettingCallEntry
{
348 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
349 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
350 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
351 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
353 //*********************************************************************************
354 //*********************************************************************************
355 //*********************************************************************************
357 /* @class IOPMTimeline
358 * @astract Tracks & records PM activity.
359 * @discussion Intended for use only as a helper-class to IOPMrootDomain.
360 * Do not subclass or directly invoke iOPMTimeline
362 class IOPMTimeline
: public OSObject
364 OSDeclareDefaultStructors( IOPMTimeline
);
367 static IOPMTimeline
* timeline(IOPMrootDomain
*root_domain
);
369 bool setProperties(OSDictionary
*d
);
370 OSDictionary
*copyInfoDictionary(void);
372 IOReturn
recordSystemPowerEvent( PMEventDetails
*details
);
374 IOReturn
recordDetailedPowerEvent( PMEventDetails
*details
);
376 IOMemoryDescriptor
*getPMTraceMemoryDescriptor();
378 uint32_t getNumEventsLoggedThisPeriod();
379 void setNumEventsLoggedThisPeriod(uint32_t newCount
);
380 bool isSleepCycleInProgress();
381 void setSleepCycleInProgressFlag(bool flag
);
386 void setEventsTrackedCount(uint32_t newTracked
);
387 void setEventsRecordingLevel(uint32_t eventsTrackedBits
);
388 static uint32_t _atomicIndexIncrement(uint32_t *index
, uint32_t limit
);
391 kPMTimelineRecordTardyDrivers
= 1 << 0,
392 kPMTmielineRecordSystemEvents
= 1 << 1,
393 kPMTimelineRecordAllDrivers
= 1 << 2,
394 kPMTimelineRecordOff
= 0,
395 kPMTimelineRecordDefault
= 3,
396 kPMTimelineRecordDebug
= 7
399 // eventsRecordingLevel is a bitfield defining which PM driver events will get logged
400 // into the PM buffer.
401 uint32_t eventsRecordingLevel
;
403 // pmTraceMemoryDescriptor represents the memory block that IOPMTimeLine records PM trace points into.
404 IOBufferMemoryDescriptor
*pmTraceMemoryDescriptor
;
406 // Pointer to starting address in pmTraceMemoryDescriptor
407 IOPMSystemEventRecord
*traceBuffer
;
408 IOPMTraceBufferHeader
*hdr
;
410 uint16_t systemState
;
413 IOPMrootDomain
*owner
;
415 uint32_t numEventsLoggedThisPeriod
;
416 bool sleepCycleInProgress
;
419 OSDefineMetaClassAndStructors( IOPMTimeline
, OSObject
)
423 * Internal helper object for logging trace points to RTC
424 * IOPMrootDomain and only IOPMrootDomain should instantiate
425 * exactly one of these.
428 typedef void (*IOPMTracePointHandler
)(
429 void * target
, uint32_t code
, uint32_t data
);
431 class PMTraceWorker
: public OSObject
433 OSDeclareDefaultStructors(PMTraceWorker
)
435 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
437 static PMTraceWorker
*tracer( IOPMrootDomain
* );
438 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
439 void tracePoint(uint8_t phase
);
440 void tracePoint(uint8_t phase
, uint8_t data8
);
441 void traceDetail(uint32_t detail
);
442 void traceLoginWindowPhase(uint8_t phase
);
443 int recordTopLevelPCIDevice(IOService
*);
444 void RTC_TRACE(void);
445 virtual bool serialize(OSSerialize
*s
) const;
447 IOPMTracePointHandler tracePointHandler
;
448 void * tracePointTarget
;
450 IOPMrootDomain
*owner
;
451 IOLock
*pciMappingLock
;
452 OSArray
*pciDeviceBitMappings
;
454 uint8_t addedToRegistry
;
456 uint8_t loginWindowPhase
;
458 uint32_t traceData32
;
462 * PMAssertionsTracker
463 * Tracks kernel and user space PM assertions
465 class PMAssertionsTracker
: public OSObject
467 OSDeclareFinalStructors(PMAssertionsTracker
)
469 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
471 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
472 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
473 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
474 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
476 OSArray
*copyAssertionsArray(void);
477 IOPMDriverAssertionType
getActivatedAssertions(void);
478 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
480 IOReturn
handleCreateAssertion(OSData
*);
481 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
482 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
483 IOReturn
handleSetUserAssertionLevels(void * arg0
);
484 void publishProperties(void);
488 IOPMDriverAssertionID id
;
489 IOPMDriverAssertionType assertionBits
;
490 uint64_t createdTime
;
491 uint64_t modifiedTime
;
492 const OSSymbol
*ownerString
;
493 IOService
*ownerService
;
494 IOPMDriverAssertionLevel level
;
497 uint32_t tabulateProducerCount
;
498 uint32_t tabulateConsumerCount
;
500 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
503 IOPMrootDomain
*owner
;
504 OSArray
*assertionsArray
;
505 IOLock
*assertionsArrayLock
;
506 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8))); /* aligned for atomic access */
507 IOPMDriverAssertionType assertionsKernel
;
508 IOPMDriverAssertionType assertionsUser
;
509 IOPMDriverAssertionType assertionsCombined
;
512 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
516 * Internal helper object for Shutdown/Restart notifications.
518 #define kPMHaltMaxWorkers 8
519 #define kPMHaltTimeoutMS 100
521 class PMHaltWorker
: public OSObject
523 OSDeclareFinalStructors( PMHaltWorker
)
526 IOService
* service
; // service being worked on
527 AbsoluteTime startTime
; // time when work started
528 int depth
; // work on nubs at this PM-tree depth
529 int visits
; // number of nodes visited (debug)
531 bool timeout
; // service took too long
533 static PMHaltWorker
* worker( void );
534 static void main( void * arg
, wait_result_t waitResult
);
535 static void work( PMHaltWorker
* me
);
536 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
537 virtual void free( void );
540 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
543 #define super IOService
544 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
546 static void IOPMRootDomainWillShutdown(void)
548 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
550 OSKext::willShutdown();
551 for (int i
= 0; i
< 100; i
++)
553 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
561 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
563 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
566 IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
568 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
571 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
573 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
576 IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
578 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
581 IOReturn
rootDomainRestart ( void )
583 return gRootDomain
->restartSystem();
586 IOReturn
rootDomainShutdown ( void )
588 return gRootDomain
->shutdownSystem();
591 void IOSystemShutdownNotification(void)
593 IOPMRootDomainWillShutdown();
594 if (OSCompareAndSwap(0, 1, &gPagingOff
))
597 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
602 int sync_internal(void);
606 A device is always in the highest power state which satisfies its driver,
607 its policy-maker, and any power children it has, but within the constraint
608 of the power state provided by its parent. The driver expresses its desire by
609 calling changePowerStateTo(), the policy-maker expresses its desire by calling
610 changePowerStateToPriv(), and the children express their desires by calling
611 requestPowerDomainState().
613 The Root Power Domain owns the policy for idle and demand sleep for the system.
614 It is a power-managed IOService just like the others in the system.
615 It implements several power states which map to what we see as Sleep and On.
617 The sleep policy is as follows:
618 1. Sleep is prevented if the case is open so that nobody will think the machine
619 is off and plug/unplug cards.
620 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
621 3. System cannot Sleep if some object in the tree is in a power state marked
622 kIOPMPreventSystemSleep.
624 These three conditions are enforced using the "driver clamp" by calling
625 changePowerStateTo(). For example, if the case is opened,
626 changePowerStateTo(ON_STATE) is called to hold the system on regardless
627 of the desires of the children of the root or the state of the other clamp.
629 Demand Sleep is initiated by pressing the front panel power button, closing
630 the clamshell, or selecting the menu item. In this case the root's parent
631 actually initiates the power state change so that the root domain has no
632 choice and does not give applications the opportunity to veto the change.
634 Idle Sleep occurs if no objects in the tree are in a state marked
635 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
636 the root on, so it sets the "policy-maker clamp" by calling
637 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
638 This timer is set for the difference between the sleep timeout slider and the
639 display dim timeout slider. When the timer expires, it releases its clamp and
640 now nothing is holding it awake, so it falls asleep.
642 Demand sleep is prevented when the system is booting. When preferences are
643 transmitted by the loginwindow at the end of boot, a flag is cleared,
644 and this allows subsequent Demand Sleep.
647 //******************************************************************************
649 IOPMrootDomain
* IOPMrootDomain::construct( void )
651 IOPMrootDomain
*root
;
653 root
= new IOPMrootDomain
;
660 //******************************************************************************
662 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
664 IOService
* rootDomain
= (IOService
*) p0
;
665 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
666 uint32_t powerState
= rootDomain
->getPowerState();
668 DLOG("disk_sync_callout ps=%u\n", powerState
);
670 if (ON_STATE
== powerState
)
673 IOHibernateSystemSleep();
680 IOHibernateSystemPostWake();
684 rootDomain
->allowPowerChange(notifyRef
);
685 DLOG("disk_sync_callout finish\n");
688 //******************************************************************************
690 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
)
692 AbsoluteTime endTime
;
695 clock_get_uptime(&endTime
);
696 if (CMP_ABSOLUTETIME(&endTime
, startTime
) > 0)
698 SUB_ABSOLUTETIME(&endTime
, startTime
);
699 absolutetime_to_nanoseconds(endTime
, &nano
);
702 return (UInt32
)(nano
/ 1000000ULL);
705 //******************************************************************************
708 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
710 struct timeval
*swt
= (struct timeval
*)arg1
;
711 struct proc
*p
= req
->p
;
714 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
715 } else if(proc_is64bit(p
)) {
716 struct user64_timeval t
;
717 t
.tv_sec
= swt
->tv_sec
;
718 t
.tv_usec
= swt
->tv_usec
;
719 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
721 struct user32_timeval t
;
722 t
.tv_sec
= swt
->tv_sec
;
723 t
.tv_usec
= swt
->tv_usec
;
724 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
728 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
729 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
730 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
732 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
733 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
734 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
739 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
741 int new_value
, changed
;
742 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
744 if (!gWillShutdown
&& (new_value
== 1)) {
745 IOPMRootDomainWillShutdown();
752 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
753 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
754 0, 0, sysctl_willshutdown
, "I", "");
759 sysctl_progressmeterenable
760 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
763 int new_value
, changed
;
765 error
= sysctl_io_number(req
, vc_progress_meter_enable
, sizeof(int), &new_value
, &changed
);
768 vc_enable_progressmeter(new_value
);
775 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
778 int new_value
, changed
;
780 error
= sysctl_io_number(req
, vc_progress_meter_value
, sizeof(int), &new_value
, &changed
);
783 vc_set_progressmeter(new_value
);
788 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
789 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
790 0, 0, sysctl_progressmeterenable
, "I", "");
792 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
793 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
794 0, 0, sysctl_progressmeter
, "I", "");
798 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
800 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
801 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
802 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
803 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
804 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
806 //******************************************************************************
809 //******************************************************************************
811 #define kRootDomainSettingsCount 17
813 bool IOPMrootDomain::start( IOService
* nub
)
815 OSIterator
*psIterator
;
816 OSDictionary
*tmpDict
;
817 IORootParent
* patriarch
;
822 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
823 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
824 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
825 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
826 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
828 gIOPMStatsApplicationResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
829 gIOPMStatsApplicationResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
830 gIOPMStatsApplicationResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
832 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
833 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
835 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
837 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
838 gIOPMSettingAutoWakeSecondsKey
,
839 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
840 OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
),
841 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
842 gIOPMSettingDebugWakeRelativeKey
,
843 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
844 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
845 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
846 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
847 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
848 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
849 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
850 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
851 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
852 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
853 gIOPMSettingSilentRunningKey
856 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
858 IORegistryEntry
* chosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
861 if (chosenEntry
->getProperty("boot-ramdmg-size") &&
862 chosenEntry
->getProperty("boot-ramdmg-extents"))
864 gRAMDiskImageBoot
= true;
866 chosenEntry
->release();
869 queue_init(&aggressivesQueue
);
870 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
871 aggressivesData
= OSData::withCapacity(
872 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
874 featuresDictLock
= IOLockAlloc();
875 settingsCtrlLock
= IOLockAlloc();
876 setPMRootDomain(this);
878 extraSleepTimer
= thread_call_allocate(
879 idleSleepTimerExpired
,
880 (thread_call_param_t
) this);
882 diskSyncCalloutEntry
= thread_call_allocate(
884 (thread_call_param_t
) this);
886 setProperty(kIOSleepSupportedKey
, true);
888 bzero(&pmStats
, sizeof(pmStats
));
890 pmTracer
= PMTraceWorker::tracer(this);
892 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
894 userDisabledAllSleep
= false;
895 systemBooting
= true;
897 idleSleepTimerPending
= false;
899 clamshellClosed
= false;
900 clamshellExists
= false;
901 clamshellDisabled
= true;
902 acAdaptorConnected
= true;
904 // Set the default system capabilities at boot.
905 _currentCapability
= kIOPMSystemCapabilityCPU
|
906 kIOPMSystemCapabilityGraphics
|
907 kIOPMSystemCapabilityAudio
|
908 kIOPMSystemCapabilityNetwork
;
910 _pendingCapability
= _currentCapability
;
911 _desiredCapability
= _currentCapability
;
912 _highestCapability
= _currentCapability
;
913 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
915 queuedSleepWakeUUIDString
= NULL
;
916 pmStatsAppResponses
= OSArray::withCapacity(5);
917 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
918 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
919 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
920 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
921 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
923 idxPMCPUClamshell
= kCPUUnknownIndex
;
924 idxPMCPULimitedPower
= kCPUUnknownIndex
;
926 tmpDict
= OSDictionary::withCapacity(1);
927 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
930 settingsCallbacks
= OSDictionary::withCapacity(1);
932 // Create a list of the valid PM settings that we'll relay to
933 // interested clients in setProperties() => setPMSetting()
934 allowedPMSettings
= OSArray::withObjects(
935 (const OSObject
**)settingsArr
,
936 kRootDomainSettingsCount
,
939 // List of PM settings that should not automatically publish itself
940 // as a feature when registered by a listener.
941 noPublishPMSettings
= OSArray::withObjects(
942 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
944 fPMSettingsDict
= OSDictionary::withCapacity(5);
946 PMinit(); // creates gIOPMWorkLoop
948 // Create IOPMPowerStateQueue used to queue external power
949 // events, and to handle those events on the PM work loop.
950 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
951 this, OSMemberFunctionCast(IOEventSource::Action
, this,
952 &IOPMrootDomain::dispatchPowerEvent
));
953 getPMworkloop()->addEventSource(pmPowerStateQueue
);
954 #ifdef CHECK_THREAD_CONTEXT
955 gIOPMWorkLoop
= getPMworkloop();
958 // create our power parent
959 patriarch
= new IORootParent
;
961 patriarch
->attach(this);
962 patriarch
->start(this);
963 patriarch
->addPowerChild(this);
965 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
966 changePowerStateToPriv(ON_STATE
);
968 if (gIOKitDebug
& (kIOLogDriverPower1
| kIOLogDriverPower2
))
970 // Setup our PM logging & recording code
971 timeline
= IOPMTimeline::timeline(this);
973 OSDictionary
*tlInfo
= timeline
->copyInfoDictionary();
977 setProperty(kIOPMTimelineDictionaryKey
, tlInfo
);
983 // install power change handler
984 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
987 // Register for a notification when IODisplayWrangler is published
988 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
990 _displayWranglerNotifier
= addMatchingNotification(
991 gIOPublishNotification
, tmpDict
,
992 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
998 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
999 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1000 ucClassName
->release();
1002 // IOBacklightDisplay can take a long time to load at boot, or it may
1003 // not load at all if you're booting with clamshell closed. We publish
1004 // 'DisplayDims' here redundantly to get it published early and at all.
1005 psIterator
= getMatchingServices( serviceMatching("IOPMPowerSource") );
1006 if( psIterator
&& psIterator
->getNextObject() )
1008 // There's at least one battery on the system, so we publish
1009 // 'DisplayDims' support for the LCD.
1010 publishFeature("DisplayDims");
1013 psIterator
->release();
1016 sysctl_register_oid(&sysctl__kern_sleeptime
);
1017 sysctl_register_oid(&sysctl__kern_waketime
);
1018 sysctl_register_oid(&sysctl__kern_willshutdown
);
1019 #if !CONFIG_EMBEDDED
1020 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1021 sysctl_register_oid(&sysctl__kern_progressmeter
);
1022 #endif /* !CONFIG_EMBEDDED */
1025 IOHibernateSystemInit(this);
1028 registerService(); // let clients find us
1033 //******************************************************************************
1036 // Receive a setProperty call
1037 // The "System Boot" property means the system is completely booted.
1038 //******************************************************************************
1040 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1042 IOReturn return_value
= kIOReturnSuccess
;
1043 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1051 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1052 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1053 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1054 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1055 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1056 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1057 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1058 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1059 const OSSymbol
*loginwindow_tracepoint_string
= OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey
);
1060 const OSSymbol
*pmTimelineLogging_string
= OSSymbol::withCString(kIOPMTimelineDictionaryKey
);
1062 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1063 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1064 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1065 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1070 return_value
= kIOReturnBadArgument
;
1074 if ((b
= OSDynamicCast(OSBoolean
, dict
->getObject(publish_simulated_battery_string
))))
1076 publishResource(publish_simulated_battery_string
, kOSBooleanTrue
);
1079 if ((n
= OSDynamicCast(OSNumber
, dict
->getObject(idle_seconds_string
))))
1081 setProperty(idle_seconds_string
, n
);
1082 idleSeconds
= n
->unsigned32BitValue();
1085 if (boot_complete_string
&& dict
->getObject(boot_complete_string
))
1087 pmPowerStateQueue
->submitPowerEvent( kPowerEventSystemBootCompleted
);
1090 if( battery_warning_disabled_string
&& dict
->getObject(battery_warning_disabled_string
))
1092 setProperty( battery_warning_disabled_string
, dict
->getObject(battery_warning_disabled_string
));
1095 if (pmTimelineLogging_string
&& (d
= OSDynamicCast(OSDictionary
, dict
->getObject(pmTimelineLogging_string
))))
1097 if (timeline
&& timeline
->setProperties(d
))
1099 OSDictionary
*tlInfo
= timeline
->copyInfoDictionary();
1101 setProperty(kIOPMTimelineDictionaryKey
, tlInfo
);
1107 if( sys_shutdown_string
&& (b
= OSDynamicCast(OSBoolean
, dict
->getObject(sys_shutdown_string
))))
1109 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1112 if( stall_halt_string
&& (b
= OSDynamicCast(OSBoolean
, dict
->getObject(stall_halt_string
))) )
1114 setProperty(stall_halt_string
, b
);
1118 if ( hibernatemode_string
1119 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatemode_string
))))
1121 setProperty(hibernatemode_string
, n
);
1123 if ( hibernatefreeratio_string
1124 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatefreeratio_string
))))
1126 setProperty(hibernatefreeratio_string
, n
);
1128 if ( hibernatefreetime_string
1129 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatefreetime_string
))))
1131 setProperty(hibernatefreetime_string
, n
);
1134 if ( hibernatefile_string
1135 && (str
= OSDynamicCast(OSString
, dict
->getObject(hibernatefile_string
))))
1137 setProperty(hibernatefile_string
, str
);
1141 if( sleepdisabled_string
1142 && (b
= OSDynamicCast(OSBoolean
, dict
->getObject(sleepdisabled_string
))) )
1144 setProperty(sleepdisabled_string
, b
);
1145 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1147 if (ondeck_sleepwake_uuid_string
1148 && (obj
= dict
->getObject(ondeck_sleepwake_uuid_string
)))
1150 if(pmPowerStateQueue
) {
1152 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1157 if (loginwindow_tracepoint_string
1158 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(loginwindow_tracepoint_string
)))
1161 pmTracer
->traceLoginWindowPhase( n
->unsigned8BitValue() );
1164 if ((b
= OSDynamicCast(OSBoolean
, dict
->getObject(kIOPMDeepSleepEnabledKey
))))
1166 setProperty(kIOPMDeepSleepEnabledKey
, b
);
1168 if ((n
= OSDynamicCast(OSNumber
, dict
->getObject(kIOPMDeepSleepDelayKey
))))
1170 setProperty(kIOPMDeepSleepDelayKey
, n
);
1172 if ((b
= OSDynamicCast(OSBoolean
, dict
->getObject(kIOPMDestroyFVKeyOnStandbyKey
))))
1174 setProperty(kIOPMDestroyFVKeyOnStandbyKey
, b
);
1176 if ((b
= OSDynamicCast(OSBoolean
, dict
->getObject(kIOPMAutoPowerOffEnabledKey
))))
1178 setProperty(kIOPMAutoPowerOffEnabledKey
, b
);
1180 if ((n
= OSDynamicCast(OSNumber
, dict
->getObject(kIOPMAutoPowerOffDelayKey
))))
1182 setProperty(kIOPMAutoPowerOffDelayKey
, n
);
1185 // Relay our allowed PM settings onto our registered PM clients
1186 for(i
= 0; i
< allowedPMSettings
->getCount(); i
++) {
1188 type
= (OSSymbol
*)allowedPMSettings
->getObject(i
);
1191 obj
= dict
->getObject(type
);
1194 if ((gIOPMSettingAutoWakeSecondsKey
== type
) && ((n
= OSDynamicCast(OSNumber
, obj
))))
1196 UInt32 rsecs
= n
->unsigned32BitValue();
1198 autoWakeStart
= autoWakeEnd
= 0;
1201 AbsoluteTime deadline
;
1202 clock_interval_to_deadline(rsecs
+ kAutoWakePostWindow
, kSecondScale
, &deadline
);
1203 autoWakeEnd
= AbsoluteTime_to_scalar(&deadline
);
1204 if (rsecs
> kAutoWakePreWindow
)
1205 rsecs
-= kAutoWakePreWindow
;
1208 clock_interval_to_deadline(rsecs
, kSecondScale
, &deadline
);
1209 autoWakeStart
= AbsoluteTime_to_scalar(&deadline
);
1212 if (gIOPMSettingDebugWakeRelativeKey
== type
)
1214 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1215 _debugWakeSeconds
= n
->unsigned32BitValue();
1217 _debugWakeSeconds
= 0;
1220 return_value
= setPMSetting(type
, obj
);
1222 if(kIOReturnSuccess
!= return_value
) goto exit
;
1226 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1227 if(boot_complete_string
) boot_complete_string
->release();
1228 if(sys_shutdown_string
) sys_shutdown_string
->release();
1229 if(stall_halt_string
) stall_halt_string
->release();
1230 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1231 if(idle_seconds_string
) idle_seconds_string
->release();
1232 if(sleepdisabled_string
) sleepdisabled_string
->release();
1233 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1234 if(loginwindow_tracepoint_string
) loginwindow_tracepoint_string
->release();
1235 if(pmTimelineLogging_string
) pmTimelineLogging_string
->release();
1237 if(hibernatemode_string
) hibernatemode_string
->release();
1238 if(hibernatefile_string
) hibernatefile_string
->release();
1239 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1240 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1242 return return_value
;
1246 // MARK: Aggressiveness
1248 //******************************************************************************
1249 // setAggressiveness
1251 // Override IOService::setAggressiveness()
1252 //******************************************************************************
1254 IOReturn
IOPMrootDomain::setAggressiveness(
1256 unsigned long value
)
1258 return setAggressiveness( type
, value
, 0 );
1262 * Private setAggressiveness() with an internal options argument.
1264 IOReturn
IOPMrootDomain::setAggressiveness(
1266 unsigned long value
,
1267 IOOptionBits options
)
1269 AggressivesRequest
* entry
;
1270 AggressivesRequest
* request
;
1273 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1274 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1276 request
= IONew(AggressivesRequest
, 1);
1278 return kIOReturnNoMemory
;
1280 memset(request
, 0, sizeof(*request
));
1281 request
->options
= options
;
1282 request
->dataType
= kAggressivesRequestTypeRecord
;
1283 request
->data
.record
.type
= (uint32_t) type
;
1284 request
->data
.record
.value
= (uint32_t) value
;
1288 // Update disk quick spindown flag used by getAggressiveness().
1289 // Never merge requests with quick spindown flags set.
1291 if (options
& kAggressivesOptionQuickSpindownEnable
)
1292 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1293 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1294 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1297 // Coalesce requests with identical aggressives types.
1298 // Deal with callers that calls us too "aggressively".
1300 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1302 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1303 (entry
->data
.record
.type
== type
) &&
1304 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1306 entry
->data
.record
.value
= value
;
1315 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1318 AGGRESSIVES_UNLOCK();
1321 IODelete(request
, AggressivesRequest
, 1);
1323 if (options
& kAggressivesOptionSynchronous
)
1324 handleAggressivesRequests(); // not truly synchronous
1326 thread_call_enter(aggressivesThreadCall
);
1328 return kIOReturnSuccess
;
1331 //******************************************************************************
1332 // getAggressiveness
1334 // Override IOService::setAggressiveness()
1335 // Fetch the aggressiveness factor with the given type.
1336 //******************************************************************************
1338 IOReturn
IOPMrootDomain::getAggressiveness (
1340 unsigned long * outLevel
)
1346 return kIOReturnBadArgument
;
1350 // Disk quick spindown in effect, report value = 1
1352 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1353 (type
== kPMMinutesToSpinDown
))
1355 value
= kAggressivesMinValue
;
1359 // Consult the pending request queue.
1363 AggressivesRequest
* entry
;
1365 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1367 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1368 (entry
->data
.record
.type
== type
) &&
1369 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1371 value
= entry
->data
.record
.value
;
1378 // Consult the backend records.
1380 if (!source
&& aggressivesData
)
1382 AggressivesRecord
* record
;
1385 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1386 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1388 for (i
= 0; i
< count
; i
++, record
++)
1390 if (record
->type
== type
)
1392 value
= record
->value
;
1399 AGGRESSIVES_UNLOCK();
1403 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1404 source
, (uint32_t) type
, value
);
1405 *outLevel
= (unsigned long) value
;
1406 return kIOReturnSuccess
;
1410 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1411 *outLevel
= 0; // default return = 0, driver may not check for error
1412 return kIOReturnInvalid
;
1416 //******************************************************************************
1417 // joinAggressiveness
1419 // Request from IOService to join future aggressiveness broadcasts.
1420 //******************************************************************************
1422 IOReturn
IOPMrootDomain::joinAggressiveness(
1423 IOService
* service
)
1425 AggressivesRequest
* request
;
1427 if (!service
|| (service
== this))
1428 return kIOReturnBadArgument
;
1430 DLOG("joinAggressiveness %s %p\n", service
->getName(), service
);
1432 request
= IONew(AggressivesRequest
, 1);
1434 return kIOReturnNoMemory
;
1436 service
->retain(); // released by synchronizeAggressives()
1438 memset(request
, 0, sizeof(*request
));
1439 request
->dataType
= kAggressivesRequestTypeService
;
1440 request
->data
.service
= service
;
1443 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1444 AGGRESSIVES_UNLOCK();
1446 thread_call_enter(aggressivesThreadCall
);
1448 return kIOReturnSuccess
;
1451 //******************************************************************************
1452 // handleAggressivesRequests
1454 // Backend thread processes all incoming aggressiveness requests in the queue.
1455 //******************************************************************************
1458 handleAggressivesFunction(
1459 thread_call_param_t param1
,
1460 thread_call_param_t param2
)
1464 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1468 void IOPMrootDomain::handleAggressivesRequests( void )
1470 AggressivesRecord
* start
;
1471 AggressivesRecord
* record
;
1472 AggressivesRequest
* request
;
1473 queue_head_t joinedQueue
;
1477 bool pingSelf
= false;
1481 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1482 queue_empty(&aggressivesQueue
))
1485 gAggressivesState
|= kAggressivesStateBusy
;
1486 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1487 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1492 queue_init(&joinedQueue
);
1496 // Remove request from the incoming queue in FIFO order.
1497 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1498 switch (request
->dataType
)
1500 case kAggressivesRequestTypeRecord
:
1501 // Update existing record if found.
1503 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1505 if (record
->type
== request
->data
.record
.type
)
1509 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1511 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1514 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1515 kAggressivesRecordFlagModified
);
1516 DLOG("disk spindown accelerated, was %u min\n",
1520 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1522 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1525 record
->flags
|= kAggressivesRecordFlagModified
;
1526 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1527 DLOG("disk spindown restored to %u min\n",
1531 else if (record
->value
!= request
->data
.record
.value
)
1533 record
->value
= request
->data
.record
.value
;
1534 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1537 record
->flags
|= kAggressivesRecordFlagModified
;
1544 // No matching record, append a new record.
1546 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1548 AggressivesRecord newRecord
;
1550 newRecord
.flags
= kAggressivesRecordFlagModified
;
1551 newRecord
.type
= request
->data
.record
.type
;
1552 newRecord
.value
= request
->data
.record
.value
;
1553 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1555 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1556 DLOG("disk spindown accelerated\n");
1559 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1561 // OSData may have switched to another (larger) buffer.
1562 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1563 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1567 // Finished processing the request, release it.
1568 IODelete(request
, AggressivesRequest
, 1);
1571 case kAggressivesRequestTypeService
:
1572 // synchronizeAggressives() will free request.
1573 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1577 panic("bad aggressives request type %x\n", request
->dataType
);
1580 } while (!queue_empty(&aggressivesQueue
));
1582 // Release the lock to perform work, with busy flag set.
1583 if (!queue_empty(&joinedQueue
) || broadcast
)
1585 AGGRESSIVES_UNLOCK();
1586 if (!queue_empty(&joinedQueue
))
1587 synchronizeAggressives(&joinedQueue
, start
, count
);
1589 broadcastAggressives(start
, count
);
1593 // Remove the modified flag from all records.
1594 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1596 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1597 ((record
->type
== kPMMinutesToDim
) ||
1598 (record
->type
== kPMMinutesToSleep
)))
1601 record
->flags
&= ~kAggressivesRecordFlagModified
;
1604 // Check the incoming queue again since new entries may have been
1605 // added while lock was released above.
1607 } while (!queue_empty(&aggressivesQueue
));
1609 gAggressivesState
&= ~kAggressivesStateBusy
;
1612 AGGRESSIVES_UNLOCK();
1614 // Root domain is interested in system and display sleep slider changes.
1615 // Submit a power event to handle those changes on the PM work loop.
1617 if (pingSelf
&& pmPowerStateQueue
) {
1618 pmPowerStateQueue
->submitPowerEvent(
1619 kPowerEventPolicyStimulus
,
1620 (void *) kStimulusAggressivenessChanged
);
1624 //******************************************************************************
1625 // synchronizeAggressives
1627 // Push all known aggressiveness records to one or more IOService.
1628 //******************************************************************************
1630 void IOPMrootDomain::synchronizeAggressives(
1631 queue_head_t
* joinedQueue
,
1632 const AggressivesRecord
* array
,
1635 IOService
* service
;
1636 AggressivesRequest
* request
;
1637 const AggressivesRecord
* record
;
1638 IOPMDriverCallEntry callEntry
;
1642 while (!queue_empty(joinedQueue
))
1644 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1645 if (request
->dataType
== kAggressivesRequestTypeService
)
1646 service
= request
->data
.service
;
1650 IODelete(request
, AggressivesRequest
, 1);
1655 if (service
->assertPMDriverCall(&callEntry
))
1657 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1659 value
= record
->value
;
1660 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1661 value
= kAggressivesMinValue
;
1663 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1664 record
->type
, value
, service
->getName());
1665 service
->setAggressiveness(record
->type
, value
);
1667 service
->deassertPMDriverCall(&callEntry
);
1669 service
->release(); // retained by joinAggressiveness()
1674 //******************************************************************************
1675 // broadcastAggressives
1677 // Traverse PM tree and call setAggressiveness() for records that have changed.
1678 //******************************************************************************
1680 void IOPMrootDomain::broadcastAggressives(
1681 const AggressivesRecord
* array
,
1684 IORegistryIterator
* iter
;
1685 IORegistryEntry
* entry
;
1686 IOPowerConnection
* connect
;
1687 IOService
* service
;
1688 const AggressivesRecord
* record
;
1689 IOPMDriverCallEntry callEntry
;
1693 iter
= IORegistryIterator::iterateOver(
1694 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1700 while ((entry
= iter
->getNextObject()))
1702 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1703 if (!connect
|| !connect
->getReadyFlag())
1706 if ((service
= (IOService
*) connect
->copyChildEntry(gIOPowerPlane
)))
1708 if (service
->assertPMDriverCall(&callEntry
))
1710 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1712 if (record
->flags
& kAggressivesRecordFlagModified
)
1714 value
= record
->value
;
1715 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1716 value
= kAggressivesMinValue
;
1717 _LOG("broadcastAggressives %x = %u to %s\n",
1718 record
->type
, value
, service
->getName());
1719 service
->setAggressiveness(record
->type
, value
);
1722 service
->deassertPMDriverCall(&callEntry
);
1728 while (!entry
&& !iter
->isValid());
1734 // MARK: System Sleep
1736 //******************************************************************************
1737 // startIdleSleepTimer
1739 //******************************************************************************
1741 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1743 AbsoluteTime deadline
;
1748 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1749 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1750 idleSleepTimerPending
= true;
1751 DLOG("idle timer set for %u seconds\n", inSeconds
);
1755 //******************************************************************************
1756 // cancelIdleSleepTimer
1758 //******************************************************************************
1760 void IOPMrootDomain::cancelIdleSleepTimer( void )
1763 if (idleSleepTimerPending
)
1765 DLOG("idle timer cancelled\n");
1766 thread_call_cancel(extraSleepTimer
);
1767 idleSleepTimerPending
= false;
1771 //******************************************************************************
1772 // idleSleepTimerExpired
1774 //******************************************************************************
1776 static void idleSleepTimerExpired(
1777 thread_call_param_t us
, thread_call_param_t
)
1779 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
1782 //******************************************************************************
1783 // handleSleepTimerExpiration
1785 // The time between the sleep idle timeout and the next longest one has elapsed.
1786 // It's time to sleep. Start that by removing the clamp that's holding us awake.
1787 //******************************************************************************
1789 void IOPMrootDomain::handleSleepTimerExpiration( void )
1791 if (!getPMworkloop()->inGate())
1793 getPMworkloop()->runAction(
1794 OSMemberFunctionCast(IOWorkLoop::Action
, this,
1795 &IOPMrootDomain::handleSleepTimerExpiration
),
1802 DLOG("sleep timer expired\n");
1805 idleSleepTimerPending
= false;
1807 clock_get_uptime(&time
);
1808 if ((AbsoluteTime_to_scalar(&time
) > autoWakeStart
) &&
1809 (AbsoluteTime_to_scalar(&time
) < autoWakeEnd
))
1811 thread_call_enter_delayed(extraSleepTimer
, *((AbsoluteTime
*) &autoWakeEnd
));
1815 setQuickSpinDownTimeout();
1816 adjustPowerState(true);
1819 //******************************************************************************
1820 // setQuickSpinDownTimeout
1822 //******************************************************************************
1824 void IOPMrootDomain::setQuickSpinDownTimeout( void )
1828 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
1831 //******************************************************************************
1832 // restoreUserSpinDownTimeout
1834 //******************************************************************************
1836 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
1840 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
1843 //******************************************************************************
1846 //******************************************************************************
1849 IOReturn
IOPMrootDomain::sleepSystem( void )
1851 return sleepSystemOptions(NULL
);
1855 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
1857 /* sleepSystem is a public function, and may be called by any kernel driver.
1858 * And that's bad - drivers should sleep the system by calling
1859 * receivePowerNotification() instead. Drivers should not use sleepSystem.
1861 * Note that user space app calls to IOPMSleepSystem() will also travel
1862 * this code path and thus be correctly identified as software sleeps.
1865 if (options
&& options
->getObject("OSSwitch"))
1867 // Log specific sleep cause for OS Switch hibernation
1868 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
1870 return privateSleepSystem( kIOPMSleepReasonSoftware
);
1875 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
1877 static const char * IOPMSleepReasons
[] = {
1879 kIOPMClamshellSleepKey
,
1880 kIOPMPowerButtonSleepKey
,
1881 kIOPMSoftwareSleepKey
,
1882 kIOPMOSSwitchHibernationKey
,
1884 kIOPMLowPowerSleepKey
,
1885 kIOPMClamshellSleepKey
,
1886 kIOPMThermalEmergencySleepKey
,
1887 kIOPMMaintenanceSleepKey
1890 PMEventDetails
*details
;
1892 if (!checkSystemCanSleep())
1894 // Record why the system couldn't sleep
1895 details
= PMEventDetails::eventDetails(kIOPMEventTypeSleep
, NULL
,
1896 sleepReason
, kIOReturnNotPermitted
);
1898 recordAndReleasePMEvent( details
);
1899 return kIOReturnNotPermitted
;
1903 timeline
->setSleepCycleInProgressFlag(true);
1905 // Time to publish a UUID for the Sleep --> Wake cycle
1906 if(pmPowerStateQueue
) {
1907 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishSleepWakeUUID
, (void *)true);
1911 // Log the beginning of system sleep.
1912 details
= PMEventDetails::eventDetails(kIOPMEventTypeSleep
, NULL
,
1913 sleepReason
, kIOReturnSuccess
);
1915 recordAndReleasePMEvent( details
);
1917 // Record sleep cause in IORegistry
1918 lastSleepReason
= sleepReason
;
1919 sleepReason
-= (kIOPMSleepReasonClamshell
- 1);
1920 if (sleepReason
&& (sleepReason
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0]))) {
1921 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[sleepReason
]);
1924 if (pmPowerStateQueue
)
1925 pmPowerStateQueue
->submitPowerEvent(
1926 kPowerEventPolicyStimulus
,
1927 (void *) kStimulusDemandSystemSleep
);
1929 return kIOReturnSuccess
;
1932 IOReturn
IOPMrootDomain::recordPMEventGated(PMEventDetails
*record
)
1934 // If we don't have a place to log to, we can't actually
1935 // log anything. Chances are, the person who is asking us to do
1936 // the PM logging has forgotten to set the right bootflags
1938 return kIOReturnSuccess
;
1940 if(gIOPMWorkLoop
->inGate() == false) {
1942 IOReturn ret
= gIOPMWorkLoop
->runAction(
1943 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::recordPMEventGated
),
1950 // Now that we're guaranteed to be running in gate ...
1952 // Check the validity of the argument we are given
1954 return kIOReturnBadArgument
;
1956 // Record a driver event, or a system event
1957 if(record
->eventClassifier
== kIOPMEventClassDriverEvent
1958 || record
->eventClassifier
== kIOPMEventClassSystemEvent
)
1959 return this->recordPMEvent(record
);
1962 return kIOReturnBadArgument
;
1966 IOReturn
IOPMrootDomain::recordAndReleasePMEventGated(PMEventDetails
*record
)
1968 IOReturn ret
= kIOReturnBadArgument
;
1972 ret
= recordPMEventGated(record
);
1979 //******************************************************************************
1982 // This overrides powerChangeDone in IOService.
1983 //******************************************************************************
1985 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
1987 PMEventDetails
*details
;
1990 DLOG("PowerChangeDone: %u->%u\n",
1991 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
1993 switch ( getPowerState() )
1996 if (previousPowerState
!= ON_STATE
)
1999 details
= PMEventDetails::eventDetails(
2000 kIOPMEventTypeSleepDone
,
2005 recordAndReleasePMEvent( details
);
2007 // re-enable this timer for next sleep
2008 cancelIdleSleepTimer();
2011 clock_usec_t microsecs
;
2012 clock_get_calendar_microtime(&secs
, µsecs
);
2014 gIOLastSleepTime
.tv_sec
= secs
;
2015 gIOLastSleepTime
.tv_usec
= microsecs
;
2016 gIOLastWakeTime
.tv_sec
= 0;
2017 gIOLastWakeTime
.tv_usec
= 0;
2020 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2022 IOHibernateSystemHasSlept();
2024 evaluateSystemSleepPolicyFinal();
2026 LOG("System Sleep\n");
2029 getPlatform()->sleepKernel();
2031 // The CPU(s) are off at this point,
2032 // Code will resume execution here upon wake.
2034 clock_get_uptime(&systemWakeTime
);
2037 IOHibernateSystemWake();
2040 // sleep transition complete
2041 gSleepOrShutdownPending
= 0;
2043 // trip the reset of the calendar clock
2044 clock_wakeup_calendar();
2047 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2051 getPlatform()->PMLog(kIOPMrootDomainClass
, kPMLogSystemWake
, 0, 0);
2052 lowBatteryCondition
= false;
2053 lastSleepReason
= 0;
2055 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2056 _debugWakeSeconds
= 0;
2058 // And start logging the wake event here
2059 // TODO: Publish the wakeReason string as an integer
2060 details
= PMEventDetails::eventDetails(
2066 recordAndReleasePMEvent( details
);
2072 #if defined(__i386__) || defined(__x86_64__)
2073 wranglerTickled
= false;
2074 graphicsSuppressed
= false;
2075 darkWakePostTickle
= false;
2076 logGraphicsClamp
= true;
2077 logWranglerTickle
= true;
2078 sleepTimerMaintenance
= false;
2079 wranglerTickleLatched
= false;
2081 OSString
* wakeType
= OSDynamicCast(
2082 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2083 OSString
* wakeReason
= OSDynamicCast(
2084 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2086 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2088 lowBatteryCondition
= true;
2089 darkWakeMaintenance
= true;
2090 darkWakeToSleepASAP
= true;
2092 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2094 OSNumber
* hibOptions
= OSDynamicCast(
2095 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2097 if (hibernateAborted
|| ((hibOptions
&&
2098 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2100 // Hibernate aborted, or EFI brought up graphics
2101 wranglerTickled
= true;
2105 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2106 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2108 // User wake or RTC alarm
2109 wranglerTickled
= true;
2113 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2115 // SMC standby timer trumps SleepX
2116 darkWakeMaintenance
= true;
2117 darkWakeToSleepASAP
= true;
2118 sleepTimerMaintenance
= true;
2121 if ((_lastDebugWakeSeconds
!= 0) &&
2122 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2124 // SleepX before maintenance
2125 wranglerTickled
= true;
2129 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2131 darkWakeMaintenance
= true;
2132 darkWakeToSleepASAP
= true;
2136 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2138 darkWakeToSleepASAP
= true;
2139 // darkWakeMaintenance = true; // ????
2140 darkWakeSleepService
= true;
2144 // Unidentified wake source, resume to full wake if debug
2145 // alarm is pending.
2147 if (_lastDebugWakeSeconds
&&
2148 (!wakeReason
|| wakeReason
->isEqualTo("")))
2149 wranglerTickled
= true;
2151 darkWakeToSleepASAP
= true;
2157 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2159 darkWakeMaintenance
= true;
2160 darkWakeToSleepASAP
= true;
2161 sleepTimerMaintenance
= true;
2163 else if (hibernateAborted
|| !wakeType
||
2164 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2165 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2167 // Post a HID tickle immediately - except for RTC maintenance wake.
2168 wranglerTickled
= true;
2172 darkWakeMaintenance
= true;
2173 darkWakeToSleepASAP
= true;
2177 if (wranglerTickled
)
2179 else if (!darkWakeMaintenance
)
2181 // Early/late tickle for non-maintenance wake.
2182 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2183 kDarkWakeFlagHIDTickleEarly
) ||
2184 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2185 kDarkWakeFlagHIDTickleLate
))
2187 darkWakePostTickle
= true;
2190 #else /* !__i386__ && !__x86_64__ */
2191 // stay awake for at least 30 seconds
2192 wranglerTickled
= true;
2193 startIdleSleepTimer(30);
2196 changePowerStateToPriv(ON_STATE
);
2200 bool wasPrevented
= childPreventSystemSleep
;
2202 details
= PMEventDetails::eventDetails(
2203 kIOPMEventTypeWakeDone
,
2208 recordAndReleasePMEvent( details
);
2210 // Update childPreventSystemSleep flag using the capability computed
2211 // by IOSevice::rebuildChildClampBits().
2213 childPreventSystemSleep
=
2214 ((currentCapability() & kIOPMChildClamp2
) != 0);
2216 if (wasPrevented
&& !childPreventSystemSleep
)
2218 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2224 //******************************************************************************
2225 // requestPowerDomainState
2227 // Extend implementation in IOService. Running on PM work loop thread.
2229 // Examine children desires and initiate idle-sleep if all children are idle,
2230 // prevent idle and system sleep flags are not set.
2231 //******************************************************************************
2233 IOReturn
IOPMrootDomain::requestPowerDomainState (
2234 IOPMPowerFlags childDesire
,
2235 IOPowerConnection
* childConnection
,
2236 unsigned long specification
)
2240 IOPowerConnection
*connection
;
2241 IOPMPowerFlags mergedChildDesire
= 0;
2242 IOPMPowerFlags editedChildDesire
;
2243 IOPMPowerFlags thisDesire
;
2244 bool sleepASAP
= false;
2248 // Disregard disk I/O (anything besides the display wrangler) as a
2249 // factor in preventing idle sleep - based on a runtime setting.
2251 if ((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOAlways
) &&
2252 (kIOPMPreventIdleSleep
& childDesire
) &&
2253 (childConnection
!= wranglerConnection
))
2255 childDesire
&= ~kIOPMPreventIdleSleep
;
2258 // Force the child's input power requirement to 0 unless the prevent
2259 // idle-sleep flag is set. Nil input power flags maps to our state 0.
2260 // Our power clamp (deviceDesire) clamps the lowest power state at 2.
2262 editedChildDesire
= 0;
2263 if (childDesire
& kIOPMPreventIdleSleep
)
2264 editedChildDesire
|= (kIOPMPowerOn
| kIOPMPreventIdleSleep
);
2265 if (childDesire
& kIOPMPreventSystemSleep
)
2266 editedChildDesire
|= (kIOPMPowerOn
| kIOPMPreventSystemSleep
);
2268 iter
= getChildIterator(gIOPowerPlane
);
2271 while ( (next
= iter
->getNextObject()) )
2273 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
2275 // Ignore child that are in the process of joining.
2276 if (connection
->getReadyFlag() == false)
2279 // OR in the child's input power requirements.
2280 // Is this connection attached to the child that called
2281 // requestPowerDomainState()?
2283 if (connection
== childConnection
)
2285 thisDesire
= editedChildDesire
;
2290 if (connection
->getPreventIdleSleepFlag())
2291 thisDesire
|= (kIOPMPowerOn
| kIOPMPreventIdleSleep
);
2292 if (connection
->getPreventSystemSleepFlag())
2293 thisDesire
|= (kIOPMPowerOn
| kIOPMPreventSystemSleep
);
2296 mergedChildDesire
|= thisDesire
;
2297 if (thisDesire
&& (kIOLogPMRootDomain
& gIOKitDebug
))
2300 (IOService
*) connection
->getChildEntry(gIOPowerPlane
);
2301 LOG("child %p, noIdle %d, noSleep %d - %s\n",
2303 ((thisDesire
& kIOPMPreventIdleSleep
) != 0),
2304 ((thisDesire
& kIOPMPreventSystemSleep
) != 0),
2305 child
? child
->getName() : "?");
2312 DLOG("mergedChildDesire 0x%lx, extraSleepDelay %ld\n",
2313 mergedChildDesire
, extraSleepDelay
);
2315 if ( !mergedChildDesire
&& !systemBooting
)
2319 changePowerStateToPriv(ON_STATE
);
2322 // stay awake for at least idleSeconds
2323 startIdleSleepTimer(idleSeconds
);
2326 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
2332 // Drop our power clamp to SLEEP_STATE when all children became idle,
2333 // and system sleep and display sleep slider values are equal.
2335 adjustPowerState(sleepASAP
);
2337 // If our power clamp has already dropped to SLEEP_STATE, and no child
2338 // is keeping us at ON_STATE, then the following will trigger idle sleep.
2340 return super::requestPowerDomainState(
2341 editedChildDesire
, childConnection
, specification
);
2344 //******************************************************************************
2347 // Override the superclass implementation to send a different message type.
2348 //******************************************************************************
2350 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2352 DLOG("tellChangeDown %u->%u\n",
2353 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2355 if (SLEEP_STATE
== stateNum
)
2357 if (!ignoreTellChangeDown
)
2358 tracePoint( kIOPMTracePointSleepApplications
);
2360 tracePoint( kIOPMTracePointSleepPriorityClients
);
2363 if ((SLEEP_STATE
== stateNum
) && !ignoreTellChangeDown
)
2365 userActivityAtSleep
= userActivityCount
;
2366 hibernateAborted
= false;
2367 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2369 // Direct callout into OSKext so it can disable kext unloads
2370 // during sleep/wake to prevent deadlocks.
2371 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2373 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2375 // Notify platform that sleep has begun
2376 getPlatform()->callPlatformFunction(
2377 sleepMessagePEFunction
, false,
2378 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
2381 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2382 // But tellClientsWithResponse() must be called for both.
2383 ignoreTellChangeDown
= true;
2386 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2389 //******************************************************************************
2392 // Override the superclass implementation to send a different message type.
2393 // This must be idle sleep since we don't ask during any other power change.
2394 //******************************************************************************
2396 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2398 DLOG("askChangeDown %u->%u\n",
2399 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2401 // Don't log for dark wake entry
2402 if (kSystemTransitionSleep
== _systemTransitionType
)
2403 tracePoint( kIOPMTracePointSleepApplications
);
2405 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2408 //******************************************************************************
2409 // askChangeDownDone
2411 // Called by PM after all apps have responded to kIOMessageCanSystemSleep.
2412 // pmconfigd may create a deny sleep assertion before ack'ing.
2413 //******************************************************************************
2415 void IOPMrootDomain::askChangeDownDone(
2416 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2418 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2419 *inOutChangeFlags
, *cancel
,
2420 _systemTransitionType
,
2421 _currentCapability
, _pendingCapability
);
2423 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2425 // Dark->Sleep transition.
2426 // Check if there are any deny sleep assertions.
2427 // Full->Dark transition is never cancelled.
2429 if (!checkSystemCanSleep(true))
2431 // Cancel dark wake to sleep transition.
2432 // Must re-scan assertions upon entering dark wake.
2435 DLOG("cancel dark->sleep\n");
2440 //******************************************************************************
2443 // Notify registered applications and kernel clients that we are not dropping
2446 // We override the superclass implementation so we can send a different message
2447 // type to the client or application being notified.
2449 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2450 //******************************************************************************
2452 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2454 DLOG("tellNoChangeDown %u->%u\n",
2455 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2457 if (idleSeconds
&& !wrangler
)
2459 // stay awake for at least idleSeconds
2460 startIdleSleepTimer(idleSeconds
);
2462 return tellClients( kIOMessageSystemWillNotSleep
);
2465 //******************************************************************************
2468 // Notify registered applications and kernel clients that we are raising power.
2470 // We override the superclass implementation so we can send a different message
2471 // type to the client or application being notified.
2472 //******************************************************************************
2474 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2476 OSData
*publishPMStats
= NULL
;
2478 DLOG("tellChangeUp %u->%u\n",
2479 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2481 ignoreTellChangeDown
= false;
2483 if ( stateNum
== ON_STATE
)
2485 // Direct callout into OSKext so it can disable kext unloads
2486 // during sleep/wake to prevent deadlocks.
2487 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2489 // Notify platform that sleep was cancelled or resumed.
2490 getPlatform()->callPlatformFunction(
2491 sleepMessagePEFunction
, false,
2492 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2495 if (getPowerState() == ON_STATE
)
2497 // this is a quick wake from aborted sleep
2498 if (idleSeconds
&& !wrangler
)
2500 // stay awake for at least idleSeconds
2501 startIdleSleepTimer(idleSeconds
);
2503 tellClients( kIOMessageSystemWillPowerOn
);
2506 tracePoint( kIOPMTracePointWakeApplications
);
2507 publishPMStats
= OSData::withBytes(&pmStats
, sizeof(pmStats
));
2508 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
2509 publishPMStats
->release();
2510 bzero(&pmStats
, sizeof(pmStats
));
2512 if (pmStatsAppResponses
)
2514 setProperty(kIOPMSleepStatisticsAppsKey
, pmStatsAppResponses
);
2515 pmStatsAppResponses
->release();
2516 pmStatsAppResponses
= OSArray::withCapacity(5);
2519 tellClients( kIOMessageSystemHasPoweredOn
);
2523 //******************************************************************************
2524 // sysPowerDownHandler
2526 // Perform a vfs sync before system sleep.
2527 //******************************************************************************
2529 IOReturn
IOPMrootDomain::sysPowerDownHandler(
2530 void * target
, void * refCon
,
2531 UInt32 messageType
, IOService
* service
,
2532 void * messageArgs
, vm_size_t argSize
)
2536 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
2539 return kIOReturnUnsupported
;
2541 if (messageType
== kIOMessageSystemCapabilityChange
)
2543 IOPMSystemCapabilityChangeParameters
* params
=
2544 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
2546 // Interested applications have been notified of an impending power
2547 // change and have acked (when applicable).
2548 // This is our chance to save whatever state we can before powering
2550 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2553 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2554 params
->fromCapabilities
, params
->toCapabilities
,
2555 params
->changeFlags
);
2557 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
2558 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
2559 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2561 // We will ack within 20 seconds
2562 params
->maxWaitForReply
= 20 * 1000 * 1000;
2564 gRootDomain
->evaluateSystemSleepPolicyEarly();
2566 // add in time we could spend freeing pages
2567 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
2569 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
2571 DLOG("sysPowerDownHandler timeout %d s\n", (int) (params
->maxWaitForReply
/ 1000 / 1000));
2574 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2576 // Purposely delay the ack and hope that shutdown occurs quickly.
2577 // Another option is not to schedule the thread and wait for
2579 AbsoluteTime deadline
;
2580 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2581 thread_call_enter1_delayed(
2582 gRootDomain
->diskSyncCalloutEntry
,
2583 (thread_call_param_t
) params
->notifyRef
,
2588 gRootDomain
->diskSyncCalloutEntry
,
2589 (thread_call_param_t
) params
->notifyRef
);
2593 if ((params
->changeFlags
& kIOPMSystemCapabilityDidChange
) &&
2594 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) &&
2595 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2597 // We will ack within 110 seconds
2598 params
->maxWaitForReply
= 110 * 1000 * 1000;
2601 gRootDomain
->diskSyncCalloutEntry
,
2602 (thread_call_param_t
) params
->notifyRef
);
2605 ret
= kIOReturnSuccess
;
2611 //******************************************************************************
2612 // handleQueueSleepWakeUUID
2614 // Called from IOPMrootDomain when we're initiating a sleep,
2615 // or indirectly from PM configd when PM decides to clear the UUID.
2616 // PM clears the UUID several minutes after successful wake from sleep,
2617 // so that we might associate App spindumps with the immediately previous
2620 // @param obj has a retain on it. We're responsible for releasing that retain.
2621 //******************************************************************************
2623 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
2625 OSString
*str
= NULL
;
2627 if (kOSBooleanFalse
== obj
)
2629 handlePublishSleepWakeUUID(NULL
);
2631 else if ((str
= OSDynamicCast(OSString
, obj
)))
2633 // This branch caches the UUID for an upcoming sleep/wake
2634 if (queuedSleepWakeUUIDString
) {
2635 queuedSleepWakeUUIDString
->release();
2636 queuedSleepWakeUUIDString
= NULL
;
2638 queuedSleepWakeUUIDString
= str
;
2639 queuedSleepWakeUUIDString
->retain();
2641 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
2650 //******************************************************************************
2651 // handlePublishSleepWakeUUID
2653 // Called from IOPMrootDomain when we're initiating a sleep,
2654 // or indirectly from PM configd when PM decides to clear the UUID.
2655 // PM clears the UUID several minutes after successful wake from sleep,
2656 // so that we might associate App spindumps with the immediately previous
2658 //******************************************************************************
2660 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
2665 * Clear the current UUID
2667 if (gSleepWakeUUIDIsSet
)
2669 DLOG("SleepWake UUID cleared\n");
2671 OSString
*UUIDstring
= NULL
;
2674 (UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))))
2676 PMEventDetails
*details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDClear
,
2677 UUIDstring
->getCStringNoCopy(), NULL
, 0);
2679 timeline
->recordSystemPowerEvent( details
);
2682 timeline
->setNumEventsLoggedThisPeriod(0);
2685 gSleepWakeUUIDIsSet
= false;
2687 removeProperty(kIOPMSleepWakeUUIDKey
);
2688 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
2692 * Optionally, publish a new UUID
2694 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
2696 OSString
*publishThisUUID
= NULL
;
2698 publishThisUUID
= queuedSleepWakeUUIDString
;
2699 publishThisUUID
->retain();
2702 PMEventDetails
*details
;
2703 details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDSet
,
2704 publishThisUUID
->getCStringNoCopy(), NULL
, 0);
2706 timeline
->recordSystemPowerEvent( details
);
2711 if (publishThisUUID
)
2713 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
2714 publishThisUUID
->release();
2717 gSleepWakeUUIDIsSet
= true;
2718 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
2720 queuedSleepWakeUUIDString
->release();
2721 queuedSleepWakeUUIDString
= NULL
;
2725 //******************************************************************************
2726 // changePowerStateTo & changePowerStateToPriv
2728 // Override of these methods for logging purposes.
2729 //******************************************************************************
2731 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
2733 return kIOReturnUnsupported
; // ignored
2736 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
2738 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
2740 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
2741 return kIOReturnUnsupported
;
2743 return super::changePowerStateToPriv(ordinal
);
2746 //******************************************************************************
2749 //******************************************************************************
2751 bool IOPMrootDomain::activitySinceSleep(void)
2753 return (userActivityCount
!= userActivityAtSleep
);
2756 bool IOPMrootDomain::abortHibernation(void)
2758 bool ret
= activitySinceSleep();
2760 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
2762 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
2763 hibernateAborted
= true;
2769 hibernate_should_abort(void)
2772 return (gRootDomain
->abortHibernation());
2777 //******************************************************************************
2778 // sleepOnClamshellClosed
2780 // contains the logic to determine if the system should sleep when the clamshell
2782 //******************************************************************************
2784 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
2786 if (!clamshellExists
)
2789 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d\n",
2790 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
);
2792 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) );
2795 void IOPMrootDomain::sendClientClamshellNotification( void )
2797 /* Only broadcast clamshell alert if clamshell exists. */
2798 if (!clamshellExists
)
2801 setProperty(kAppleClamshellStateKey
,
2802 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
2804 setProperty(kAppleClamshellCausesSleepKey
,
2805 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
2807 /* Argument to message is a bitfiel of
2808 * ( kClamshellStateBit | kClamshellSleepBit )
2810 messageClients(kIOPMMessageClamshellStateChange
,
2811 (void *) ( (clamshellClosed
? kClamshellStateBit
: 0)
2812 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
2815 //******************************************************************************
2816 // getSleepSupported
2819 //******************************************************************************
2821 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
2823 return( platformSleepSupport
);
2826 //******************************************************************************
2827 // setSleepSupported
2830 //******************************************************************************
2832 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
2834 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
2835 OSBitOrAtomic(flags
, &platformSleepSupport
);
2838 //******************************************************************************
2842 //******************************************************************************
2844 void IOPMrootDomain::wakeFromDoze( void )
2846 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
2852 //******************************************************************************
2855 // Adds a new feature to the supported features dictionary
2856 //******************************************************************************
2858 void IOPMrootDomain::publishFeature( const char * feature
)
2860 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
2863 //******************************************************************************
2864 // publishFeature (with supported power source specified)
2866 // Adds a new feature to the supported features dictionary
2867 //******************************************************************************
2869 void IOPMrootDomain::publishFeature(
2870 const char *feature
,
2871 uint32_t supportedWhere
,
2872 uint32_t *uniqueFeatureID
)
2874 static uint16_t next_feature_id
= 500;
2876 OSNumber
*new_feature_data
= NULL
;
2877 OSNumber
*existing_feature
= NULL
;
2878 OSArray
*existing_feature_arr
= NULL
;
2879 OSObject
*osObj
= NULL
;
2880 uint32_t feature_value
= 0;
2882 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
2884 if(!supportedWhere
) {
2885 // Feature isn't supported anywhere!
2889 if(next_feature_id
> 5000) {
2890 // Far, far too many features!
2894 if(featuresDictLock
) IOLockLock(featuresDictLock
);
2896 OSDictionary
*features
=
2897 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
2899 // Create new features dict if necessary
2900 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
2901 features
= OSDictionary::withDictionary(features
);
2903 features
= OSDictionary::withCapacity(1);
2906 // Create OSNumber to track new feature
2908 next_feature_id
+= 1;
2909 if( uniqueFeatureID
) {
2910 // We don't really mind if the calling kext didn't give us a place
2911 // to stash their unique id. Many kexts don't plan to unload, and thus
2912 // have no need to remove themselves later.
2913 *uniqueFeatureID
= next_feature_id
;
2916 feature_value
= (uint32_t)next_feature_id
;
2917 feature_value
<<= 16;
2918 feature_value
+= supportedWhere
;
2920 new_feature_data
= OSNumber::withNumber(
2921 (unsigned long long)feature_value
, 32);
2923 // Does features object already exist?
2924 if( (osObj
= features
->getObject(feature
)) )
2926 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
2928 // We need to create an OSArray to hold the now 2 elements.
2929 existing_feature_arr
= OSArray::withObjects(
2930 (const OSObject
**)&existing_feature
, 1, 2);
2931 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
2933 // Add object to existing array
2934 existing_feature_arr
= OSArray::withArray(
2935 existing_feature_arr
,
2936 existing_feature_arr
->getCount() + 1);
2939 if (existing_feature_arr
)
2941 existing_feature_arr
->setObject(new_feature_data
);
2942 features
->setObject(feature
, existing_feature_arr
);
2943 existing_feature_arr
->release();
2944 existing_feature_arr
= 0;
2947 // The easy case: no previously existing features listed. We simply
2948 // set the OSNumber at key 'feature' and we're on our way.
2949 features
->setObject(feature
, new_feature_data
);
2952 new_feature_data
->release();
2954 setProperty(kRootDomainSupportedFeatures
, features
);
2956 features
->release();
2958 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
2960 // Notify EnergySaver and all those in user space so they might
2961 // re-populate their feature specific UI
2962 if(pmPowerStateQueue
) {
2963 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
2967 //******************************************************************************
2968 // removePublishedFeature
2970 // Removes previously published feature
2971 //******************************************************************************
2973 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
2975 IOReturn ret
= kIOReturnError
;
2976 uint32_t feature_value
= 0;
2977 uint16_t feature_id
= 0;
2978 bool madeAChange
= false;
2980 OSSymbol
*dictKey
= NULL
;
2981 OSCollectionIterator
*dictIterator
= NULL
;
2982 OSArray
*arrayMember
= NULL
;
2983 OSNumber
*numberMember
= NULL
;
2984 OSObject
*osObj
= NULL
;
2985 OSNumber
*osNum
= NULL
;
2986 OSArray
*arrayMemberCopy
;
2988 if (kBadPMFeatureID
== removeFeatureID
)
2989 return kIOReturnNotFound
;
2991 if(featuresDictLock
) IOLockLock(featuresDictLock
);
2993 OSDictionary
*features
=
2994 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
2996 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
2998 // Any modifications to the dictionary are made to the copy to prevent
2999 // races & crashes with userland clients. Dictionary updated
3000 // automically later.
3001 features
= OSDictionary::withDictionary(features
);
3004 ret
= kIOReturnNotFound
;
3008 // We iterate 'features' dictionary looking for an entry tagged
3009 // with 'removeFeatureID'. If found, we remove it from our tracking
3010 // structures and notify the OS via a general interest message.
3012 dictIterator
= OSCollectionIterator::withCollection(features
);
3017 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3019 osObj
= features
->getObject(dictKey
);
3021 // Each Feature is either tracked by an OSNumber
3022 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3024 feature_value
= numberMember
->unsigned32BitValue();
3025 feature_id
= (uint16_t)(feature_value
>> 16);
3027 if( feature_id
== (uint16_t)removeFeatureID
)
3030 features
->removeObject(dictKey
);
3035 // Or tracked by an OSArray of OSNumbers
3036 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3038 unsigned int arrayCount
= arrayMember
->getCount();
3040 for(unsigned int i
=0; i
<arrayCount
; i
++)
3042 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3047 feature_value
= osNum
->unsigned32BitValue();
3048 feature_id
= (uint16_t)(feature_value
>> 16);
3050 if( feature_id
== (uint16_t)removeFeatureID
)
3053 if( 1 == arrayCount
) {
3054 // If the array only contains one element, remove
3056 features
->removeObject(dictKey
);
3058 // Otherwise remove the element from a copy of the array.
3059 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3060 if (arrayMemberCopy
)
3062 arrayMemberCopy
->removeObject(i
);
3063 features
->setObject(dictKey
, arrayMemberCopy
);
3064 arrayMemberCopy
->release();
3075 dictIterator
->release();
3079 ret
= kIOReturnSuccess
;
3081 setProperty(kRootDomainSupportedFeatures
, features
);
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
);
3089 ret
= kIOReturnNotFound
;
3093 if(features
) features
->release();
3094 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3098 //******************************************************************************
3099 // publishPMSetting (private)
3101 // Should only be called by PMSettingObject to publish a PM Setting as a
3102 // supported feature.
3103 //******************************************************************************
3105 void IOPMrootDomain::publishPMSetting(
3106 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3108 if (noPublishPMSettings
&&
3109 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3111 // Setting found in noPublishPMSettings array
3112 *featureID
= kBadPMFeatureID
;
3117 feature
->getCStringNoCopy(), where
, featureID
);
3120 //******************************************************************************
3121 // setPMSetting (private)
3123 // Internal helper to relay PM settings changes from user space to individual
3124 // drivers. Should be called only by IOPMrootDomain::setProperties.
3125 //******************************************************************************
3127 IOReturn
IOPMrootDomain::setPMSetting(
3128 const OSSymbol
*type
,
3131 PMSettingCallEntry
*entries
= 0;
3132 OSArray
*chosen
= 0;
3133 const OSArray
*array
;
3134 PMSettingObject
*pmso
;
3135 thread_t thisThread
;
3136 int i
, j
, count
, capacity
;
3139 return kIOReturnBadArgument
;
3143 // Update settings dict so changes are visible from copyPMSetting().
3144 fPMSettingsDict
->setObject(type
, object
);
3146 // Prep all PMSetting objects with the given 'type' for callout.
3147 array
= (const OSArray
*) settingsCallbacks
->getObject(type
);
3148 if (!array
|| ((capacity
= array
->getCount()) == 0))
3151 // Array to retain PMSetting objects targeted for callout.
3152 chosen
= OSArray::withCapacity(capacity
);
3154 goto unlock_exit
; // error
3156 entries
= IONew(PMSettingCallEntry
, capacity
);
3158 goto unlock_exit
; // error
3159 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3161 thisThread
= current_thread();
3163 for (i
= 0, j
= 0; i
<capacity
; i
++)
3165 pmso
= (PMSettingObject
*) array
->getObject(i
);
3168 entries
[j
].thread
= thisThread
;
3169 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3170 chosen
->setObject(pmso
);
3179 // Call each pmso in the chosen array.
3180 for (i
=0; i
<count
; i
++)
3182 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3183 pmso
->dispatchPMSetting(type
, object
);
3187 for (i
=0; i
<count
; i
++)
3189 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3190 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3191 if (pmso
->waitThread
)
3193 PMSETTING_WAKEUP(pmso
);
3199 if (chosen
) chosen
->release();
3200 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3202 return kIOReturnSuccess
;
3205 //******************************************************************************
3206 // copyPMSetting (public)
3208 // Allows kexts to safely read setting values, without being subscribed to
3210 //******************************************************************************
3212 OSObject
* IOPMrootDomain::copyPMSetting(
3213 OSSymbol
*whichSetting
)
3215 OSObject
*obj
= NULL
;
3217 if(!whichSetting
) return NULL
;
3220 obj
= fPMSettingsDict
->getObject(whichSetting
);
3229 //******************************************************************************
3230 // registerPMSettingController (public)
3232 // direct wrapper to registerPMSettingController with uint32_t power source arg
3233 //******************************************************************************
3235 IOReturn
IOPMrootDomain::registerPMSettingController(
3236 const OSSymbol
* settings
[],
3237 IOPMSettingControllerCallback func
,
3242 return registerPMSettingController(
3244 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3245 func
, target
, refcon
, handle
);
3248 //******************************************************************************
3249 // registerPMSettingController (public)
3251 // Kexts may register for notifications when a particular setting is changed.
3252 // A list of settings is available in IOPM.h.
3254 // * settings - An OSArray containing OSSymbols. Caller should populate this
3255 // array with a list of settings caller wants notifications from.
3256 // * func - A C function callback of the type IOPMSettingControllerCallback
3257 // * target - caller may provide an OSObject *, which PM will pass as an
3258 // target to calls to "func"
3259 // * refcon - caller may provide an void *, which PM will pass as an
3260 // argument to calls to "func"
3261 // * handle - This is a return argument. We will populate this pointer upon
3262 // call success. Hold onto this and pass this argument to
3263 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3265 // kIOReturnSuccess on success
3266 //******************************************************************************
3268 IOReturn
IOPMrootDomain::registerPMSettingController(
3269 const OSSymbol
* settings
[],
3270 uint32_t supportedPowerSources
,
3271 IOPMSettingControllerCallback func
,
3276 PMSettingObject
*pmso
= NULL
;
3277 OSObject
*pmsh
= NULL
;
3278 OSArray
*list
= NULL
;
3281 if (NULL
== settings
||
3285 return kIOReturnBadArgument
;
3288 pmso
= PMSettingObject::pmSettingObject(
3289 (IOPMrootDomain
*) this, func
, target
,
3290 refcon
, supportedPowerSources
, settings
, &pmsh
);
3294 return kIOReturnInternalError
;
3298 for (i
=0; settings
[i
]; i
++)
3300 list
= (OSArray
*) settingsCallbacks
->getObject(settings
[i
]);
3302 // New array of callbacks for this setting
3303 list
= OSArray::withCapacity(1);
3304 settingsCallbacks
->setObject(settings
[i
], list
);
3308 // Add caller to the callback list
3309 list
->setObject(pmso
);
3313 // Return handle to the caller, the setting object is private.
3316 return kIOReturnSuccess
;
3319 //******************************************************************************
3320 // deregisterPMSettingObject (private)
3322 // Only called from PMSettingObject.
3323 //******************************************************************************
3325 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3327 thread_t thisThread
= current_thread();
3328 PMSettingCallEntry
*callEntry
;
3329 OSCollectionIterator
*iter
;
3337 pmso
->disabled
= true;
3339 // Wait for all callout threads to finish.
3342 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3344 if (callEntry
->thread
!= thisThread
)
3352 assert(0 == pmso
->waitThread
);
3353 pmso
->waitThread
= thisThread
;
3354 PMSETTING_WAIT(pmso
);
3355 pmso
->waitThread
= 0;
3359 // Search each PM settings array in the kernel.
3360 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3363 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3365 array
= (OSArray
*) settingsCallbacks
->getObject(sym
);
3366 index
= array
->getNextIndexOfObject(pmso
, 0);
3368 array
->removeObject(index
);
3379 //******************************************************************************
3380 // informCPUStateChange
3382 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3383 // running on battery, with the lid closed, etc.
3385 // informCPUStateChange is a no-op on non x86 systems
3386 // only x86 has explicit support in the IntelCPUPowerManagement kext
3387 //******************************************************************************
3389 void IOPMrootDomain::informCPUStateChange(
3393 #if defined(__i386__) || defined(__x86_64__)
3395 pmioctlVariableInfo_t varInfoStruct
;
3397 const char *varNameStr
= NULL
;
3398 int32_t *varIndex
= NULL
;
3400 if (kInformAC
== type
) {
3401 varNameStr
= kIOPMRootDomainBatPowerCString
;
3402 varIndex
= &idxPMCPULimitedPower
;
3403 } else if (kInformLid
== type
) {
3404 varNameStr
= kIOPMRootDomainLidCloseCString
;
3405 varIndex
= &idxPMCPUClamshell
;
3410 // Set the new value!
3411 // pmCPUControl will assign us a new ID if one doesn't exist yet
3412 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
3413 varInfoStruct
.varID
= *varIndex
;
3414 varInfoStruct
.varType
= vBool
;
3415 varInfoStruct
.varInitValue
= value
;
3416 varInfoStruct
.varCurValue
= value
;
3417 strncpy( (char *)varInfoStruct
.varName
,
3418 (const char *)varNameStr
,
3419 strlen(varNameStr
) + 1 );
3422 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
3424 // pmCPU only assigns numerical id's when a new varName is specified
3426 && (*varIndex
== kCPUUnknownIndex
))
3428 // pmCPUControl has assigned us a new variable ID.
3429 // Let's re-read the structure we just SET to learn that ID.
3430 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
3434 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3435 *varIndex
= varInfoStruct
.varID
;
3441 #endif /* __i386__ || __x86_64__ */
3445 // MARK: Deep Sleep Policy
3449 //******************************************************************************
3450 // evaluateSystemSleepPolicy
3451 //******************************************************************************
3453 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
3457 kIOPMSleepFlagHibernate
= 0x00000001,
3458 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
3461 struct IOPMSystemSleepPolicyEntry
3463 uint32_t factorMask
;
3464 uint32_t factorBits
;
3465 uint32_t sleepFlags
;
3466 uint32_t wakeEvents
;
3467 } __attribute__((packed
));
3469 struct IOPMSystemSleepPolicyTable
3473 uint16_t entryCount
;
3474 IOPMSystemSleepPolicyEntry entries
[];
3475 } __attribute__((packed
));
3477 bool IOPMrootDomain::evaluateSystemSleepPolicy(
3478 IOPMSystemSleepParameters
* params
, int sleepPhase
)
3480 const IOPMSystemSleepPolicyTable
* pt
;
3481 OSObject
* prop
= 0;
3482 OSData
* policyData
;
3483 uint64_t currentFactors
= 0;
3484 uint32_t standbyDelay
;
3485 uint32_t powerOffDelay
;
3487 bool standbyEnabled
;
3488 bool powerOffEnabled
;
3491 // Get platform's sleep policy table
3492 if (!_sleepPolicyHandler
)
3494 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
3495 if (!prop
) goto done
;
3498 // Fetch additional settings
3499 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
3500 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
3501 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
3502 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
3503 DLOG("standby %d delay %u, powerOff %d delay %u, hibernate %u\n",
3504 standbyEnabled
, standbyDelay
, powerOffEnabled
, powerOffDelay
,
3507 // pmset level overrides
3508 if ((hibernateMode
& kIOHibernateModeOn
) == 0)
3510 standbyEnabled
= false;
3511 powerOffEnabled
= false;
3513 else if (!(hibernateMode
& kIOHibernateModeSleep
))
3515 // Force hibernate (i.e. mode 25)
3516 // If standby is enabled, force standy.
3517 // If poweroff is enabled, force poweroff.
3519 currentFactors
|= kIOPMSleepFactorStandbyForced
;
3520 else if (powerOffEnabled
)
3521 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
3523 currentFactors
|= kIOPMSleepFactorHibernateForced
;
3526 // Current factors based on environment and assertions
3527 if (sleepTimerMaintenance
)
3528 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3529 if (!clamshellClosed
)
3530 currentFactors
|= kIOPMSleepFactorLidOpen
;
3531 if (acAdaptorConnected
)
3532 currentFactors
|= kIOPMSleepFactorACPower
;
3533 if (lowBatteryCondition
)
3534 currentFactors
|= kIOPMSleepFactorBatteryLow
;
3536 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
3537 if (!standbyEnabled
)
3538 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
3539 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
3540 kIOPMDriverAssertionLevelOff
)
3541 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
3542 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
3543 kIOPMDriverAssertionLevelOff
)
3544 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
3545 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
3546 kIOPMDriverAssertionLevelOff
)
3547 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
3548 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
3549 kIOPMDriverAssertionLevelOff
)
3550 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
3551 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit8
) !=
3552 kIOPMDriverAssertionLevelOff
)
3553 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
3554 if (!powerOffEnabled
)
3555 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
3557 DLOG("sleep factors 0x%llx\n", currentFactors
);
3559 // Clear the output params
3560 bzero(params
, sizeof(*params
));
3562 if (_sleepPolicyHandler
)
3564 if (!_sleepPolicyVars
)
3566 _sleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
3567 if (!_sleepPolicyVars
)
3569 bzero(_sleepPolicyVars
, sizeof(*_sleepPolicyVars
));
3571 _sleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
3572 _sleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
3573 if (kIOPMSleepPhase1
== sleepPhase
)
3575 _sleepPolicyVars
->currentCapability
= _currentCapability
;
3576 _sleepPolicyVars
->highestCapability
= _highestCapability
;
3577 _sleepPolicyVars
->sleepReason
= lastSleepReason
;
3578 _sleepPolicyVars
->hibernateMode
= hibernateMode
;
3579 _sleepPolicyVars
->standbyDelay
= standbyDelay
;
3580 _sleepPolicyVars
->poweroffDelay
= powerOffDelay
;
3582 _sleepPolicyVars
->sleepFactors
= currentFactors
;
3583 _sleepPolicyVars
->sleepPhase
= sleepPhase
;
3585 if ((_sleepPolicyHandler(_sleepPolicyTarget
, _sleepPolicyVars
, params
) !=
3586 kIOReturnSuccess
) || (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
3587 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
3588 (kIOPMSystemSleepParametersVersion
!= params
->version
))
3590 MSG("sleep policy handler error\n");
3594 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
3595 params
->version
, params
->sleepType
, params
->sleepFlags
,
3596 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
3601 // Policy table is meaningless without standby enabled
3602 if (!standbyEnabled
)
3605 // Validate the sleep policy table
3606 policyData
= OSDynamicCast(OSData
, prop
);
3607 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
3610 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
3611 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
3612 (pt
->version
!= 1) || (0 == pt
->entryCount
))
3615 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
3616 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
3619 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
3621 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
3622 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
3624 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
3625 entry
->factorMask
, entry
->factorBits
,
3626 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
3630 DLOG("^ found match\n");
3633 params
->version
= kIOPMSystemSleepParametersVersion
;
3634 params
->reserved1
= 1;
3635 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
3636 params
->sleepType
= kIOPMSleepTypeStandby
;
3638 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
3640 params
->ecWakeEvents
= entry
->wakeEvents
;
3641 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
3642 params
->ecWakeTimer
= standbyDelay
;
3653 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
3655 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
3657 // Evaluate early (priority interest phase), before drivers sleep.
3659 DLOG("%s\n", __FUNCTION__
);
3660 removeProperty(kIOPMSystemSleepParametersKey
);
3662 hibernateDisabled
= false;
3664 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
3666 // Save for late evaluation if sleep is aborted
3667 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
3669 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
))
3671 if (!hibernateNoDefeat
&&
3672 (gEarlySystemSleepParams
.sleepType
== kIOPMSleepTypeNormalSleep
))
3674 // Disable hibernate setup for normal sleep
3675 hibernateDisabled
= true;
3679 // Publish IOPMSystemSleepType
3680 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
3681 if (sleepType
== kIOPMSleepTypeInvalid
)
3684 sleepType
= kIOPMSleepTypeNormalSleep
;
3685 if (hibernateMode
& kIOHibernateModeOn
)
3686 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
3687 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
3689 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
3690 (gEarlySystemSleepParams
.ecPoweroffTimer
))
3692 // report the lowest possible sleep state
3693 sleepType
= kIOPMSleepTypePowerOff
;
3696 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
3699 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
3701 IOPMSystemSleepParameters params
;
3702 OSData
* paramsData
;
3704 // Evaluate sleep policy after sleeping drivers but before platform sleep.
3706 DLOG("%s\n", __FUNCTION__
);
3708 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
))
3710 if ((hibernateDisabled
|| hibernateAborted
) &&
3711 (params
.sleepType
!= kIOPMSleepTypeNormalSleep
))
3713 // Final evaluation picked a state requiring hibernation,
3714 // but hibernate setup was skipped. Retry using the early
3715 // sleep parameters.
3717 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
3718 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
3719 params
.ecWakeTimer
= 1;
3720 hibernateNoDefeat
= true;
3721 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
3722 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
);
3726 hibernateNoDefeat
= false;
3729 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
3732 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
3733 paramsData
->release();
3736 if (params
.sleepType
>= kIOPMSleepTypeHibernate
)
3738 // Disable safe sleep to force the hibernate path
3739 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
3744 bool IOPMrootDomain::getHibernateSettings(
3745 uint32_t * hibernateModePtr
,
3746 uint32_t * hibernateFreeRatio
,
3747 uint32_t * hibernateFreeTime
)
3749 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
3750 // has updated the hibernateDisabled flag.
3752 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
3753 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
3754 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
3755 if (hibernateDisabled
)
3756 *hibernateModePtr
= 0;
3757 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
3761 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
3763 OSObject
* optionsProp
;
3764 OSDictionary
* optionsDict
;
3769 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
3770 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
3774 obj
= optionsDict
->getObject(key
);
3775 if (obj
) obj
->retain();
3779 obj
= copyProperty(key
);
3781 if (obj
&& (num
= OSDynamicCast(OSNumber
, obj
)))
3783 *option
= num
->unsigned32BitValue();
3790 optionsProp
->release();
3794 #endif /* HIBERNATION */
3797 // MARK: Shutdown and Restart
3799 //******************************************************************************
3800 // handlePlatformHaltRestart
3802 //******************************************************************************
3804 struct HaltRestartApplierContext
{
3805 IOPMrootDomain
* RootDomain
;
3806 unsigned long PowerState
;
3807 IOPMPowerFlags PowerFlags
;
3813 platformHaltRestartApplier( OSObject
* object
, void * context
)
3815 IOPowerStateChangeNotification notify
;
3816 HaltRestartApplierContext
* ctx
;
3817 AbsoluteTime startTime
;
3820 ctx
= (HaltRestartApplierContext
*) context
;
3822 memset(¬ify
, 0, sizeof(notify
));
3823 notify
.powerRef
= (void *)ctx
->Counter
;
3824 notify
.returnValue
= 0;
3825 notify
.stateNumber
= ctx
->PowerState
;
3826 notify
.stateFlags
= ctx
->PowerFlags
;
3828 clock_get_uptime(&startTime
);
3829 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
3830 deltaTime
= computeDeltaTimeMS(&startTime
);
3832 if ((deltaTime
> kPMHaltTimeoutMS
) ||
3833 (gIOKitDebug
& kIOLogPMRootDomain
))
3835 _IOServiceInterestNotifier
* notifier
;
3836 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
3838 // IOService children of IOPMrootDomain are not instrumented.
3839 // Only IORootParent currently falls under that group.
3843 LOG("%s handler %p took %u ms\n",
3844 (ctx
->MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
3845 (ctx
->MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
3846 notifier
->handler
, (uint32_t) deltaTime
);
3853 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
3855 HaltRestartApplierContext ctx
;
3856 AbsoluteTime startTime
;
3859 memset(&ctx
, 0, sizeof(ctx
));
3860 ctx
.RootDomain
= this;
3862 clock_get_uptime(&startTime
);
3866 case kPEUPSDelayHaltCPU
:
3867 ctx
.PowerState
= OFF_STATE
;
3868 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
3872 ctx
.PowerState
= RESTART_STATE
;
3873 ctx
.MessageType
= kIOMessageSystemWillRestart
;
3877 ctx
.PowerState
= ON_STATE
;
3878 ctx
.MessageType
= kIOMessageSystemPagingOff
;
3879 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
3886 // Notify legacy clients
3887 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
3889 // For normal shutdown, turn off File Server Mode.
3890 if (kPEHaltCPU
== pe_type
)
3892 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
3893 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
3896 setPMSetting(setting
, num
);
3902 if (kPEPagingOff
!= pe_type
)
3904 // Notify in power tree order
3905 notifySystemShutdown(this, ctx
.MessageType
);
3908 deltaTime
= computeDeltaTimeMS(&startTime
);
3909 LOG("%s all drivers took %u ms\n",
3910 (ctx
.MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
3911 (ctx
.MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
3912 (uint32_t) deltaTime
);
3915 //******************************************************************************
3918 //******************************************************************************
3920 IOReturn
IOPMrootDomain::shutdownSystem( void )
3922 return kIOReturnUnsupported
;
3925 //******************************************************************************
3928 //******************************************************************************
3930 IOReturn
IOPMrootDomain::restartSystem( void )
3932 return kIOReturnUnsupported
;
3936 // MARK: System Capability
3938 //******************************************************************************
3939 // tagPowerPlaneService
3941 // Running on PM work loop thread.
3942 //******************************************************************************
3944 void IOPMrootDomain::tagPowerPlaneService(
3945 IOService
* service
,
3946 IOPMActions
* actions
)
3949 bool isDisplayWrangler
;
3951 memset(actions
, 0, sizeof(*actions
));
3952 actions
->target
= this;
3954 if (service
== this)
3956 actions
->actionPowerChangeStart
=
3957 OSMemberFunctionCast(
3958 IOPMActionPowerChangeStart
, this,
3959 &IOPMrootDomain::handleOurPowerChangeStart
);
3961 actions
->actionPowerChangeDone
=
3962 OSMemberFunctionCast(
3963 IOPMActionPowerChangeDone
, this,
3964 &IOPMrootDomain::handleOurPowerChangeDone
);
3966 actions
->actionPowerChangeOverride
=
3967 OSMemberFunctionCast(
3968 IOPMActionPowerChangeOverride
, this,
3969 &IOPMrootDomain::overrideOurPowerChange
);
3974 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
3975 if (isDisplayWrangler
)
3978 wranglerConnection
= (IOService
*) service
->getParentEntry(gIOPowerPlane
);
3981 isDisplayWrangler
= false;
3984 #if defined(__i386__) || defined(__x86_64__)
3985 if (isDisplayWrangler
)
3986 flags
|= kPMActionsFlagIsDisplayWrangler
;
3987 if (service
->getProperty("IOPMStrictTreeOrder"))
3988 flags
|= kPMActionsFlagIsGraphicsDevice
;
3989 if (service
->getProperty("IOPMUnattendedWakePowerState"))
3990 flags
|= kPMActionsFlagIsAudioDevice
;
3993 // Find the power connection object that is a child of the PCI host
3994 // bridge, and has a graphics/audio device attached below. Mark the
3995 // power branch for delayed child notifications.
3999 IORegistryEntry
* child
= service
;
4000 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4002 while (child
!= this)
4004 if ((parent
== pciHostBridgeDriver
) ||
4007 if (OSDynamicCast(IOPowerConnection
, child
))
4009 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4010 conn
->delayChildNotification
= true;
4015 parent
= child
->getParentEntry(gIOPowerPlane
);
4021 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4022 actions
->parameter
|= flags
;
4023 actions
->actionPowerChangeOverride
=
4024 OSMemberFunctionCast(
4025 IOPMActionPowerChangeOverride
, this,
4026 &IOPMrootDomain::overridePowerChangeForUIService
);
4028 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4030 actions
->actionActivityTickle
=
4031 OSMemberFunctionCast(
4032 IOPMActionActivityTickle
, this,
4033 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4038 // Locate the first PCI host bridge for PMTrace.
4039 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4041 IOService
* provider
= service
->getProvider();
4042 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4043 provider
->inPlane(gIODTPlane
))
4045 pciHostBridgeDevice
= provider
;
4046 pciHostBridgeDriver
= service
;
4047 DLOG("PMTrace found PCI host bridge %s->%s\n",
4048 provider
->getName(), service
->getName());
4052 // Tag top-level PCI devices. The order of PMinit() call does not
4053 // change across boots and is used as the PCI bit number.
4054 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4056 // Would prefer to check built-in property, but tagPowerPlaneService()
4057 // is called before pciDevice->registerService().
4058 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4059 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4061 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4064 // Save the assigned bit for fast lookup.
4065 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4067 actions
->actionPowerChangeStart
=
4068 OSMemberFunctionCast(
4069 IOPMActionPowerChangeStart
, this,
4070 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4072 actions
->actionPowerChangeDone
=
4073 OSMemberFunctionCast(
4074 IOPMActionPowerChangeDone
, this,
4075 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4081 //******************************************************************************
4082 // PM actions for root domain
4083 //******************************************************************************
4085 void IOPMrootDomain::overrideOurPowerChange(
4086 IOService
* service
,
4087 IOPMActions
* actions
,
4088 unsigned long * inOutPowerState
,
4089 uint32_t * inOutChangeFlags
)
4091 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4092 uint32_t changeFlags
= *inOutChangeFlags
;
4093 uint32_t currentPowerState
= (uint32_t) getPowerState();
4095 if ((currentPowerState
== powerState
) ||
4096 (changeFlags
& kIOPMParentInitiated
))
4098 // FIXME: cancel any parent change (unexpected)
4099 // Root parent is permanently pegged at max power,
4100 // kIOPMParentInitiated is unexpected.
4104 if (powerState
< currentPowerState
)
4106 if ((changeFlags
& kIOPMSkipAskPowerDown
) == 0)
4108 /* Convenient place to run any code at idle sleep time
4109 * IOPMrootDomain initiates an idle sleep here
4111 * Set last sleep cause accordingly.
4113 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishSleepWakeUUID
, (void *)true);
4115 lastSleepReason
= kIOPMSleepReasonIdle
;
4116 setProperty(kRootDomainSleepReasonKey
, kIOPMIdleSleepKey
);
4118 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4120 // Root domain is dropping power state ON->SLEEP.
4121 // If system is in full wake, first drop to dark wake.
4123 darkWakeToSleepASAP
= true;
4125 // Drop graphics capability.
4126 // No transition if system is already in dark wake.
4128 _desiredCapability
&= ~(
4129 kIOPMSystemCapabilityGraphics
|
4130 kIOPMSystemCapabilityAudio
);
4132 *inOutPowerState
= ON_STATE
;
4133 *inOutChangeFlags
|= kIOPMSynchronize
;
4135 // Revert device desire from SLEEP->ON.
4136 changePowerStateToPriv(ON_STATE
);
4141 void IOPMrootDomain::handleOurPowerChangeStart(
4142 IOService
* service
,
4143 IOPMActions
* actions
,
4144 uint32_t powerState
,
4145 uint32_t * inOutChangeFlags
)
4147 uint32_t changeFlags
= *inOutChangeFlags
;
4148 uint32_t currentPowerState
= (uint32_t) getPowerState();
4150 _systemTransitionType
= kSystemTransitionNone
;
4151 _systemMessageClientMask
= 0;
4152 capabilityLoss
= false;
4154 // 1. Explicit capability change.
4156 if (changeFlags
& kIOPMSynchronize
)
4158 if (powerState
== ON_STATE
)
4160 if (changeFlags
& kIOPMSyncNoChildNotify
)
4161 _systemTransitionType
= kSystemTransitionNewCapClient
;
4163 _systemTransitionType
= kSystemTransitionCapability
;
4167 // 2. Going to sleep (cancellation still possible).
4169 else if (powerState
< currentPowerState
)
4170 _systemTransitionType
= kSystemTransitionSleep
;
4172 // 3. Woke from (idle or demand) sleep.
4174 else if (!systemBooting
&&
4175 (changeFlags
& kIOPMSelfInitiated
) &&
4176 (powerState
> currentPowerState
))
4178 _systemTransitionType
= kSystemTransitionWake
;
4179 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4180 kIOPMSystemCapabilityNetwork
;
4182 // Check for early HID events (e.g. LID open)
4183 if (wranglerTickled
)
4185 _desiredCapability
|= (
4186 kIOPMSystemCapabilityGraphics
|
4187 kIOPMSystemCapabilityAudio
);
4191 // Update pending wake capability at the beginning of every
4192 // state transition (including synchronize). This will become
4193 // the current capability at the end of the transition.
4195 if (kSystemTransitionSleep
== _systemTransitionType
)
4197 _pendingCapability
= 0;
4198 capabilityLoss
= true;
4200 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4202 _pendingCapability
= _desiredCapability
|
4203 kIOPMSystemCapabilityCPU
|
4204 kIOPMSystemCapabilityNetwork
;
4206 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4207 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4209 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4210 (_pendingCapability
== _currentCapability
))
4212 // Cancel the PM state change.
4213 _systemTransitionType
= kSystemTransitionNone
;
4214 *inOutChangeFlags
|= kIOPMNotDone
;
4216 if (__builtin_popcount(_pendingCapability
) <
4217 __builtin_popcount(_currentCapability
))
4218 capabilityLoss
= true;
4219 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4220 rejectWranglerTickle
= true;
4223 // 1. Capability change.
4225 if (kSystemTransitionCapability
== _systemTransitionType
)
4227 // Dark to Full transition.
4228 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4230 tracePoint( kIOPMTracePointDarkWakeExit
);
4231 wranglerSleepIgnored
= false;
4232 sleepTimerMaintenance
= false;
4233 hibernateNoDefeat
= false;
4234 _systemMessageClientMask
= kSystemMessageClientUser
;
4235 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4236 _systemMessageClientMask
|= kSystemMessageClientKernel
;
4238 tellClients(kIOMessageSystemWillPowerOn
);
4241 // Full to Dark transition.
4242 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4244 tracePoint( kIOPMTracePointDarkWakeEntry
);
4245 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4246 _systemMessageClientMask
= kSystemMessageClientUser
;
4252 else if (kSystemTransitionSleep
== _systemTransitionType
)
4254 // Beginning of a system sleep transition.
4255 // Cancellation is still possible.
4256 tracePoint( kIOPMTracePointSleepStarted
, lastSleepReason
);
4258 _systemMessageClientMask
= kSystemMessageClientAll
;
4259 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4260 _systemMessageClientMask
&= ~kSystemMessageClientApp
;
4261 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4262 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
4264 // Optimization to ignore wrangler power down thus skipping
4265 // the disk spindown and arming the idle timer for demand sleep.
4267 if (changeFlags
& kIOPMIgnoreChildren
)
4269 wranglerSleepIgnored
= true;
4272 logWranglerTickle
= false;
4277 else if (kSystemTransitionWake
== _systemTransitionType
)
4279 wranglerSleepIgnored
= false;
4281 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4283 _systemMessageClientMask
= kSystemMessageClientAll
;
4287 _systemMessageClientMask
= kSystemMessageClientConfigd
;
4290 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
4291 tellClients(kIOMessageSystemWillPowerOn
);
4294 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
4295 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
4297 _systemStateGeneration
++;
4298 systemDarkWake
= false;
4300 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4302 currentPowerState
, powerState
, *inOutChangeFlags
,
4303 _systemTransitionType
, _systemStateGeneration
,
4304 _systemMessageClientMask
,
4305 _desiredCapability
, _currentCapability
, _pendingCapability
);
4309 void IOPMrootDomain::handleOurPowerChangeDone(
4310 IOService
* service
,
4311 IOPMActions
* actions
,
4312 uint32_t powerState
,
4313 uint32_t changeFlags
)
4315 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4317 _systemTransitionType
= kSystemTransitionNone
;
4321 if (_systemTransitionType
!= kSystemTransitionNone
)
4323 uint32_t currentPowerState
= (uint32_t) getPowerState();
4325 if (changeFlags
& kIOPMNotDone
)
4327 // Power down was cancelled or vetoed.
4328 _pendingCapability
= _currentCapability
;
4329 lastSleepReason
= 0;
4331 if (((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4332 (_currentCapability
& kIOPMSystemCapabilityCPU
))
4334 pmPowerStateQueue
->submitPowerEvent(
4335 kPowerEventPolicyStimulus
,
4336 (void *) kStimulusDarkWakeReentry
,
4337 _systemStateGeneration
);
4340 // Revert device desire to max.
4341 changePowerStateToPriv(ON_STATE
);
4345 // Send message on dark wake to full wake promotion.
4346 // tellChangeUp() handles the normal SLEEP->ON case.
4348 if (kSystemTransitionCapability
== _systemTransitionType
)
4350 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4352 tellClients(kIOMessageSystemHasPoweredOn
);
4353 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
4354 // Re-evaluate clamshell state ourselves when graphics
4355 // will not get kIOMessageSystemHasPoweredOn.
4357 if (clamshellClosed
&&
4358 ((_systemMessageClientMask
& kSystemMessageClientKernel
) == 0))
4360 receivePowerNotification( kLocalEvalClamshellCommand
);
4364 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4365 wranglerTickled
= false;
4368 // Reset state after exiting from dark wake.
4370 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
4371 CAP_LOSS(kIOPMSystemCapabilityCPU
))
4373 darkWakeMaintenance
= false;
4374 darkWakeToSleepASAP
= false;
4375 pciCantSleepValid
= false;
4376 rejectWranglerTickle
= false;
4379 // Entered dark mode.
4381 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4382 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
4384 if (((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOInDark
) == 0) &&
4385 (kSystemTransitionWake
== _systemTransitionType
) &&
4386 (_lastDebugWakeSeconds
== 0))
4388 OSObject
* prop
= copyProperty(kIOPMRootDomainWakeTypeKey
);
4391 OSString
* wakeType
= OSDynamicCast(OSString
, prop
);
4393 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeNetwork
))
4395 // Woke from network and entered dark wake.
4396 if (darkWakeToSleepASAP
)
4398 DLOG("cleared darkWakeToSleepASAP\n");
4399 darkWakeToSleepASAP
= false;
4406 // Queue an evaluation of whether to remain in dark wake,
4407 // and for how long. This serves the purpose of draining
4408 // any assertions from the queue.
4410 pmPowerStateQueue
->submitPowerEvent(
4411 kPowerEventPolicyStimulus
,
4412 (void *) kStimulusDarkWakeEntry
,
4413 _systemStateGeneration
);
4417 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4418 "dcp %x:%x:%x, dbgtimer %u\n",
4419 currentPowerState
, powerState
, changeFlags
,
4420 _systemTransitionType
, _systemStateGeneration
,
4421 _systemMessageClientMask
,
4422 _desiredCapability
, _currentCapability
, _pendingCapability
,
4423 _lastDebugWakeSeconds
);
4425 // Update current system capability.
4427 if (_currentCapability
!= _pendingCapability
)
4428 _currentCapability
= _pendingCapability
;
4430 // Update highest system capability.
4432 if (!CAP_CURRENT(kIOPMSystemCapabilityCPU
))
4433 _highestCapability
= 0; // reset at sleep state
4435 _highestCapability
|= _currentCapability
;
4437 if (darkWakePostTickle
&&
4438 (kSystemTransitionWake
== _systemTransitionType
) &&
4439 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4440 kDarkWakeFlagHIDTickleLate
)
4442 darkWakePostTickle
= false;
4446 // Reset tracepoint at completion of capability change,
4447 // completion of wake transition, and aborted sleep transition.
4449 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
4450 (_systemTransitionType
== kSystemTransitionWake
) ||
4451 ((_systemTransitionType
== kSystemTransitionSleep
) &&
4452 (changeFlags
& kIOPMNotDone
)))
4454 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
4455 tracePoint( kIOPMTracePointSystemUp
, 0 );
4458 _systemTransitionType
= kSystemTransitionNone
;
4459 _systemMessageClientMask
= 0;
4461 logGraphicsClamp
= false;
4465 //******************************************************************************
4466 // PM actions for graphics and audio.
4467 //******************************************************************************
4469 void IOPMrootDomain::overridePowerChangeForUIService(
4470 IOService
* service
,
4471 IOPMActions
* actions
,
4472 unsigned long * inOutPowerState
,
4473 uint32_t * inOutChangeFlags
)
4475 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4476 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
4478 if (kSystemTransitionNone
== _systemTransitionType
)
4480 // Not in midst of a system transition.
4481 // Do not modify power limit enable state.
4483 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4485 // Activate power limiter.
4487 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4488 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
4490 actions
->parameter
|= kPMActionsFlagLimitPower
;
4492 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4493 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0))
4495 actions
->parameter
|= kPMActionsFlagLimitPower
;
4497 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
4498 (_systemTransitionType
== kSystemTransitionSleep
))
4500 // For graphics devices, arm the limiter when entering
4501 // system sleep. Not when dropping to dark wake.
4502 actions
->parameter
|= kPMActionsFlagLimitPower
;
4505 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4507 DLOG("+ plimit %s %p\n",
4508 service
->getName(), service
);
4513 // Remove power limit.
4515 if ((actions
->parameter
& (
4516 kPMActionsFlagIsDisplayWrangler
|
4517 kPMActionsFlagIsGraphicsDevice
)) &&
4518 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
4520 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4522 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4523 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
4525 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4528 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4530 DLOG("- plimit %s %p\n",
4531 service
->getName(), service
);
4535 if (gRAMDiskImageBoot
&&
4536 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
4538 // Tag devices subject to power suppression.
4539 *inOutChangeFlags
|= kIOPMPowerSuppressed
;
4542 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4544 uint32_t maxPowerState
= (uint32_t)(-1);
4546 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
4548 // Enforce limit for system power/cap transitions.
4551 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4552 (!gRAMDiskImageBoot
|| (service
->getPowerState() > 0)))
4554 // Forces a 3->1 transition sequence
4555 if (changeFlags
& kIOPMDomainWillChange
)
4563 // Deny all self-initiated changes when power is limited.
4564 // Wrangler tickle should never defeat the limiter.
4566 maxPowerState
= service
->getPowerState();
4569 if (powerState
> maxPowerState
)
4571 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
4572 service
->getName(), service
, powerState
, maxPowerState
,
4574 *inOutPowerState
= maxPowerState
;
4576 if (darkWakePostTickle
&&
4577 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4578 (changeFlags
& kIOPMDomainWillChange
) &&
4579 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4580 kDarkWakeFlagHIDTickleEarly
))
4582 darkWakePostTickle
= false;
4587 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
4589 if (logGraphicsClamp
)
4594 clock_get_uptime(&now
);
4595 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
4596 absolutetime_to_nanoseconds(now
, &nsec
);
4597 MSG("Graphics suppressed %u ms\n",
4598 ((int)((nsec
) / 1000000ULL)));
4600 graphicsSuppressed
= true;
4605 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
4606 IOService
* service
,
4607 IOPMActions
* actions
)
4609 // Warning: Not running in PM work loop context - don't modify state !!!
4610 // Trap tickle directed to IODisplayWrangler while running with graphics
4611 // capability suppressed.
4613 assert(service
== wrangler
);
4615 if (service
== wrangler
)
4617 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
4618 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
4620 userActivityCount
++;
4621 DLOG("display wrangler tickled1 %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
4625 if (!wranglerTickled
&&
4626 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
4628 DLOG("display wrangler tickled\n");
4629 if (kIOLogPMRootDomain
& gIOKitDebug
)
4630 OSReportWithBacktrace("Dark wake display tickle");
4631 if (pmPowerStateQueue
)
4633 pmPowerStateQueue
->submitPowerEvent(
4634 kPowerEventPolicyStimulus
,
4635 (void *) kStimulusDarkWakeActivityTickle
);
4640 //******************************************************************************
4641 // Approve usage of delayed child notification by PM.
4642 //******************************************************************************
4644 bool IOPMrootDomain::shouldDelayChildNotification(
4645 IOService
* service
)
4647 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
4649 (kSystemTransitionWake
== _systemTransitionType
))
4651 DLOG("%s: delay child notify\n", service
->getName());
4657 //******************************************************************************
4658 // PM actions for PCI device.
4659 //******************************************************************************
4661 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
4662 IOService
* service
,
4663 IOPMActions
* actions
,
4664 uint32_t powerState
,
4665 uint32_t * inOutChangeFlags
)
4667 pmTracer
->tracePCIPowerChange(
4668 PMTraceWorker::kPowerChangeStart
,
4669 service
, *inOutChangeFlags
,
4670 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
4673 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
4674 IOService
* service
,
4675 IOPMActions
* actions
,
4676 uint32_t powerState
,
4677 uint32_t changeFlags
)
4679 pmTracer
->tracePCIPowerChange(
4680 PMTraceWorker::kPowerChangeCompleted
,
4681 service
, changeFlags
,
4682 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
4685 //******************************************************************************
4688 // Override IOService::registerInterest() to intercept special clients.
4689 //******************************************************************************
4691 IONotifier
* IOPMrootDomain::registerInterest(
4692 const OSSymbol
* typeOfInterest
,
4693 IOServiceInterestHandler handler
,
4694 void * target
, void * ref
)
4696 IONotifier
* notifier
;
4697 bool isSystemCapabilityClient
;
4698 bool isKernelCapabilityClient
;
4700 isSystemCapabilityClient
=
4702 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
4704 isKernelCapabilityClient
=
4706 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
4708 if (isSystemCapabilityClient
)
4709 typeOfInterest
= gIOAppPowerStateInterest
;
4711 notifier
= super::registerInterest(typeOfInterest
, handler
, target
, ref
);
4712 if (notifier
&& pmPowerStateQueue
)
4714 if (isSystemCapabilityClient
)
4717 if (pmPowerStateQueue
->submitPowerEvent(
4718 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
4719 notifier
->release();
4722 if (isKernelCapabilityClient
)
4725 if (pmPowerStateQueue
->submitPowerEvent(
4726 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
4727 notifier
->release();
4734 //******************************************************************************
4735 // systemMessageFilter
4737 //******************************************************************************
4739 bool IOPMrootDomain::systemMessageFilter(
4740 void * object
, void * arg1
, void * arg2
, void * arg3
)
4742 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
4743 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
4744 bool isCapClient
= false;
4748 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
4749 (!isCapMsg
|| !_joinedCapabilityClients
||
4750 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
4753 // Capability change message for app and kernel clients.
4757 if ((context
->notifyType
== kNotifyPriority
) ||
4758 (context
->notifyType
== kNotifyCapabilityChangePriority
))
4761 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
4762 (object
== (void *) systemCapabilityNotifier
))
4768 IOPMSystemCapabilityChangeParameters
* capArgs
=
4769 (IOPMSystemCapabilityChangeParameters
*) arg2
;
4771 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4773 capArgs
->fromCapabilities
= 0;
4774 capArgs
->toCapabilities
= _currentCapability
;
4775 capArgs
->changeFlags
= 0;
4779 capArgs
->fromCapabilities
= _currentCapability
;
4780 capArgs
->toCapabilities
= _pendingCapability
;
4782 if (context
->isPreChange
)
4783 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
4785 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
4788 // Capability change messages only go to the PM configd plugin.
4789 // Wait for response post-change if capabilitiy is increasing.
4790 // Wait for response pre-change if capability is decreasing.
4792 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
4793 ( (capabilityLoss
&& context
->isPreChange
) ||
4794 (!capabilityLoss
&& !context
->isPreChange
) ) )
4796 // app has not replied yet, wait for it
4797 *((OSObject
**) arg3
) = kOSBooleanFalse
;
4804 // Capability client will always see kIOMessageCanSystemSleep,
4805 // even for demand sleep.
4807 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
4808 (kIOMessageSystemWillNotSleep
== context
->messageType
))
4810 if (object
== (OSObject
*) systemCapabilityNotifier
)
4816 // Not idle sleep, don't ask apps.
4817 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
4823 // Reject capability change messages for legacy clients.
4824 // Reject legacy system sleep messages for capability client.
4826 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
4831 // Filter system sleep messages.
4833 if ((context
->notifyType
== kNotifyApps
) &&
4834 (_systemMessageClientMask
& kSystemMessageClientApp
))
4838 else if ((context
->notifyType
== kNotifyPriority
) &&
4839 (_systemMessageClientMask
& kSystemMessageClientKernel
))
4846 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
4848 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
4849 if (_joinedCapabilityClients
->getCount() == 0)
4851 DLOG("destroyed capability client set %p\n",
4852 _joinedCapabilityClients
);
4853 _joinedCapabilityClients
->release();
4854 _joinedCapabilityClients
= 0;
4861 //******************************************************************************
4862 // setMaintenanceWakeCalendar
4864 //******************************************************************************
4866 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
4867 const IOPMCalendarStruct
* calendar
)
4873 return kIOReturnBadArgument
;
4875 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
4877 return kIOReturnNoMemory
;
4879 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
4880 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
4882 if (kPMCalendarTypeSleepService
== calendar
->selector
)
4884 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
4893 // MARK: Display Wrangler
4895 //******************************************************************************
4896 // displayWranglerNotification
4898 // Handle the notification when the IODisplayWrangler changes power state.
4899 //******************************************************************************
4901 IOReturn
IOPMrootDomain::displayWranglerNotification(
4902 void * target
, void * refCon
,
4903 UInt32 messageType
, IOService
* service
,
4904 void * messageArgument
, vm_size_t argSize
)
4907 int displayPowerState
;
4908 IOPowerStateChangeNotification
* params
=
4909 (IOPowerStateChangeNotification
*) messageArgument
;
4911 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
4912 (messageType
!= kIOMessageDeviceHasPoweredOn
))
4913 return kIOReturnUnsupported
;
4917 return kIOReturnUnsupported
;
4919 displayPowerState
= params
->stateNumber
;
4920 DLOG("DisplayWrangler message 0x%x, power state %d\n",
4921 (uint32_t) messageType
, displayPowerState
);
4923 switch (messageType
) {
4924 case kIOMessageDeviceWillPowerOff
:
4926 // Display wrangler has dropped power due to display idle
4927 // or force system sleep.
4932 // 1 Not visible to user
4933 // 0 Not visible to user
4935 if (displayPowerState
> 2)
4938 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
4941 case kIOMessageDeviceHasPoweredOn
:
4943 // Display wrangler has powered on due to user activity
4944 // or wake from sleep.
4946 if ( 4 != displayPowerState
)
4949 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
4953 return kIOReturnUnsupported
;
4956 //******************************************************************************
4957 // displayWranglerMatchPublished
4959 // Receives a notification when the IODisplayWrangler is published.
4960 // When it's published we install a power state change handler.
4961 //******************************************************************************
4963 bool IOPMrootDomain::displayWranglerMatchPublished(
4966 IOService
* newService
,
4967 IONotifier
* notifier __unused
)
4970 // found the display wrangler, now install a handler
4971 if( !newService
->registerInterest( gIOGeneralInterest
,
4972 &displayWranglerNotification
, target
, 0) )
4980 //******************************************************************************
4983 //******************************************************************************
4985 void IOPMrootDomain::reportUserInput( void )
4992 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
4995 wrangler
= (IOService
*) iter
->getNextObject();
5001 wrangler
->activityTickle(0,0);
5005 //******************************************************************************
5006 // blockDisplayWranglerTickle
5007 //******************************************************************************
5009 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
5014 // Not too late to prevent the display from lighting up
5015 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
5016 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
5017 !checkSystemCanSustainFullWake())
5019 wranglerTickleLatched
= true;
5023 wranglerTickleLatched
= false;
5026 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
5028 wranglerTickleLatched
= false;
5030 pmPowerStateQueue
->submitPowerEvent(
5031 kPowerEventPolicyStimulus
,
5032 (void *) kStimulusDarkWakeActivityTickle
);
5035 return wranglerTickleLatched
;
5044 //******************************************************************************
5047 // Notification on battery class IOPowerSource appearance
5048 //******************************************************************************
5050 bool IOPMrootDomain::batteryPublished(
5053 IOService
* resourceService
,
5054 IONotifier
* notifier __unused
)
5056 // rdar://2936060&4435589
5057 // All laptops have dimmable LCD displays
5058 // All laptops have batteries
5059 // So if this machine has a battery, publish the fact that the backlight
5060 // supports dimming.
5061 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
5067 // MARK: System PM Policy
5069 //******************************************************************************
5070 // checkSystemCanSleep
5072 //******************************************************************************
5074 bool IOPMrootDomain::checkSystemCanSleep( IOOptionBits options
)
5078 // Conditions that prevent idle and demand system sleep.
5081 if (userDisabledAllSleep
)
5083 err
= 1; // 1. user-space sleep kill switch
5087 if (systemBooting
|| systemShutdown
)
5089 err
= 2; // 2. restart or shutdown in progress
5096 // Conditions above pegs the system at full wake.
5097 // Conditions below prevent system sleep but does not prevent
5098 // dark wake, and must be called from gated context.
5101 err
= 3; // 3. config does not support sleep
5105 if (lowBatteryCondition
)
5107 break; // always sleep on low battery
5110 if (childPreventSystemSleep
)
5112 err
= 4; // 4. child prevent system sleep clamp
5116 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
5117 kIOPMDriverAssertionLevelOn
)
5119 err
= 5; // 5. CPU assertion
5123 if (pciCantSleepValid
)
5125 if (pciCantSleepFlag
)
5126 err
= 6; // 6. PCI card does not support PM (cached)
5129 else if (sleepSupportedPEFunction
&&
5130 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5133 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
5134 ret
= getPlatform()->callPlatformFunction(
5135 sleepSupportedPEFunction
, false,
5136 NULL
, NULL
, NULL
, NULL
);
5137 pciCantSleepValid
= true;
5138 pciCantSleepFlag
= false;
5139 if ((platformSleepSupport
& kPCICantSleep
) ||
5140 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
5142 err
= 6; // 6. PCI card does not support PM
5143 pciCantSleepFlag
= true;
5152 DLOG("System sleep prevented by %d\n", err
);
5158 //******************************************************************************
5159 // checkSystemCanSustainFullWake
5160 //******************************************************************************
5162 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
5165 if (lowBatteryCondition
)
5167 // Low battery wake, or received a low battery notification
5168 // while system is awake.
5172 if (clamshellExists
&& clamshellClosed
&& !acAdaptorConnected
)
5174 // Lid closed on battery power
5181 //******************************************************************************
5184 // Conditions that affect our wake/sleep decision has changed.
5185 // If conditions dictate that the system must remain awake, clamp power
5186 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
5187 // is TRUE, then remove the power clamp and allow the power state to drop
5189 //******************************************************************************
5191 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
5193 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
5194 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
);
5198 if ((sleepSlider
== 0) || !checkSystemCanSleep())
5200 changePowerStateToPriv(ON_STATE
);
5202 else if ( sleepASAP
)
5204 changePowerStateToPriv(SLEEP_STATE
);
5208 //******************************************************************************
5209 // dispatchPowerEvent
5211 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
5212 //******************************************************************************
5214 void IOPMrootDomain::dispatchPowerEvent(
5215 uint32_t event
, void * arg0
, uint64_t arg1
)
5217 DLOG("power event %u args %p 0x%llx\n", event
, arg0
, arg1
);
5222 case kPowerEventFeatureChanged
:
5223 messageClients(kIOPMMessageFeatureChange
, this);
5226 case kPowerEventReceivedPowerNotification
:
5227 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
5230 case kPowerEventSystemBootCompleted
:
5233 systemBooting
= false;
5235 // If lid is closed, re-send lid closed notification
5236 // now that booting is complete.
5237 if ( clamshellClosed
)
5239 handlePowerNotification(kLocalEvalClamshellCommand
);
5241 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
5245 case kPowerEventSystemShutdown
:
5246 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
5248 /* We set systemShutdown = true during shutdown
5249 to prevent sleep at unexpected times while loginwindow is trying
5250 to shutdown apps and while the OS is trying to transition to
5253 Set to true during shutdown, as soon as loginwindow shows
5254 the "shutdown countdown dialog", through individual app
5255 termination, and through black screen kernel shutdown.
5257 systemShutdown
= true;
5260 A shutdown was initiated, but then the shutdown
5261 was cancelled, clearing systemShutdown to false here.
5263 systemShutdown
= false;
5267 case kPowerEventUserDisabledSleep
:
5268 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
5271 case kPowerEventRegisterSystemCapabilityClient
:
5272 if (systemCapabilityNotifier
)
5274 systemCapabilityNotifier
->release();
5275 systemCapabilityNotifier
= 0;
5279 systemCapabilityNotifier
= (IONotifier
*) arg0
;
5280 systemCapabilityNotifier
->retain();
5282 /* intentional fall-through */
5284 case kPowerEventRegisterKernelCapabilityClient
:
5285 if (!_joinedCapabilityClients
)
5286 _joinedCapabilityClients
= OSSet::withCapacity(8);
5289 IONotifier
* notify
= (IONotifier
*) arg0
;
5290 if (_joinedCapabilityClients
)
5292 _joinedCapabilityClients
->setObject(notify
);
5293 synchronizePowerTree( kIOPMSyncNoChildNotify
);
5299 case kPowerEventPolicyStimulus
:
5302 int stimulus
= (uintptr_t) arg0
;
5303 evaluatePolicy( stimulus
, (uint32_t) arg1
);
5307 case kPowerEventAssertionCreate
:
5309 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
5314 case kPowerEventAssertionRelease
:
5316 pmAssertions
->handleReleaseAssertion(arg1
);
5320 case kPowerEventAssertionSetLevel
:
5322 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
5326 case kPowerEventQueueSleepWakeUUID
:
5327 handleQueueSleepWakeUUID((OSObject
*)arg0
);
5329 case kPowerEventPublishSleepWakeUUID
:
5330 handlePublishSleepWakeUUID((bool)arg0
);
5335 //******************************************************************************
5336 // systemPowerEventOccurred
5338 // The power controller is notifying us of a hardware-related power management
5339 // event that we must handle.
5341 // systemPowerEventOccurred covers the same functionality that
5342 // receivePowerNotification does; it simply provides a richer API for conveying
5343 // more information.
5344 //******************************************************************************
5346 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5347 const OSSymbol
*event
,
5350 IOReturn attempt
= kIOReturnSuccess
;
5351 OSNumber
*newNumber
= NULL
;
5354 return kIOReturnBadArgument
;
5356 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
5358 return kIOReturnInternalError
;
5360 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
5362 newNumber
->release();
5367 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5368 const OSSymbol
*event
,
5371 OSDictionary
*thermalsDict
= NULL
;
5372 bool shouldUpdate
= true;
5374 if (!event
|| !value
)
5375 return kIOReturnBadArgument
;
5378 // We reuse featuresDict Lock because it already exists and guards
5379 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
5380 // of stepping on that lock.
5381 if (featuresDictLock
) IOLockLock(featuresDictLock
);
5383 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
5385 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
5386 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
5388 thermalsDict
= OSDictionary::withCapacity(1);
5391 if (!thermalsDict
) {
5392 shouldUpdate
= false;
5396 thermalsDict
->setObject (event
, value
);
5398 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
5400 thermalsDict
->release();
5404 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
5407 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
5409 return kIOReturnSuccess
;
5412 //******************************************************************************
5413 // receivePowerNotification
5415 // The power controller is notifying us of a hardware-related power management
5416 // event that we must handle. This may be a result of an 'environment' interrupt
5417 // from the power mgt micro.
5418 //******************************************************************************
5420 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
5422 pmPowerStateQueue
->submitPowerEvent(
5423 kPowerEventReceivedPowerNotification
, (void *) msg
);
5424 return kIOReturnSuccess
;
5427 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
5429 bool eval_clamshell
= false;
5434 * Local (IOPMrootDomain only) eval clamshell command
5436 if (msg
& kLocalEvalClamshellCommand
)
5438 eval_clamshell
= true;
5444 if (msg
& kIOPMOverTemp
)
5446 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
5447 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
5453 if (msg
& kIOPMSleepNow
)
5455 privateSleepSystem (kIOPMSleepReasonSoftware
);
5461 if (msg
& kIOPMPowerEmergency
)
5463 lowBatteryCondition
= true;
5464 privateSleepSystem (kIOPMSleepReasonLowPower
);
5470 if (msg
& kIOPMClamshellOpened
)
5472 // Received clamshel open message from clamshell controlling driver
5473 // Update our internal state and tell general interest clients
5474 clamshellClosed
= false;
5475 clamshellExists
= true;
5477 // Don't issue a hid tickle when lid is open and polled on wake
5478 if (msg
& kIOPMSetValue
)
5484 informCPUStateChange(kInformLid
, 0);
5486 // Tell general interest clients
5487 sendClientClamshellNotification();
5489 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
5490 || (lastSleepReason
== kIOPMSleepReasonIdle
)
5491 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
5492 if (aborting
) userActivityCount
++;
5493 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
5498 * Send the clamshell interest notification since the lid is closing.
5500 if (msg
& kIOPMClamshellClosed
)
5502 // Received clamshel open message from clamshell controlling driver
5503 // Update our internal state and tell general interest clients
5504 clamshellClosed
= true;
5505 clamshellExists
= true;
5508 informCPUStateChange(kInformLid
, 1);
5510 // Tell general interest clients
5511 sendClientClamshellNotification();
5513 // And set eval_clamshell = so we can attempt
5514 eval_clamshell
= true;
5518 * Set Desktop mode (sent from graphics)
5520 * -> reevaluate lid state
5522 if (msg
& kIOPMSetDesktopMode
)
5524 desktopMode
= (0 != (msg
& kIOPMSetValue
));
5525 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
5527 sendClientClamshellNotification();
5529 // Re-evaluate the lid state
5530 if( clamshellClosed
)
5532 eval_clamshell
= true;
5537 * AC Adaptor connected
5539 * -> reevaluate lid state
5541 if (msg
& kIOPMSetACAdaptorConnected
)
5543 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
5544 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
5547 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
5549 // Tell BSD if AC is connected
5550 // 0 == external power source; 1 == on battery
5551 post_sys_powersource(acAdaptorConnected
? 0:1);
5553 sendClientClamshellNotification();
5555 // Re-evaluate the lid state
5556 if( clamshellClosed
)
5558 eval_clamshell
= true;
5561 // Lack of AC may have latched a display wrangler tickle.
5562 // This mirrors the hardware's USB wake event latch, where a latched
5563 // USB wake event followed by an AC attach will trigger a full wake.
5564 latchDisplayWranglerTickle( false );
5568 * Enable Clamshell (external display disappear)
5570 * -> reevaluate lid state
5572 if (msg
& kIOPMEnableClamshell
)
5574 // Re-evaluate the lid state
5575 // System should sleep on external display disappearance
5576 // in lid closed operation.
5577 if( clamshellClosed
&& (true == clamshellDisabled
) )
5579 eval_clamshell
= true;
5582 clamshellDisabled
= false;
5584 sendClientClamshellNotification();
5588 * Disable Clamshell (external display appeared)
5589 * We don't bother re-evaluating clamshell state. If the system is awake,
5590 * the lid is probably open.
5592 if (msg
& kIOPMDisableClamshell
)
5594 clamshellDisabled
= true;
5596 sendClientClamshellNotification();
5600 * Evaluate clamshell and SLEEP if appropiate
5602 if ( eval_clamshell
&& shouldSleepOnClamshellClosed() )
5606 privateSleepSystem (kIOPMSleepReasonClamshell
);
5608 else if ( eval_clamshell
)
5610 evaluatePolicy( kStimulusDarkWakeEvaluate
);
5616 if (msg
& kIOPMPowerButton
)
5618 if (!wranglerAsleep
)
5620 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
5621 // Check that power button sleep is enabled
5623 if( kOSBooleanTrue
!= getProperty(pbs
))
5624 privateSleepSystem (kIOPMSleepReasonPowerButton
);
5632 //******************************************************************************
5635 // Evaluate root-domain policy in response to external changes.
5636 //******************************************************************************
5638 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
5642 int idleSleepEnabled
: 1;
5643 int idleSleepDisabled
: 1;
5644 int displaySleep
: 1;
5645 int sleepDelayChanged
: 1;
5646 int evaluateDarkWake
: 1;
5651 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
5658 case kStimulusDisplayWranglerSleep
:
5659 if (!wranglerAsleep
)
5661 wranglerAsleep
= true;
5662 clock_get_uptime(&wranglerSleepTime
);
5663 flags
.bit
.displaySleep
= true;
5667 case kStimulusDisplayWranglerWake
:
5668 wranglerAsleep
= false;
5669 flags
.bit
.idleSleepDisabled
= true;
5672 case kStimulusAggressivenessChanged
:
5674 unsigned long minutesToIdleSleep
= 0;
5675 unsigned long minutesToDisplayDim
= 0;
5676 unsigned long minutesDelta
= 0;
5678 // Fetch latest display and system sleep slider values.
5679 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
5680 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
5681 DLOG("aggressiveness changed: system %u->%u, display %u\n",
5682 (uint32_t) sleepSlider
,
5683 (uint32_t) minutesToIdleSleep
,
5684 (uint32_t) minutesToDisplayDim
);
5686 DLOG("idle time -> %ld secs (ena %d)\n",
5687 idleSeconds
, (minutesToIdleSleep
!= 0));
5689 if (0x7fffffff == minutesToIdleSleep
)
5690 minutesToIdleSleep
= idleSeconds
;
5692 // How long to wait before sleeping the system once
5693 // the displays turns off is indicated by 'extraSleepDelay'.
5695 if ( minutesToIdleSleep
> minutesToDisplayDim
)
5696 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
5698 if ((sleepSlider
== 0) && (minutesToIdleSleep
!= 0))
5699 flags
.bit
.idleSleepEnabled
= true;
5701 if ((sleepSlider
!= 0) && (minutesToIdleSleep
== 0))
5702 flags
.bit
.idleSleepDisabled
= true;
5704 if ((minutesDelta
!= extraSleepDelay
) &&
5705 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
5706 flags
.bit
.sleepDelayChanged
= true;
5708 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
5709 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
5711 // Reconsider decision to remain in dark wake
5712 flags
.bit
.evaluateDarkWake
= true;
5715 sleepSlider
= minutesToIdleSleep
;
5716 extraSleepDelay
= minutesDelta
;
5719 case kStimulusDemandSystemSleep
:
5720 changePowerStateWithOverrideTo( SLEEP_STATE
);
5723 case kStimulusAllowSystemSleepChanged
:
5724 // FIXME: de-compose to change flags.
5728 case kStimulusDarkWakeActivityTickle
:
5729 if (false == wranglerTickled
)
5731 uint32_t options
= 0;
5732 IOService
* pciRoot
= 0;
5734 if (rejectWranglerTickle
)
5736 DLOG("rejected tickle, type %u capability %x:%x\n",
5737 _systemTransitionType
,
5738 _currentCapability
, _pendingCapability
);
5742 if (latchDisplayWranglerTickle(true))
5744 DLOG("latched tickle\n");
5748 _desiredCapability
|=
5749 (kIOPMSystemCapabilityGraphics
|
5750 kIOPMSystemCapabilityAudio
);
5752 if ((kSystemTransitionWake
== _systemTransitionType
) &&
5753 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
5754 !graphicsSuppressed
)
5756 DLOG("Promoting to full wake\n");
5758 // Elevate to full wake while waking up to dark wake.
5759 // PM will hold off notifying the graphics subsystem about
5760 // system wake as late as possible, so if a HID event does
5761 // arrive, we can turn on graphics on this wake cycle, and
5762 // not have to wait till the following cycle. That latency
5763 // can be huge on some systems. However, once any graphics
5764 // suppression has taken effect, it is too late. All other
5765 // graphics devices must be similarly suppressed. But the
5766 // delay till the following cycle should be very short.
5768 _pendingCapability
|=
5769 (kIOPMSystemCapabilityGraphics
|
5770 kIOPMSystemCapabilityAudio
);
5772 // Immediately bring up audio and graphics.
5773 pciRoot
= pciHostBridgeDriver
;
5775 // Notify clients about full wake.
5776 _systemMessageClientMask
= kSystemMessageClientAll
;
5777 tellClients(kIOMessageSystemWillPowerOn
);
5780 // Unsafe to cancel once graphics was powered.
5781 // If system woke from dark wake, the return to sleep can
5782 // be cancelled. But "awake -> dark -> sleep" transition
5783 // cannot be cancelled.
5785 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
5786 options
|= kIOPMSyncCancelPowerDown
;
5789 synchronizePowerTree( options
, pciRoot
);
5790 wranglerTickled
= true;
5791 // IOGraphics doesn't lit the display even though graphics
5792 // is enanbled in kIOMessageSystemCapabilityChange message(radar 9502104)
5793 // So, do an explicit activity tickle
5795 wrangler
->activityTickle(0,0);
5797 if (logWranglerTickle
)
5802 clock_get_uptime(&now
);
5803 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
5804 absolutetime_to_nanoseconds(now
, &nsec
);
5805 MSG("HID tickle %u ms\n",
5806 ((int)((nsec
) / 1000000ULL)));
5807 logWranglerTickle
= false;
5812 case kStimulusDarkWakeEntry
:
5813 case kStimulusDarkWakeReentry
:
5814 // Any system transitions since the last dark wake transition
5815 // will invalid the stimulus.
5817 if (arg
== _systemStateGeneration
)
5819 DLOG("dark wake entry\n");
5820 systemDarkWake
= true;
5821 wranglerAsleep
= true;
5822 clock_get_uptime(&wranglerSleepTime
);
5824 // Always accelerate disk spindown while in dark wake,
5825 // even if system does not support/allow sleep.
5827 cancelIdleSleepTimer();
5828 setQuickSpinDownTimeout();
5829 flags
.bit
.evaluateDarkWake
= true;
5833 case kStimulusDarkWakeEvaluate
:
5836 flags
.bit
.evaluateDarkWake
= true;
5838 #if !DARK_TO_FULL_EVALUATE_CLAMSHELL
5841 // Not through kLocalEvalClamshellCommand to avoid loop.
5842 if (clamshellClosed
&& shouldSleepOnClamshellClosed() &&
5843 checkSystemCanSleep(true))
5845 privateSleepSystem( kIOPMSleepReasonClamshell
);
5851 } /* switch(stimulus) */
5853 if (flags
.bit
.evaluateDarkWake
&& !wranglerTickled
)
5855 if (darkWakeToSleepASAP
||
5856 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
5858 // System currently in dark wake, and no children and
5859 // assertion prevent system sleep.
5861 if (checkSystemCanSleep(true))
5863 if (lowBatteryCondition
)
5865 lastSleepReason
= kIOPMSleepReasonLowPower
;
5866 setProperty(kRootDomainSleepReasonKey
, kIOPMLowPowerSleepKey
);
5868 else if (darkWakeMaintenance
)
5870 lastSleepReason
= kIOPMSleepReasonMaintenance
;
5871 setProperty(kRootDomainSleepReasonKey
, kIOPMMaintenanceSleepKey
);
5873 else if (darkWakeSleepService
)
5875 lastSleepReason
= kIOPMSleepReasonSleepServiceExit
;
5876 setProperty(kRootDomainSleepReasonKey
, kIOPMSleepServiceExitKey
);
5878 changePowerStateWithOverrideTo( SLEEP_STATE
);
5882 // Parked in dark wake, a tickle will return to full wake
5883 rejectWranglerTickle
= false;
5885 } else // non-maintenance (network) dark wake
5887 if (checkSystemCanSleep(true))
5889 // Release power clamp, and wait for children idle.
5890 adjustPowerState(true);
5894 changePowerStateToPriv(ON_STATE
);
5896 rejectWranglerTickle
= false;
5902 // The rest are irrelevant while system is in dark wake.
5906 if (flags
.bit
.displaySleep
|| flags
.bit
.sleepDelayChanged
)
5908 bool cancelQuickSpindown
= false;
5910 if (flags
.bit
.sleepDelayChanged
)
5912 DLOG("extra sleep timer changed\n");
5913 cancelIdleSleepTimer();
5914 cancelQuickSpindown
= true;
5918 DLOG("display sleep\n");
5921 if (wranglerAsleep
&& !wranglerSleepIgnored
)
5923 if ( extraSleepDelay
)
5925 // Start a timer here if the System Sleep timer is greater
5926 // than the Display Sleep timer.
5928 startIdleSleepTimer(gRootDomain
->extraSleepDelay
* 60);
5930 else if ( sleepSlider
)
5932 // Accelerate disk spindown if system sleep and display sleep
5933 // sliders are set to the same value (e.g. both set to 5 min),
5934 // and display is about to go dark. Check the system sleep is
5935 // not set to never sleep. Disk sleep setting is ignored.
5937 setQuickSpinDownTimeout();
5938 cancelQuickSpindown
= false;
5942 if (cancelQuickSpindown
)
5943 restoreUserSpinDownTimeout();
5946 if (flags
.bit
.idleSleepEnabled
)
5948 DLOG("idle sleep timer enabled\n");
5951 changePowerStateToPriv(ON_STATE
);
5954 startIdleSleepTimer( idleSeconds
);
5959 // Start idle sleep timer if wrangler went to sleep
5960 // while system sleep was disabled. Disk spindown is
5961 // accelerated upon timer expiration.
5967 uint32_t minutesSinceDisplaySleep
= 0;
5968 uint32_t sleepDelay
;
5970 clock_get_uptime(&now
);
5971 if (CMP_ABSOLUTETIME(&now
, &wranglerSleepTime
) > 0)
5973 SUB_ABSOLUTETIME(&now
, &wranglerSleepTime
);
5974 absolutetime_to_nanoseconds(now
, &nanos
);
5975 minutesSinceDisplaySleep
= nanos
/ (60000000000ULL);
5978 if (extraSleepDelay
> minutesSinceDisplaySleep
)
5980 sleepDelay
= extraSleepDelay
- minutesSinceDisplaySleep
;
5984 sleepDelay
= 1; // 1 min
5987 startIdleSleepTimer(sleepDelay
* 60);
5988 DLOG("display slept %u min, set idle timer to %u min\n",
5989 minutesSinceDisplaySleep
, sleepDelay
);
5994 if (flags
.bit
.idleSleepDisabled
)
5996 DLOG("idle sleep timer disabled\n");
5997 cancelIdleSleepTimer();
5998 restoreUserSpinDownTimeout();
6003 //******************************************************************************
6004 // evaluateAssertions
6006 //******************************************************************************
6007 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
6009 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
6011 messageClients(kIOPMMessageDriverAssertionsChanged
);
6013 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
6016 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
6018 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
6019 wrangler
->setIgnoreIdleTimer( value
);
6022 if (changedBits
& kIOPMDriverAssertionCPUBit
)
6023 evaluatePolicy(kStimulusDarkWakeEvaluate
);
6029 //******************************************************************************
6032 //******************************************************************************
6034 void IOPMrootDomain::pmStatsRecordEvent(
6036 AbsoluteTime timestamp
)
6038 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
6039 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
6043 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
6045 absolutetime_to_nanoseconds(timestamp
, &nsec
);
6047 switch (eventIndex
) {
6048 case kIOPMStatsHibernateImageWrite
:
6050 pmStats
.hibWrite
.start
= nsec
;
6052 pmStats
.hibWrite
.stop
= nsec
;
6055 delta
= pmStats
.hibWrite
.stop
- pmStats
.hibWrite
.start
;
6056 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
6059 case kIOPMStatsHibernateImageRead
:
6061 pmStats
.hibRead
.start
= nsec
;
6063 pmStats
.hibRead
.stop
= nsec
;
6066 delta
= pmStats
.hibRead
.stop
- pmStats
.hibRead
.start
;
6067 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
6074 * Appends a record of the application response to
6075 * IOPMrootDomain::pmStatsAppResponses
6077 void IOPMrootDomain::pmStatsRecordApplicationResponse(
6078 const OSSymbol
*response
,
6084 OSDictionary
*responseDescription
= NULL
;
6085 OSNumber
*delayNum
= NULL
;
6086 OSNumber
*pidNum
= NULL
;
6087 OSNumber
*msgNum
= NULL
;
6088 const OSSymbol
*appname
;
6089 const OSSymbol
*entryName
;
6090 OSObject
*entryType
;
6093 if (!pmStatsAppResponses
|| pmStatsAppResponses
->getCount() > 50)
6097 while ((responseDescription
= (OSDictionary
*) pmStatsAppResponses
->getObject(i
++)))
6099 entryType
= responseDescription
->getObject(_statsResponseTypeKey
);
6100 entryName
= (OSSymbol
*) responseDescription
->getObject(_statsNameKey
);
6101 if (entryName
&& (entryType
== response
) && entryName
->isEqualTo(name
))
6103 OSNumber
* entryValue
;
6104 entryValue
= (OSNumber
*) responseDescription
->getObject(_statsTimeMSKey
);
6105 if (entryValue
&& (entryValue
->unsigned32BitValue() < delay_ms
))
6106 entryValue
->setValue(delay_ms
);
6111 responseDescription
= OSDictionary::withCapacity(5);
6112 if (responseDescription
)
6115 responseDescription
->setObject(_statsResponseTypeKey
, response
);
6118 if (messageType
!= 0) {
6119 msgNum
= OSNumber::withNumber(messageType
, 32);
6121 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
6126 if (name
&& (strlen(name
) > 0))
6128 appname
= OSSymbol::withCString(name
);
6130 responseDescription
->setObject(_statsNameKey
, appname
);
6135 if (app_pid
!= -1) {
6136 pidNum
= OSNumber::withNumber(app_pid
, 32);
6138 responseDescription
->setObject(_statsPIDKey
, pidNum
);
6143 delayNum
= OSNumber::withNumber(delay_ms
, 32);
6145 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
6146 delayNum
->release();
6149 if (pmStatsAppResponses
) {
6150 pmStatsAppResponses
->setObject(responseDescription
);
6153 responseDescription
->release();
6159 // MARK: PMTraceWorker
6161 //******************************************************************************
6162 // TracePoint support
6164 //******************************************************************************
6166 #define kIOPMRegisterNVRAMTracePointHandlerKey \
6167 "IOPMRegisterNVRAMTracePointHandler"
6169 IOReturn
IOPMrootDomain::callPlatformFunction(
6170 const OSSymbol
* functionName
,
6171 bool waitForFunction
,
6172 void * param1
, void * param2
,
6173 void * param3
, void * param4
)
6175 if (pmTracer
&& functionName
&&
6176 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
6177 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
6179 uint32_t tracePointPhases
, tracePointPCI
;
6180 uint64_t statusCode
;
6182 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
6183 pmTracer
->tracePointTarget
= (void *) param2
;
6184 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
6185 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
6186 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
6187 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
6189 MSG("Sleep failure code 0x%08x 0x%08x\n",
6190 tracePointPCI
, tracePointPhases
);
6192 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
6193 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
6195 return kIOReturnSuccess
;
6197 else if (functionName
&&
6198 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
6200 if (_sleepPolicyHandler
)
6201 return kIOReturnExclusiveAccess
;
6203 return kIOReturnBadArgument
;
6204 _sleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
6205 _sleepPolicyTarget
= (void *) param2
;
6206 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
6207 return kIOReturnSuccess
;
6210 return super::callPlatformFunction(
6211 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
6214 void IOPMrootDomain::tracePoint( uint8_t point
)
6217 pmTracer
->tracePoint(point
);
6220 void IOPMrootDomain::tracePoint( uint8_t point
, uint8_t data
)
6223 pmTracer
->tracePoint(point
, data
);
6226 void IOPMrootDomain::traceDetail( uint32_t detail
)
6229 pmTracer
->traceDetail( detail
);
6232 //******************************************************************************
6233 // PMTraceWorker Class
6235 //******************************************************************************
6238 #define super OSObject
6239 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
6241 #define kPMBestGuessPCIDevicesCount 25
6242 #define kPMMaxRTCBitfieldSize 32
6244 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
6248 me
= OSTypeAlloc( PMTraceWorker
);
6249 if (!me
|| !me
->init())
6254 DLOG("PMTraceWorker %p\n", me
);
6256 // Note that we cannot instantiate the PCI device -> bit mappings here, since
6257 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
6258 // this dictionary lazily.
6260 me
->pciDeviceBitMappings
= NULL
;
6261 me
->pciMappingLock
= IOLockAlloc();
6262 me
->tracePhase
= kIOPMTracePointSystemUp
;
6263 me
->loginWindowPhase
= 0;
6264 me
->traceData32
= 0;
6268 void PMTraceWorker::RTC_TRACE(void)
6270 if (tracePointHandler
&& tracePointTarget
)
6274 wordA
= (tracePhase
<< 24) | (loginWindowPhase
<< 16) |
6277 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
6278 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
6282 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
6284 const OSSymbol
* deviceName
;
6287 IOLockLock(pciMappingLock
);
6289 if (!pciDeviceBitMappings
)
6291 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
6292 if (!pciDeviceBitMappings
)
6296 // Check for bitmask overflow.
6297 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
6300 if ((deviceName
= pciDevice
->copyName()) &&
6301 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
6302 pciDeviceBitMappings
->setObject(deviceName
))
6304 index
= pciDeviceBitMappings
->getCount() - 1;
6305 _LOG("PMTrace PCI array: set object %s => %d\n",
6306 deviceName
->getCStringNoCopy(), index
);
6309 deviceName
->release();
6310 if (!addedToRegistry
&& (index
>= 0))
6311 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
6314 IOLockUnlock(pciMappingLock
);
6318 bool PMTraceWorker::serialize(OSSerialize
*s
) const
6321 if (pciDeviceBitMappings
)
6323 IOLockLock(pciMappingLock
);
6324 ok
= pciDeviceBitMappings
->serialize(s
);
6325 IOLockUnlock(pciMappingLock
);
6330 void PMTraceWorker::tracePoint(uint8_t phase
)
6332 // clear trace detail when phase begins
6333 if (tracePhase
!= phase
)
6338 DLOG("trace point 0x%02x\n", tracePhase
);
6342 void PMTraceWorker::tracePoint(uint8_t phase
, uint8_t data8
)
6344 // clear trace detail when phase begins
6345 if (tracePhase
!= phase
)
6351 DLOG("trace point 0x%02x 0x%02x\n", tracePhase
, traceData8
);
6355 void PMTraceWorker::traceDetail(uint32_t detail
)
6357 if (kIOPMTracePointSleepPriorityClients
!= tracePhase
)
6360 traceData32
= detail
;
6361 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
6366 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
6368 loginWindowPhase
= phase
;
6370 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
6374 void PMTraceWorker::tracePCIPowerChange(
6375 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
6378 uint32_t expectedFlag
;
6380 // Ignore PCI changes outside of system sleep/wake.
6381 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
6382 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
6385 // Only record the WillChange transition when going to sleep,
6386 // and the DidChange on the way up.
6387 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
6388 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
6389 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
6390 if (changeFlags
!= expectedFlag
)
6393 // Mark this device off in our bitfield
6394 if (bitNum
< kPMMaxRTCBitfieldSize
)
6396 bitMask
= (1 << bitNum
);
6398 if (kPowerChangeStart
== type
)
6400 traceData32
|= bitMask
;
6401 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
6402 service
->getName(), bitNum
, bitMask
, traceData32
);
6406 traceData32
&= ~bitMask
;
6407 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
6408 service
->getName(), bitNum
, bitMask
, traceData32
);
6416 // MARK: PMHaltWorker
6418 //******************************************************************************
6419 // PMHaltWorker Class
6421 //******************************************************************************
6423 static unsigned int gPMHaltBusyCount
;
6424 static unsigned int gPMHaltIdleCount
;
6425 static int gPMHaltDepth
;
6426 static unsigned long gPMHaltEvent
;
6427 static IOLock
* gPMHaltLock
= 0;
6428 static OSArray
* gPMHaltArray
= 0;
6429 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
6431 PMHaltWorker
* PMHaltWorker::worker( void )
6437 me
= OSTypeAlloc( PMHaltWorker
);
6438 if (!me
|| !me
->init())
6441 me
->lock
= IOLockAlloc();
6445 DLOG("PMHaltWorker %p\n", me
);
6446 me
->retain(); // thread holds extra retain
6447 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
6452 thread_deallocate(thread
);
6457 if (me
) me
->release();
6461 void PMHaltWorker::free( void )
6463 DLOG("PMHaltWorker free %p\n", this);
6469 return OSObject::free();
6472 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
6474 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
6476 IOLockLock( gPMHaltLock
);
6478 me
->depth
= gPMHaltDepth
;
6479 IOLockUnlock( gPMHaltLock
);
6481 while (me
->depth
>= 0)
6483 PMHaltWorker::work( me
);
6485 IOLockLock( gPMHaltLock
);
6486 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
6488 // This is the last thread to finish work on this level,
6489 // inform everyone to start working on next lower level.
6491 me
->depth
= gPMHaltDepth
;
6492 gPMHaltIdleCount
= 0;
6493 thread_wakeup((event_t
) &gPMHaltIdleCount
);
6497 // One or more threads are still working on this level,
6498 // this thread must wait.
6499 me
->depth
= gPMHaltDepth
- 1;
6501 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
6502 } while (me
->depth
!= gPMHaltDepth
);
6504 IOLockUnlock( gPMHaltLock
);
6507 // No more work to do, terminate thread
6508 DLOG("All done for worker: %p (visits = %u)\n", me
, me
->visits
);
6509 thread_wakeup( &gPMHaltDepth
);
6513 void PMHaltWorker::work( PMHaltWorker
* me
)
6515 IOService
* service
;
6517 AbsoluteTime startTime
;
6526 // Claim an unit of work from the shared pool
6527 IOLockLock( gPMHaltLock
);
6528 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
6531 service
= (IOService
*)inner
->getAnyObject();
6535 inner
->removeObject(service
);
6538 IOLockUnlock( gPMHaltLock
);
6540 break; // no more work at this depth
6542 clock_get_uptime(&startTime
);
6544 if (!service
->isInactive() &&
6545 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
6547 IOLockLock(me
->lock
);
6548 me
->startTime
= startTime
;
6549 me
->service
= service
;
6550 me
->timeout
= false;
6551 IOLockUnlock(me
->lock
);
6553 service
->systemWillShutdown( gPMHaltEvent
);
6555 // Wait for driver acknowledgement
6556 IOLockLock(me
->lock
);
6557 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
6559 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
6562 timeout
= me
->timeout
;
6563 IOLockUnlock(me
->lock
);
6566 deltaTime
= computeDeltaTimeMS(&startTime
);
6567 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
6568 (gIOKitDebug
& kIOLogPMRootDomain
))
6570 LOG("%s driver %s (%p) took %u ms\n",
6571 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
6572 "PowerOff" : "Restart",
6573 service
->getName(), service
,
6574 (uint32_t) deltaTime
);
6582 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
6585 AbsoluteTime startTime
;
6586 AbsoluteTime endTime
;
6590 IOLockLock(me
->lock
);
6591 if (me
->service
&& !me
->timeout
)
6593 startTime
= me
->startTime
;
6595 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
6597 SUB_ABSOLUTETIME(&endTime
, &startTime
);
6598 absolutetime_to_nanoseconds(endTime
, &nano
);
6600 if (nano
> 3000000000ULL)
6603 MSG("%s still waiting on %s\n",
6604 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
6605 "PowerOff" : "Restart",
6606 me
->service
->getName());
6609 IOLockUnlock(me
->lock
);
6613 //******************************************************************************
6614 // acknowledgeSystemWillShutdown
6616 // Acknowledgement from drivers that they have prepared for shutdown/restart.
6617 //******************************************************************************
6619 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
6621 PMHaltWorker
* worker
;
6627 //DLOG("%s acknowledged\n", from->getName());
6628 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
6631 worker
= (PMHaltWorker
*) prop
;
6632 IOLockLock(worker
->lock
);
6633 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
6634 thread_wakeup((event_t
) worker
);
6635 IOLockUnlock(worker
->lock
);
6640 DLOG("%s acknowledged without worker property\n",
6646 //******************************************************************************
6647 // notifySystemShutdown
6649 // Notify all objects in PM tree that system will shutdown or restart
6650 //******************************************************************************
6653 notifySystemShutdown( IOService
* root
, unsigned long event
)
6655 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
6656 IORegistryIterator
* iter
;
6657 IORegistryEntry
* entry
;
6660 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
6661 AbsoluteTime deadline
;
6662 unsigned int totalNodes
= 0;
6664 unsigned int rootDepth
;
6665 unsigned int numWorkers
;
6671 DLOG("%s event = %lx\n", __FUNCTION__
, event
);
6673 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
6675 // Iterate the entire PM tree starting from root
6677 rootDepth
= root
->getDepth( gIOPowerPlane
);
6678 if (!rootDepth
) goto done
;
6680 // debug - for repeated test runs
6681 while (PMHaltWorker::metaClass
->getInstanceCount())
6686 gPMHaltArray
= OSArray::withCapacity(40);
6687 if (!gPMHaltArray
) goto done
;
6690 gPMHaltArray
->flushCollection();
6694 gPMHaltLock
= IOLockAlloc();
6695 if (!gPMHaltLock
) goto done
;
6698 if (!gPMHaltClientAcknowledgeKey
)
6700 gPMHaltClientAcknowledgeKey
=
6701 OSSymbol::withCStringNoCopy("PMShutdown");
6702 if (!gPMHaltClientAcknowledgeKey
) goto done
;
6705 gPMHaltEvent
= event
;
6707 // Depth-first walk of PM plane
6709 iter
= IORegistryIterator::iterateOver(
6710 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
6714 while ((entry
= iter
->getNextObject()))
6716 node
= OSDynamicCast(IOService
, entry
);
6721 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
6724 depth
= node
->getDepth( gIOPowerPlane
);
6725 if (depth
<= rootDepth
)
6730 // adjust to zero based depth
6731 depth
-= (rootDepth
+ 1);
6733 // gPMHaltArray is an array of containers, each container
6734 // refers to nodes with the same depth.
6736 count
= gPMHaltArray
->getCount();
6737 while (depth
>= count
)
6739 // expand array and insert placeholders
6740 gPMHaltArray
->setObject(PLACEHOLDER
);
6743 count
= gPMHaltArray
->getCount();
6746 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
6747 if (inner
== PLACEHOLDER
)
6749 inner
= OSSet::withCapacity(40);
6752 gPMHaltArray
->replaceObject(depth
, inner
);
6757 // PM nodes that appear more than once in the tree will have
6758 // the same depth, OSSet will refuse to add the node twice.
6760 ok
= inner
->setObject(node
);
6763 DLOG("Skipped PM node %s\n", node
->getName());
6769 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
6772 if (inner
!= PLACEHOLDER
)
6773 count
= inner
->getCount();
6774 DLOG("Nodes at depth %u = %u\n", i
, count
);
6777 // strip placeholders (not all depths are populated)
6779 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
6781 if (inner
== PLACEHOLDER
)
6783 gPMHaltArray
->removeObject(i
);
6786 count
= inner
->getCount();
6787 if (count
> numWorkers
)
6789 totalNodes
+= count
;
6793 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
6796 gPMHaltBusyCount
= 0;
6797 gPMHaltIdleCount
= 0;
6798 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
6800 // Create multiple workers (and threads)
6802 if (numWorkers
> kPMHaltMaxWorkers
)
6803 numWorkers
= kPMHaltMaxWorkers
;
6805 DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
6806 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
6808 for (unsigned int i
= 0; i
< numWorkers
; i
++)
6809 workers
[i
] = PMHaltWorker::worker();
6811 // Wait for workers to exhaust all available work
6813 IOLockLock(gPMHaltLock
);
6814 while (gPMHaltDepth
>= 0)
6816 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
6818 waitResult
= IOLockSleepDeadline(
6819 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
6820 if (THREAD_TIMED_OUT
== waitResult
)
6823 clock_get_uptime(&now
);
6825 IOLockUnlock(gPMHaltLock
);
6826 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
6829 PMHaltWorker::checkTimeout(workers
[i
], &now
);
6831 IOLockLock(gPMHaltLock
);
6834 IOLockUnlock(gPMHaltLock
);
6836 // Release all workers
6838 for (unsigned int i
= 0; i
< numWorkers
; i
++)
6841 workers
[i
]->release();
6842 // worker also retained by it's own thread
6846 DLOG("%s done\n", __FUNCTION__
);
6850 //*********************************************************************************
6851 // Sleep/Wake logging
6853 //*********************************************************************************
6855 IOMemoryDescriptor
*IOPMrootDomain::getPMTraceMemoryDescriptor(void)
6858 return timeline
->getPMTraceMemoryDescriptor();
6863 // Forwards external reports of detailed events to IOPMTimeline
6864 IOReturn
IOPMrootDomain::recordPMEvent(PMEventDetails
*details
)
6866 if (timeline
&& details
) {
6870 // Record a detailed driver power change event, or...
6871 if(details
->eventClassifier
== kIOPMEventClassDriverEvent
) {
6872 rc
= timeline
->recordDetailedPowerEvent( details
);
6875 // Record a system power management event
6876 else if(details
->eventClassifier
== kIOPMEventClassSystemEvent
) {
6877 rc
= timeline
->recordSystemPowerEvent( details
);
6880 return kIOReturnBadArgument
;
6883 // If we get to record this message, then we've reached the
6884 // end of another successful Sleep --> Wake cycle
6885 // At this point, we pat ourselves in the back and allow
6886 // our Sleep --> Wake UUID to be published
6887 if(details
->eventType
== kIOPMEventTypeWakeDone
) {
6888 timeline
->setSleepCycleInProgressFlag(false);
6892 // Check if its time to clear the timeline buffer
6893 if(getProperty(kIOPMSleepWakeUUIDKey)
6894 && timeline->isSleepCycleInProgress() == false
6895 && timeline->getNumEventsLoggedThisPeriod() > 500) {
6897 // Clear the old UUID
6898 if(pmPowerStateQueue) {
6899 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)false );
6906 return kIOReturnNotReady
;
6909 IOReturn
IOPMrootDomain::recordAndReleasePMEvent(PMEventDetails
*details
)
6911 IOReturn ret
= kIOReturnBadArgument
;
6915 ret
= recordPMEvent(details
);
6922 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6924 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
6925 IOPMDriverAssertionType whichAssertionBits
,
6926 IOPMDriverAssertionLevel assertionLevel
,
6927 IOService
*ownerService
,
6928 const char *ownerDescription
)
6931 IOPMDriverAssertionID newAssertion
;
6936 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
6938 if (kIOReturnSuccess
== ret
)
6939 return newAssertion
;
6944 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
6947 return kIOReturnInternalError
;
6949 return pmAssertions
->releaseAssertion(releaseAssertion
);
6952 IOReturn
IOPMrootDomain::setPMAssertionLevel(
6953 IOPMDriverAssertionID assertionID
,
6954 IOPMDriverAssertionLevel assertionLevel
)
6956 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
6959 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
6961 IOPMDriverAssertionType sysLevels
;
6963 if (!pmAssertions
|| whichAssertion
== 0)
6964 return kIOPMDriverAssertionLevelOff
;
6966 sysLevels
= pmAssertions
->getActivatedAssertions();
6968 // Check that every bit set in argument 'whichAssertion' is asserted
6969 // in the aggregate bits.
6970 if ((sysLevels
& whichAssertion
) == whichAssertion
)
6971 return kIOPMDriverAssertionLevelOn
;
6973 return kIOPMDriverAssertionLevelOff
;
6976 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
6979 return kIOReturnNotFound
;
6981 return pmAssertions
->setUserAssertionLevels(inLevels
);
6984 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
6988 pmAssertions
->publishProperties();
6990 return( IOService::serializeProperties(s
) );
6993 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6996 // MARK: PMSettingHandle
6998 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
7000 void PMSettingHandle::free( void )
7004 pmso
->clientHandleFreed();
7013 // MARK: PMSettingObject
7016 #define super OSObject
7017 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
7020 * Static constructor/initializer for PMSettingObject
7022 PMSettingObject
*PMSettingObject::pmSettingObject(
7023 IOPMrootDomain
*parent_arg
,
7024 IOPMSettingControllerCallback handler_arg
,
7025 OSObject
*target_arg
,
7026 uintptr_t refcon_arg
,
7027 uint32_t supportedPowerSources
,
7028 const OSSymbol
* settings
[],
7029 OSObject
**handle_obj
)
7031 uint32_t settingCount
= 0;
7032 PMSettingObject
*pmso
= 0;
7033 PMSettingHandle
*pmsh
= 0;
7035 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
7038 // count OSSymbol entries in NULL terminated settings array
7039 while (settings
[settingCount
]) {
7042 if (0 == settingCount
)
7045 pmso
= new PMSettingObject
;
7046 if (!pmso
|| !pmso
->init())
7049 pmsh
= new PMSettingHandle
;
7050 if (!pmsh
|| !pmsh
->init())
7053 queue_init(&pmso
->calloutQueue
);
7054 pmso
->parent
= parent_arg
;
7055 pmso
->func
= handler_arg
;
7056 pmso
->target
= target_arg
;
7057 pmso
->refcon
= refcon_arg
;
7058 pmso
->settingCount
= settingCount
;
7060 pmso
->retain(); // handle holds a retain on pmso
7064 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
7065 if (pmso
->publishedFeatureID
) {
7066 for (unsigned int i
=0; i
<settingCount
; i
++) {
7067 // Since there is now at least one listener to this setting, publish
7068 // PM root domain support for it.
7069 parent_arg
->publishPMSetting( settings
[i
],
7070 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
7078 if (pmso
) pmso
->release();
7079 if (pmsh
) pmsh
->release();
7083 void PMSettingObject::free( void )
7085 if (publishedFeatureID
) {
7086 for (uint32_t i
=0; i
<settingCount
; i
++) {
7087 if (publishedFeatureID
[i
]) {
7088 parent
->removePublishedFeature( publishedFeatureID
[i
] );
7092 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
7098 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
7100 (*func
)(target
, type
, object
, refcon
);
7103 void PMSettingObject::clientHandleFreed( void )
7105 parent
->deregisterPMSettingObject(this);
7109 // MARK: IOPMTimeline
7112 #define super OSObject
7114 //*********************************************************************************
7115 //*********************************************************************************
7116 //*********************************************************************************
7118 IOPMTimeline
*IOPMTimeline::timeline(IOPMrootDomain
*root_domain
)
7120 IOPMTimeline
*myself
;
7125 myself
= new IOPMTimeline
;
7128 myself
->owner
= root_domain
;
7135 bool IOPMTimeline::init(void)
7137 if (!super::init()) {
7141 logLock
= IOLockAlloc();
7143 // Fresh timeline, no events logged yet
7144 this->numEventsLoggedThisPeriod
= 0;
7145 this->sleepCycleInProgress
= false;
7147 //this->setEventsRecordingLevel(1); // TODO
7148 this->setEventsTrackedCount(kIOPMDefaultSystemEventsTracked
);
7153 void IOPMTimeline::free(void)
7155 if (pmTraceMemoryDescriptor
) {
7156 pmTraceMemoryDescriptor
->release();
7157 pmTraceMemoryDescriptor
= NULL
;
7160 IOLockFree(logLock
);
7165 IOMemoryDescriptor
*IOPMTimeline::getPMTraceMemoryDescriptor()
7167 return pmTraceMemoryDescriptor
;
7170 //*********************************************************************************
7171 //*********************************************************************************
7172 //*********************************************************************************
7174 bool IOPMTimeline::setProperties(OSDictionary
*d
)
7177 OSBoolean
*b
= NULL
;
7178 bool changed
= false;
7180 /* Changes size of detailed events buffer */
7181 n
= (OSNumber
*)d
->getObject(kIOPMTimelineSystemNumberTrackedKey
);
7182 if (OSDynamicCast(OSNumber
, n
))
7185 this->setEventsTrackedCount(n
->unsigned32BitValue());
7189 /* enables or disables system events */
7190 b
= (OSBoolean
*)d
->getObject(kIOPMTimelineEnabledKey
);
7194 this->setEventsRecordingLevel((int)(kOSBooleanTrue
== b
));
7200 //*********************************************************************************
7201 //*********************************************************************************
7202 //*********************************************************************************
7204 OSDictionary
*IOPMTimeline::copyInfoDictionary(void)
7206 OSDictionary
*out
= OSDictionary::withCapacity(3);
7212 n
= OSNumber::withNumber(hdr
->sizeEntries
, 32);
7213 out
->setObject(kIOPMTimelineSystemNumberTrackedKey
, n
);
7216 n
= OSNumber::withNumber(hdr
->sizeBytes
, 32);
7217 out
->setObject(kIOPMTimelineSystemBufferSizeKey
, n
);
7221 out
->setObject(kIOPMTimelineEnabledKey
, eventsRecordingLevel
? kOSBooleanTrue
: kOSBooleanFalse
);
7226 //*********************************************************************************
7227 //*********************************************************************************
7228 //*********************************************************************************
7230 /* IOPMTimeline::recordSystemPowerEvent()
7232 * Expected "type" arguments are listed in IOPMPrivate.h under enum "SystemEventTypes"
7233 * Type arguments include "system events", and "Intermediate events"
7235 * - System Events have paired "start" and "stop" events.
7236 * - A start event shall be followed by a stop event.
7237 * - Any number of Intermediate Events may fall between the
7238 * start and stop events.
7239 * - Intermediate events are meaningless outside the bounds of a system event's
7240 * start & stoup routines.
7241 * - It's invalid to record a Start event without a following Stop event; e.g. two
7242 * Start events without an intervenining Stop event is invalid.
7245 * - The first recorded system event shall be preceded by an entry with type == 0
7246 * - IOPMTimeline may choose not to record intermediate events while there's not
7247 * a system event in process.
7249 IOReturn
IOPMTimeline::recordSystemPowerEvent( PMEventDetails
*details
)
7251 static bool wakeDonePending
= true;
7252 IOPMSystemEventRecord
*record_to
= NULL
;
7253 OSString
*swUUIDKey
= NULL
;
7254 uint32_t useIndex
= 0;
7257 return kIOReturnBadArgument
;
7260 return kIOReturnNotReady
;
7262 if (details
->eventType
== kIOPMEventTypeWakeDone
)
7264 if(!wakeDonePending
)
7265 return kIOReturnBadArgument
;
7268 IOLockLock(logLock
);
7270 if (details
->eventType
== kIOPMEventTypeWake
) {
7271 wakeDonePending
= true;
7272 } else if (details
->eventType
== kIOPMEventTypeWakeDone
) {
7273 wakeDonePending
= false;
7276 systemState
= details
->eventType
;
7278 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
7280 // The entry immediately after the latest entry (and thus
7281 // immediately before the first entry) shall have a type 0.
7282 if (useIndex
+ 1 >= hdr
->sizeEntries
) {
7283 traceBuffer
[useIndex
+ 1].eventType
= 0;
7285 traceBuffer
[0].eventType
= 0;
7288 record_to
= &traceBuffer
[useIndex
];
7289 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
7292 record_to
->eventType
= details
->eventType
;
7293 record_to
->eventReason
= details
->reason
;
7294 record_to
->eventResult
= details
->result
;
7295 pmEventTimeStamp(&record_to
->timestamp
);
7297 // If caller doesn't provide a UUID, we'll use the UUID that's posted
7298 // on IOPMrootDomain under key kIOPMSleepWakeUUIDKey
7299 if (!details
->uuid
) {
7300 swUUIDKey
= OSDynamicCast(OSString
, owner
->copyProperty(kIOPMSleepWakeUUIDKey
));
7303 details
->uuid
= swUUIDKey
->getCStringNoCopy();
7307 strncpy(record_to
->uuid
, details
->uuid
, kMaxPMStringLength
);
7310 swUUIDKey
->release();
7312 numEventsLoggedThisPeriod
++;
7315 IOLockUnlock(logLock
);
7317 return kIOReturnSuccess
;
7321 //*********************************************************************************
7322 //*********************************************************************************
7323 //*********************************************************************************
7325 IOReturn
IOPMTimeline::recordDetailedPowerEvent( PMEventDetails
*details
)
7327 IOPMSystemEventRecord
*record_to
= NULL
;
7330 if (!details
->eventType
|| !details
->ownerName
)
7331 return kIOReturnBadArgument
;
7333 IOLockLock(logLock
);
7335 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
7337 record_to
= (IOPMSystemEventRecord
*)&traceBuffer
[useIndex
];
7338 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
7341 record_to
->eventType
= details
->eventType
;
7342 if (details
->ownerName
&& (strlen(details
->ownerName
) > 1)) {
7343 strlcpy( record_to
->ownerName
,
7345 sizeof(record_to
->ownerName
));
7348 record_to
->ownerDisambiguateID
= details
->ownerUnique
;
7350 if (details
->interestName
&& (strlen(details
->interestName
) > 1)) {
7351 strlcpy(record_to
->interestName
,
7352 details
->interestName
,
7353 sizeof(record_to
->interestName
));
7356 record_to
->oldState
= details
->oldState
;
7357 record_to
->newState
= details
->newState
;
7358 record_to
->eventResult
= details
->result
;
7359 record_to
->elapsedTimeUS
= details
->elapsedTimeUS
;
7360 pmEventTimeStamp(&record_to
->timestamp
);
7362 numEventsLoggedThisPeriod
++;
7365 IOLockUnlock(logLock
);
7366 return kIOReturnSuccess
;
7369 uint32_t IOPMTimeline::getNumEventsLoggedThisPeriod() {
7370 return this->numEventsLoggedThisPeriod
;
7373 void IOPMTimeline::setNumEventsLoggedThisPeriod(uint32_t newCount
) {
7374 this->numEventsLoggedThisPeriod
= newCount
;
7377 bool IOPMTimeline::isSleepCycleInProgress() {
7378 return this->sleepCycleInProgress
;
7381 void IOPMTimeline::setSleepCycleInProgressFlag(bool flag
) {
7382 this->sleepCycleInProgress
= flag
;
7384 //*********************************************************************************
7385 //*********************************************************************************
7386 //*********************************************************************************
7388 void IOPMTimeline::setEventsTrackedCount(uint32_t newTracked
)
7390 size_t make_buf_size
= 0;
7392 make_buf_size
= sizeof(IOPMTraceBufferHeader
) + (newTracked
* sizeof(IOPMSystemEventRecord
));
7394 IOLockLock(logLock
);
7396 if (pmTraceMemoryDescriptor
) {
7397 pmTraceMemoryDescriptor
->release();
7398 pmTraceMemoryDescriptor
= NULL
;
7404 if (0 == newTracked
)
7406 IOLog("IOPMrootDomain -> erased buffer.\n");
7410 pmTraceMemoryDescriptor
= IOBufferMemoryDescriptor::withOptions(
7411 kIOMemoryKernelUserShared
| kIODirectionIn
, make_buf_size
);
7413 if (!pmTraceMemoryDescriptor
)
7415 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns NULL\n", (int)make_buf_size
);
7419 pmTraceMemoryDescriptor
->prepare(kIODirectionIn
);
7421 // Header occupies the first sizeof(IOPMTraceBufferHeader) bytes
7422 hdr
= (IOPMTraceBufferHeader
*)pmTraceMemoryDescriptor
->getBytesNoCopy();
7424 // Recorded events occupy the remaining bulk of the buffer
7425 traceBuffer
= (IOPMSystemEventRecord
*)((uint8_t *)hdr
+ sizeof(IOPMTraceBufferHeader
));
7427 bzero(hdr
, make_buf_size
);
7429 hdr
->sizeBytes
= make_buf_size
;
7430 hdr
->sizeEntries
= newTracked
;
7432 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns bufferMB with address 0x%08x\n", (int)make_buf_size
, (unsigned int)(uintptr_t)traceBuffer
);
7435 IOLockUnlock(logLock
);
7438 //*********************************************************************************
7439 //*********************************************************************************
7440 //*********************************************************************************
7442 void IOPMTimeline::setEventsRecordingLevel(uint32_t eventsTrackedBits
)
7451 /* static helper to IOPMTimeline
7453 uint32_t IOPMTimeline::_atomicIndexIncrement(uint32_t *index
, uint32_t limit
)
7463 inc_index
= (was_index
+1)%limit
;
7464 } while (!OSCompareAndSwap(was_index
, inc_index
, index
));
7470 // MARK: PMAssertionsTracker
7472 //*********************************************************************************
7473 //*********************************************************************************
7474 //*********************************************************************************
7475 // class PMAssertionsTracker Implementation
7477 #define kAssertUniqueIDStart 500
7479 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
7481 PMAssertionsTracker
*myself
;
7483 myself
= new PMAssertionsTracker
;
7487 myself
->owner
= rootDomain
;
7488 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
7489 myself
->assertionsArray
= OSArray::withCapacity(5);
7490 myself
->assertionsKernel
= 0;
7491 myself
->assertionsUser
= 0;
7492 myself
->assertionsCombined
= 0;
7493 myself
->assertionsArrayLock
= IOLockAlloc();
7494 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
7496 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
7504 * - Update assertionsKernel to reflect the state of all
7505 * assertions in the kernel.
7506 * - Update assertionsCombined to reflect both kernel & user space.
7508 void PMAssertionsTracker::tabulate(void)
7512 PMAssertStruct
*_a
= NULL
;
7515 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
7516 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
7520 assertionsKernel
= 0;
7521 assertionsCombined
= 0;
7523 if (!assertionsArray
)
7526 if ((count
= assertionsArray
->getCount()))
7528 for (i
=0; i
<count
; i
++)
7530 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7533 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
7534 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
7535 assertionsKernel
|= _a
->assertionBits
;
7540 tabulateProducerCount
++;
7541 assertionsCombined
= assertionsKernel
| assertionsUser
;
7543 if ((assertionsKernel
!= oldKernel
) ||
7544 (assertionsCombined
!= oldCombined
))
7546 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
7550 void PMAssertionsTracker::publishProperties( void )
7552 OSArray
*assertionsSummary
= NULL
;
7554 if (tabulateConsumerCount
!= tabulateProducerCount
)
7556 IOLockLock(assertionsArrayLock
);
7558 tabulateConsumerCount
= tabulateProducerCount
;
7560 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
7562 assertionsSummary
= copyAssertionsArray();
7563 if (assertionsSummary
)
7565 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
7566 assertionsSummary
->release();
7570 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
7573 /* Publish the IOPMrootDomain property "DriverPMAssertions"
7575 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
7577 IOLockUnlock(assertionsArrayLock
);
7581 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
7583 PMAssertStruct
*_a
= NULL
;
7590 && (count
= assertionsArray
->getCount()))
7592 for (i
=0; i
<count
; i
++)
7594 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7597 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
7598 if (_a
&& (_id
== _a
->id
)) {
7615 /* PMAssertionsTracker::handleCreateAssertion
7616 * Perform assertion work on the PM workloop. Do not call directly.
7618 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
7624 IOLockLock(assertionsArrayLock
);
7625 assertionsArray
->setObject(newAssertion
);
7626 IOLockUnlock(assertionsArrayLock
);
7627 newAssertion
->release();
7631 return kIOReturnSuccess
;
7634 /* PMAssertionsTracker::createAssertion
7635 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
7638 IOReturn
PMAssertionsTracker::createAssertion(
7639 IOPMDriverAssertionType which
,
7640 IOPMDriverAssertionLevel level
,
7641 IOService
*serviceID
,
7642 const char *whoItIs
,
7643 IOPMDriverAssertionID
*outID
)
7645 OSData
*dataStore
= NULL
;
7646 PMAssertStruct track
;
7648 // Warning: trillions and trillions of created assertions may overflow the unique ID.
7649 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
7650 track
.level
= level
;
7651 track
.assertionBits
= which
;
7652 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
) : 0;
7653 track
.ownerService
= serviceID
;
7654 track
.modifiedTime
= 0;
7655 pmEventTimeStamp(&track
.createdTime
);
7657 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
7660 if (track
.ownerString
)
7661 track
.ownerString
->release();
7662 return kIOReturnNoMemory
;
7667 if (owner
&& owner
->pmPowerStateQueue
) {
7668 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
7671 return kIOReturnSuccess
;
7674 /* PMAssertionsTracker::handleReleaseAssertion
7675 * Runs in PM workloop. Do not call directly.
7677 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
7678 IOPMDriverAssertionID _id
)
7683 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
7686 return kIOReturnNotFound
;
7688 IOLockLock(assertionsArrayLock
);
7689 if (assertStruct
->ownerString
)
7690 assertStruct
->ownerString
->release();
7692 assertionsArray
->removeObject(index
);
7693 IOLockUnlock(assertionsArrayLock
);
7696 return kIOReturnSuccess
;
7699 /* PMAssertionsTracker::releaseAssertion
7700 * Releases an assertion and affects system behavior if appropiate.
7701 * Actual work happens on PM workloop.
7703 IOReturn
PMAssertionsTracker::releaseAssertion(
7704 IOPMDriverAssertionID _id
)
7706 if (owner
&& owner
->pmPowerStateQueue
) {
7707 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
7709 return kIOReturnSuccess
;
7712 /* PMAssertionsTracker::handleSetAssertionLevel
7713 * Runs in PM workloop. Do not call directly.
7715 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
7716 IOPMDriverAssertionID _id
,
7717 IOPMDriverAssertionLevel _level
)
7719 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
7723 if (!assertStruct
) {
7724 return kIOReturnNotFound
;
7727 IOLockLock(assertionsArrayLock
);
7728 pmEventTimeStamp(&assertStruct
->modifiedTime
);
7729 assertStruct
->level
= _level
;
7730 IOLockUnlock(assertionsArrayLock
);
7733 return kIOReturnSuccess
;
7736 /* PMAssertionsTracker::setAssertionLevel
7738 IOReturn
PMAssertionsTracker::setAssertionLevel(
7739 IOPMDriverAssertionID _id
,
7740 IOPMDriverAssertionLevel _level
)
7742 if (owner
&& owner
->pmPowerStateQueue
) {
7743 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
7744 (void *)_level
, _id
);
7747 return kIOReturnSuccess
;
7750 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
7752 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
7756 if (new_user_levels
!= assertionsUser
)
7758 assertionsUser
= new_user_levels
;
7759 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
7763 return kIOReturnSuccess
;
7766 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
7767 IOPMDriverAssertionType new_user_levels
)
7769 if (gIOPMWorkLoop
) {
7770 gIOPMWorkLoop
->runAction(
7771 OSMemberFunctionCast(
7774 &PMAssertionsTracker::handleSetUserAssertionLevels
),
7776 (void *) &new_user_levels
, 0, 0, 0);
7779 return kIOReturnSuccess
;
7783 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
7787 OSArray
*outArray
= NULL
;
7789 if (!assertionsArray
||
7790 (0 == (count
= assertionsArray
->getCount())) ||
7791 (NULL
== (outArray
= OSArray::withCapacity(count
))))
7796 for (i
=0; i
<count
; i
++)
7798 PMAssertStruct
*_a
= NULL
;
7800 OSDictionary
*details
= NULL
;
7802 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7803 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
7805 OSNumber
*_n
= NULL
;
7807 details
= OSDictionary::withCapacity(7);
7811 outArray
->setObject(details
);
7814 _n
= OSNumber::withNumber(_a
->id
, 64);
7816 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
7819 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
7821 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
7824 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
7826 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
7829 _n
= OSNumber::withNumber((uintptr_t)_a
->ownerService
, 64);
7831 details
->setObject(kIOPMDriverAssertionOwnerServiceKey
, _n
);
7834 _n
= OSNumber::withNumber(_a
->level
, 64);
7836 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
7839 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
7841 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
7845 if (_a
->ownerString
) {
7846 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
7855 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
7857 return assertionsCombined
;
7860 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
7861 IOPMDriverAssertionType type
)
7863 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
7865 return kIOPMDriverAssertionLevelOn
;
7867 return kIOPMDriverAssertionLevelOff
;
7871 //*********************************************************************************
7872 //*********************************************************************************
7873 //*********************************************************************************
7876 static void pmEventTimeStamp(uint64_t *recordTS
)
7884 // We assume tsec fits into 32 bits; 32 bits holds enough
7885 // seconds for 136 years since the epoch in 1970.
7886 clock_get_calendar_microtime(&tsec
, &tusec
);
7889 // Pack the sec & microsec calendar time into a uint64_t, for fun.
7891 *recordTS
|= (uint32_t)tusec
;
7892 *recordTS
|= ((uint64_t)tsec
<< 32);
7898 // MARK: IORootParent
7900 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7902 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
7904 // The reason that root domain needs a root parent is to facilitate demand
7905 // sleep, since a power change from the root parent cannot be vetoed.
7907 // The above statement is no longer true since root domain now performs
7908 // demand sleep using overrides. But root parent remains to avoid changing
7909 // the power tree stacking. Root parent is parked at the max power state.
7912 static IOPMPowerState patriarchPowerStates
[2] =
7914 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
7915 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
7918 void IORootParent::initialize( void )
7922 bool IORootParent::start( IOService
* nub
)
7924 IOService::start(nub
);
7925 attachToParent( getRegistryRoot(), gIOPowerPlane
);
7927 registerPowerDriver(this, patriarchPowerStates
, 2);
7932 void IORootParent::shutDownSystem( void )
7936 void IORootParent::restartSystem( void )
7940 void IORootParent::sleepSystem( void )
7944 void IORootParent::dozeSystem( void )
7948 void IORootParent::sleepToDoze( void )
7952 void IORootParent::wakeSystem( void )
7956 OSObject
* IORootParent::copyProperty( const char * aKey
) const
7958 return (IOService::copyProperty(aKey
));